diff --git a/apps/scandic-web/components/HotelReservation/MyStay/Ancillaries/AddAncillaryFlow/AddAncillaryFlowModal/Steps/ConfirmationStep/index.tsx b/apps/scandic-web/components/HotelReservation/MyStay/Ancillaries/AddAncillaryFlow/AddAncillaryFlowModal/Steps/ConfirmationStep/index.tsx index 32381c2f9..922d2f6f3 100644 --- a/apps/scandic-web/components/HotelReservation/MyStay/Ancillaries/AddAncillaryFlow/AddAncillaryFlowModal/Steps/ConfirmationStep/index.tsx +++ b/apps/scandic-web/components/HotelReservation/MyStay/Ancillaries/AddAncillaryFlow/AddAncillaryFlowModal/Steps/ConfirmationStep/index.tsx @@ -20,6 +20,8 @@ import { useAddAncillaryStore } from "@/stores/my-stay/add-ancillary-flow" import useLang from "@/hooks/useLang" import { trackUpdatePaymentMethod } from "@/utils/tracking" +import { ancillaryError } from "../../../schema" + import styles from "./confirmationStep.module.css" import type { ConfirmationStepProps } from "@/types/components/myPages/myStay/ancillaries" @@ -219,6 +221,12 @@ export default function ConfirmationStep({ @@ -229,6 +237,17 @@ export default function ConfirmationStep({ + + + + {intl.formatMessage({ + id: "addAncillary.confirmationStep.optInForEmail", + defaultMessage: + "I want to receive an updated booking confirmation email reflecting this add-on", + })} + + + ) diff --git a/apps/scandic-web/components/HotelReservation/MyStay/Ancillaries/AddAncillaryFlow/AddAncillaryFlowModal/index.tsx b/apps/scandic-web/components/HotelReservation/MyStay/Ancillaries/AddAncillaryFlow/AddAncillaryFlowModal/index.tsx index 6e7edc4bd..08c391f37 100644 --- a/apps/scandic-web/components/HotelReservation/MyStay/Ancillaries/AddAncillaryFlow/AddAncillaryFlowModal/index.tsx +++ b/apps/scandic-web/components/HotelReservation/MyStay/Ancillaries/AddAncillaryFlow/AddAncillaryFlowModal/index.tsx @@ -97,6 +97,7 @@ export default function AddAncillaryFlowModal({ deliveryTime: defaultDeliveryTime, optionalText: "", termsAndConditions: false, + optInEmail: false, paymentMethod: booking.guaranteeInfo ? PaymentMethodEnum.card : savedCreditCards?.length @@ -152,6 +153,7 @@ export default function AddAncillaryFlowModal({ ancillaryDeliveryTime: selectedAncillary?.requiresDeliveryTime ? data.deliveryTime : undefined, + emailOptOut: !data.optInEmail, packages: packages, language: lang, }, diff --git a/apps/scandic-web/components/HotelReservation/MyStay/Ancillaries/AddAncillaryFlow/schema.ts b/apps/scandic-web/components/HotelReservation/MyStay/Ancillaries/AddAncillaryFlow/schema.ts index e2ed0d9c9..8ee928fc4 100644 --- a/apps/scandic-web/components/HotelReservation/MyStay/Ancillaries/AddAncillaryFlow/schema.ts +++ b/apps/scandic-web/components/HotelReservation/MyStay/Ancillaries/AddAncillaryFlow/schema.ts @@ -7,6 +7,11 @@ const quantitySchemaWithoutRefine = z.object({ quantityWithCard: z.number().nullable(), }) +export const ancillaryError = { + TERMS_NOT_ACCEPTED: "TERMS_NOT_ACCEPTED", + MIN_QUANTITY_NOT_REACHED: "MIN_QUANTITY_NOT_REACHED", +} as const + export const quantitySchema = z .object({}) .merge(quantitySchemaWithoutRefine) @@ -14,7 +19,7 @@ export const quantitySchema = z (data) => (data.quantityWithPoints ?? 0) > 0 || (data.quantityWithCard ?? 0) > 0, { - message: "You must select at least one quantity", + message: ancillaryError.MIN_QUANTITY_NOT_REACHED, path: ["quantityWithCard"], } ) @@ -23,7 +28,10 @@ export const ancillaryFormSchema = z .object({ deliveryTime: z.string(), optionalText: z.string(), - termsAndConditions: z.boolean(), + termsAndConditions: z + .boolean() + .refine((value) => value === true, ancillaryError.TERMS_NOT_ACCEPTED), + optInEmail: z.boolean(), paymentMethod: nullableStringValidator, }) .merge(quantitySchemaWithoutRefine) @@ -31,7 +39,7 @@ export const ancillaryFormSchema = z (data) => (data.quantityWithPoints ?? 0) > 0 || (data.quantityWithCard ?? 0) > 0, { - message: "You must select at least one quantity", + message: ancillaryError.MIN_QUANTITY_NOT_REACHED, path: ["quantityWithCard"], } ) diff --git a/apps/scandic-web/components/HotelReservation/MyStay/Ancillaries/AddedAncillaries/RemoveButton.tsx b/apps/scandic-web/components/HotelReservation/MyStay/Ancillaries/AddedAncillaries/RemoveButton.tsx index 25e97b672..b0c200e3a 100644 --- a/apps/scandic-web/components/HotelReservation/MyStay/Ancillaries/AddedAncillaries/RemoveButton.tsx +++ b/apps/scandic-web/components/HotelReservation/MyStay/Ancillaries/AddedAncillaries/RemoveButton.tsx @@ -76,6 +76,13 @@ export default function RemoveButton({ if (!data) { throw new Error() } + toast.success( + intl.formatMessage({ + id: "myStay.removeAncillary.success", + defaultMessage: + "The product has now been removed from your booking.", + }) + ) utils.booking.get.invalidate({ refId: refId, }) diff --git a/apps/scandic-web/components/HotelReservation/MyStay/Ancillaries/GuaranteeCallback/index.tsx b/apps/scandic-web/components/HotelReservation/MyStay/Ancillaries/GuaranteeCallback/index.tsx index 2b9f92443..b781857a1 100644 --- a/apps/scandic-web/components/HotelReservation/MyStay/Ancillaries/GuaranteeCallback/index.tsx +++ b/apps/scandic-web/components/HotelReservation/MyStay/Ancillaries/GuaranteeCallback/index.tsx @@ -56,6 +56,7 @@ export default function GuaranteeAncillaryHandler({ ancillaryDeliveryTime: selectedAncillary.requiresDeliveryTime ? formData.deliveryTime : undefined, + emailOptOut: !formData.optInEmail, packages, language: lang, }, diff --git a/apps/scandic-web/utils/getErrorMessage.ts b/apps/scandic-web/utils/getErrorMessage.ts index fc3c656e0..3ae8cde82 100644 --- a/apps/scandic-web/utils/getErrorMessage.ts +++ b/apps/scandic-web/utils/getErrorMessage.ts @@ -8,11 +8,22 @@ import { signupErrors } from "@scandic-hotels/trpc/routers/user/schemas" import { editProfileErrors } from "@/components/Forms/Edit/Profile/schema" import { findMyBookingErrors } from "@/components/HotelReservation/FindMyBooking/schema" +import { ancillaryError } from "@/components/HotelReservation/MyStay/Ancillaries/AddAncillaryFlow/schema" import type { IntlShape } from "react-intl" export function getErrorMessage(intl: IntlShape, errorCode?: string) { switch (errorCode) { + case ancillaryError.MIN_QUANTITY_NOT_REACHED: + return intl.formatMessage({ + id: "addAncillary.selectQuantityStep.minQuantityNotReached", + defaultMessage: "You must select at least one quantity", + }) + case ancillaryError.TERMS_NOT_ACCEPTED: + return intl.formatMessage({ + id: "addAncillary.confirmationStep.termsAndConditionsNotice", + defaultMessage: "You must accept the terms and conditions to proceed", + }) case findMyBookingErrors.BOOKING_NUMBER_INVALID: return intl.formatMessage({ id: "error.invalidBookingNumber", diff --git a/packages/trpc/lib/routers/booking/input.ts b/packages/trpc/lib/routers/booking/input.ts index 7cca42f3e..990a7d666 100644 --- a/packages/trpc/lib/routers/booking/input.ts +++ b/packages/trpc/lib/routers/booking/input.ts @@ -14,6 +14,7 @@ export const addPackageInput = z.object({ comment: z.string().optional(), }) ), + emailOptOut: z.boolean(), language: z.nativeEnum(Lang).transform((val) => langToApiLang[val]), }) diff --git a/packages/trpc/lib/routers/booking/mutation/index.ts b/packages/trpc/lib/routers/booking/mutation/index.ts index 2878db24f..e864048b4 100644 --- a/packages/trpc/lib/routers/booking/mutation/index.ts +++ b/packages/trpc/lib/routers/booking/mutation/index.ts @@ -145,7 +145,7 @@ export const bookingMutationRouter = router({ headers, body: body, }, - { language } + { language, emailOptOut: input.emailOptOut } ) if (!apiResponse.ok) {