fix: validate member in enter details store

This commit is contained in:
Christel Westerberg
2024-11-01 15:10:42 +01:00
parent ccca27d2e6
commit 3e41703df1
7 changed files with 31 additions and 14 deletions

View File

@@ -1,3 +1,5 @@
import { getProfileSafely } from "@/lib/trpc/memoizedRequests"
import EnterDetailsProvider from "@/components/HotelReservation/EnterDetails/Provider" import EnterDetailsProvider from "@/components/HotelReservation/EnterDetails/Provider"
import SelectedRoom from "@/components/HotelReservation/EnterDetails/SelectedRoom" import SelectedRoom from "@/components/HotelReservation/EnterDetails/SelectedRoom"
import { setLang } from "@/i18n/serverContext" import { setLang } from "@/i18n/serverContext"
@@ -20,11 +22,15 @@ export default async function StepLayout({
hotelHeader: React.ReactNode hotelHeader: React.ReactNode
sidePeek: React.ReactNode sidePeek: React.ReactNode
summary: React.ReactNode summary: React.ReactNode
}>) { }
>) {
setLang(params.lang) setLang(params.lang)
preload() preload()
const user = await getProfileSafely()
return ( return (
<EnterDetailsProvider step={params.step} > <EnterDetailsProvider step={params.step} isMember={!!user}>
<main className={styles.layout}> <main className={styles.layout}>
{hotelHeader} {hotelHeader}
<div className={styles.content}> <div className={styles.content}>

View File

@@ -13,7 +13,7 @@ import Input from "@/components/TempDesignSystem/Form/Input"
import Phone from "@/components/TempDesignSystem/Form/Phone" import Phone from "@/components/TempDesignSystem/Form/Phone"
import Body from "@/components/TempDesignSystem/Text/Body" import Body from "@/components/TempDesignSystem/Text/Body"
import { detailsSchema, signedInDetailsSchema } from "./schema" import { guestDetailsSchema, signedInDetailsSchema } from "./schema"
import Signup from "./Signup" import Signup from "./Signup"
import styles from "./details.module.css" import styles from "./details.module.css"
@@ -53,7 +53,7 @@ export default function Details({ user }: DetailsProps) {
}, },
criteriaMode: "all", criteriaMode: "all",
mode: "all", mode: "all",
resolver: zodResolver(user ? signedInDetailsSchema : detailsSchema), resolver: zodResolver(user ? signedInDetailsSchema : guestDetailsSchema),
reValidateMode: "onChange", reValidateMode: "onChange",
}) })

View File

@@ -36,15 +36,17 @@ export const joinDetailsSchema = baseDetailsSchema.merge(
}) })
) )
export const detailsSchema = z.discriminatedUnion("join", [ export const guestDetailsSchema = z.discriminatedUnion("join", [
notJoinDetailsSchema, notJoinDetailsSchema,
joinDetailsSchema, joinDetailsSchema,
]) ])
// For signed in users we accept partial or invalid data. Users cannot
// change their info in this flow, so we don't want to validate it.
export const signedInDetailsSchema = z.object({ export const signedInDetailsSchema = z.object({
countryCode: z.string().optional(), countryCode: z.string().optional(),
email: z.string().email().optional(), email: z.string().optional(),
firstName: z.string().optional(), firstName: z.string().optional(),
lastName: z.string().optional(), lastName: z.string().optional(),
phoneNumber: phoneValidator().optional(), phoneNumber: z.string().optional(),
}) })

View File

@@ -8,16 +8,17 @@ import {
initEditDetailsState, initEditDetailsState,
} from "@/stores/enter-details" } from "@/stores/enter-details"
import { StepEnum } from "@/types/components/hotelReservation/enterDetails/step" import { EnterDetailsProviderProps } from "@/types/components/hotelReservation/enterDetails/store"
export default function EnterDetailsProvider({ export default function EnterDetailsProvider({
step, step,
isMember,
children, children,
}: PropsWithChildren<{ step: StepEnum }>) { }: PropsWithChildren<EnterDetailsProviderProps>) {
const searchParams = useSearchParams() const searchParams = useSearchParams()
const initialStore = useRef<EnterDetailsStore>() const initialStore = useRef<EnterDetailsStore>()
if (!initialStore.current) { if (!initialStore.current) {
initialStore.current = initEditDetailsState(step, searchParams) initialStore.current = initEditDetailsState(step, searchParams, isMember)
} }
return ( return (

View File

@@ -5,7 +5,10 @@ import { create, useStore } from "zustand"
import { bedTypeSchema } from "@/components/HotelReservation/EnterDetails/BedType/schema" import { bedTypeSchema } from "@/components/HotelReservation/EnterDetails/BedType/schema"
import { breakfastStoreSchema } from "@/components/HotelReservation/EnterDetails/Breakfast/schema" import { breakfastStoreSchema } from "@/components/HotelReservation/EnterDetails/Breakfast/schema"
import { detailsSchema } from "@/components/HotelReservation/EnterDetails/Details/schema" import {
guestDetailsSchema,
signedInDetailsSchema,
} from "@/components/HotelReservation/EnterDetails/Details/schema"
import { getQueryParamsForEnterDetails } from "@/components/HotelReservation/SelectRate/RoomSelection/utils" import { getQueryParamsForEnterDetails } from "@/components/HotelReservation/SelectRate/RoomSelection/utils"
import type { BookingData } from "@/types/components/hotelReservation/enterDetails/bookingData" import type { BookingData } from "@/types/components/hotelReservation/enterDetails/bookingData"
@@ -39,7 +42,8 @@ interface EnterDetailsState {
export function initEditDetailsState( export function initEditDetailsState(
currentStep: StepEnum, currentStep: StepEnum,
searchParams: ReadonlyURLSearchParams searchParams: ReadonlyURLSearchParams,
isMember: boolean
) { ) {
const isBrowser = typeof window !== "undefined" const isBrowser = typeof window !== "undefined"
const sessionData = isBrowser const sessionData = isBrowser
@@ -93,6 +97,7 @@ export function initEditDetailsState(
initialData = { ...initialData, ...validatedBreakfast.data } initialData = { ...initialData, ...validatedBreakfast.data }
isValid[StepEnum.breakfast] = true isValid[StepEnum.breakfast] = true
} }
const detailsSchema = isMember ? signedInDetailsSchema : guestDetailsSchema
const validatedDetails = detailsSchema.safeParse(inputUserData) const validatedDetails = detailsSchema.safeParse(inputUserData)
if (validatedDetails.success) { if (validatedDetails.success) {
validPaths.push(StepEnum.payment) validPaths.push(StepEnum.payment)

View File

@@ -1,10 +1,10 @@
import { z } from "zod" import { z } from "zod"
import { detailsSchema } from "@/components/HotelReservation/EnterDetails/Details/schema" import { guestDetailsSchema } from "@/components/HotelReservation/EnterDetails/Details/schema"
import type { SafeUser } from "@/types/user" import type { SafeUser } from "@/types/user"
export type DetailsSchema = z.output<typeof detailsSchema> export type DetailsSchema = z.output<typeof guestDetailsSchema>
export interface DetailsProps { export interface DetailsProps {
user: SafeUser user: SafeUser

View File

@@ -0,0 +1,3 @@
import { StepEnum } from "./step"
export type EnterDetailsProviderProps = { step: StepEnum; isMember: boolean }