Merged in feat/SW-659-payment-send-query-params (pull request #727)

feat(SW-659): Receive query params from Planet callbacks

* feat(SW-659): read confirmation number from url and update callback url if dev

* fix(SW-659): moved callback url into env variable


Approved-by: Simon.Emanuelsson
This commit is contained in:
Tobias Johansson
2024-10-23 11:51:44 +00:00
parent d2817c5f8c
commit 025c5c8291
5 changed files with 44 additions and 23 deletions

View File

@@ -22,9 +22,11 @@ import type { LangParams, PageArgs } from "@/types/params"
export default async function BookingConfirmationPage({ export default async function BookingConfirmationPage({
params, params,
}: PageArgs<LangParams>) { searchParams,
}: PageArgs<LangParams, { confirmationNumber: string }>) {
const confirmationNumber = searchParams.confirmationNumber
const booking = await serverClient().booking.confirmation({ const booking = await serverClient().booking.confirmation({
confirmationNumber: "991697377", confirmationNumber,
}) })
if (!booking) { if (!booking) {

View File

@@ -1,6 +1,6 @@
import { NextRequest, NextResponse } from "next/server" import { NextRequest, NextResponse } from "next/server"
import { env } from "process"
import { BOOKING_CONFIRMATION_NUMBER } from "@/constants/booking"
import { Lang } from "@/constants/languages" import { Lang } from "@/constants/languages"
import { import {
bookingConfirmation, bookingConfirmation,
@@ -17,14 +17,24 @@ export async function GET(
console.log(`[payment-callback] callback started`) console.log(`[payment-callback] callback started`)
const lang = params.lang as Lang const lang = params.lang as Lang
const status = params.status const status = params.status
const returnUrl = new URL(`${publicURL}/${payment[lang]}`)
if (status === "success") { const queryParams = request.nextUrl.searchParams
const confirmationNumber = queryParams.get(BOOKING_CONFIRMATION_NUMBER)
if (status === "success" && confirmationNumber) {
const confirmationUrl = new URL(`${publicURL}/${bookingConfirmation[lang]}`) const confirmationUrl = new URL(`${publicURL}/${bookingConfirmation[lang]}`)
confirmationUrl.searchParams.set(
BOOKING_CONFIRMATION_NUMBER,
confirmationNumber
)
console.log(`[payment-callback] redirecting to: ${confirmationUrl}`) console.log(`[payment-callback] redirecting to: ${confirmationUrl}`)
return NextResponse.redirect(confirmationUrl) return NextResponse.redirect(confirmationUrl)
} }
const returnUrl = new URL(`${publicURL}/${payment[lang]}`)
returnUrl.search = queryParams.toString()
if (status === "cancel") { if (status === "cancel") {
returnUrl.searchParams.set("cancel", "true") returnUrl.searchParams.set("cancel", "true")
} }

View File

@@ -1,14 +1,13 @@
"use client" "use client"
import { zodResolver } from "@hookform/resolvers/zod" import { zodResolver } from "@hookform/resolvers/zod"
import { useRouter } from "next/navigation" import { useRouter, useSearchParams } from "next/navigation"
import { useEffect, useState } from "react" import { useEffect, useMemo, useState } from "react"
import { Label as AriaLabel } from "react-aria-components" import { Label as AriaLabel } from "react-aria-components"
import { FormProvider, useForm } from "react-hook-form" import { FormProvider, useForm } from "react-hook-form"
import { useIntl } from "react-intl" import { useIntl } from "react-intl"
import { import {
BOOKING_CONFIRMATION_NUMBER,
BookingStatusEnum, BookingStatusEnum,
PAYMENT_METHOD_TITLES, PAYMENT_METHOD_TITLES,
PaymentMethodEnum, PaymentMethodEnum,
@@ -17,7 +16,9 @@ import {
bookingTermsAndConditions, bookingTermsAndConditions,
privacyPolicy, privacyPolicy,
} from "@/constants/currentWebHrefs" } from "@/constants/currentWebHrefs"
import { env } from "@/env/client"
import { trpc } from "@/lib/trpc/client" import { trpc } from "@/lib/trpc/client"
import { useEnterDetailsStore } from "@/stores/enter-details"
import LoadingSpinner from "@/components/LoadingSpinner" import LoadingSpinner from "@/components/LoadingSpinner"
import Button from "@/components/TempDesignSystem/Button" import Button from "@/components/TempDesignSystem/Button"
@@ -51,6 +52,9 @@ export default function Payment({
const router = useRouter() const router = useRouter()
const lang = useLang() const lang = useLang()
const intl = useIntl() const intl = useIntl()
const queryParams = useSearchParams()
const { firstName, lastName, email, phoneNumber, countryCode } =
useEnterDetailsStore((state) => state.data)
const [confirmationNumber, setConfirmationNumber] = useState<string>("") const [confirmationNumber, setConfirmationNumber] = useState<string>("")
const methods = useForm<PaymentFormData>({ const methods = useForm<PaymentFormData>({
@@ -90,14 +94,15 @@ export default function Payment({
) )
useEffect(() => { useEffect(() => {
if (confirmationNumber && bookingStatus?.data?.paymentUrl) { if (bookingStatus?.data?.paymentUrl) {
// Planet doesn't support query params so we have to store values in session storage
sessionStorage.setItem(BOOKING_CONFIRMATION_NUMBER, confirmationNumber)
router.push(bookingStatus.data.paymentUrl) router.push(bookingStatus.data.paymentUrl)
} }
}, [confirmationNumber, bookingStatus, router]) }, [bookingStatus, router])
function handleSubmit(data: PaymentFormData) { function handleSubmit(data: PaymentFormData) {
const allQueryParams =
queryParams.size > 0 ? `?${queryParams.toString()}` : ""
// set payment method to card if saved card is submitted // set payment method to card if saved card is submitted
const paymentMethod = isPaymentMethodEnum(data.paymentMethod) const paymentMethod = isPaymentMethodEnum(data.paymentMethod)
? data.paymentMethod ? data.paymentMethod
@@ -118,13 +123,13 @@ export default function Payment({
rateCode: "SAVEEU", rateCode: "SAVEEU",
roomTypeCode: "QC", roomTypeCode: "QC",
guest: { guest: {
title: "Mr", title: "Mr", // TODO: do we need title?
firstName: "Test", firstName,
lastName: "User", lastName,
email: "test.user@scandichotels.com", email,
phoneCountryCodePrefix: "string", phoneCountryCodePrefix: phoneNumber.slice(0, 3),
phoneNumber: "string", phoneNumber: phoneNumber.slice(3),
countryCode: "string", countryCode,
}, },
packages: { packages: {
breakfast: true, breakfast: true,
@@ -150,9 +155,9 @@ export default function Payment({
phoneCountryCode: "", phoneCountryCode: "",
phoneSubscriber: "", phoneSubscriber: "",
}, },
success: `api/web/payment-callback/${lang}/success`, success: `${env.NEXT_PUBLIC_PAYMENT_CALLBACK_URL}/${lang}/success`,
error: `api/web/payment-callback/${lang}/error`, error: `${env.NEXT_PUBLIC_PAYMENT_CALLBACK_URL}/${lang}/error${allQueryParams}`,
cancel: `api/web/payment-callback/${lang}/cancel`, cancel: `${env.NEXT_PUBLIC_PAYMENT_CALLBACK_URL}/${lang}/cancel${allQueryParams}`,
}, },
}) })
} }

View File

@@ -11,7 +11,7 @@ export enum BedTypeEnum {
Unknown = "Unknown", Unknown = "Unknown",
} }
export const BOOKING_CONFIRMATION_NUMBER = "bookingConfirmationNumber" export const BOOKING_CONFIRMATION_NUMBER = "confirmationNumber"
export enum PaymentMethodEnum { export enum PaymentMethodEnum {
card = "card", card = "card",

4
env/client.ts vendored
View File

@@ -5,10 +5,14 @@ export const env = createEnv({
client: { client: {
NEXT_PUBLIC_NODE_ENV: z.enum(["development", "test", "production"]), NEXT_PUBLIC_NODE_ENV: z.enum(["development", "test", "production"]),
NEXT_PUBLIC_PORT: z.string().default("3000"), NEXT_PUBLIC_PORT: z.string().default("3000"),
NEXT_PUBLIC_PAYMENT_CALLBACK_URL: z
.string()
.default("/api/web/payment-callback"),
}, },
emptyStringAsUndefined: true, emptyStringAsUndefined: true,
runtimeEnv: { runtimeEnv: {
NEXT_PUBLIC_NODE_ENV: process.env.NODE_ENV, NEXT_PUBLIC_NODE_ENV: process.env.NODE_ENV,
NEXT_PUBLIC_PORT: process.env.NEXT_PUBLIC_PORT, NEXT_PUBLIC_PORT: process.env.NEXT_PUBLIC_PORT,
NEXT_PUBLIC_PAYMENT_CALLBACK_URL: `${process.env.NODE_ENV === "development" ? `http://localhost:${process.env.NEXT_PUBLIC_PORT}` : ""}/api/web/payment-callback`,
}, },
}) })