feat(SW-1773): add proper validation to form and query

This commit is contained in:
Christian Andolf
2025-02-27 16:28:58 +01:00
parent 21255f8557
commit c98ac88ac0
12 changed files with 74 additions and 26 deletions

View File

@@ -14,6 +14,7 @@ import Link from "@/components/TempDesignSystem/Link"
import Body from "@/components/TempDesignSystem/Text/Body"
import Caption from "@/components/TempDesignSystem/Text/Caption"
import Title from "@/components/TempDesignSystem/Text/Title"
import { toast } from "@/components/TempDesignSystem/Toasts"
import useLang from "@/hooks/useLang"
import { type FindMyBookingFormSchema, findMyBookingFormSchema } from "./schema"
@@ -25,12 +26,6 @@ export default function Form() {
const intl = useIntl()
const lang = useLang()
const form = useForm<FindMyBookingFormSchema>({
defaultValues: {
reservationNumber: "",
firstName: "",
lastName: "",
email: "",
},
resolver: zodResolver(findMyBookingFormSchema),
mode: "all",
criteriaMode: "all",
@@ -39,23 +34,30 @@ export default function Form() {
const update = trpc.booking.createRefId.useMutation({
onSuccess: (result) => {
const values = form.getValues()
const value = new URLSearchParams(values).toString()
document.cookie = `bv=${value}; Path=/; Max-Age=30; Secure; SameSite=Strict`
router.push(
`/${lang}/hotelreservation/my-stay/${encodeURIComponent(result.refId)}`
)
},
onError: (error) => {
console.log("Failed to create ref id", error)
console.error("Failed to create ref id", error)
toast.error(
intl.formatMessage({
id: "Failed to submit form, please try again later.",
})
)
},
})
async function onSubmit(data: FindMyBookingFormSchema) {
const value = new URLSearchParams(data).toString()
document.cookie = `bv=${value}; Path=/; Max-Age=30; Secure; SameSite=Strict`
update.mutate({
confirmationNumber: data.reservationNumber,
bookingNumber: data.bookingNumber,
lastName: data.lastName,
})
}
return (
<FormProvider {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className={styles.form}>
@@ -71,8 +73,8 @@ export default function Form() {
</div>
<div className={styles.inputs}>
<Input
label="Reservation number"
name="reservationNumber"
label="Booking number"
name="bookingNumber"
placeholder="XXXXXX"
registerOptions={{ required: true }}
/>
@@ -123,7 +125,7 @@ export default function Form() {
type="submit"
intent="primary"
theme="base"
disabled={form.formState.isSubmitting}
disabled={form.formState.isSubmitting || update.isPending}
>
{intl.formatMessage({ id: "Find" })}
</Button>

View File

@@ -1,14 +1,22 @@
import { z } from "zod"
export const findMyBookingFormSchema = z.object({
reservationNumber: z.string(),
firstName: z.string().max(250).trim().min(1, {
bookingNumber: z
.string()
.trim()
.regex(/^[0-9]+(-[0-9])?$/, {
message: "Invalid booking number",
})
.min(1, {
message: "Booking number is required",
}),
firstName: z.string().trim().max(250).min(1, {
message: "First name is required",
}),
lastName: z.string().max(250).trim().min(1, {
lastName: z.string().trim().max(250).min(1, {
message: "Last name is required",
}),
email: z.string().max(250).email(),
email: z.string().max(250).email({ message: "Email address is required" }),
})
export interface FindMyBookingFormSchema

View File

@@ -1,6 +1,7 @@
"use client"
import { Text, TextField } from "react-aria-components"
import { Controller, useFormContext } from "react-hook-form"
import { useIntl } from "react-intl"
import { CheckIcon, InfoCircleIcon } from "@/components/Icons"
import AriaInputWithLabel from "@/components/TempDesignSystem/Form/Input/AriaInputWithLabel"
@@ -25,6 +26,7 @@ export default function Input({
registerOptions = {},
type = "text",
}: InputProps) {
const intl = useIntl()
const { control } = useFormContext()
let numberAttributes: HTMLAttributes<HTMLInputElement> = {}
if (type === "number") {
@@ -73,7 +75,7 @@ export default function Input({
{fieldState.error ? (
<Caption className={styles.error} fontOnly>
<InfoCircleIcon color="red" />
{fieldState.error.message}
{intl.formatMessage({ id: fieldState.error.message })}
</Caption>
) : null}
</TextField>