diff --git a/apps/scandic-web/components/HotelReservation/MyStay/Ancillaries/AddAncillaryFlow/AddAncillaryFlowModal/Steps/ConfirmationStep/confirmationStep.module.css b/apps/scandic-web/components/HotelReservation/MyStay/Ancillaries/AddAncillaryFlow/AddAncillaryFlowModal/Steps/ConfirmationStep/confirmationStep.module.css index 53f4a83d5..8d66a8e9c 100644 --- a/apps/scandic-web/components/HotelReservation/MyStay/Ancillaries/AddAncillaryFlow/AddAncillaryFlowModal/Steps/ConfirmationStep/confirmationStep.module.css +++ b/apps/scandic-web/components/HotelReservation/MyStay/Ancillaries/AddAncillaryFlow/AddAncillaryFlowModal/Steps/ConfirmationStep/confirmationStep.module.css @@ -4,12 +4,6 @@ gap: var(--Space-x2); } -.termsAndConditions { - display: grid; - gap: var(--Space-x2); - color: var(--Text-Secondary); -} - .totalPointsContainer { display: flex; justify-content: space-between; @@ -17,9 +11,27 @@ padding: var(--Space-x1) var(--Space-x15); border-radius: var(--Corner-radius-md); } +.guarantee { + display: flex; + flex-direction: column; + gap: var(--Space-x2); + background-color: var(--Surface-Secondary-Default); + border-radius: var(--Corner-radius-lg); + padding: var(--Space-x2); +} + +.paymentInfo { + display: flex; + gap: var(--Space-x1); + align-items: flex-start; +} .totalPoints { display: flex; gap: var(--Space-x15); align-items: center; } + +.accordionItem { + border-radius: var(--Corner-radius-md); +} 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 6c6da2638..1c04bcc2d 100755 --- 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 @@ -1,27 +1,23 @@ import { useWatch } from "react-hook-form" import { useIntl } from "react-intl" -import { AlertTypeEnum } from "@scandic-hotels/common/constants/alert" import { PaymentMethodEnum } from "@scandic-hotels/common/constants/paymentMethod" -import { bookingTermsAndConditionsRoutes } from "@scandic-hotels/common/constants/routes/bookingTermsAndConditionsRoutes" -import { privacyPolicyRoutes } from "@scandic-hotels/common/constants/routes/privacyPolicyRoutes" import { dt } from "@scandic-hotels/common/dt" +import AccordionItem from "@scandic-hotels/design-system/Accordion/AccordionItem" import { Alert } from "@scandic-hotels/design-system/Alert" -import Checkbox from "@scandic-hotels/design-system/Form/Checkbox" +import { Divider } from "@scandic-hotels/design-system/Divider" import { PaymentOption } from "@scandic-hotels/design-system/Form/PaymentOption" import { PaymentOptionsGroup } from "@scandic-hotels/design-system/Form/PaymentOptionsGroup" import { SelectPaymentMethod } from "@scandic-hotels/design-system/Form/SelectPaymentMethod" import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon" -import { TextLink } from "@scandic-hotels/design-system/TextLink" import { Typography } from "@scandic-hotels/design-system/Typography" import { useAddAncillaryStore } from "@/stores/my-stay/add-ancillary-flow" +import TermsAndConditions from "@/components/HotelReservation/MyStay/TermsAndConditions" 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" @@ -33,17 +29,20 @@ export default function ConfirmationStep({ }: ConfirmationStepProps) { const intl = useIntl() const lang = useLang() - const { checkInDate, guaranteeInfo, selectedAncillary } = + + const { checkInDate, guaranteeInfo, selectedAncillary, booking } = useAddAncillaryStore((state) => ({ checkInDate: state.booking.checkInDate, guaranteeInfo: state.booking.guaranteeInfo, selectedAncillary: state.selectedAncillary, + booking: state.booking, })) const refundableDate = dt(checkInDate) .subtract(1, "day") .locale(lang) .format("23:59, dddd, D MMMM YYYY") + const mustBeGuaranteed = !guaranteeInfo && booking.isGuaranteeable const quantityWithCard = useWatch({ name: "quantityWithCard" }) const quantityWithPoints = useWatch({ name: "quantityWithPoints" }) const currentPoints = user?.membership?.currentPoints ?? 0 @@ -51,20 +50,22 @@ export default function ConfirmationStep({ quantityWithPoints && selectedAncillary?.points ? selectedAncillary.points * quantityWithPoints : null + + const accordionTitle = intl.formatMessage({ + id: "myStay.guarantee.guaranteeInformation", + defaultMessage: + "By adding your card, you also guarantee your room booking for late arrival ", + }) + + const accordionContent = intl.formatMessage({ + id: "myStay.guarantee.guaranteeInformation.content", + defaultMessage: + "The hotel will hold your booking, even if you arrive after 18:00. Your card will only be charged in the event of a no-show.", + }) + return (
- -

- {intl.formatMessage( - { - id: "addAncillary.confirmationStep.refundPolicy", - defaultMessage: - "All ancillaries are fully refundable until {date}. Time selection and special requests are also modifiable.", - }, - { date: refundableDate } - )} -

-
+ {error && } {!!quantityWithPoints && ( <> @@ -107,118 +108,118 @@ export default function ConfirmationStep({ )} {!!quantityWithCard && ( <> -
- -

- {intl.formatMessage({ - id: "addAncillary.confirmationStep.reserveWithCard", - defaultMessage: "Reserve with Card", - })} -

-
-
- -

+ +

{intl.formatMessage({ - id: "addAncillary.confirmationStep.paymentAtCheckInInfo", - defaultMessage: - "Payment will be made on check-in. The card will be only used to guarantee the ancillary in case of no-show.", + id: "addAncillary.confirmationStep.reserveWithCard", + defaultMessage: "Reserve with Card", })} +

+
+ +

+ {intl.formatMessage( + { + id: "addAncillary.confirmationStep.refundPolicy", + defaultMessage: + "All ancillaries are fully refundable until {date}. Time selection and special requests are also modifiable.", + }, + { date: refundableDate } + )}

- {guaranteeInfo ? ( - - - - ) : ( - <> - {error ? ( - - ) : ( - +
+ + + +

+ {intl.formatMessage({ + id: "myStay.ancillary.guarantee.headingText", + defaultMessage: "Payment will be made on check-in", + })} +

+
+ +

+ {intl.formatMessage({ + id: "myStay.ancillary.guarantee.infoText", + defaultMessage: + "The card is used to reserve your extras. You will be charged in case of no-show.", + })} +

+
+
+
+ {guaranteeInfo ? ( + <> + + +

+ {intl.formatMessage({ + id: "payment.savedCard", + defaultMessage: "Saved card", + })} +

+
+ + + + + ) : ( + <> +
+ + +

+ {intl.formatMessage({ + id: "myStay.ancillary.guarantee.confirmationText", + defaultMessage: + "Confirm and provide your payment card details in the next step", + })} +

+
+
+ {mustBeGuaranteed && ( + + +

{accordionContent}

+
+
+ )} + {savedCreditCards && } + ({ + ...card, + cardType: card.cardType as PaymentMethodEnum, + }))} + onChange={(method) => { + trackUpdatePaymentMethod({ method }) + }} + formName={"paymentMethod"} /> - )} - - ({ - ...card, - cardType: card.cardType as PaymentMethodEnum, - }))} - onChange={(method) => { - trackUpdatePaymentMethod({ method }) - }} - formName={"paymentMethod"} - /> - - )} + + )} +
)} - -
- -

- {intl.formatMessage( - { - id: "addAncillary.confirmationStep.termsAndConditionsNotice", - defaultMessage: - "Yes, I accept the general Booking & Cancellation Terms, and understand that Scandic will process my personal data in accordance with Scandic's Privacy policy. There you can learn more about what data we process, your rights and where to turn if you have questions.", - }, - { - termsAndConditionsLink: (str) => ( - - {str} - - ), - privacyPolicyLink: (str) => ( - - {str} - - ), - } - )} -

-
- - - - {intl.formatMessage({ - id: "booking.acceptBookingTerms", - defaultMessage: "I accept the booking and cancellation terms", - })} - - - -
+ ) } diff --git a/apps/scandic-web/components/HotelReservation/MyStay/Modal/index.tsx b/apps/scandic-web/components/HotelReservation/MyStay/Modal/index.tsx index 82be1e27c..53584dc21 100644 --- a/apps/scandic-web/components/HotelReservation/MyStay/Modal/index.tsx +++ b/apps/scandic-web/components/HotelReservation/MyStay/Modal/index.tsx @@ -5,9 +5,21 @@ import ModalContent from "./ModalContent" import styles from "./modal.module.css" -export default function Modal({ children }: React.PropsWithChildren) { +export default function Modal({ + children, + isOpen, + onOpenChange, +}: React.PropsWithChildren<{ + isOpen?: boolean + onOpenChange?: (value: boolean) => void +}>) { return ( - + {children} ) diff --git a/apps/scandic-web/hooks/booking/useGuaranteePaymentFailedToast.ts b/apps/scandic-web/components/HotelReservation/MyStay/ReferenceCard/Actions/Upcoming/GuaranteePaymentFailed/index.tsx similarity index 58% rename from apps/scandic-web/hooks/booking/useGuaranteePaymentFailedToast.ts rename to apps/scandic-web/components/HotelReservation/MyStay/ReferenceCard/Actions/Upcoming/GuaranteePaymentFailed/index.tsx index 45e4c3978..2f5fe3f63 100644 --- a/apps/scandic-web/hooks/booking/useGuaranteePaymentFailedToast.ts +++ b/apps/scandic-web/components/HotelReservation/MyStay/ReferenceCard/Actions/Upcoming/GuaranteePaymentFailed/index.tsx @@ -1,21 +1,26 @@ -"use client" - import { usePathname, useRouter, useSearchParams } from "next/navigation" -import { useCallback, useEffect, useRef } from "react" +import { useCallback, useEffect, useState } from "react" import { useIntl } from "react-intl" -import { toast } from "@scandic-hotels/design-system/Toast" +import { AlertTypeEnum } from "@scandic-hotels/common/constants/alert" import { BookingErrorCodeEnum } from "@scandic-hotels/trpc/enums/bookingErrorCode" +import Modal from "@/components/HotelReservation/MyStay/Modal" import { isAncillaryError } from "@/components/HotelReservation/MyStay/utils" -export function useGuaranteePaymentFailedToast() { - const hasRunOnce = useRef(false) +import GuaranteeDialog from "../ManageStay/Actions/GuaranteeLateArrival/GuaranteeDialog" + +export default function GuaranteePaymentFailed() { const intl = useIntl() const searchParams = useSearchParams() const pathname = usePathname() const router = useRouter() + const [alert, setAlert] = useState<{ + type: AlertTypeEnum + message: string + } | null>(null) + const getErrorMessage = useCallback( (errorCode: string | null) => { switch (errorCode) { @@ -37,33 +42,36 @@ export function useGuaranteePaymentFailedToast() { ) useEffect(() => { - // To prevent multiple toasts in strict mode - if (hasRunOnce.current) { - return - } const errorCode = searchParams.get("errorCode") if (!errorCode) { return } - // Ancillary errors are handled in AddAncillaryFlowModal if (isAncillaryError(searchParams)) { - hasRunOnce.current = true return } - const errorMessage = getErrorMessage(errorCode) - const toastType = + const message = getErrorMessage(errorCode) + const type = errorCode === BookingErrorCodeEnum.TransactionCancelled - ? "warning" - : "error" + ? AlertTypeEnum.Warning + : AlertTypeEnum.Alarm - toast[toastType](errorMessage) + setAlert({ type, message }) - const queryParams = new URLSearchParams(searchParams.toString()) - queryParams.delete("errorCode") + const newParams = new URLSearchParams(searchParams.toString()) + newParams.delete("errorCode") - router.push(`${pathname}?${queryParams.toString()}`) - hasRunOnce.current = true + router.replace(`${pathname}?${newParams.toString()}`) }, [searchParams, pathname, router, getErrorMessage]) + + if (!alert) { + return null + } + + return ( + setAlert(null)}> + + + ) } diff --git a/apps/scandic-web/components/HotelReservation/MyStay/ReferenceCard/Actions/Upcoming/ManageStay/Actions/GuaranteeLateArrival/Form/form.module.css b/apps/scandic-web/components/HotelReservation/MyStay/ReferenceCard/Actions/Upcoming/ManageStay/Actions/GuaranteeLateArrival/Form/form.module.css index f1009d584..c07653c6b 100644 --- a/apps/scandic-web/components/HotelReservation/MyStay/ReferenceCard/Actions/Upcoming/ManageStay/Actions/GuaranteeLateArrival/Form/form.module.css +++ b/apps/scandic-web/components/HotelReservation/MyStay/ReferenceCard/Actions/Upcoming/ManageStay/Actions/GuaranteeLateArrival/Form/form.module.css @@ -13,13 +13,18 @@ gap: var(--Space-x3); } -.termsAndConditions { - color: var(--Text-Secondary); - display: grid; +.guarantee { + display: flex; + flex-direction: column; gap: var(--Space-x2); + background-color: var(--Surface-Secondary-Default); + border-radius: var(--Corner-radius-lg); + padding: var(--Space-x2); } -.termsAndConditions .checkbox span { +.paymentInfo { + display: flex; + gap: var(--Space-x1); align-items: flex-start; } diff --git a/apps/scandic-web/components/HotelReservation/MyStay/ReferenceCard/Actions/Upcoming/ManageStay/Actions/GuaranteeLateArrival/Form/index.tsx b/apps/scandic-web/components/HotelReservation/MyStay/ReferenceCard/Actions/Upcoming/ManageStay/Actions/GuaranteeLateArrival/Form/index.tsx index 4416362ba..634c20b48 100644 --- a/apps/scandic-web/components/HotelReservation/MyStay/ReferenceCard/Actions/Upcoming/ManageStay/Actions/GuaranteeLateArrival/Form/index.tsx +++ b/apps/scandic-web/components/HotelReservation/MyStay/ReferenceCard/Actions/Upcoming/ManageStay/Actions/GuaranteeLateArrival/Form/index.tsx @@ -6,15 +6,13 @@ import { useIntl } from "react-intl" import { writeGlaToSessionStorage } from "@scandic-hotels/booking-flow/components/EnterDetails/Payment/PaymentCallback/helpers" import { PaymentMethodEnum } from "@scandic-hotels/common/constants/paymentMethod" -import { bookingTermsAndConditionsRoutes } from "@scandic-hotels/common/constants/routes/bookingTermsAndConditionsRoutes" import { guaranteeCallback } from "@scandic-hotels/common/constants/routes/hotelReservation" -import { privacyPolicyRoutes } from "@scandic-hotels/common/constants/routes/privacyPolicyRoutes" import { formatPrice } from "@scandic-hotels/common/utils/numberFormatting" +import { Alert } from "@scandic-hotels/design-system/Alert" import { Divider } from "@scandic-hotels/design-system/Divider" -import Checkbox from "@scandic-hotels/design-system/Form/Checkbox" import { SelectPaymentMethod } from "@scandic-hotels/design-system/Form/SelectPaymentMethod" +import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon" import { LoadingSpinner } from "@scandic-hotels/design-system/LoadingSpinner" -import Link from "@scandic-hotels/design-system/OldDSLink" import { toast } from "@scandic-hotels/design-system/Toast" import { Typography } from "@scandic-hotels/design-system/Typography" import { trackGlaSaveCardAttempt } from "@scandic-hotels/tracking/payment" @@ -23,6 +21,7 @@ import { isWebview } from "@/constants/routes/webviews" import { env } from "@/env/client" import { useMyStayStore } from "@/stores/my-stay" +import TermsAndConditions from "@/components/HotelReservation/MyStay/TermsAndConditions" import { useGuaranteeBooking } from "@/hooks/booking/useGuaranteeBooking" import useLang from "@/hooks/useLang" import { trackUpdatePaymentMethod } from "@/utils/tracking" @@ -31,7 +30,12 @@ import { type GuaranteeFormData, paymentSchema } from "./schema" import styles from "./form.module.css" -export default function Form() { +import type { AlertTypeEnum } from "@scandic-hotels/common/constants/alert" + +interface FormProps { + error?: { type: AlertTypeEnum; message: string } +} +export default function Form({ error }: FormProps) { const intl = useIntl() const lang = useLang() const pathname = usePathname() @@ -114,38 +118,6 @@ export default function Form() { } } - const guaranteeMsg = intl.formatMessage( - { - id: "myStay.gla.termsAndConditionsMessage", - defaultMessage: - "I accept the terms for this stay and the general Booking & Cancellation Terms, and understand Scandic will process my personal data for this stay in accordance with Scandic's Privacy Policy.", - }, - { - termsAndConditionsLink: (str) => ( - e.stopPropagation()} - > - {str} - - ), - privacyPolicyLink: (str) => ( - e.stopPropagation()} - > - {str} - - ), - } - ) - return (
- ({ - ...card, - cardType: card.cardType as PaymentMethodEnum, - }))} - onChange={(method) => { - trackUpdatePaymentMethod({ method }) - }} - formName="paymentMethod" - /> - -
- - -

{guaranteeMsg}

+ {error && } +
+
+ + + +

+ {intl.formatMessage({ + id: "myStay.guarantee.headingText", + defaultMessage: "Planning to arrive after 18.00?", + })} +

+
+ +

+ {intl.formatMessage({ + id: "myStay.guarantee.infoText", + defaultMessage: + "Guarantee with a credit card is required to secure your booking. Without this guarantee, your room may be released after 18:00 in case of no-show.", + })} +

+
+
+
+
+ + +

+ {intl.formatMessage({ + id: "myStay.guarantee.headingText", + defaultMessage: + "Confirm and provide your payment card details in the next step", + })} +

- +
+ {savedCreditCards && } + ({ + ...card, + cardType: card.cardType as PaymentMethodEnum, + }))} + onChange={(method) => { + trackUpdatePaymentMethod({ method }) + }} + formName="paymentMethod" + />
+ +
diff --git a/apps/scandic-web/components/HotelReservation/MyStay/ReferenceCard/Actions/Upcoming/ManageStay/Actions/GuaranteeLateArrival/Form/schema.ts b/apps/scandic-web/components/HotelReservation/MyStay/ReferenceCard/Actions/Upcoming/ManageStay/Actions/GuaranteeLateArrival/Form/schema.ts index c66223238..abcf44d0c 100644 --- a/apps/scandic-web/components/HotelReservation/MyStay/ReferenceCard/Actions/Upcoming/ManageStay/Actions/GuaranteeLateArrival/Form/schema.ts +++ b/apps/scandic-web/components/HotelReservation/MyStay/ReferenceCard/Actions/Upcoming/ManageStay/Actions/GuaranteeLateArrival/Form/schema.ts @@ -1,10 +1,14 @@ import { z } from "zod" +export const paymentError = { + TERMS_REQUIRED: "TERMS_REQUIRED", +} as const + export const paymentSchema = z.object({ paymentMethod: z.string().nullable(), - termsAndConditions: z.boolean().refine((value) => value === true, { - message: "You must accept the terms and conditions", - }), + termsAndConditions: z + .boolean() + .refine((value) => value === true, paymentError.TERMS_REQUIRED), }) export type GuaranteeFormData = z.output diff --git a/apps/scandic-web/components/HotelReservation/MyStay/ReferenceCard/Actions/Upcoming/ManageStay/Actions/GuaranteeLateArrival/guarantee.module.css b/apps/scandic-web/components/HotelReservation/MyStay/ReferenceCard/Actions/Upcoming/ManageStay/Actions/GuaranteeLateArrival/GuaranteeDialog/guaranteeDialog.module.css similarity index 65% rename from apps/scandic-web/components/HotelReservation/MyStay/ReferenceCard/Actions/Upcoming/ManageStay/Actions/GuaranteeLateArrival/guarantee.module.css rename to apps/scandic-web/components/HotelReservation/MyStay/ReferenceCard/Actions/Upcoming/ManageStay/Actions/GuaranteeLateArrival/GuaranteeDialog/guaranteeDialog.module.css index 4b01c9a1e..2e13cea40 100644 --- a/apps/scandic-web/components/HotelReservation/MyStay/ReferenceCard/Actions/Upcoming/ManageStay/Actions/GuaranteeLateArrival/guarantee.module.css +++ b/apps/scandic-web/components/HotelReservation/MyStay/ReferenceCard/Actions/Upcoming/ManageStay/Actions/GuaranteeLateArrival/GuaranteeDialog/guaranteeDialog.module.css @@ -1,3 +1,4 @@ .dialog { max-width: 690px; + outline: none; } diff --git a/apps/scandic-web/components/HotelReservation/MyStay/ReferenceCard/Actions/Upcoming/ManageStay/Actions/GuaranteeLateArrival/GuaranteeDialog/index.tsx b/apps/scandic-web/components/HotelReservation/MyStay/ReferenceCard/Actions/Upcoming/ManageStay/Actions/GuaranteeLateArrival/GuaranteeDialog/index.tsx new file mode 100644 index 000000000..93f189fec --- /dev/null +++ b/apps/scandic-web/components/HotelReservation/MyStay/ReferenceCard/Actions/Upcoming/ManageStay/Actions/GuaranteeLateArrival/GuaranteeDialog/index.tsx @@ -0,0 +1,48 @@ +import { Dialog } from "react-aria-components" +import { useIntl } from "react-intl" + +import Modal from "@/components/HotelReservation/MyStay/Modal" + +import Form from "../Form" + +import styles from "./guaranteeDialog.module.css" + +import type { AlertTypeEnum } from "@scandic-hotels/common/constants/alert" + +interface GuaranteeDialogProps { + error?: { type: AlertTypeEnum; message: string } +} + +export default function GuaranteeDialog({ error }: GuaranteeDialogProps) { + const intl = useIntl() + const text = intl.formatMessage({ + id: "myStay.gla.heading", + defaultMessage: "Add late arrival guarantee", + }) + return ( + + {({ close }) => ( + + + + + + + + {intl.formatMessage({ + id: "common.back", + defaultMessage: "Back", + })} + + + {intl.formatMessage({ + id: "common.confirm", + defaultMessage: "Confirm", + })} + + + + )} + + ) +} diff --git a/apps/scandic-web/components/HotelReservation/MyStay/ReferenceCard/Actions/Upcoming/ManageStay/Actions/GuaranteeLateArrival/index.tsx b/apps/scandic-web/components/HotelReservation/MyStay/ReferenceCard/Actions/Upcoming/ManageStay/Actions/GuaranteeLateArrival/index.tsx index 0bde2f589..5b0f4b930 100644 --- a/apps/scandic-web/components/HotelReservation/MyStay/ReferenceCard/Actions/Upcoming/ManageStay/Actions/GuaranteeLateArrival/index.tsx +++ b/apps/scandic-web/components/HotelReservation/MyStay/ReferenceCard/Actions/Upcoming/ManageStay/Actions/GuaranteeLateArrival/index.tsx @@ -1,18 +1,14 @@ "use client" -import { Dialog, DialogTrigger } from "react-aria-components" +import { DialogTrigger } from "react-aria-components" import { useIntl } from "react-intl" -import { Typography } from "@scandic-hotels/design-system/Typography" - import { useMyStayStore } from "@/stores/my-stay" import Modal from "@/components/HotelReservation/MyStay/Modal" import { trackMyStayPageLink } from "@/utils/tracking" import ActionsButton from "../ActionsButton" -import Form from "./Form" - -import styles from "./guarantee.module.css" +import GuaranteeDialog from "./GuaranteeDialog" export default function GuaranteeLateArrival() { const intl = useIntl() @@ -29,14 +25,9 @@ export default function GuaranteeLateArrival() { trackMyStayPageLink("guarantee late arrival") } - const arriveLateMsg = intl.formatMessage({ - id: "myStay.gla.arriveLateMessage", - defaultMessage: - "Planning to arrive after 18.00? Secure your room by guaranteeing it with a credit card. Without the guarantee and in case of no-show, the room might be reallocated after 18:00.", - }) const text = intl.formatMessage({ id: "myStay.gla.heading", - defaultMessage: "Guarantee late arrival", + defaultMessage: "Add late arrival guarantee", }) return ( @@ -47,34 +38,7 @@ export default function GuaranteeLateArrival() { icon="check" /> - - {({ close }) => ( - - - -

{arriveLateMsg}

-
-
- - - - - - {intl.formatMessage({ - id: "common.back", - defaultMessage: "Back", - })} - - - {intl.formatMessage({ - id: "myStay.gla.guarantee", - defaultMessage: "Guarantee", - })} - - -
- )} -
+
) diff --git a/apps/scandic-web/components/HotelReservation/MyStay/ReferenceCard/GuaranteeInfo/GuaranteeInfoModal/guaranteeInfoModal.module.css b/apps/scandic-web/components/HotelReservation/MyStay/ReferenceCard/GuaranteeInfo/GuaranteeInfoModal/guaranteeInfoModal.module.css new file mode 100644 index 000000000..046219bd3 --- /dev/null +++ b/apps/scandic-web/components/HotelReservation/MyStay/ReferenceCard/GuaranteeInfo/GuaranteeInfoModal/guaranteeInfoModal.module.css @@ -0,0 +1,34 @@ +.content { + display: grid; + gap: var(--Space-x3); + align-content: start; + margin-top: var(--Space-x2); +} + +.infoButton { + background-color: transparent; + border-width: 0; + padding: var(--Space-x025); + color: var(--Icon-Interactive-Default); + cursor: pointer; + flex-shrink: 0; +} + +.closeButton { + justify-self: stretch; +} + +@media screen and (min-width: 768px) { + .content { + max-width: 512px; + } + + .closeButton { + justify-self: end; + min-width: 150px; + } +} + +.textSecondary { + color: var(--Text-Secondary); +} diff --git a/apps/scandic-web/components/HotelReservation/MyStay/ReferenceCard/GuaranteeInfo/GuaranteeInfoModal/index.tsx b/apps/scandic-web/components/HotelReservation/MyStay/ReferenceCard/GuaranteeInfo/GuaranteeInfoModal/index.tsx new file mode 100644 index 000000000..f39bd49e3 --- /dev/null +++ b/apps/scandic-web/components/HotelReservation/MyStay/ReferenceCard/GuaranteeInfo/GuaranteeInfoModal/index.tsx @@ -0,0 +1,75 @@ +"use client" + +import { useState } from "react" +import { Button as ButtonRAC } from "react-aria-components" +import { useIntl } from "react-intl" + +import { Button } from "@scandic-hotels/design-system/Button" +import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon" +import Modal from "@scandic-hotels/design-system/Modal" +import { Typography } from "@scandic-hotels/design-system/Typography" + +import styles from "./guaranteeInfoModal.module.css" + +export function GuaranteeInfoModal() { + const [isOpen, setIsOpen] = useState(false) + const intl = useIntl() + + return ( + <> + setIsOpen(true)} + > + + + +
+ +

+ {intl.formatMessage({ + id: "myStay.guaranteeInfo.description", + defaultMessage: + "The hotel will hold your booking, even if you arrive after 18:00. In case of a no-show, you will be charged for the first night.", + })} +

+
+ +

+ {intl.formatMessage({ + id: "myStay.guaranteeInfoModal.ancillariesInfo", + defaultMessage: + "If you added extras, they'll be charged in case of a no-show, unless cancelled by 23:59 the night before.", + })} +

+
+ + +
+
+ + ) +} diff --git a/apps/scandic-web/components/HotelReservation/MyStay/ReferenceCard/GuaranteeInfo/guaranteeInfo.module.css b/apps/scandic-web/components/HotelReservation/MyStay/ReferenceCard/GuaranteeInfo/guaranteeInfo.module.css index fe9adce2d..b8508ea70 100644 --- a/apps/scandic-web/components/HotelReservation/MyStay/ReferenceCard/GuaranteeInfo/guaranteeInfo.module.css +++ b/apps/scandic-web/components/HotelReservation/MyStay/ReferenceCard/GuaranteeInfo/guaranteeInfo.module.css @@ -5,7 +5,7 @@ } .label { - align-items: center; + align-items: flex-start; display: flex; gap: var(--Space-x1); } @@ -13,3 +13,9 @@ .textDefault { color: var(--Text-Default); } + +.guaranteeInfo { + display: flex; + align-items: flex-start; + gap: var(--Space-x05); +} diff --git a/apps/scandic-web/components/HotelReservation/MyStay/ReferenceCard/GuaranteeInfo/index.tsx b/apps/scandic-web/components/HotelReservation/MyStay/ReferenceCard/GuaranteeInfo/index.tsx index 3cbfb17f4..9b3fe8466 100644 --- a/apps/scandic-web/components/HotelReservation/MyStay/ReferenceCard/GuaranteeInfo/index.tsx +++ b/apps/scandic-web/components/HotelReservation/MyStay/ReferenceCard/GuaranteeInfo/index.tsx @@ -6,20 +6,20 @@ import { Typography } from "@scandic-hotels/design-system/Typography" import { useMyStayStore } from "@/stores/my-stay" +import { GuaranteeInfoModal } from "./GuaranteeInfoModal" + import styles from "./guaranteeInfo.module.css" export default function GuaranteeInfo() { const intl = useIntl() - const { allRoomsAreCancelled, guaranteeInfo, priceType } = useMyStayStore( - (state) => ({ - allRoomsAreCancelled: state.allRoomsAreCancelled, + const { isGuaranteeable, guaranteeInfo, allRoomsAreCancelled } = + useMyStayStore((state) => ({ + isGuaranteeable: state.bookedRoom.isGuaranteeable, guaranteeInfo: state.bookedRoom.guaranteeInfo, - priceType: state.bookedRoom.priceType, - }) - ) + allRoomsAreCancelled: state.allRoomsAreCancelled, + })) - const isRewardNight = priceType === "points" - if (allRoomsAreCancelled || (!guaranteeInfo && !isRewardNight)) { + if ((isGuaranteeable && !guaranteeInfo) || allRoomsAreCancelled) { return null } @@ -30,20 +30,23 @@ export default function GuaranteeInfo() {

{intl.formatMessage({ - id: "myStay.lateArrival", - defaultMessage: "Late arrival", + id: "myStay.bookingGuaranteed", + defaultMessage: "Booking guaranteed", + })} +

+
+
+
+ + +

+ {intl.formatMessage({ + id: "myStay.roomHeldAfter18", + defaultMessage: "Room held after 18:00", })}

- -

- {intl.formatMessage({ - id: "myStay.checkInAfter18", - defaultMessage: "Check-in after 18:00", - })} -

-
) } diff --git a/apps/scandic-web/components/HotelReservation/MyStay/ReferenceCard/index.tsx b/apps/scandic-web/components/HotelReservation/MyStay/ReferenceCard/index.tsx index 6565e9a99..f7629eba3 100644 --- a/apps/scandic-web/components/HotelReservation/MyStay/ReferenceCard/index.tsx +++ b/apps/scandic-web/components/HotelReservation/MyStay/ReferenceCard/index.tsx @@ -4,9 +4,8 @@ import { useIntl } from "react-intl" import { Divider } from "@scandic-hotels/design-system/Divider" import { Typography } from "@scandic-hotels/design-system/Typography" -import { useGuaranteePaymentFailedToast } from "@/hooks/booking/useGuaranteePaymentFailedToast" - import TotalPrice from "../Rooms/TotalPrice" +import GuaranteePaymentFailed from "./Actions/Upcoming/GuaranteePaymentFailed" import Actions from "./Actions" import BookingCode from "./BookingCode" import Cancellations from "./Cancellations" @@ -20,7 +19,6 @@ import styles from "./referenceCard.module.css" export function ReferenceCard() { const intl = useIntl() - useGuaranteePaymentFailedToast() return (
@@ -44,6 +42,7 @@ export function ReferenceCard() {
+
) } diff --git a/apps/scandic-web/components/HotelReservation/MyStay/ReferenceCard/referenceCard.module.css b/apps/scandic-web/components/HotelReservation/MyStay/ReferenceCard/referenceCard.module.css index d2e7fe997..c8f5d69d5 100644 --- a/apps/scandic-web/components/HotelReservation/MyStay/ReferenceCard/referenceCard.module.css +++ b/apps/scandic-web/components/HotelReservation/MyStay/ReferenceCard/referenceCard.module.css @@ -12,8 +12,9 @@ } .row { - align-items: center; display: flex; justify-content: space-between; padding-top: var(--Space-x1); + gap: var(--Space-x2); + text-align: end; } diff --git a/apps/scandic-web/components/HotelReservation/MyStay/Rooms/SingleRoom/BookingInformation/PriceDetails/index.tsx b/apps/scandic-web/components/HotelReservation/MyStay/Rooms/SingleRoom/BookingInformation/PriceDetails/index.tsx index 5364689a9..69fcf2e8f 100644 --- a/apps/scandic-web/components/HotelReservation/MyStay/Rooms/SingleRoom/BookingInformation/PriceDetails/index.tsx +++ b/apps/scandic-web/components/HotelReservation/MyStay/Rooms/SingleRoom/BookingInformation/PriceDetails/index.tsx @@ -1,39 +1,15 @@ "use client" import { useIntl } from "react-intl" -import { sumPackages } from "@scandic-hotels/booking-flow/utils/SelectRate" import { Typography } from "@scandic-hotels/design-system/Typography" -import { useMyStayStore } from "@/stores/my-stay" - -import PriceType from "@/components/HotelReservation/MyStay/PriceType" +import TotalPrice from "../../../TotalPrice" import styles from "./details.module.css" export default function PriceDetails() { const intl = useIntl() - const pricing = useMyStayStore((state) => ({ - cheques: state.bookedRoom.cheques, - formattedTotalPrice: state.totalPrice, - isCancelled: state.bookedRoom.isCancelled, - currencyCode: state.bookedRoom.currencyCode, - packages: state.bookedRoom.packages, - priceType: state.bookedRoom.priceType, - rateDefinition: state.bookedRoom.rateDefinition, - totalPoints: state.bookedRoom.totalPoints, - totalPrice: state.bookedRoom.totalPrice, - vouchers: state.bookedRoom.vouchers, - })) - - let totalPrice = pricing.totalPrice - // API returns negative values for totalPrice - // on voucher bookings (╯°□°)╯︵ ┻━┻ - if (pricing.vouchers && totalPrice < 0) { - const pkgsSum = sumPackages(pricing.packages) - totalPrice = pkgsSum.price - } - return (
@@ -45,7 +21,7 @@ export default function PriceDetails() { })}

- +
) diff --git a/apps/scandic-web/components/HotelReservation/MyStay/Rooms/SingleRoom/RoomDetailsSidePeek.tsx b/apps/scandic-web/components/HotelReservation/MyStay/Rooms/SingleRoom/RoomDetailsSidePeek.tsx index 8a63efa9d..9dd3c364f 100644 --- a/apps/scandic-web/components/HotelReservation/MyStay/Rooms/SingleRoom/RoomDetailsSidePeek.tsx +++ b/apps/scandic-web/components/HotelReservation/MyStay/Rooms/SingleRoom/RoomDetailsSidePeek.tsx @@ -23,7 +23,11 @@ export default function RoomDetailsSidePeek({ user, }: RoomDetailsSidePeekProps) { const intl = useIntl() - const bookedRoom = useMyStayStore((state) => state.bookedRoom) + const { bookedRoom, totalPrice } = useMyStayStore((state) => ({ + bookedRoom: state.bookedRoom, + totalPrice: state.totalPrice, + })) + const [isOpen, setIsOpen] = useState(false) return ( @@ -53,7 +57,11 @@ export default function RoomDetailsSidePeek({ isOpen={isOpen} onClose={() => setIsOpen(false)} > - + ) diff --git a/apps/scandic-web/components/HotelReservation/MyStay/Rooms/TotalPrice.tsx b/apps/scandic-web/components/HotelReservation/MyStay/Rooms/TotalPrice.tsx index 111801834..07c6e7a39 100644 --- a/apps/scandic-web/components/HotelReservation/MyStay/Rooms/TotalPrice.tsx +++ b/apps/scandic-web/components/HotelReservation/MyStay/Rooms/TotalPrice.tsx @@ -1,41 +1,22 @@ "use client" -import { sumPackages } from "@scandic-hotels/booking-flow/utils/SelectRate" import { useMyStayStore } from "@/stores/my-stay" -import PriceType from "../PriceType" +import Price from "../PriceType/Price" import type { PriceType as _PriceType } from "@/types/components/hotelReservation/myStay/myStay" export default function TotalPrice() { - const { bookedRoom, formattedTotalPrice, rooms } = useMyStayStore( - (state) => ({ - bookedRoom: state.bookedRoom, - formattedTotalPrice: state.totalPrice, - rooms: state.rooms, - }) - ) - - const totalCheques = rooms.reduce((total, room) => total + room.cheques, 0) - const totalPoints = rooms.reduce((total, room) => total + room.totalPoints, 0) - - let totalPrice = rooms.reduce((total, room) => total + room.totalPrice, 0) - if (rooms.some((room) => room.vouchers)) { - const pkgsSum = sumPackages(rooms.flatMap((r) => r.packages || [])) - totalPrice = pkgsSum.price - } - + const { bookedRoom, totalPrice } = useMyStayStore((state) => ({ + bookedRoom: state.bookedRoom, + totalPrice: state.totalPrice, + rooms: state.rooms, + })) return ( - ) } diff --git a/apps/scandic-web/components/HotelReservation/MyStay/TermsAndConditions/index.tsx b/apps/scandic-web/components/HotelReservation/MyStay/TermsAndConditions/index.tsx new file mode 100644 index 000000000..863efe95b --- /dev/null +++ b/apps/scandic-web/components/HotelReservation/MyStay/TermsAndConditions/index.tsx @@ -0,0 +1,84 @@ +import { useFormContext } from "react-hook-form" +import { useIntl } from "react-intl" + +import { bookingTermsAndConditionsRoutes } from "@scandic-hotels/common/constants/routes/bookingTermsAndConditionsRoutes" +import { privacyPolicyRoutes } from "@scandic-hotels/common/constants/routes/privacyPolicyRoutes" +import Checkbox from "@scandic-hotels/design-system/Form/Checkbox" +import { ErrorMessage } from "@scandic-hotels/design-system/Form/ErrorMessage" +import { TextLink } from "@scandic-hotels/design-system/TextLink" +import { Typography } from "@scandic-hotels/design-system/Typography" + +import useLang from "@/hooks/useLang" +import { getErrorMessage } from "@/utils/getErrorMessage" + +import styles from "./termsAndConditions.module.css" + +export default function TermsAndConditions() { + const intl = useIntl() + const lang = useLang() + const { + formState: { errors }, + } = useFormContext() + const termsAndConditionsMsg = intl.formatMessage( + { + id: "myStay.guarantee.termsAndConditions", + defaultMessage: + "Please accept the general Booking & Cancellation Terms and acknowledge that your data will be processed in accordance with Scandic's Privacy policy .", + }, + { + termsAndConditionsLink: (str) => ( + + {str} + + ), + privacyPolicyLink: (str) => ( + + {str} + + ), + } + ) + return ( +
+ + + + {intl.formatMessage({ + id: "booking.acceptBookingTerms", + defaultMessage: "I accept the booking and cancellation terms", + })} + + + + + +

{termsAndConditionsMsg}

+
+ +
+
+ ) +} diff --git a/apps/scandic-web/components/HotelReservation/MyStay/TermsAndConditions/termsAndConditions.module.css b/apps/scandic-web/components/HotelReservation/MyStay/TermsAndConditions/termsAndConditions.module.css new file mode 100644 index 000000000..d0ad98cfc --- /dev/null +++ b/apps/scandic-web/components/HotelReservation/MyStay/TermsAndConditions/termsAndConditions.module.css @@ -0,0 +1,5 @@ +.termsAndConditions { + display: grid; + gap: var(--Space-x1); + color: var(--Text-Secondary); +} diff --git a/apps/scandic-web/components/HotelReservation/MyStay/utils/mapRoomDetails.ts b/apps/scandic-web/components/HotelReservation/MyStay/utils/mapRoomDetails.ts index 5b432dab1..09bf49a5a 100644 --- a/apps/scandic-web/components/HotelReservation/MyStay/utils/mapRoomDetails.ts +++ b/apps/scandic-web/components/HotelReservation/MyStay/utils/mapRoomDetails.ts @@ -93,7 +93,7 @@ export function mapRoomDetails({ const priceType = getPriceType( booking.cheques, - booking.totalPoints, + booking.roomPoints, booking.vouchers ) diff --git a/apps/scandic-web/components/SidePeeks/BookedRoomSidePeekContent/index.tsx b/apps/scandic-web/components/SidePeeks/BookedRoomSidePeekContent/index.tsx index 879bbcab8..96a89d674 100644 --- a/apps/scandic-web/components/SidePeeks/BookedRoomSidePeekContent/index.tsx +++ b/apps/scandic-web/components/SidePeeks/BookedRoomSidePeekContent/index.tsx @@ -16,6 +16,7 @@ import { RoomPackageCodeEnum } from "@scandic-hotels/trpc/enums/roomFilter" import GuestDetails from "@/components/HotelReservation/MyStay/GuestDetails" import PriceType from "@/components/HotelReservation/MyStay/PriceType" +import Price from "@/components/HotelReservation/MyStay/PriceType/Price" import { hasModifiableRate } from "@/components/HotelReservation/MyStay/utils" import useLang from "@/hooks/useLang" import { mapApiImagesToGalleryImages } from "@/utils/imageGallery" @@ -70,11 +71,13 @@ type Room = Pick< interface BookedRoomSidepeekContentProps { room: Room user: SafeUser + totalPriceBooking?: string } export default function BookedRoomSidePeekContent({ room, user, + totalPriceBooking, }: BookedRoomSidepeekContentProps) { const intl = useIntl() const lang = useLang() @@ -407,18 +410,25 @@ export default function BookedRoomSidePeekContent({ })}

- - + {totalPriceBooking ? ( + + ) : ( + + )} diff --git a/apps/scandic-web/stores/my-stay/helpers.ts b/apps/scandic-web/stores/my-stay/helpers.ts index d8188c0e3..e306b33a3 100644 --- a/apps/scandic-web/stores/my-stay/helpers.ts +++ b/apps/scandic-web/stores/my-stay/helpers.ts @@ -28,7 +28,7 @@ export function calculateTotalPrice( } // room.totalPrice is a negative value when // its a vouchers booking (╯°□°)╯︵ ┻━┻ - if (room.totalPrice && !room.vouchers) { + if (room.totalPrice > 0) { total.cash = total.cash + room.totalPrice } return total @@ -42,13 +42,6 @@ export function calculateTotalPrice( ) let totalPrice = "" - if (totals.cheques) { - totalPrice = `${totals.cheques} ${CurrencyEnum.CC}` - } - if (totals.points) { - const appendTotalPrice = totalPrice ? `${totalPrice} + ` : "" - totalPrice = `${appendTotalPrice}${totals.points} ${CurrencyEnum.POINTS}` - } if (totals.vouchers) { const appendTotalPrice = totalPrice ? `${totalPrice} + ` : "" totalPrice = `${appendTotalPrice}${totals.vouchers} ${intl.formatMessage( @@ -62,6 +55,13 @@ export function calculateTotalPrice( } )}` } + if (totals.cheques) { + totalPrice = `${totals.cheques} ${CurrencyEnum.CC}` + } + if (totals.points) { + const appendTotalPrice = totalPrice ? `${totalPrice} + ` : "" + totalPrice = `${appendTotalPrice}${totals.points} ${CurrencyEnum.POINTS}` + } if (totals.cash) { const appendTotalPrice = totalPrice ? `${totalPrice} + ` : "" const cashPrice = formatPrice(intl, totals.cash, currency) diff --git a/apps/scandic-web/utils/getErrorMessage.ts b/apps/scandic-web/utils/getErrorMessage.ts index 010de0b38..f2aab01ff 100644 --- a/apps/scandic-web/utils/getErrorMessage.ts +++ b/apps/scandic-web/utils/getErrorMessage.ts @@ -9,6 +9,7 @@ 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 { paymentError } from "@/components/HotelReservation/MyStay/ReferenceCard/Actions/Upcoming/ManageStay/Actions/GuaranteeLateArrival/Form/schema" import type { IntlShape } from "react-intl" @@ -22,9 +23,10 @@ export function getErrorMessage(intl: IntlShape, errorCode?: string) { defaultMessage: "You must select at least one quantity", }) case ancillaryError.TERMS_NOT_ACCEPTED: + case paymentError.TERMS_REQUIRED: return intl.formatMessage({ - id: "addAncillary.confirmationStep.termsAndConditionsNoticeError", - defaultMessage: "You must accept the terms and conditions to proceed", + id: "common.mustAcceptTermsError", + defaultMessage: "You must accept the terms and conditions", }) case findMyBookingErrors.BOOKING_NUMBER_INVALID: return intl.formatMessage({ diff --git a/packages/booking-flow/lib/components/EnterDetails/Payment/GuaranteeDetails/guaranteeDetails.module.css b/packages/booking-flow/lib/components/EnterDetails/Payment/GuaranteeDetails/guaranteeDetails.module.css deleted file mode 100644 index 4e8e6c7fe..000000000 --- a/packages/booking-flow/lib/components/EnterDetails/Payment/GuaranteeDetails/guaranteeDetails.module.css +++ /dev/null @@ -1,22 +0,0 @@ -.content { - display: flex; - flex-direction: column; - gap: var(--Space-x1); - padding-top: var(--Space-x2); -} - -.content ol { - margin: 0; -} - -.summary { - list-style: none; - display: flex; - align-items: center; - gap: var(--Space-x05); -} - -.summary::-webkit-details-marker, -.summary::marker { - display: none; -} diff --git a/packages/booking-flow/lib/components/EnterDetails/Payment/GuaranteeDetails/index.tsx b/packages/booking-flow/lib/components/EnterDetails/Payment/GuaranteeDetails/index.tsx deleted file mode 100644 index ec2a5a739..000000000 --- a/packages/booking-flow/lib/components/EnterDetails/Payment/GuaranteeDetails/index.tsx +++ /dev/null @@ -1,68 +0,0 @@ -import { useIntl } from "react-intl" - -import Body from "@scandic-hotels/design-system/Body" -import Caption from "@scandic-hotels/design-system/Caption" -import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon" - -import styles from "./guaranteeDetails.module.css" - -export default function GuaranteeDetails() { - const intl = useIntl() - return ( -
- - - {intl.formatMessage({ - id: "common.howItWorks", - defaultMessage: "How it works", - })} - - - -
- - {intl.formatMessage({ - id: "enterDetails.payment.guaranteeInfoDescription", - defaultMessage: - "When guaranteeing your booking, we will hold the booking until 07:00 until the day after check-in. This will provide you as a guest with added flexibility for check-in times.", - })} - - - {intl.formatMessage({ - id: "enterDetails.payment.guaranteeInfoWhatToDo", - defaultMessage: "What you have to do to guarantee booking:", - })} - -
    - -
  1. - {intl.formatMessage({ - id: "enterDetails.payment.guaranteeInfoCompleteBooking", - defaultMessage: "Complete the booking", - })} -
  2. - - -
  3. - {intl.formatMessage({ - id: "enterDetails.payment.guaranteeInfoProvideCard", - defaultMessage: "Provide a payment card in the next step", - })} -
  4. - -
- - {intl.formatMessage({ - id: "enterDetails.payment.guaranteeInfoMandatoryNote", - defaultMessage: - "Please note that this is mandatory, and that your card will only be charged in the event of a no-show.", - })} - -
-
- ) -} diff --git a/packages/design-system/lib/components/Accordion/Accordion.stories.tsx b/packages/design-system/lib/components/Accordion/Accordion.stories.tsx index e71d132b0..e07224cc5 100644 --- a/packages/design-system/lib/components/Accordion/Accordion.stories.tsx +++ b/packages/design-system/lib/components/Accordion/Accordion.stories.tsx @@ -12,7 +12,7 @@ const meta: Meta = { argTypes: { type: { control: 'select', - options: ['card', 'sidepeek'], + options: ['card', 'sidepeek', 'inline'], }, }, } @@ -137,3 +137,22 @@ export const WithSubtitle: Story = { ), } + +export const Inline: Story = { + args: { + type: 'inline', + }, + render: () => ( + + + +

+ All rooms feature comfortable beds, modern amenities, and + complimentary Wi-Fi. Check-in is available from 3 PM and check-out + is at 12 PM. +

+
+
+
+ ), +} diff --git a/packages/design-system/lib/components/Accordion/AccordionItem/accordionItem.module.css b/packages/design-system/lib/components/Accordion/AccordionItem/accordionItem.module.css index fa52eb9bd..18cd315e6 100644 --- a/packages/design-system/lib/components/Accordion/AccordionItem/accordionItem.module.css +++ b/packages/design-system/lib/components/Accordion/AccordionItem/accordionItem.module.css @@ -18,6 +18,19 @@ } } + &.inline { + list-style: none; + padding: var(--Space-x15); + background-color: var(--Surface-Primary-Default); + .content { + padding: var(--Space-x1) 0 0 0; + } + + .summary:hover { + background-color: transparent; + } + } + .summary:hover { background-color: var(--Surface-Primary-Hover); } diff --git a/packages/design-system/lib/components/Accordion/AccordionItem/index.tsx b/packages/design-system/lib/components/Accordion/AccordionItem/index.tsx index 04a5e095d..1b2b7ab74 100644 --- a/packages/design-system/lib/components/Accordion/AccordionItem/index.tsx +++ b/packages/design-system/lib/components/Accordion/AccordionItem/index.tsx @@ -93,6 +93,10 @@ export default function AccordionItem({

{title}

+ ) : type === 'inline' ? ( + +

{title}

+
) : (
{subtitle || showAsSubtitle ? ( diff --git a/packages/design-system/lib/components/Accordion/AccordionItem/variants.ts b/packages/design-system/lib/components/Accordion/AccordionItem/variants.ts index 3bb4f384f..99b4d61c0 100644 --- a/packages/design-system/lib/components/Accordion/AccordionItem/variants.ts +++ b/packages/design-system/lib/components/Accordion/AccordionItem/variants.ts @@ -7,6 +7,7 @@ export const accordionItemVariants = cva(styles.accordionItem, { type: { card: styles.card, sidepeek: styles.sidepeek, + inline: styles.inline, }, }, defaultVariants: { diff --git a/packages/design-system/lib/components/Accordion/variants.ts b/packages/design-system/lib/components/Accordion/variants.ts index 129e2a61b..e8038284a 100644 --- a/packages/design-system/lib/components/Accordion/variants.ts +++ b/packages/design-system/lib/components/Accordion/variants.ts @@ -7,6 +7,7 @@ export const accordionVariants = cva(styles.accordion, { type: { card: styles.card, sidepeek: styles.sidepeek, + inline: styles.inline, }, }, defaultVariants: { diff --git a/packages/design-system/lib/components/Form/PaymentOption/PaymentOption.tsx b/packages/design-system/lib/components/Form/PaymentOption/PaymentOption.tsx index 63083018d..a1e524271 100644 --- a/packages/design-system/lib/components/Form/PaymentOption/PaymentOption.tsx +++ b/packages/design-system/lib/components/Form/PaymentOption/PaymentOption.tsx @@ -12,11 +12,13 @@ export type PaymentOptionProps = { value: PaymentMethodEnum label: string cardNumber?: string + hideRadioButton?: boolean } export function PaymentOption({ value, label, cardNumber, + hideRadioButton = false, }: PaymentOptionProps) { return ( ( <>
- + {!hideRadioButton && ( + + )} diff --git a/packages/design-system/lib/components/Form/SelectPaymentMethod/index.tsx b/packages/design-system/lib/components/Form/SelectPaymentMethod/index.tsx index c8b2ca36e..8219bb014 100644 --- a/packages/design-system/lib/components/Form/SelectPaymentMethod/index.tsx +++ b/packages/design-system/lib/components/Form/SelectPaymentMethod/index.tsx @@ -31,12 +31,19 @@ export function SelectPaymentMethod({ formName, }: SelectPaymentMethodProps) { const intl = useIntl() + const hasSavedCards = paymentMethods.length > 0 + + if (!hasSavedCards) { + return null + } + const mySavedCardsLabel = paymentMethods.length ? intl.formatMessage({ id: 'payment.mySavedCards', defaultMessage: 'My saved cards', }) : undefined + const otherCardLabel = paymentMethods.length ? intl.formatMessage({ id: 'common.other', @@ -44,8 +51,6 @@ export function SelectPaymentMethod({ }) : undefined - const hasSavedCards = paymentMethods.length > 0 - return (
- {hasSavedCards ? ( - <> - - {mySavedCardsLabel} - - {paymentMethods?.map((paymentMethods) => { - const label = - PAYMENT_METHOD_TITLES[paymentMethods.cardType] || - paymentMethods.alias || - paymentMethods.cardType - - return ( - - ) - })} - - {otherCardLabel} - - - ) : null} + + {mySavedCardsLabel} + + {paymentMethods?.map((paymentMethods) => { + const label = + PAYMENT_METHOD_TITLES[paymentMethods.cardType] || + paymentMethods.alias || + paymentMethods.cardType + return ( + + ) + })} + + {otherCardLabel} +