feat: add conditional signup values
This commit is contained in:
67
actions/registerUserBookingFlow.ts
Normal file
67
actions/registerUserBookingFlow.ts
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
"use server"
|
||||||
|
|
||||||
|
import { parsePhoneNumber } from "libphonenumber-js"
|
||||||
|
import { z } from "zod"
|
||||||
|
|
||||||
|
import { serviceServerActionProcedure } from "@/server/trpc"
|
||||||
|
|
||||||
|
import { phoneValidator } from "@/utils/phoneValidator"
|
||||||
|
|
||||||
|
const registerUserPayload = z.object({
|
||||||
|
firstName: z.string(),
|
||||||
|
lastName: z.string(),
|
||||||
|
dateOfBirth: z.string(),
|
||||||
|
address: z.object({
|
||||||
|
countryCode: z.string(),
|
||||||
|
zipCode: z.string(),
|
||||||
|
}),
|
||||||
|
email: z.string(),
|
||||||
|
phoneNumber: phoneValidator("Phone is required"),
|
||||||
|
})
|
||||||
|
|
||||||
|
export const registerUserBookingFlow = serviceServerActionProcedure
|
||||||
|
.input(registerUserPayload)
|
||||||
|
.mutation(async function ({ ctx, input }) {
|
||||||
|
const payload = {
|
||||||
|
...input,
|
||||||
|
language: ctx.lang,
|
||||||
|
phoneNumber: parsePhoneNumber(input.phoneNumber)
|
||||||
|
.formatNational()
|
||||||
|
.replace(/\s+/g, ""),
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Consume the API to register the user as soon as passwordless signup is enabled.
|
||||||
|
// let apiResponse
|
||||||
|
// try {
|
||||||
|
// apiResponse = await api.post(api.endpoints.v1.profile, {
|
||||||
|
// body: payload,
|
||||||
|
// headers: {
|
||||||
|
// Authorization: `Bearer ${ctx.serviceToken}`,
|
||||||
|
// },
|
||||||
|
// })
|
||||||
|
// } catch (error) {
|
||||||
|
// console.error("Unexpected error", error)
|
||||||
|
// return { success: false, error: "Unexpected error" }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if (!apiResponse.ok) {
|
||||||
|
// const text = await apiResponse.text()
|
||||||
|
// console.error(text)
|
||||||
|
// console.error(
|
||||||
|
// "registerUserBookingFlow api error",
|
||||||
|
// JSON.stringify({
|
||||||
|
// query: input,
|
||||||
|
// error: {
|
||||||
|
// status: apiResponse.status,
|
||||||
|
// statusText: apiResponse.statusText,
|
||||||
|
// error: text,
|
||||||
|
// },
|
||||||
|
// })
|
||||||
|
// )
|
||||||
|
// return { success: false, error: "API error" }
|
||||||
|
// }
|
||||||
|
// const json = await apiResponse.json()
|
||||||
|
// console.log("registerUserBookingFlow: json", json)
|
||||||
|
|
||||||
|
return { success: true, data: payload }
|
||||||
|
})
|
||||||
@@ -56,7 +56,7 @@ export default function AdultSelector({ roomIndex = 0 }: AdultSelectorProps) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<section className={styles.container}>
|
<section className={styles.container}>
|
||||||
<Caption color="uiTextHighContrast" textTransform="bold">
|
<Caption color="uiTextHighContrast" type="bold">
|
||||||
{adultsLabel}
|
{adultsLabel}
|
||||||
</Caption>
|
</Caption>
|
||||||
<Counter
|
<Counter
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ export default function ChildSelector({ roomIndex = 0 }: ChildSelectorProps) {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<section className={styles.container}>
|
<section className={styles.container}>
|
||||||
<Caption color="uiTextHighContrast" textTransform="bold">
|
<Caption color="uiTextHighContrast" type="bold">
|
||||||
{childrenLabel}
|
{childrenLabel}
|
||||||
</Caption>
|
</Caption>
|
||||||
<Counter
|
<Counter
|
||||||
|
|||||||
@@ -0,0 +1,97 @@
|
|||||||
|
"use client"
|
||||||
|
|
||||||
|
import { useEffect, useState } from "react"
|
||||||
|
import { useWatch } from "react-hook-form"
|
||||||
|
import { useIntl } from "react-intl"
|
||||||
|
|
||||||
|
import { privacyPolicy } from "@/constants/currentWebHrefs"
|
||||||
|
|
||||||
|
import Checkbox from "@/components/TempDesignSystem/Form/Checkbox"
|
||||||
|
import CheckboxCard from "@/components/TempDesignSystem/Form/ChoiceCard/Checkbox"
|
||||||
|
import DateSelect from "@/components/TempDesignSystem/Form/Date"
|
||||||
|
import Input from "@/components/TempDesignSystem/Form/Input"
|
||||||
|
import Link from "@/components/TempDesignSystem/Link"
|
||||||
|
import Body from "@/components/TempDesignSystem/Text/Body"
|
||||||
|
import Caption from "@/components/TempDesignSystem/Text/Caption"
|
||||||
|
import useLang from "@/hooks/useLang"
|
||||||
|
|
||||||
|
import styles from "./signup.module.css"
|
||||||
|
|
||||||
|
export default function Signup({ name }: { name: string }) {
|
||||||
|
const lang = useLang()
|
||||||
|
const intl = useIntl()
|
||||||
|
|
||||||
|
const [isJoinChecked, setIsJoinChecked] = useState(false)
|
||||||
|
|
||||||
|
const joinValue = useWatch({ name })
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// In order to avoid hydration errors the state needs to be set as side effect,
|
||||||
|
// since the join value can come from search params
|
||||||
|
setIsJoinChecked(joinValue)
|
||||||
|
}, [joinValue])
|
||||||
|
|
||||||
|
const list = [
|
||||||
|
{ title: intl.formatMessage({ id: "Earn bonus nights & points" }) },
|
||||||
|
{ title: intl.formatMessage({ id: "Get member benefits & offers" }) },
|
||||||
|
{ title: intl.formatMessage({ id: "Join at no cost" }) },
|
||||||
|
]
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={styles.container}>
|
||||||
|
<CheckboxCard
|
||||||
|
highlightSubtitle
|
||||||
|
list={list}
|
||||||
|
name={name}
|
||||||
|
subtitle={intl.formatMessage(
|
||||||
|
{
|
||||||
|
id: "{difference}{amount} {currency}",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
amount: "491",
|
||||||
|
currency: "SEK",
|
||||||
|
difference: "-",
|
||||||
|
}
|
||||||
|
)}
|
||||||
|
title={intl.formatMessage({ id: "Join Scandic Friends" })}
|
||||||
|
/>
|
||||||
|
{isJoinChecked ? (
|
||||||
|
<div className={styles.additionalFormData}>
|
||||||
|
<div className={styles.dateField}>
|
||||||
|
<header>
|
||||||
|
<Caption type="bold">
|
||||||
|
{intl.formatMessage({ id: "Birth date" })} *
|
||||||
|
</Caption>
|
||||||
|
</header>
|
||||||
|
<DateSelect
|
||||||
|
name="dateOfBirth"
|
||||||
|
registerOptions={{ required: true }}
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
name="zipCode"
|
||||||
|
label={intl.formatMessage({ id: "Zip code" })}
|
||||||
|
registerOptions={{ required: true }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<Checkbox name="termsAccepted" registerOptions={{ required: true }}>
|
||||||
|
<Body>
|
||||||
|
{intl.formatMessage({
|
||||||
|
id: "Yes, I accept the Terms and conditions for Scandic Friends and understand that Scandic will process my personal data in accordance with",
|
||||||
|
})}{" "}
|
||||||
|
<Link
|
||||||
|
variant="underscored"
|
||||||
|
color="peach80"
|
||||||
|
target="_blank"
|
||||||
|
href={privacyPolicy[lang]}
|
||||||
|
>
|
||||||
|
{intl.formatMessage({ id: "Scandic's Privacy Policy." })}
|
||||||
|
</Link>
|
||||||
|
</Body>
|
||||||
|
</Checkbox>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
.container {
|
||||||
|
display: grid;
|
||||||
|
grid-column: 1/-1;
|
||||||
|
gap: var(--Spacing-x3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.additionalFormData {
|
||||||
|
display: grid;
|
||||||
|
gap: var(--Spacing-x4);
|
||||||
|
}
|
||||||
|
|
||||||
|
.dateField {
|
||||||
|
display: grid;
|
||||||
|
gap: var(--Spacing-x1);
|
||||||
|
}
|
||||||
@@ -6,14 +6,16 @@ import { useIntl } from "react-intl"
|
|||||||
|
|
||||||
import { useEnterDetailsStore } from "@/stores/enter-details"
|
import { useEnterDetailsStore } from "@/stores/enter-details"
|
||||||
|
|
||||||
|
import { registerUserBookingFlow } from "@/actions/registerUserBookingFlow"
|
||||||
import Button from "@/components/TempDesignSystem/Button"
|
import Button from "@/components/TempDesignSystem/Button"
|
||||||
import CheckboxCard from "@/components/TempDesignSystem/Form/ChoiceCard/Checkbox"
|
|
||||||
import CountrySelect from "@/components/TempDesignSystem/Form/Country"
|
import CountrySelect from "@/components/TempDesignSystem/Form/Country"
|
||||||
import Input from "@/components/TempDesignSystem/Form/Input"
|
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 { toast } from "@/components/TempDesignSystem/Toasts"
|
||||||
|
|
||||||
import { detailsSchema, signedInDetailsSchema } from "./schema"
|
import { detailsSchema, signedInDetailsSchema } from "./schema"
|
||||||
|
import Signup from "./Signup"
|
||||||
|
|
||||||
import styles from "./details.module.css"
|
import styles from "./details.module.css"
|
||||||
|
|
||||||
@@ -25,28 +27,30 @@ import type {
|
|||||||
const formID = "enter-details"
|
const formID = "enter-details"
|
||||||
export default function Details({ user }: DetailsProps) {
|
export default function Details({ user }: DetailsProps) {
|
||||||
const intl = useIntl()
|
const intl = useIntl()
|
||||||
|
|
||||||
const list = [
|
|
||||||
{ title: intl.formatMessage({ id: "Earn bonus nights & points" }) },
|
|
||||||
{ title: intl.formatMessage({ id: "Get member benefits & offers" }) },
|
|
||||||
{ title: intl.formatMessage({ id: "Join at no cost" }) },
|
|
||||||
]
|
|
||||||
|
|
||||||
const initialData = useEnterDetailsStore((state) => ({
|
const initialData = useEnterDetailsStore((state) => ({
|
||||||
countryCode: state.data.countryCode,
|
countryCode: state.data.countryCode,
|
||||||
email: state.data.email,
|
email: state.data.email,
|
||||||
firstname: state.data.firstname,
|
firstName: state.data.firstName,
|
||||||
lastname: state.data.lastname,
|
lastName: state.data.lastName,
|
||||||
phoneNumber: state.data.phoneNumber,
|
phoneNumber: state.data.phoneNumber,
|
||||||
|
join: state.data.join,
|
||||||
|
dateOfBirth: state.data.dateOfBirth,
|
||||||
|
zipCode: state.data.zipCode,
|
||||||
|
termsAccepted: state.data.termsAccepted,
|
||||||
}))
|
}))
|
||||||
|
|
||||||
const methods = useForm<DetailsSchema>({
|
const methods = useForm<DetailsSchema>({
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
countryCode: user?.address?.countryCode ?? initialData.countryCode,
|
countryCode: user?.address?.countryCode ?? initialData.countryCode,
|
||||||
email: user?.email ?? initialData.email,
|
email: user?.email ?? initialData.email,
|
||||||
firstname: user?.firstName ?? initialData.firstname,
|
firstName: user?.firstName ?? initialData.firstName,
|
||||||
lastname: user?.lastName ?? initialData.lastname,
|
lastName: user?.lastName ?? initialData.lastName,
|
||||||
phoneNumber: user?.phoneNumber ?? initialData.phoneNumber,
|
phoneNumber: user?.phoneNumber ?? initialData.phoneNumber,
|
||||||
|
//@ts-expect-error: We use a literal for join to be true or false, which does not convert to a boolean
|
||||||
|
join: initialData.join,
|
||||||
|
dateOfBirth: initialData.dateOfBirth,
|
||||||
|
zipCode: initialData.zipCode,
|
||||||
|
termsAccepted: initialData.termsAccepted,
|
||||||
},
|
},
|
||||||
criteriaMode: "all",
|
criteriaMode: "all",
|
||||||
mode: "all",
|
mode: "all",
|
||||||
@@ -56,10 +60,39 @@ export default function Details({ user }: DetailsProps) {
|
|||||||
|
|
||||||
const completeStep = useEnterDetailsStore((state) => state.completeStep)
|
const completeStep = useEnterDetailsStore((state) => state.completeStep)
|
||||||
|
|
||||||
|
// const errorMessage = intl.formatMessage({
|
||||||
|
// id: "An error occurred. Please try again.",
|
||||||
|
// })
|
||||||
|
|
||||||
const onSubmit = useCallback(
|
const onSubmit = useCallback(
|
||||||
(values: DetailsSchema) => {
|
async function (values: DetailsSchema) {
|
||||||
|
if (values.join) {
|
||||||
|
const signupVals = {
|
||||||
|
firstName: values.firstName,
|
||||||
|
lastName: values.lastName,
|
||||||
|
email: values.email,
|
||||||
|
phoneNumber: values.phoneNumber,
|
||||||
|
address: {
|
||||||
|
zipCode: values.zipCode,
|
||||||
|
countryCode: values.countryCode,
|
||||||
|
},
|
||||||
|
dateOfBirth: values.dateOfBirth,
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = await registerUserBookingFlow(signupVals)
|
||||||
|
if (!res.success) {
|
||||||
|
// if (res.error) {
|
||||||
|
// toast.error(res.error)
|
||||||
|
// } else {
|
||||||
|
// toast.error(errorMessage)
|
||||||
|
// }
|
||||||
|
return
|
||||||
|
}
|
||||||
|
console.log("Signed up user: ", res)
|
||||||
|
}
|
||||||
completeStep(values)
|
completeStep(values)
|
||||||
},
|
},
|
||||||
|
|
||||||
[completeStep]
|
[completeStep]
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -77,14 +110,14 @@ export default function Details({ user }: DetailsProps) {
|
|||||||
onSubmit={methods.handleSubmit(onSubmit)}
|
onSubmit={methods.handleSubmit(onSubmit)}
|
||||||
>
|
>
|
||||||
<Input
|
<Input
|
||||||
label={intl.formatMessage({ id: "Firstname" })}
|
label={intl.formatMessage({ id: "First name" })}
|
||||||
name="firstname"
|
name="firstName"
|
||||||
readOnly={!!user}
|
readOnly={!!user}
|
||||||
registerOptions={{ required: true }}
|
registerOptions={{ required: true }}
|
||||||
/>
|
/>
|
||||||
<Input
|
<Input
|
||||||
label={intl.formatMessage({ id: "Lastname" })}
|
label={intl.formatMessage({ id: "Last name" })}
|
||||||
name="lastname"
|
name="lastName"
|
||||||
readOnly={!!user}
|
readOnly={!!user}
|
||||||
registerOptions={{ required: true }}
|
registerOptions={{ required: true }}
|
||||||
/>
|
/>
|
||||||
@@ -109,26 +142,9 @@ export default function Details({ user }: DetailsProps) {
|
|||||||
readOnly={!!user}
|
readOnly={!!user}
|
||||||
registerOptions={{ required: true }}
|
registerOptions={{ required: true }}
|
||||||
/>
|
/>
|
||||||
|
{user ? null : <Signup name="join" />}
|
||||||
</form>
|
</form>
|
||||||
<footer className={styles.footer}>
|
<footer className={styles.footer}>
|
||||||
{user ? null : (
|
|
||||||
<CheckboxCard
|
|
||||||
highlightSubtitle
|
|
||||||
list={list}
|
|
||||||
name="join"
|
|
||||||
subtitle={intl.formatMessage(
|
|
||||||
{
|
|
||||||
id: "{difference}{amount} {currency}",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
amount: "491",
|
|
||||||
currency: "SEK",
|
|
||||||
difference: "-",
|
|
||||||
}
|
|
||||||
)}
|
|
||||||
title={intl.formatMessage({ id: "Join Scandic Friends" })}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
<Button
|
<Button
|
||||||
disabled={!methods.formState.isValid}
|
disabled={!methods.formState.isValid}
|
||||||
form={formID}
|
form={formID}
|
||||||
|
|||||||
@@ -2,18 +2,49 @@ import { z } from "zod"
|
|||||||
|
|
||||||
import { phoneValidator } from "@/utils/phoneValidator"
|
import { phoneValidator } from "@/utils/phoneValidator"
|
||||||
|
|
||||||
export const detailsSchema = z.object({
|
export const baseDetailsSchema = z.object({
|
||||||
countryCode: z.string(),
|
countryCode: z.string(),
|
||||||
email: z.string().email(),
|
email: z.string().email(),
|
||||||
firstname: z.string(),
|
firstName: z.string(),
|
||||||
lastname: z.string(),
|
lastName: z.string(),
|
||||||
phoneNumber: phoneValidator(),
|
phoneNumber: phoneValidator(),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
export const notJoinDetailsSchema = baseDetailsSchema.merge(
|
||||||
|
z.object({
|
||||||
|
join: z.literal(false),
|
||||||
|
zipCode: z.string().optional(),
|
||||||
|
dateOfBirth: z.string().optional(),
|
||||||
|
termsAccepted: z.boolean().default(false),
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
export const joinDetailsSchema = baseDetailsSchema.merge(
|
||||||
|
z.object({
|
||||||
|
join: z.literal(true),
|
||||||
|
zipCode: z.string().min(1, { message: "Zip code is required" }),
|
||||||
|
dateOfBirth: z.string(),
|
||||||
|
termsAccepted: z.literal(true, {
|
||||||
|
errorMap: (err, ctx) => {
|
||||||
|
switch (err.code) {
|
||||||
|
case "invalid_literal":
|
||||||
|
return { message: "You must accept the terms and conditions" }
|
||||||
|
}
|
||||||
|
return { message: ctx.defaultError }
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
export const detailsSchema = z.discriminatedUnion("join", [
|
||||||
|
notJoinDetailsSchema,
|
||||||
|
joinDetailsSchema,
|
||||||
|
])
|
||||||
|
|
||||||
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().email().optional(),
|
||||||
firstname: z.string().optional(),
|
firstName: z.string().optional(),
|
||||||
lastname: z.string().optional(),
|
lastName: z.string().optional(),
|
||||||
phoneNumber: phoneValidator().optional(),
|
phoneNumber: phoneValidator().optional(),
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -20,54 +20,30 @@ export default function SectionAccordion({
|
|||||||
children,
|
children,
|
||||||
}: React.PropsWithChildren<SectionAccordionProps>) {
|
}: React.PropsWithChildren<SectionAccordionProps>) {
|
||||||
const intl = useIntl()
|
const intl = useIntl()
|
||||||
const [isComplete, setIsComplete] = useState(false)
|
|
||||||
const currentStep = useEnterDetailsStore((state) => state.currentStep)
|
const currentStep = useEnterDetailsStore((state) => state.currentStep)
|
||||||
|
const [isComplete, setIsComplete] = useState(false)
|
||||||
|
const [isOpen, setIsOpen] = useState(false)
|
||||||
|
|
||||||
const isValid = useEnterDetailsStore((state) => state.isValid[step])
|
const isValid = useEnterDetailsStore((state) => state.isValid[step])
|
||||||
|
|
||||||
const navigate = useEnterDetailsStore((state) => state.navigate)
|
const navigate = useEnterDetailsStore((state) => state.navigate)
|
||||||
|
|
||||||
const contentRef = useRef<HTMLDivElement>(null)
|
|
||||||
const circleRef = useRef<HTMLDivElement>(null)
|
|
||||||
|
|
||||||
const isOpen = currentStep === step
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const content = contentRef.current
|
|
||||||
const circle = circleRef.current
|
|
||||||
if (content) {
|
|
||||||
if (isOpen) {
|
|
||||||
content.style.maxHeight = `${content.scrollHeight}px`
|
|
||||||
} else {
|
|
||||||
content.style.maxHeight = "0"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (circle) {
|
|
||||||
if (isOpen) {
|
|
||||||
circle.style.backgroundColor = `var(--UI-Text-Placeholder);`
|
|
||||||
} else {
|
|
||||||
circle.style.backgroundColor = `var(--Base-Surface-Subtle-Hover);`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, [isOpen])
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// We need to set the state on mount because of hydration errors
|
// We need to set the state on mount because of hydration errors
|
||||||
setIsComplete(isValid)
|
setIsComplete(isValid)
|
||||||
}, [isValid])
|
}, [isValid])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setIsOpen(currentStep === step)
|
||||||
|
}, [currentStep, step])
|
||||||
|
|
||||||
function onModify() {
|
function onModify() {
|
||||||
navigate(step)
|
navigate(step)
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className={styles.wrapper} data-open={isOpen}>
|
<section className={styles.wrapper} data-open={isOpen} data-step={step}>
|
||||||
<div className={styles.iconWrapper}>
|
<div className={styles.iconWrapper}>
|
||||||
<div
|
<div className={styles.circle} data-checked={isComplete}>
|
||||||
className={styles.circle}
|
|
||||||
data-checked={isComplete}
|
|
||||||
ref={circleRef}
|
|
||||||
>
|
|
||||||
{isComplete ? (
|
{isComplete ? (
|
||||||
<CheckIcon color="white" height="16" width="16" />
|
<CheckIcon color="white" height="16" width="16" />
|
||||||
) : null}
|
) : null}
|
||||||
@@ -79,6 +55,7 @@ export default function SectionAccordion({
|
|||||||
<Footnote
|
<Footnote
|
||||||
asChild
|
asChild
|
||||||
textTransform="uppercase"
|
textTransform="uppercase"
|
||||||
|
type="label"
|
||||||
color="uiTextPlaceholder"
|
color="uiTextPlaceholder"
|
||||||
>
|
>
|
||||||
<h2>{header}</h2>
|
<h2>{header}</h2>
|
||||||
@@ -105,9 +82,7 @@ export default function SectionAccordion({
|
|||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
</header>
|
</header>
|
||||||
<div className={styles.content} ref={contentRef}>
|
<div className={styles.content}>{children}</div>
|
||||||
{children}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -22,12 +22,14 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.main {
|
.main {
|
||||||
display: flex;
|
display: grid;
|
||||||
flex-direction: column;
|
|
||||||
gap: var(--Spacing-x3);
|
gap: var(--Spacing-x3);
|
||||||
width: 100%;
|
width: 100%;
|
||||||
border-bottom: 1px solid var(--Primary-Light-On-Surface-Divider-subtle);
|
border-bottom: 1px solid var(--Primary-Light-On-Surface-Divider-subtle);
|
||||||
padding-bottom: var(--Spacing-x3);
|
padding-bottom: var(--Spacing-x3);
|
||||||
|
|
||||||
|
transition: 0.4s ease-out;
|
||||||
|
grid-template-rows: 2em 0fr;
|
||||||
}
|
}
|
||||||
|
|
||||||
.headerContainer {
|
.headerContainer {
|
||||||
@@ -70,12 +72,23 @@
|
|||||||
background-color: var(--Base-Surface-Subtle-Hover);
|
background-color: var(--Base-Surface-Subtle-Hover);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.wrapper[data-open="true"] .main {
|
||||||
|
grid-template-rows: 2em 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
transition: max-height 0.4s ease-out;
|
}
|
||||||
max-height: 0;
|
|
||||||
|
@keyframes allowOverflow {
|
||||||
|
0% {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
overflow: visible;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.wrapper[data-open="true"] .content {
|
.wrapper[data-open="true"] .content {
|
||||||
max-height: 1000px;
|
animation: allowOverflow 0.4s 0.4s ease;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,8 +20,8 @@ import type { DateProps } from "./date"
|
|||||||
|
|
||||||
export default function DateSelect({ name, registerOptions = {} }: DateProps) {
|
export default function DateSelect({ name, registerOptions = {} }: DateProps) {
|
||||||
const intl = useIntl()
|
const intl = useIntl()
|
||||||
const d = useWatch({ name })
|
const currentValue = useWatch({ name })
|
||||||
const { control, setValue } = useFormContext()
|
const { control, setValue, trigger } = useFormContext()
|
||||||
const { field } = useController({
|
const { field } = useController({
|
||||||
control,
|
control,
|
||||||
name,
|
name,
|
||||||
@@ -47,7 +47,7 @@ export default function DateSelect({ name, registerOptions = {} }: DateProps) {
|
|||||||
}))
|
}))
|
||||||
const years = rangeArray(1900, currentYear - 18)
|
const years = rangeArray(1900, currentYear - 18)
|
||||||
.reverse()
|
.reverse()
|
||||||
.map((year) => ({ value: year, label: `${year}` }))
|
.map((year) => ({ value: year, label: year.toString() }))
|
||||||
|
|
||||||
function createOnSelect(selector: DateName) {
|
function createOnSelect(selector: DateName) {
|
||||||
/**
|
/**
|
||||||
@@ -68,6 +68,8 @@ export default function DateSelect({ name, registerOptions = {} }: DateProps) {
|
|||||||
const month = selector === DateName.month ? value : newSegments.month
|
const month = selector === DateName.month ? value : newSegments.month
|
||||||
if (year !== null && month !== null) {
|
if (year !== null && month !== null) {
|
||||||
newSegments.daysInMonth = dt().year(year).month(month).daysInMonth()
|
newSegments.daysInMonth = dt().year(year).month(month).daysInMonth()
|
||||||
|
} else if (month !== null) {
|
||||||
|
newSegments.daysInMonth = dt().month(month).daysInMonth()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,6 +81,7 @@ export default function DateSelect({ name, registerOptions = {} }: DateProps) {
|
|||||||
.set("date", Math.min(newSegments.date!, newSegments.daysInMonth))
|
.set("date", Math.min(newSegments.date!, newSegments.daysInMonth))
|
||||||
|
|
||||||
setValue(name, newDate.format("YYYY-MM-DD"))
|
setValue(name, newDate.format("YYYY-MM-DD"))
|
||||||
|
trigger(name)
|
||||||
}
|
}
|
||||||
setDateSegment(newSegments)
|
setDateSegment(newSegments)
|
||||||
}
|
}
|
||||||
@@ -95,9 +98,9 @@ export default function DateSelect({ name, registerOptions = {} }: DateProps) {
|
|||||||
* date, but we can't check isNan since
|
* date, but we can't check isNan since
|
||||||
* we recieve the date as "1999-01-01"
|
* we recieve the date as "1999-01-01"
|
||||||
*/
|
*/
|
||||||
dateValue = dt(d).isValid() ? parseDate(d) : null
|
dateValue = dt(currentValue).isValid() ? parseDate(currentValue) : null
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error)
|
console.warn("Known error for parse date in DateSelect: ", error)
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -133,6 +136,7 @@ export default function DateSelect({ name, registerOptions = {} }: DateProps) {
|
|||||||
defaultSelectedKey={
|
defaultSelectedKey={
|
||||||
segment.isPlaceholder ? undefined : segment.value
|
segment.isPlaceholder ? undefined : segment.value
|
||||||
}
|
}
|
||||||
|
value={segment.isPlaceholder ? undefined : segment.value}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
@@ -151,6 +155,7 @@ export default function DateSelect({ name, registerOptions = {} }: DateProps) {
|
|||||||
defaultSelectedKey={
|
defaultSelectedKey={
|
||||||
segment.isPlaceholder ? undefined : segment.value
|
segment.isPlaceholder ? undefined : segment.value
|
||||||
}
|
}
|
||||||
|
value={segment.isPlaceholder ? undefined : segment.value}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
@@ -169,6 +174,7 @@ export default function DateSelect({ name, registerOptions = {} }: DateProps) {
|
|||||||
defaultSelectedKey={
|
defaultSelectedKey={
|
||||||
segment.isPlaceholder ? undefined : segment.value
|
segment.isPlaceholder ? undefined : segment.value
|
||||||
}
|
}
|
||||||
|
value={segment.isPlaceholder ? undefined : segment.value}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
"Already a friend?": "Allerede en ven?",
|
"Already a friend?": "Allerede en ven?",
|
||||||
"Amenities": "Faciliteter",
|
"Amenities": "Faciliteter",
|
||||||
"Amusement park": "Forlystelsespark",
|
"Amusement park": "Forlystelsespark",
|
||||||
|
"An error occurred. Please try again.": "Der opstod en fejl. Prøv venligst igen.",
|
||||||
"An error occurred trying to manage your preferences, please try again later.": "Der opstod en fejl under forsøget på at administrere dine præferencer. Prøv venligst igen senere.",
|
"An error occurred trying to manage your preferences, please try again later.": "Der opstod en fejl under forsøget på at administrere dine præferencer. Prøv venligst igen senere.",
|
||||||
"An error occurred when adding a credit card, please try again later.": "Der opstod en fejl under tilføjelse af et kreditkort. Prøv venligst igen senere.",
|
"An error occurred when adding a credit card, please try again later.": "Der opstod en fejl under tilføjelse af et kreditkort. Prøv venligst igen senere.",
|
||||||
"An error occurred when trying to update profile.": "Der opstod en fejl under forsøg på at opdatere profilen.",
|
"An error occurred when trying to update profile.": "Der opstod en fejl under forsøg på at opdatere profilen.",
|
||||||
@@ -105,7 +106,7 @@
|
|||||||
"Fair": "Messe",
|
"Fair": "Messe",
|
||||||
"Find booking": "Find booking",
|
"Find booking": "Find booking",
|
||||||
"Find hotels": "Find hotel",
|
"Find hotels": "Find hotel",
|
||||||
"Firstname": "Fornavn",
|
"First name": "Fornavn",
|
||||||
"Flexibility": "Fleksibilitet",
|
"Flexibility": "Fleksibilitet",
|
||||||
"Follow us": "Følg os",
|
"Follow us": "Følg os",
|
||||||
"Former Scandic Hotel": "Tidligere Scandic Hotel",
|
"Former Scandic Hotel": "Tidligere Scandic Hotel",
|
||||||
@@ -138,7 +139,7 @@
|
|||||||
"Join at no cost": "Tilmeld dig uden omkostninger",
|
"Join at no cost": "Tilmeld dig uden omkostninger",
|
||||||
"King bed": "Kingsize-seng",
|
"King bed": "Kingsize-seng",
|
||||||
"Language": "Sprog",
|
"Language": "Sprog",
|
||||||
"Lastname": "Efternavn",
|
"Last name": "Efternavn",
|
||||||
"Latest searches": "Seneste søgninger",
|
"Latest searches": "Seneste søgninger",
|
||||||
"Left": "tilbage",
|
"Left": "tilbage",
|
||||||
"Level": "Niveau",
|
"Level": "Niveau",
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
"Already a friend?": "Sind wir schon Freunde?",
|
"Already a friend?": "Sind wir schon Freunde?",
|
||||||
"Amenities": "Annehmlichkeiten",
|
"Amenities": "Annehmlichkeiten",
|
||||||
"Amusement park": "Vergnügungspark",
|
"Amusement park": "Vergnügungspark",
|
||||||
|
"An error occurred. Please try again.": "Es ist ein Fehler aufgetreten. Bitte versuchen Sie es erneut.",
|
||||||
"An error occurred trying to manage your preferences, please try again later.": "Beim Versuch, Ihre Einstellungen zu verwalten, ist ein Fehler aufgetreten. Bitte versuchen Sie es später erneut.",
|
"An error occurred trying to manage your preferences, please try again later.": "Beim Versuch, Ihre Einstellungen zu verwalten, ist ein Fehler aufgetreten. Bitte versuchen Sie es später erneut.",
|
||||||
"An error occurred when adding a credit card, please try again later.": "Beim Hinzufügen einer Kreditkarte ist ein Fehler aufgetreten. Bitte versuchen Sie es später erneut.",
|
"An error occurred when adding a credit card, please try again later.": "Beim Hinzufügen einer Kreditkarte ist ein Fehler aufgetreten. Bitte versuchen Sie es später erneut.",
|
||||||
"An error occurred when trying to update profile.": "Beim Versuch, das Profil zu aktualisieren, ist ein Fehler aufgetreten.",
|
"An error occurred when trying to update profile.": "Beim Versuch, das Profil zu aktualisieren, ist ein Fehler aufgetreten.",
|
||||||
@@ -105,7 +106,7 @@
|
|||||||
"Fair": "Messe",
|
"Fair": "Messe",
|
||||||
"Find booking": "Buchung finden",
|
"Find booking": "Buchung finden",
|
||||||
"Find hotels": "Hotels finden",
|
"Find hotels": "Hotels finden",
|
||||||
"Firstname": "Vorname",
|
"First name": "Vorname",
|
||||||
"Flexibility": "Flexibilität",
|
"Flexibility": "Flexibilität",
|
||||||
"Follow us": "Folgen Sie uns",
|
"Follow us": "Folgen Sie uns",
|
||||||
"Former Scandic Hotel": "Ehemaliges Scandic Hotel",
|
"Former Scandic Hotel": "Ehemaliges Scandic Hotel",
|
||||||
@@ -138,7 +139,7 @@
|
|||||||
"Join at no cost": "Kostenlos beitreten",
|
"Join at no cost": "Kostenlos beitreten",
|
||||||
"King bed": "Kingsize-Bett",
|
"King bed": "Kingsize-Bett",
|
||||||
"Language": "Sprache",
|
"Language": "Sprache",
|
||||||
"Lastname": "Nachname",
|
"Last name": "Nachname",
|
||||||
"Latest searches": "Letzte Suchanfragen",
|
"Latest searches": "Letzte Suchanfragen",
|
||||||
"Left": "übrig",
|
"Left": "übrig",
|
||||||
"Level": "Level",
|
"Level": "Level",
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
"Already a friend?": "Already a friend?",
|
"Already a friend?": "Already a friend?",
|
||||||
"Amenities": "Amenities",
|
"Amenities": "Amenities",
|
||||||
"Amusement park": "Amusement park",
|
"Amusement park": "Amusement park",
|
||||||
|
"An error occurred. Please try again.": "An error occurred. Please try again.",
|
||||||
"An error occurred trying to manage your preferences, please try again later.": "An error occurred trying to manage your preferences, please try again later.",
|
"An error occurred trying to manage your preferences, please try again later.": "An error occurred trying to manage your preferences, please try again later.",
|
||||||
"An error occurred when adding a credit card, please try again later.": "An error occurred when adding a credit card, please try again later.",
|
"An error occurred when adding a credit card, please try again later.": "An error occurred when adding a credit card, please try again later.",
|
||||||
"An error occurred when trying to update profile.": "An error occurred when trying to update profile.",
|
"An error occurred when trying to update profile.": "An error occurred when trying to update profile.",
|
||||||
@@ -108,7 +109,7 @@
|
|||||||
"Fair": "Fair",
|
"Fair": "Fair",
|
||||||
"Find booking": "Find booking",
|
"Find booking": "Find booking",
|
||||||
"Find hotels": "Find hotels",
|
"Find hotels": "Find hotels",
|
||||||
"Firstname": "Firstname",
|
"First name": "First name",
|
||||||
"Flexibility": "Flexibility",
|
"Flexibility": "Flexibility",
|
||||||
"Follow us": "Follow us",
|
"Follow us": "Follow us",
|
||||||
"Former Scandic Hotel": "Former Scandic Hotel",
|
"Former Scandic Hotel": "Former Scandic Hotel",
|
||||||
@@ -141,7 +142,7 @@
|
|||||||
"Join at no cost": "Join at no cost",
|
"Join at no cost": "Join at no cost",
|
||||||
"King bed": "King bed",
|
"King bed": "King bed",
|
||||||
"Language": "Language",
|
"Language": "Language",
|
||||||
"Lastname": "Lastname",
|
"Last name": "Last name",
|
||||||
"Latest searches": "Latest searches",
|
"Latest searches": "Latest searches",
|
||||||
"Left": "left",
|
"Left": "left",
|
||||||
"Level": "Level",
|
"Level": "Level",
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
"Already a friend?": "Oletko jo ystävä?",
|
"Already a friend?": "Oletko jo ystävä?",
|
||||||
"Amenities": "Mukavuudet",
|
"Amenities": "Mukavuudet",
|
||||||
"Amusement park": "Huvipuisto",
|
"Amusement park": "Huvipuisto",
|
||||||
|
"An error occurred. Please try again.": "Tapahtui virhe. Yritä uudelleen.",
|
||||||
"An error occurred trying to manage your preferences, please try again later.": "Asetusten hallinnassa tapahtui virhe. Yritä myöhemmin uudelleen.",
|
"An error occurred trying to manage your preferences, please try again later.": "Asetusten hallinnassa tapahtui virhe. Yritä myöhemmin uudelleen.",
|
||||||
"An error occurred when adding a credit card, please try again later.": "Luottokorttia lisättäessä tapahtui virhe. Yritä myöhemmin uudelleen.",
|
"An error occurred when adding a credit card, please try again later.": "Luottokorttia lisättäessä tapahtui virhe. Yritä myöhemmin uudelleen.",
|
||||||
"An error occurred when trying to update profile.": "Profiilia päivitettäessä tapahtui virhe.",
|
"An error occurred when trying to update profile.": "Profiilia päivitettäessä tapahtui virhe.",
|
||||||
@@ -105,7 +106,7 @@
|
|||||||
"Fair": "Messukeskus",
|
"Fair": "Messukeskus",
|
||||||
"Find booking": "Etsi varaus",
|
"Find booking": "Etsi varaus",
|
||||||
"Find hotels": "Etsi hotelleja",
|
"Find hotels": "Etsi hotelleja",
|
||||||
"Firstname": "Etunimi",
|
"First name": "Etunimi",
|
||||||
"Flexibility": "Joustavuus",
|
"Flexibility": "Joustavuus",
|
||||||
"Follow us": "Seuraa meitä",
|
"Follow us": "Seuraa meitä",
|
||||||
"Former Scandic Hotel": "Entinen Scandic-hotelli",
|
"Former Scandic Hotel": "Entinen Scandic-hotelli",
|
||||||
@@ -138,7 +139,7 @@
|
|||||||
"Join at no cost": "Liity maksutta",
|
"Join at no cost": "Liity maksutta",
|
||||||
"King bed": "King-vuode",
|
"King bed": "King-vuode",
|
||||||
"Language": "Kieli",
|
"Language": "Kieli",
|
||||||
"Lastname": "Sukunimi",
|
"Last name": "Sukunimi",
|
||||||
"Latest searches": "Viimeisimmät haut",
|
"Latest searches": "Viimeisimmät haut",
|
||||||
"Left": "jäljellä",
|
"Left": "jäljellä",
|
||||||
"Level": "Level",
|
"Level": "Level",
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
"Already a friend?": "Allerede Friend?",
|
"Already a friend?": "Allerede Friend?",
|
||||||
"Amenities": "Fasiliteter",
|
"Amenities": "Fasiliteter",
|
||||||
"Amusement park": "Tivoli",
|
"Amusement park": "Tivoli",
|
||||||
|
"An error occurred. Please try again.": "Det oppsto en feil. Vennligst prøv igjen.",
|
||||||
"An error occurred trying to manage your preferences, please try again later.": "Det oppstod en feil under forsøket på å administrere innstillingene dine. Prøv igjen senere.",
|
"An error occurred trying to manage your preferences, please try again later.": "Det oppstod en feil under forsøket på å administrere innstillingene dine. Prøv igjen senere.",
|
||||||
"An error occurred when adding a credit card, please try again later.": "Det oppstod en feil ved å legge til et kredittkort. Prøv igjen senere.",
|
"An error occurred when adding a credit card, please try again later.": "Det oppstod en feil ved å legge til et kredittkort. Prøv igjen senere.",
|
||||||
"An error occurred when trying to update profile.": "Det oppstod en feil under forsøk på å oppdatere profilen.",
|
"An error occurred when trying to update profile.": "Det oppstod en feil under forsøk på å oppdatere profilen.",
|
||||||
@@ -104,7 +105,7 @@
|
|||||||
"Fair": "Messe",
|
"Fair": "Messe",
|
||||||
"Find booking": "Finn booking",
|
"Find booking": "Finn booking",
|
||||||
"Find hotels": "Finn hotell",
|
"Find hotels": "Finn hotell",
|
||||||
"Firstname": "Fornavn",
|
"First name": "Fornavn",
|
||||||
"Flexibility": "Fleksibilitet",
|
"Flexibility": "Fleksibilitet",
|
||||||
"Follow us": "Følg oss",
|
"Follow us": "Følg oss",
|
||||||
"Former Scandic Hotel": "Tidligere Scandic-hotell",
|
"Former Scandic Hotel": "Tidligere Scandic-hotell",
|
||||||
@@ -136,7 +137,7 @@
|
|||||||
"Join at no cost": "Bli med uten kostnad",
|
"Join at no cost": "Bli med uten kostnad",
|
||||||
"King bed": "King-size-seng",
|
"King bed": "King-size-seng",
|
||||||
"Language": "Språk",
|
"Language": "Språk",
|
||||||
"Lastname": "Etternavn",
|
"Last name": "Etternavn",
|
||||||
"Latest searches": "Siste søk",
|
"Latest searches": "Siste søk",
|
||||||
"Left": "igjen",
|
"Left": "igjen",
|
||||||
"Level": "Nivå",
|
"Level": "Nivå",
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
"Already a friend?": "Är du redan en vän?",
|
"Already a friend?": "Är du redan en vän?",
|
||||||
"Amenities": "Bekvämligheter",
|
"Amenities": "Bekvämligheter",
|
||||||
"Amusement park": "Nöjespark",
|
"Amusement park": "Nöjespark",
|
||||||
|
"An error occurred. Please try again.": "Ett fel uppstod. Försök igen.",
|
||||||
"An error occurred trying to manage your preferences, please try again later.": "Ett fel uppstod när du försökte hantera dina inställningar, försök igen senare.",
|
"An error occurred trying to manage your preferences, please try again later.": "Ett fel uppstod när du försökte hantera dina inställningar, försök igen senare.",
|
||||||
"An error occurred when adding a credit card, please try again later.": "Ett fel uppstod när ett kreditkort lades till, försök igen senare.",
|
"An error occurred when adding a credit card, please try again later.": "Ett fel uppstod när ett kreditkort lades till, försök igen senare.",
|
||||||
"An error occurred when trying to update profile.": "Ett fel uppstod när du försökte uppdatera profilen.",
|
"An error occurred when trying to update profile.": "Ett fel uppstod när du försökte uppdatera profilen.",
|
||||||
@@ -104,7 +105,7 @@
|
|||||||
"Fair": "Mässa",
|
"Fair": "Mässa",
|
||||||
"Find booking": "Hitta bokning",
|
"Find booking": "Hitta bokning",
|
||||||
"Find hotels": "Hitta hotell",
|
"Find hotels": "Hitta hotell",
|
||||||
"Firstname": "Förnamn",
|
"First name": "Förnamn",
|
||||||
"Flexibility": "Flexibilitet",
|
"Flexibility": "Flexibilitet",
|
||||||
"Follow us": "Följ oss",
|
"Follow us": "Följ oss",
|
||||||
"Former Scandic Hotel": "Tidigare Scandichotell",
|
"Former Scandic Hotel": "Tidigare Scandichotell",
|
||||||
@@ -136,7 +137,7 @@
|
|||||||
"Join at no cost": "Gå med utan kostnad",
|
"Join at no cost": "Gå med utan kostnad",
|
||||||
"King bed": "King size-säng",
|
"King bed": "King size-säng",
|
||||||
"Language": "Språk",
|
"Language": "Språk",
|
||||||
"Lastname": "Efternamn",
|
"Last name": "Efternamn",
|
||||||
"Latest searches": "Senaste sökningarna",
|
"Latest searches": "Senaste sökningarna",
|
||||||
"Left": "kvar",
|
"Left": "kvar",
|
||||||
"Level": "Nivå",
|
"Level": "Nivå",
|
||||||
|
|||||||
@@ -22,7 +22,10 @@ interface EnterDetailsState {
|
|||||||
activeSidePeek: SidePeekEnum | null
|
activeSidePeek: SidePeekEnum | null
|
||||||
isValid: Record<StepEnum, boolean>
|
isValid: Record<StepEnum, boolean>
|
||||||
completeStep: (updatedData: Partial<EnterDetailsState["data"]>) => void
|
completeStep: (updatedData: Partial<EnterDetailsState["data"]>) => void
|
||||||
navigate: (step: StepEnum, searchParams?: Record<string, string>) => void
|
navigate: (
|
||||||
|
step: StepEnum,
|
||||||
|
searchParams?: Record<string, string | boolean>
|
||||||
|
) => void
|
||||||
openSidePeek: (key: SidePeekEnum | null) => void
|
openSidePeek: (key: SidePeekEnum | null) => void
|
||||||
closeSidePeek: () => void
|
closeSidePeek: () => void
|
||||||
}
|
}
|
||||||
@@ -37,26 +40,34 @@ export function initEditDetailsState(currentStep: StepEnum) {
|
|||||||
breakfast: undefined,
|
breakfast: undefined,
|
||||||
countryCode: "",
|
countryCode: "",
|
||||||
email: "",
|
email: "",
|
||||||
firstname: "",
|
firstName: "",
|
||||||
lastname: "",
|
lastName: "",
|
||||||
phoneNumber: "",
|
phoneNumber: "",
|
||||||
|
join: false,
|
||||||
|
zipCode: "",
|
||||||
|
dateOfBirth: undefined,
|
||||||
|
termsAccepted: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
let inputData = {}
|
let inputData = {}
|
||||||
if (search?.size) {
|
if (search?.size) {
|
||||||
const searchParams: Record<string, string> = {}
|
const searchParams: Record<string, string | boolean> = {}
|
||||||
search.forEach((value, key) => {
|
search.forEach((value, key) => {
|
||||||
searchParams[key] = value
|
// Handle boolean values
|
||||||
|
|
||||||
|
if (value === "true" || value === "false") {
|
||||||
|
searchParams[key] = JSON.parse(value) as true | false
|
||||||
|
} else {
|
||||||
|
searchParams[key] = value
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
inputData = searchParams
|
inputData = searchParams
|
||||||
} else if (sessionData) {
|
|
||||||
inputData = JSON.parse(sessionData)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const validPaths = [StepEnum.selectBed]
|
const validPaths = [StepEnum.selectBed]
|
||||||
|
|
||||||
let initialData = defaultData
|
let initialData: EnterDetailsState["data"] = defaultData
|
||||||
|
|
||||||
const isValid = {
|
const isValid = {
|
||||||
[StepEnum.selectBed]: false,
|
[StepEnum.selectBed]: false,
|
||||||
@@ -100,7 +111,7 @@ export function initEditDetailsState(currentStep: StepEnum) {
|
|||||||
const query = new URLSearchParams(window.location.search)
|
const query = new URLSearchParams(window.location.search)
|
||||||
if (searchParams) {
|
if (searchParams) {
|
||||||
Object.entries(searchParams).forEach(([key, value]) => {
|
Object.entries(searchParams).forEach(([key, value]) => {
|
||||||
query.set(key, value)
|
query.set(key, value ? value.toString() : "")
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { detailsSchema } from "@/components/HotelReservation/EnterDetails/Detail
|
|||||||
|
|
||||||
import type { SafeUser } from "@/types/user"
|
import type { SafeUser } from "@/types/user"
|
||||||
|
|
||||||
export interface DetailsSchema extends z.output<typeof detailsSchema> {}
|
export type DetailsSchema = z.output<typeof detailsSchema>
|
||||||
|
|
||||||
export interface DetailsProps {
|
export interface DetailsProps {
|
||||||
user: SafeUser
|
user: SafeUser
|
||||||
|
|||||||
Reference in New Issue
Block a user