From 1bd8fe6821414b0f07ab3ae894c0e6024f30bdb1 Mon Sep 17 00:00:00 2001 From: Anton Gunnarsson Date: Tue, 5 Aug 2025 09:20:20 +0000 Subject: [PATCH] Merged in feat/sw-2879-booking-widget-to-booking-flow-package (pull request #2532) feat(SW-2879): Move BookingWidget to booking-flow package * Fix lockfile * Fix styling * a tiny little booking widget test * Tiny fixes * Merge branch 'master' into feat/sw-2879-booking-widget-to-booking-flow-package * Remove unused scripts * lint:fix * Merge branch 'master' into feat/sw-2879-booking-widget-to-booking-flow-package * Tiny lint fixes * update test * Update Input in booking-flow * Clean up comments etc * Merge branch 'master' into feat/sw-2879-booking-widget-to-booking-flow-package * Setup tracking context for booking-flow * Add missing use client * Fix temp tracking function * Pass booking to booking-widget * Remove comment * Add use client to booking widget tracking provider * Add use client to tracking functions * Merge branch 'master' into feat/sw-2879-booking-widget-to-booking-flow-package * Move debug page * Merge branch 'master' into feat/sw-2879-booking-widget-to-booking-flow-package * Merge branch 'master' into feat/sw-2879-booking-widget-to-booking-flow-package * Merge branch 'master' into feat/sw-2879-booking-widget-to-booking-flow-package Approved-by: Bianca Widstam --- apps/partner-sas/app/[lang]/debug/page.tsx | 53 +++++ apps/partner-sas/app/[lang]/layout.tsx | 52 +++-- apps/partner-sas/app/[lang]/page.module.css | 4 - apps/partner-sas/app/[lang]/page.tsx | 51 ++--- apps/partner-sas/app/favicon.ico | Bin 0 -> 7406 bytes apps/partner-sas/app/utils/tracking.ts | 11 + .../[lang] => components}/ClientComponent.tsx | 0 apps/partner-sas/components/IntlProvider.tsx | 24 ++ apps/partner-sas/globals.css | 107 +++++++++ apps/partner-sas/next.config.ts | 22 +- apps/partner-sas/package.json | 1 + apps/partner-sas/playwright.config.ts | 20 +- .../public/_static/icons/cancel.svg | 1 + apps/partner-sas/tests/booking-widget.spec.ts | 206 +++++++++++++++++ apps/partner-sas/tests/dummy.spec.ts | 7 - .../(contentTypes)/start_page/[uid]/page.tsx | 3 +- .../payment-callback/page.tsx | 8 +- .../alternative-hotels/map/page.tsx | 3 +- .../(standard)/alternative-hotels/page.tsx | 5 +- .../(standard)/details/page.tsx | 3 +- .../(standard)/select-hotel/map/page.tsx | 3 +- .../(standard)/select-hotel/page.tsx | 5 +- .../(standard)/select-rate/page.tsx | 2 +- .../destination_city_page/[uid]/page.tsx | 10 +- .../(contentTypes)/hotel_page/[uid]/page.tsx | 10 +- .../hotelreservation/[...paths]/loading.tsx | 2 +- .../@bookingwidget/hotelreservation/page.tsx | 10 +- .../app/[lang]/(live)/@bookingwidget/page.tsx | 10 +- apps/scandic-web/app/[lang]/(live)/layout.tsx | 30 ++- .../sas-x-scandic/transfer/success/page.tsx | 2 +- .../components/BookingWidget/index.tsx | 39 ---- .../CityMap/HotelList/index.tsx | 2 +- .../DestinationSearch/Form.tsx | 3 +- .../ContentType/DestinationPage/Map/index.tsx | 2 +- .../SidebarContentWrapper/index.tsx | 6 +- .../ContentType/HotelMapPage/Client.tsx | 2 +- .../HotelPage/Map/MapWithCard/index.tsx | 5 +- .../HotelPage/SidePeeks/Room/index.tsx | 3 +- .../HotelPage/TabNavigation/index.tsx | 5 +- .../ContentType/StartPage/index.tsx | 8 +- .../components/DatePicker/Single/Desktop.tsx | 8 +- .../components/DatePicker/Single/Mobile.tsx | 8 +- .../BookingConfirmation/Receipt/index.tsx | 2 +- .../BookingConfirmation/Rooms/Room/index.tsx | 8 +- .../BookingConfirmation/Tracking/index.tsx | 3 +- .../Payment/BookingAlert/index.tsx | 2 +- .../PaymentCallback/HandleErrorCallback.tsx | 3 +- .../EnterDetails/Payment/PaymentClient.tsx | 5 +- .../EnterDetails/StorageCleaner.tsx | 3 +- .../EnterDetails/Summary/UI/index.tsx | 3 +- .../EnterDetails/Tracking/index.tsx | 3 +- .../HotelReservation/HotelCard/index.tsx | 10 +- .../HotelCardListing/index.tsx | 6 +- .../AddAncillaryFlowModal/index.tsx | 2 +- .../MyStay/Receipt/Footer/index.tsx | 3 +- .../CancelStay/Steps/Confirmation/index.tsx | 2 +- .../ChangeDates/Steps/Confirmation/index.tsx | 2 +- .../ChangeDates/Steps/Form/NewDates/index.tsx | 3 +- .../GuaranteeLateArrival/Form/index.tsx | 2 +- .../MyStay/ReferenceCard/Dates/index.tsx | 2 +- .../MyStay/Rooms/MultiRoom/Room.tsx | 2 +- .../Rooms/SingleRoom/Details/ModifyBy.tsx | 2 +- .../PriceDetailsTable/index.tsx | 3 +- .../SelectHotel/BookingCodeFilter/index.tsx | 5 +- .../MobileMapButtonContainer/index.tsx | 7 +- .../SelectHotel/NoAvailabilityAlert.tsx | 3 +- .../SelectHotelMapContent/index.tsx | 16 +- .../MobileSummary/Content/index.tsx | 2 +- .../RateSummary/MobileSummary/Summary.tsx | 2 +- .../Rooms/MultiRoomWrapper/index.tsx | 2 +- .../Rooms/NoAvailabilityAlert/index.tsx | 2 +- .../RoomsHeader/BookingCodeFilter/index.tsx | 3 +- .../Rates/BreakfastMessage/index.tsx | 3 +- .../RoomsList/RoomListItem/Rates/Campaign.tsx | 2 +- .../RoomListItem/Rates/Redemptions.tsx | 2 +- .../RoomsList/RoomListItem/Rates/Regular.tsx | 2 +- .../RoomsList/RoomListItem/Rates/index.tsx | 2 +- .../SelectRate/RoomsContainer/index.tsx | 5 +- .../SelectRate/Tracking/index.tsx | 5 +- .../components/MapContainer/index.tsx | 2 +- .../MyPages/DigitalTeamMemberCard/Content.tsx | 2 +- .../SidePeeks/BookedRoomSidePeek/index.tsx | 3 +- .../components/SitewideAlert/index.tsx | 7 +- .../StickyMeetingPackageWidget/index.tsx | 4 +- .../TempDesignSystem/Breadcrumbs/index.tsx | 3 +- apps/scandic-web/constants/booking.ts | 2 - .../constants/routes/hotelReservation.js | 69 ------ apps/scandic-web/hooks/useScrollSpy.ts | 2 +- .../lib/trpc/memoizedRequests/index.ts | 32 --- apps/scandic-web/package.json | 9 - .../stores/enter-details/helpers.ts | 2 +- .../scandic-web/stores/enter-details/index.ts | 6 +- apps/scandic-web/stores/select-rate/index.ts | 4 +- apps/scandic-web/stores/tracking.ts | 2 +- .../bookingWidget/guestsRoomsPicker.ts | 38 ---- .../types/components/bookingWidget/index.ts | 42 ---- .../types/components/datepicker.ts | 21 -- .../types/components/form/bookingwidget.ts | 12 - .../components/hotelReservation/booking.ts | 3 - .../hotelReservation/enterDetails/details.ts | 2 +- .../selectHotel/selectHotel.ts | 2 +- .../hotelReservation/selectRate/selectRate.ts | 3 +- apps/scandic-web/types/components/search.ts | 39 ---- .../types/enums/bookingCodeFilter.ts | 4 - .../types/providers/enter-details.ts | 2 +- apps/scandic-web/types/stores/rates.ts | 2 +- apps/scandic-web/utils/getErrorMessage.ts | 41 ---- apps/scandic-web/utils/hotelSearchDetails.ts | 3 +- apps/scandic-web/utils/tracking/base.ts | 2 + apps/scandic-web/utils/tracking/booking.ts | 2 + .../lib/components/BookingFlowInput/errors.ts | 53 +++++ .../lib/components/BookingFlowInput/index.tsx | 109 +++++++++ .../BookingFlowInput/input.module.css | 17 ++ .../BookingFlowTrackingProvider.tsx | 16 ++ .../BookingCode/booking-code.module.css | 0 .../FormContent/BookingCode/index.tsx | 14 +- .../FormContent/Input/index.tsx | 0 .../FormContent/Input/input.module.css | 0 .../FormContent/RewardNight/index.tsx | 7 +- .../RewardNight/reward-night.module.css | 0 .../ClearSearchButton/button.module.css | 0 .../SearchList/ClearSearchButton/index.tsx | 10 +- .../SearchList/ClearSearchButton/variants.ts | 0 .../SearchList/Dialog/dialog.module.css | 0 .../Search/SearchList/Dialog/index.tsx | 11 +- .../Search/SearchList/Dialog/variants.ts | 0 .../Search/SearchList/List/Label.tsx | 0 .../Search/SearchList/List/ListItem/index.tsx | 8 +- .../List/ListItem/listItem.module.css | 0 .../SearchList/List/ListItem/variants.ts | 0 .../Search/SearchList/List/index.tsx | 8 +- .../Search/SearchList/List/list.module.css | 0 .../FormContent/Search/SearchList/index.tsx | 20 +- .../Search/SearchList/searchList.module.css | 0 .../FormContent/Search/index.tsx | 5 +- .../FormContent/Search/search.module.css | 0 .../FormContent/ValidationError/index.tsx | 0 .../validationError.module.css | 0 .../FormContent/Voucher/index.tsx | 0 .../FormContent/Voucher/voucher.module.css | 0 .../FormContent/formContent.module.css | 0 .../BookingWidgetForm}/FormContent/index.tsx | 18 +- .../BookingWidgetForm}/FormContent/utils.ts | 0 .../BookingWidgetForm}/form.module.css | 0 .../BookingWidgetForm}/index.tsx | 32 +-- .../BookingWidgetForm}/schema.ts | 0 .../BookingWidgetForm}/variants.ts | 0 .../lib}/components/BookingWidget/Client.tsx | 63 ++--- .../DatePicker/Range/Desktop.tsx | 13 +- .../DatePicker/Range/Mobile.tsx | 11 +- .../DatePicker/Range/desktop.module.css | 0 .../DatePicker/Range/mobile.module.css | 0 .../DatePicker/date-picker.module.css | 0 .../BookingWidget}/DatePicker/index.tsx | 17 +- .../BookingWidget/DatePicker/locales.ts | 11 + .../FloatingBookingWidget.module.css | 0 .../FloatingBookingWidgetClient.tsx | 4 +- .../FloatingBookingWidget/index.tsx | 10 +- .../AdultSelector/adult-selector.module.css | 0 .../GuestsRoomsPicker/AdultSelector/index.tsx | 8 +- .../ChildSelector/ChildInfoSelector.tsx | 17 +- .../ChildSelector/child-selector.module.css | 0 .../GuestsRoomsPicker/ChildSelector/index.tsx | 10 +- .../Counter/counter.module.css | 0 .../GuestsRoomsPicker/Counter/index.tsx | 8 +- .../BookingWidget}/GuestsRoomsPicker/Form.tsx | 5 +- .../GuestsRoomsPicker/GuestsRoom/index.tsx | 9 +- .../guests-rooms-picker.module.css | 0 .../GuestsRoomsPicker/index.tsx | 4 +- .../MobileToggleButton/button.module.css | 0 .../MobileToggleButton/index.tsx | 13 +- .../lib/components/BookingWidget/Skeleton.tsx | 30 +++ .../BookingWidget/bookingWidget.module.css | 0 .../lib/components/BookingWidget/index.tsx | 73 ++++++ .../lib}/components/BookingWidget/variant.ts | 0 .../Modal/ModalContentWithActions/index.tsx | 69 ++++++ .../modalContent.module.css | 45 ++++ .../lib/components/TEMP/Modal/index.tsx | 215 ++++++++++++++++++ .../components/TEMP/Modal/modal.module.css | 95 ++++++++ .../lib/components/TEMP/Modal/modal.ts | 36 +++ .../components/TEMP/Modal/motionVariants.ts | 23 ++ .../lib/components/TEMP/Modal/variants.ts | 17 ++ packages/booking-flow/lib/hooks/useLang.ts | 17 ++ .../lib}/hooks/useSearchHistory.ts | 2 +- packages/booking-flow/lib/index.tsx | 28 --- packages/booking-flow/lib/misc/searchType.ts | 4 + .../lib}/stores/bookingCode-filter.ts | 6 +- packages/booking-flow/lib/trackingContext.tsx | 26 +++ .../booking-flow/lib/trpc/memoizedRequests.ts | 48 ++++ packages/booking-flow/lib/types.ts | 1 + .../lib}/utils/searchParams.test.ts | 0 .../booking-flow/lib}/utils/searchParams.ts | 2 +- .../booking-flow/lib}/utils/url.ts | 65 +++++- packages/booking-flow/package.json | 23 +- .../common}/constants/dateFormats.ts | 2 +- .../constants/routes/hotelReservation.ts | 41 ++++ .../common}/hooks/useStickyPosition.ts | 5 +- packages/common/package.json | 11 +- .../common}/stores/sticky-position.ts | 0 .../common}/utils/debounce.ts | 0 .../common}/utils/isValidJson.ts | 0 packages/common/utils/maskValue.ts | 2 +- .../lib/components/OldDSButton/button.ts | 20 -- .../lib/components/OldDSButton/index.tsx | 21 +- .../campaignOverviewPage/utils.ts | 3 +- yarn.lock | 14 ++ 206 files changed, 1936 insertions(+), 796 deletions(-) create mode 100644 apps/partner-sas/app/[lang]/debug/page.tsx delete mode 100644 apps/partner-sas/app/[lang]/page.module.css create mode 100644 apps/partner-sas/app/favicon.ico create mode 100644 apps/partner-sas/app/utils/tracking.ts rename apps/partner-sas/{app/[lang] => components}/ClientComponent.tsx (100%) create mode 100644 apps/partner-sas/components/IntlProvider.tsx create mode 100644 apps/partner-sas/globals.css create mode 100644 apps/partner-sas/public/_static/icons/cancel.svg create mode 100644 apps/partner-sas/tests/booking-widget.spec.ts delete mode 100644 apps/partner-sas/tests/dummy.spec.ts delete mode 100644 apps/scandic-web/components/BookingWidget/index.tsx delete mode 100644 apps/scandic-web/constants/routes/hotelReservation.js delete mode 100644 apps/scandic-web/types/components/bookingWidget/guestsRoomsPicker.ts delete mode 100644 apps/scandic-web/types/components/bookingWidget/index.ts delete mode 100644 apps/scandic-web/types/components/datepicker.ts delete mode 100644 apps/scandic-web/types/components/form/bookingwidget.ts delete mode 100644 apps/scandic-web/types/components/hotelReservation/booking.ts delete mode 100644 apps/scandic-web/types/enums/bookingCodeFilter.ts create mode 100644 packages/booking-flow/lib/components/BookingFlowInput/errors.ts create mode 100644 packages/booking-flow/lib/components/BookingFlowInput/index.tsx create mode 100644 packages/booking-flow/lib/components/BookingFlowInput/input.module.css create mode 100644 packages/booking-flow/lib/components/BookingFlowTrackingProvider.tsx rename {apps/scandic-web/components/Forms/BookingWidget => packages/booking-flow/lib/components/BookingWidget/BookingWidgetForm}/FormContent/BookingCode/booking-code.module.css (100%) rename {apps/scandic-web/components/Forms/BookingWidget => packages/booking-flow/lib/components/BookingWidget/BookingWidgetForm}/FormContent/BookingCode/index.tsx (97%) rename {apps/scandic-web/components/Forms/BookingWidget => packages/booking-flow/lib/components/BookingWidget/BookingWidgetForm}/FormContent/Input/index.tsx (100%) rename {apps/scandic-web/components/Forms/BookingWidget => packages/booking-flow/lib/components/BookingWidget/BookingWidgetForm}/FormContent/Input/input.module.css (100%) rename {apps/scandic-web/components/Forms/BookingWidget => packages/booking-flow/lib/components/BookingWidget/BookingWidgetForm}/FormContent/RewardNight/index.tsx (96%) rename {apps/scandic-web/components/Forms/BookingWidget => packages/booking-flow/lib/components/BookingWidget/BookingWidgetForm}/FormContent/RewardNight/reward-night.module.css (100%) rename {apps/scandic-web/components/Forms/BookingWidget => packages/booking-flow/lib/components/BookingWidget/BookingWidgetForm}/FormContent/Search/SearchList/ClearSearchButton/button.module.css (100%) rename {apps/scandic-web/components/Forms/BookingWidget => packages/booking-flow/lib/components/BookingWidget/BookingWidgetForm}/FormContent/Search/SearchList/ClearSearchButton/index.tsx (84%) rename {apps/scandic-web/components/Forms/BookingWidget => packages/booking-flow/lib/components/BookingWidget/BookingWidgetForm}/FormContent/Search/SearchList/ClearSearchButton/variants.ts (100%) rename {apps/scandic-web/components/Forms/BookingWidget => packages/booking-flow/lib/components/BookingWidget/BookingWidgetForm}/FormContent/Search/SearchList/Dialog/dialog.module.css (100%) rename {apps/scandic-web/components/Forms/BookingWidget => packages/booking-flow/lib/components/BookingWidget/BookingWidgetForm}/FormContent/Search/SearchList/Dialog/index.tsx (51%) rename {apps/scandic-web/components/Forms/BookingWidget => packages/booking-flow/lib/components/BookingWidget/BookingWidgetForm}/FormContent/Search/SearchList/Dialog/variants.ts (100%) rename {apps/scandic-web/components/Forms/BookingWidget => packages/booking-flow/lib/components/BookingWidget/BookingWidgetForm}/FormContent/Search/SearchList/List/Label.tsx (100%) rename {apps/scandic-web/components/Forms/BookingWidget => packages/booking-flow/lib/components/BookingWidget/BookingWidgetForm}/FormContent/Search/SearchList/List/ListItem/index.tsx (88%) rename {apps/scandic-web/components/Forms/BookingWidget => packages/booking-flow/lib/components/BookingWidget/BookingWidgetForm}/FormContent/Search/SearchList/List/ListItem/listItem.module.css (100%) rename {apps/scandic-web/components/Forms/BookingWidget => packages/booking-flow/lib/components/BookingWidget/BookingWidgetForm}/FormContent/Search/SearchList/List/ListItem/variants.ts (100%) rename {apps/scandic-web/components/Forms/BookingWidget => packages/booking-flow/lib/components/BookingWidget/BookingWidgetForm}/FormContent/Search/SearchList/List/index.tsx (88%) rename {apps/scandic-web/components/Forms/BookingWidget => packages/booking-flow/lib/components/BookingWidget/BookingWidgetForm}/FormContent/Search/SearchList/List/list.module.css (100%) rename {apps/scandic-web/components/Forms/BookingWidget => packages/booking-flow/lib/components/BookingWidget/BookingWidgetForm}/FormContent/Search/SearchList/index.tsx (92%) rename {apps/scandic-web/components/Forms/BookingWidget => packages/booking-flow/lib/components/BookingWidget/BookingWidgetForm}/FormContent/Search/SearchList/searchList.module.css (100%) rename {apps/scandic-web/components/Forms/BookingWidget => packages/booking-flow/lib/components/BookingWidget/BookingWidgetForm}/FormContent/Search/index.tsx (97%) rename {apps/scandic-web/components/Forms/BookingWidget => packages/booking-flow/lib/components/BookingWidget/BookingWidgetForm}/FormContent/Search/search.module.css (100%) rename {apps/scandic-web/components/Forms/BookingWidget => packages/booking-flow/lib/components/BookingWidget/BookingWidgetForm}/FormContent/ValidationError/index.tsx (100%) rename {apps/scandic-web/components/Forms/BookingWidget => packages/booking-flow/lib/components/BookingWidget/BookingWidgetForm}/FormContent/ValidationError/validationError.module.css (100%) rename {apps/scandic-web/components/Forms/BookingWidget => packages/booking-flow/lib/components/BookingWidget/BookingWidgetForm}/FormContent/Voucher/index.tsx (100%) rename {apps/scandic-web/components/Forms/BookingWidget => packages/booking-flow/lib/components/BookingWidget/BookingWidgetForm}/FormContent/Voucher/voucher.module.css (100%) rename {apps/scandic-web/components/Forms/BookingWidget => packages/booking-flow/lib/components/BookingWidget/BookingWidgetForm}/FormContent/formContent.module.css (100%) rename {apps/scandic-web/components/Forms/BookingWidget => packages/booking-flow/lib/components/BookingWidget/BookingWidgetForm}/FormContent/index.tsx (94%) rename {apps/scandic-web/components/Forms/BookingWidget => packages/booking-flow/lib/components/BookingWidget/BookingWidgetForm}/FormContent/utils.ts (100%) rename {apps/scandic-web/components/Forms/BookingWidget => packages/booking-flow/lib/components/BookingWidget/BookingWidgetForm}/form.module.css (100%) rename {apps/scandic-web/components/Forms/BookingWidget => packages/booking-flow/lib/components/BookingWidget/BookingWidgetForm}/index.tsx (82%) rename {apps/scandic-web/components/Forms/BookingWidget => packages/booking-flow/lib/components/BookingWidget/BookingWidgetForm}/schema.ts (100%) rename {apps/scandic-web/components/Forms/BookingWidget => packages/booking-flow/lib/components/BookingWidget/BookingWidgetForm}/variants.ts (100%) rename {apps/scandic-web => packages/booking-flow/lib}/components/BookingWidget/Client.tsx (85%) rename {apps/scandic-web/components => packages/booking-flow/lib/components/BookingWidget}/DatePicker/Range/Desktop.tsx (93%) rename {apps/scandic-web/components => packages/booking-flow/lib/components/BookingWidget}/DatePicker/Range/Mobile.tsx (94%) rename {apps/scandic-web/components => packages/booking-flow/lib/components/BookingWidget}/DatePicker/Range/desktop.module.css (100%) rename {apps/scandic-web/components => packages/booking-flow/lib/components/BookingWidget}/DatePicker/Range/mobile.module.css (100%) rename {apps/scandic-web/components => packages/booking-flow/lib/components/BookingWidget}/DatePicker/date-picker.module.css (100%) rename {apps/scandic-web/components => packages/booking-flow/lib/components/BookingWidget}/DatePicker/index.tsx (94%) create mode 100644 packages/booking-flow/lib/components/BookingWidget/DatePicker/locales.ts rename {apps/scandic-web => packages/booking-flow/lib}/components/BookingWidget/FloatingBookingWidget/FloatingBookingWidget.module.css (100%) rename {apps/scandic-web => packages/booking-flow/lib}/components/BookingWidget/FloatingBookingWidget/FloatingBookingWidgetClient.tsx (93%) rename {apps/scandic-web => packages/booking-flow/lib}/components/BookingWidget/FloatingBookingWidget/index.tsx (78%) rename {apps/scandic-web/components => packages/booking-flow/lib/components/BookingWidget}/GuestsRoomsPicker/AdultSelector/adult-selector.module.css (100%) rename {apps/scandic-web/components => packages/booking-flow/lib/components/BookingWidget}/GuestsRoomsPicker/AdultSelector/index.tsx (91%) rename {apps/scandic-web/components => packages/booking-flow/lib/components/BookingWidget}/GuestsRoomsPicker/ChildSelector/ChildInfoSelector.tsx (94%) rename {apps/scandic-web/components => packages/booking-flow/lib/components/BookingWidget}/GuestsRoomsPicker/ChildSelector/child-selector.module.css (100%) rename {apps/scandic-web/components => packages/booking-flow/lib/components/BookingWidget}/GuestsRoomsPicker/ChildSelector/index.tsx (89%) rename {apps/scandic-web/components => packages/booking-flow/lib/components/BookingWidget}/GuestsRoomsPicker/Counter/counter.module.css (100%) rename {apps/scandic-web/components => packages/booking-flow/lib/components/BookingWidget}/GuestsRoomsPicker/Counter/index.tsx (88%) rename {apps/scandic-web/components => packages/booking-flow/lib/components/BookingWidget}/GuestsRoomsPicker/Form.tsx (96%) rename {apps/scandic-web/components => packages/booking-flow/lib/components/BookingWidget}/GuestsRoomsPicker/GuestsRoom/index.tsx (87%) rename {apps/scandic-web/components => packages/booking-flow/lib/components/BookingWidget}/GuestsRoomsPicker/guests-rooms-picker.module.css (100%) rename {apps/scandic-web/components => packages/booking-flow/lib/components/BookingWidget}/GuestsRoomsPicker/index.tsx (96%) rename {apps/scandic-web => packages/booking-flow/lib}/components/BookingWidget/MobileToggleButton/button.module.css (100%) rename {apps/scandic-web => packages/booking-flow/lib}/components/BookingWidget/MobileToggleButton/index.tsx (96%) create mode 100644 packages/booking-flow/lib/components/BookingWidget/Skeleton.tsx rename {apps/scandic-web => packages/booking-flow/lib}/components/BookingWidget/bookingWidget.module.css (100%) create mode 100644 packages/booking-flow/lib/components/BookingWidget/index.tsx rename {apps/scandic-web => packages/booking-flow/lib}/components/BookingWidget/variant.ts (100%) create mode 100644 packages/booking-flow/lib/components/TEMP/Modal/ModalContentWithActions/index.tsx create mode 100644 packages/booking-flow/lib/components/TEMP/Modal/ModalContentWithActions/modalContent.module.css create mode 100644 packages/booking-flow/lib/components/TEMP/Modal/index.tsx create mode 100644 packages/booking-flow/lib/components/TEMP/Modal/modal.module.css create mode 100644 packages/booking-flow/lib/components/TEMP/Modal/modal.ts create mode 100644 packages/booking-flow/lib/components/TEMP/Modal/motionVariants.ts create mode 100644 packages/booking-flow/lib/components/TEMP/Modal/variants.ts create mode 100644 packages/booking-flow/lib/hooks/useLang.ts rename {apps/scandic-web => packages/booking-flow/lib}/hooks/useSearchHistory.ts (98%) delete mode 100644 packages/booking-flow/lib/index.tsx create mode 100644 packages/booking-flow/lib/misc/searchType.ts rename {apps/scandic-web => packages/booking-flow/lib}/stores/bookingCode-filter.ts (68%) create mode 100644 packages/booking-flow/lib/trackingContext.tsx create mode 100644 packages/booking-flow/lib/trpc/memoizedRequests.ts create mode 100644 packages/booking-flow/lib/types.ts rename {apps/scandic-web => packages/booking-flow/lib}/utils/searchParams.test.ts (100%) rename {apps/scandic-web => packages/booking-flow/lib}/utils/searchParams.ts (99%) rename {apps/scandic-web => packages/booking-flow/lib}/utils/url.ts (81%) rename {apps/scandic-web => packages/common}/constants/dateFormats.ts (92%) rename {apps/scandic-web => packages/common}/hooks/useStickyPosition.ts (98%) rename {apps/scandic-web => packages/common}/stores/sticky-position.ts (100%) rename {apps/scandic-web => packages/common}/utils/debounce.ts (100%) rename {apps/scandic-web => packages/common}/utils/isValidJson.ts (100%) delete mode 100644 packages/design-system/lib/components/OldDSButton/button.ts diff --git a/apps/partner-sas/app/[lang]/debug/page.tsx b/apps/partner-sas/app/[lang]/debug/page.tsx new file mode 100644 index 000000000..dd7d3dc9d --- /dev/null +++ b/apps/partner-sas/app/[lang]/debug/page.tsx @@ -0,0 +1,53 @@ +import { BookingWidget } from "@scandic-hotels/booking-flow/BookingWidget" +import { parseBookingWidgetSearchParams } from "@scandic-hotels/booking-flow/utils/url" +import { Typography } from "@scandic-hotels/design-system/Typography" + +import { serverClient } from "@/lib/trpc" + +import { getIntl } from "@/i18n" +import { getLang } from "@/i18n/serverContext" + +import { ClientComponent } from "../../../components/ClientComponent" + +type SearchParams = { + searchParams: Promise +} + +export default async function Debug(props: SearchParams) { + const searchParams = await props.searchParams + const intl = await getIntl() + const lang = await getLang() + const caller = await serverClient() + const destinations = await caller.autocomplete.destinations({ + lang, + includeTypes: ["hotels"], + query: "Göteborg", + }) + const hotel = destinations.hits.hotels[0].name + + const booking = parseBookingWidgetSearchParams(searchParams) + + return ( +
+ + {/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */} +

from booking-flow package:

+
+ +
+ + {/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */} +

hello world with data: {hotel}

+
+ + {/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */} +

+ translated: + {intl.formatMessage({ defaultMessage: "Map of the city" })} +

+
+
+ +
+ ) +} diff --git a/apps/partner-sas/app/[lang]/layout.tsx b/apps/partner-sas/app/[lang]/layout.tsx index cc501de95..63e8789fa 100644 --- a/apps/partner-sas/app/[lang]/layout.tsx +++ b/apps/partner-sas/app/[lang]/layout.tsx @@ -1,7 +1,9 @@ -import "@scandic-hotels/design-system/style.css" import "@scandic-hotels/design-system/fonts.css" +import "@scandic-hotels/design-system/style.css" import "@/public/_static/css/design-system-new-deprecated.css" +import "../../globals.css" +import { BookingFlowTrackingProvider } from "@scandic-hotels/booking-flow/BookingFlowTrackingProvider" import { Lang } from "@scandic-hotels/common/constants/language" import { TrpcProvider } from "@scandic-hotels/trpc/Provider" @@ -9,6 +11,8 @@ import { getMessages } from "@/i18n" import ClientIntlProvider from "@/i18n/Provider" import { setLang } from "@/i18n/serverContext" +import { trackBookingSearchClick } from "../utils/tracking" + import type { Metadata } from "next" export const metadata: Metadata = { @@ -35,21 +39,39 @@ export default async function RootLayout(props: RootLayoutProps) { return ( - - {/* eslint-disable-next-line @next/next/no-css-tags */} - - {/* eslint-disable-next-line @next/next/no-css-tags */} - - + {/* TODO */} - - {/* TODO handle onError */} - {children} - +
+ + {/* TODO handle onError */} + + +
+ {/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */} +

SAS

+
+
{children}
+
+
+
+
) diff --git a/apps/partner-sas/app/[lang]/page.module.css b/apps/partner-sas/app/[lang]/page.module.css deleted file mode 100644 index 0c38093bf..000000000 --- a/apps/partner-sas/app/[lang]/page.module.css +++ /dev/null @@ -1,4 +0,0 @@ -.page { - padding-left: 200px; - padding-top: 200px; -} diff --git a/apps/partner-sas/app/[lang]/page.tsx b/apps/partner-sas/app/[lang]/page.tsx index be56c55ef..c42416e12 100644 --- a/apps/partner-sas/app/[lang]/page.tsx +++ b/apps/partner-sas/app/[lang]/page.tsx @@ -1,44 +1,29 @@ -import { Temp } from "@scandic-hotels/booking-flow/test-entry" -import { Lang } from "@scandic-hotels/common/constants/language" -import { Typography } from "@scandic-hotels/design-system/Typography" +import { BookingWidget } from "@scandic-hotels/booking-flow/BookingWidget" +import { parseBookingWidgetSearchParams } from "@scandic-hotels/booking-flow/utils/url" import { serverClient } from "@/lib/trpc" -import { getIntl } from "@/i18n" +import { getLang } from "@/i18n/serverContext" -import { ClientComponent } from "./ClientComponent" +import type { Lang } from "@scandic-hotels/common/constants/language" -import styles from "./page.module.css" +type SearchParams = { + searchParams: Promise +} -export default async function Home() { - const intl = await getIntl() - const caller = await serverClient() - const destinations = await caller.autocomplete.destinations({ - lang: Lang.en, - includeTypes: ["hotels"], - query: "Göteborg", - }) - const hotel = destinations.hits.hotels[0].name +export default async function Home(props: SearchParams<{ lang: Lang }>) { + const searchParams = await props.searchParams + + // TODO we need this import right now to ensure configureServerClient is called, + // but we should ensure it's called in a layout instead. + const _caller = await serverClient() + const lang = await getLang() + + const booking = parseBookingWidgetSearchParams(searchParams) return ( -
-
- - {/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */} -

hello world with data: {hotel}

-
- -

{intl.formatMessage({ defaultMessage: "Map of the city" })}

-
-
- -
- - {/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */} -

from booking-flow package:

-
- -
+
+
) } diff --git a/apps/partner-sas/app/favicon.ico b/apps/partner-sas/app/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..a29b7b4577b1afdee3ae5b350f2371ff75c008ba GIT binary patch literal 7406 zcmeI02UOEn7r?IzqqtGrvWJBAm+68qWCul5R1g8hZH+-u!G&9i3eIY)R_m^|R%@-J z)={h0Q>JWCK$Z-Vy|MQ_5)uMQ`}dsz)`*7fVL33? zBp%XIYv4_G9oShVz^N|_!POxNN=h2w9hTFl3SrKyG^nj@0`=ih@c2z%rVfgV8X#hC9(;A85ZoM-VA|vq@bOB6ckddYy1EH!urxP+fa}-Z!GeGc z(9?_o1DzN!Gm3)=7B3+`uO245BtuzQBh=M3!?~}E;N%x?;pUA}SQ7XO8XKEIOC=gs z@iIYIJsRR;tH5qz0#sHu!LcI+P=)oJnQ2f{(*z$re1L`XGQh+j4klW@gyf`ZC@pOS zC%Z(L;+hPFh4oNh-wd;7q(Xpix_Ey-wLa~@zhDQPI(iH}hO3Cj4SHF7_I4gTV4`qH zOLvI7t}B>~HEbE^Gf27T2u*E{t%BIb$*Eh{F`dMHOXV(|U2H`Cp)6xlB`bA(VZWcd zlG2c=;}nHmJBPlLRo(1F%1&k)O#jvnHinI|vY({lVIeYi(iu2#w6mxAc#%>cqX|8_ zkJM8W^_`qNxKr4U!sUubN$bD;iHM(7#lpct{4;&Jwp8>}=w})ISn7|6Z~gUgIedGi z1U^4pK>g74DJft*_9gXc#2*#p*F$Vf72Li39@ehPqW+ioHsYU%Zz6t)_|zBAE8qnB zwVm5?V5Vm(tX%$@`XRPf47`l521DH#^smK`lvoW9e<_2=efeh4_KArgU)RY>i zsAz<%-;}^_Ps$-|!y7nuv;dA{AwILI=>zDfMN_~0_H8{BVu_Edf}iichc!W2aN%qb z`1zz$pYJj$2||Lifa{b*V@F1MZL80J{;UG$dJdKH3Dp54{@S{ zG-D%9Z#t+0xt@Dh*S@paXzuSbpq+eO?@+6r0SaVtwwrxB@xY-Y19(&z&h68=o!HKa zjZy`6(C$dBUViPw{0S)K1-X3YxqNbaA)mi?ADhEl)6KTs4<}Ss9HYQt@0#C{DIGK1 zpupid$`tdL&Si7h`(?|m9sD^wE2Ak?qsQ7U?bfj!$gVE-nktwWv1o{fp7d0E)Q005 zumi#s!rA`5n(gF#rBQv?2jKY&$5X27(_YT!D^8!L-Cf6R#bU;JT)XdY`93|%En&+- ztfjyFf7t(j`zpdIm?DB7mR3&bfgRB!

MjYsMg}lwq6ZPr7-A!ZE)i$85vglQ4`8 z=78RqOA&^#w@v^9WEjFRB>%jBuZ(hxh*>sV3kYfKE|VBXwxFvXhW#w4F5`7g<7Ghf#NVVo1k z--6fFRNyUp4YQ`F()^a>;)HFAiyJ84Jh)#5mo5~;!H9g=ur8bOj)--}nZ|d>I(fNu z5FJ$sw{Mlg?j5-hv?8;We~gfO2>YZY*HHGka=C=^&yj-#@ZHrCxQ2z~#w33xJVf&B zWs6=>E}G$yLfJ?cxk$uE1qH}>m{$`{3g%}~R+@{fv~G14%)>mH{ z&+$HjdK{J%2I*;8I-3i@g9TRWso}u z^$}4}hjn&V9lfU@_YQ=y$bCQ*-c_8zI}O5EG=~7jM=bvYA{iGs9Mf9vxP6KQr~Q z7SnPVP@QF9Cr4e;!Q*jYknpV0+4aAbvztCs7O*6g1x)0Ht8z9|`D=BtHj7~$f4Edz z-eMFY>5kwTV;J?GvmAq!ph;BTr&tWhQU{KIngyUiE((IEQFs5XOgIvhi?ekQ!_zgV`x z>a%>*7p(kAwn|&c093~p=3SN8`5*iL&{j#JcWWX&!mQ(?9nFT^Tl>@1GydI=xonou zkZK;e)bbBuSmz&gI&QsiKP!ko^RkqZM0e=@*7LSc(Bh~CU&_&s@cmi!j*0Nh(U;*0 zX3Nu$P_*&T+ay5uOr9V +> + +export default function ClientIntlProvider({ + children, + locale, + defaultLocale, + messages, +}: ClientIntlProviderProps) { + return ( + + {children} + + ) +} diff --git a/apps/partner-sas/globals.css b/apps/partner-sas/globals.css new file mode 100644 index 000000000..4bd623dc1 --- /dev/null +++ b/apps/partner-sas/globals.css @@ -0,0 +1,107 @@ +:root { + --current-max-width: 113.5rem; + + --max-width: 94.5rem; + --max-width-content: min(calc(100dvw - var(--max-width-spacing)), 74.75rem); + --max-width-text-block: 49.5rem; + --current-mobile-site-header-height: 52.41px; + --max-width-navigation: 89.5rem; + + --max-width-single-spacing: var(--Layout-Mobile-Margin-Margin-min); + --max-width-spacing: calc(var(--max-width-single-spacing) * 2); + --max-width-page: min( + calc(100dvw - var(--max-width-spacing)), + var(--max-width-navigation) + ); + + --sitewide-alert-height: 0px; /* Will be overridden when a sitewide alert is visible */ + --main-menu-mobile-height: 75px; + --main-menu-desktop-height: 125px; + --booking-widget-mobile-height: 75px; + --booking-widget-tablet-height: 150px; + --booking-widget-desktop-height: 77px; + --hotel-page-map-desktop-width: 23.75rem; + + /* Z-INDEX */ + --header-z-index: 11; + --menu-overlay-z-index: 11; + --booking-widget-z-index: 10; + --booking-widget-open-z-index: 100; + --dialog-z-index: 9; + --back-to-top-button: 80; + --language-switcher-z-index: 85; + --sidepeek-z-index: 100; + --lightbox-z-index: 150; + --default-modal-overlay-z-index: 100; + --default-modal-z-index: 101; + + --modal-box-shadow: 0px 4px 24px 0px rgba(38, 32, 30, 0.08); + --popup-box-shadow: 0 0 14px 6px rgba(0, 0, 0, 0.1); + + @supports (interpolate-size: allow-keywords) { + interpolate-size: allow-keywords; + } +} + +* { + box-sizing: border-box; +} + +html, +body { + margin: 0; + padding: 0; + scroll-behavior: smooth; +} + +body { + min-height: 100dvh; + overflow-x: hidden; + display: flex; + flex-direction: column; + color: var(--Text-Default); +} + +body.overflow-hidden { + overflow: hidden; +} + +.root { + isolation: isolate; +} + +/* From Tailwind */ +.sr-only { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border-width: 0; +} + +ul { + padding-inline-start: 0; + margin-block-start: 0; + margin-block-end: 0; +} + +@media screen and (min-width: 768px) { + :root { + --max-width-single-spacing: var(--Layout-Tablet-Margin-Margin-min); + } + + body.overflow-hidden { + overflow: auto; + overflow-x: hidden; + } +} + +@media screen and (min-width: 1367px) { + :root { + --max-width-single-spacing: var(--Layout-Desktop-Margin-Margin-min); + } +} diff --git a/apps/partner-sas/next.config.ts b/apps/partner-sas/next.config.ts index 8f084731f..ff3059491 100644 --- a/apps/partner-sas/next.config.ts +++ b/apps/partner-sas/next.config.ts @@ -12,6 +12,17 @@ const nextConfig: NextConfig = { ], output: "standalone", + experimental: { + swcPlugins: [ + [ + "@swc/plugin-formatjs", + { + ast: true, + }, + ], + ], + }, + webpack: function (config: any) { config.module.rules.push( { @@ -27,17 +38,6 @@ const nextConfig: NextConfig = { return config }, - - experimental: { - swcPlugins: [ - [ - "@swc/plugin-formatjs", - { - ast: true, - }, - ], - ], - }, } export default Sentry.withSentryConfig(nextConfig, { diff --git a/apps/partner-sas/package.json b/apps/partner-sas/package.json index 8a844ca63..5fc0ffabb 100644 --- a/apps/partner-sas/package.json +++ b/apps/partner-sas/package.json @@ -34,6 +34,7 @@ "@playwright/test": "^1.53.1", "@scandic-hotels/common": "workspace:*", "@scandic-hotels/typescript-config": "workspace:*", + "@swc/plugin-formatjs": "^3.2.2", "@types/node": "^20", "@types/react": "19.1.0", "@types/react-dom": "19.1.0", diff --git a/apps/partner-sas/playwright.config.ts b/apps/partner-sas/playwright.config.ts index e3ba29f89..b0f9671f9 100644 --- a/apps/partner-sas/playwright.config.ts +++ b/apps/partner-sas/playwright.config.ts @@ -28,25 +28,37 @@ export default defineConfig({ /* Base URL to use in actions like `await page.goto('/')`. */ baseURL: "http://localhost:3001", + /* How long to wait for actions to complete. */ + actionTimeout: 15 * 1000, + /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ - trace: "on-first-retry", + trace: process.env.CI ? "on-first-retry" : "retain-on-failure", }, /* Configure projects for major browsers */ projects: [ { name: "chromium", - use: { ...devices["Desktop Chrome"] }, + use: { + ...devices["Desktop Chrome"], + viewport: { width: 1400, height: 720 }, + }, }, { name: "firefox", - use: { ...devices["Desktop Firefox"] }, + use: { + ...devices["Desktop Firefox"], + viewport: { width: 1400, height: 720 }, + }, }, { name: "webkit", - use: { ...devices["Desktop Safari"] }, + use: { + ...devices["Desktop Safari"], + viewport: { width: 1400, height: 720 }, + }, }, /* Test against mobile viewports. */ diff --git a/apps/partner-sas/public/_static/icons/cancel.svg b/apps/partner-sas/public/_static/icons/cancel.svg new file mode 100644 index 000000000..9b72e85a0 --- /dev/null +++ b/apps/partner-sas/public/_static/icons/cancel.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/apps/partner-sas/tests/booking-widget.spec.ts b/apps/partner-sas/tests/booking-widget.spec.ts new file mode 100644 index 000000000..517042be7 --- /dev/null +++ b/apps/partner-sas/tests/booking-widget.spec.ts @@ -0,0 +1,206 @@ +import { expect, type Page, test } from "@playwright/test" + +import { serializeBookingSearchParams } from "@scandic-hotels/booking-flow/utils/url" +import { ChildBedMapEnum } from "@scandic-hotels/trpc/enums/childBedMapEnum" + +test("can make a search with city", async ({ page }) => { + await page.goto("/") + + // Search for city + const combobox = page.getByRole("combobox", { name: /where to/i }) + await combobox.click() + await combobox.fill("stockholm") + await page.getByRole("option", { name: /stockholm sweden/i }).click() + + // Open datepicker + // If we had better accessibility for our datepicker this would be so much easier + const today = new Date() + const tomorrow = new Date(today) + tomorrow.setDate(today.getDate() + 1) + + await page + .getByRole("button", { + name: `${formatDate(today)} - ${formatDate(tomorrow)}`, + }) + .click() + + // Select future dates + const twoDaysFromNow = new Date(today) + twoDaysFromNow.setDate(today.getDate() + 2) + await clickDatePickerDate(page, twoDaysFromNow) + + const threeDaysFromNow = new Date(today) + threeDaysFromNow.setDate(today.getDate() + 3) + await clickDatePickerDate(page, threeDaysFromNow) + + await page + .getByRole("button", { + name: /select dates/i, + }) + .click() + + // Select rooms and guests + // Once again, better accessibility would make this so much easier + await page.getByRole("button", { name: /1 room, 1 adult/i }).click() + const roomsDialog = page.getByRole("dialog") + const room1section = roomsDialog.getByText(/room 1/i).locator("..") + + // Add 1 adult + await room1section + .locator("section") + .filter({ hasText: /adults/i }) + .getByRole("button", { name: /add/i }) + .click() + + // Add 1 child aged 10 + await room1section + .locator("section") + .filter({ hasText: /children/i }) + .getByRole("button", { name: /add/i }) + .click() + await room1section.getByRole("button", { name: /age/i }).click() + await page.getByRole("option", { name: /10/i }).click() + + await page.getByRole("button", { name: /add room/i }).click() + + const room2section = roomsDialog.getByText(/room 2/i).locator("..") + + // Add 2 adults + await room2section + .locator("section") + .filter({ hasText: /adults/i }) + .getByRole("button", { name: /add/i }) + .click({ clickCount: 2 }) + + await roomsDialog.getByRole("button", { name: /done/i }).click() + + await page.getByRole("button", { name: /search/i }).click() + + // Assert that we navigated to the correct URL + const expectedSearchParams = serializeBookingSearchParams({ + rooms: [ + { + adults: 2, + childrenInRoom: [{ age: 10, bed: ChildBedMapEnum.IN_EXTRA_BED }], + }, + { + adults: 3, + childrenInRoom: [], + }, + ], + fromDate: twoDaysFromNow.toISOString().split("T")[0], + toDate: threeDaysFromNow.toISOString().split("T")[0], + city: "STOCKHOLM", + }) + + await expect(page).toHaveURL( + `/en/hotelreservation/select-hotel?${expectedSearchParams}` + ) +}) + +test("can make a search with hotel", async ({ page }) => { + await page.goto("/") + + // Search for hotel + const combobox = page.getByRole("combobox", { name: /where to/i }) + await combobox.click() + await combobox.fill("downtown camper") + await page.getByRole("option", { name: /downtown camper/i }).click() + + // Open datepicker + // If we had better accessibility for our datepicker this would be so much easier + const today = new Date() + const tomorrow = new Date(today) + tomorrow.setDate(today.getDate() + 1) + + await page + .getByRole("button", { + name: `${formatDate(today)} - ${formatDate(tomorrow)}`, + }) + .click() + + // Select future dates + const twoDaysFromNow = new Date(today) + twoDaysFromNow.setDate(today.getDate() + 2) + await clickDatePickerDate(page, twoDaysFromNow) + + const threeDaysFromNow = new Date(today) + threeDaysFromNow.setDate(today.getDate() + 3) + await clickDatePickerDate(page, threeDaysFromNow) + + await page + .getByRole("button", { + name: /select dates/i, + }) + .click() + + // Select rooms and guests + // Once again, better accessibility would make this so much easier + await page.getByRole("button", { name: /1 room, 1 adult/i }).click() + const roomsDialog = page.getByRole("dialog") + const room1section = roomsDialog.getByText(/room 1/i).locator("..") + + // Add 1 adult + await room1section + .locator("section") + .filter({ hasText: /adults/i }) + .getByRole("button", { name: /add/i }) + .click() + + // Add 1 child aged 10 + await room1section + .locator("section") + .filter({ hasText: /children/i }) + .getByRole("button", { name: /add/i }) + .click() + await room1section.getByRole("button", { name: /age/i }).click() + await page.getByRole("option", { name: /10/i }).click() + + await page.getByRole("button", { name: /add room/i }).click() + + const room2section = roomsDialog.getByText(/room 2/i).locator("..") + + // Add 2 adults + await room2section + .locator("section") + .filter({ hasText: /adults/i }) + .getByRole("button", { name: /add/i }) + .click({ clickCount: 2 }) + + await roomsDialog.getByRole("button", { name: /done/i }).click() + + await page.getByRole("button", { name: /search/i }).click() + + // Assert that we navigated to the correct URL + const expectedSearchParams = serializeBookingSearchParams({ + rooms: [ + { + adults: 2, + childrenInRoom: [{ age: 10, bed: ChildBedMapEnum.IN_EXTRA_BED }], + }, + { + adults: 3, + childrenInRoom: [], + }, + ], + fromDate: twoDaysFromNow.toISOString().split("T")[0], + toDate: threeDaysFromNow.toISOString().split("T")[0], + hotelId: "879", // Downtown Camper + }) + + await expect(page).toHaveURL( + `/en/hotelreservation/select-rate?${expectedSearchParams}` + ) +}) + +const formatDate = (date: Date) => { + const day = date.getDate() + const month = date.toLocaleDateString("en-US", { month: "short" }) + const weekday = date.toLocaleDateString("en-US", { weekday: "short" }) + return `${weekday}, ${day} ${month}` +} + +const clickDatePickerDate = async (page: Page, date: Date) => { + const dateString = date.toISOString().split("T")[0] // YYYY-MM-DD format + await page.locator(`[data-day="${dateString}"]`).getByRole("button").click() +} diff --git a/apps/partner-sas/tests/dummy.spec.ts b/apps/partner-sas/tests/dummy.spec.ts deleted file mode 100644 index 02f5c17ba..000000000 --- a/apps/partner-sas/tests/dummy.spec.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { expect, test } from "@playwright/test" - -test("has text", async ({ page }) => { - await page.goto("/") - - await expect(page.getByText(/hello world/i)).toBeVisible() -}) diff --git a/apps/scandic-web/app/[lang]/(live)/(public)/(contentTypes)/start_page/[uid]/page.tsx b/apps/scandic-web/app/[lang]/(live)/(public)/(contentTypes)/start_page/[uid]/page.tsx index 3b44d3394..d9764acbe 100644 --- a/apps/scandic-web/app/[lang]/(live)/(public)/(contentTypes)/start_page/[uid]/page.tsx +++ b/apps/scandic-web/app/[lang]/(live)/(public)/(contentTypes)/start_page/[uid]/page.tsx @@ -1,5 +1,6 @@ +import { parseBookingWidgetSearchParams } from "@scandic-hotels/booking-flow/utils/url" + import StartPage from "@/components/ContentType/StartPage" -import { parseBookingWidgetSearchParams } from "@/utils/url" import type { NextSearchParams, PageArgs } from "@/types/params" diff --git a/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(payment-callback)/payment-callback/page.tsx b/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(payment-callback)/payment-callback/page.tsx index a9f1764c8..dae04872e 100644 --- a/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(payment-callback)/payment-callback/page.tsx +++ b/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(payment-callback)/payment-callback/page.tsx @@ -1,5 +1,9 @@ import { notFound } from "next/navigation" +import { + bookingConfirmation, + details, +} from "@scandic-hotels/common/constants/routes/hotelReservation" import { logger } from "@scandic-hotels/common/logger" import { getServiceToken } from "@scandic-hotels/common/tokenManager" import { BookingErrorCodeEnum } from "@scandic-hotels/trpc/enums/bookingErrorCode" @@ -8,10 +12,6 @@ import { encrypt } from "@scandic-hotels/trpc/utils/encryption" import { isValidSession } from "@scandic-hotels/trpc/utils/session" import { PaymentCallbackStatusEnum } from "@/constants/booking" -import { - bookingConfirmation, - details, -} from "@/constants/routes/hotelReservation" import { serverClient } from "@/lib/trpc/server" import { auth } from "@/auth" diff --git a/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/alternative-hotels/map/page.tsx b/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/alternative-hotels/map/page.tsx index 531888573..76d833824 100644 --- a/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/alternative-hotels/map/page.tsx +++ b/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/alternative-hotels/map/page.tsx @@ -1,10 +1,11 @@ import { notFound } from "next/navigation" import { Suspense } from "react" +import { parseSelectHotelSearchParams } from "@scandic-hotels/booking-flow/utils/url" + import { SelectHotelMapContainer } from "@/components/HotelReservation/SelectHotel/SelectHotelMap/SelectHotelMapContainer" import { SelectHotelMapContainerSkeleton } from "@/components/HotelReservation/SelectHotel/SelectHotelMap/SelectHotelMapContainerSkeleton" import { MapContainer } from "@/components/MapContainer" -import { parseSelectHotelSearchParams } from "@/utils/url" import styles from "./page.module.css" diff --git a/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/alternative-hotels/page.tsx b/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/alternative-hotels/page.tsx index ca0d50e4c..ef67a2f8d 100644 --- a/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/alternative-hotels/page.tsx +++ b/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/alternative-hotels/page.tsx @@ -3,8 +3,10 @@ import { cookies } from "next/headers" import { notFound } from "next/navigation" import { Suspense } from "react" +import { parseSelectHotelSearchParams } from "@scandic-hotels/booking-flow/utils/url" +import { alternativeHotelsMap } from "@scandic-hotels/common/constants/routes/hotelReservation" + import { FamilyAndFriendsCodes } from "@/constants/booking" -import { alternativeHotelsMap } from "@/constants/routes/hotelReservation" import FnFNotAllowedAlert from "@/components/HotelReservation/FnFNotAllowedAlert/FnFNotAllowedAlert" import SelectHotel from "@/components/HotelReservation/SelectHotel" @@ -13,7 +15,6 @@ import { getTracking } from "@/components/HotelReservation/SelectHotel/tracking" import TrackingSDK from "@/components/TrackingSDK" import { getIntl } from "@/i18n" import { getHotelSearchDetails } from "@/utils/hotelSearchDetails" -import { parseSelectHotelSearchParams } from "@/utils/url" import { type LangParams, diff --git a/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/details/page.tsx b/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/details/page.tsx index 3bbf2990a..5e518c44f 100644 --- a/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/details/page.tsx +++ b/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/details/page.tsx @@ -2,6 +2,8 @@ import { cookies } from "next/headers" import { notFound } from "next/navigation" import { Suspense } from "react" +import { parseDetailsSearchParams } from "@scandic-hotels/booking-flow/utils/url" + import { FamilyAndFriendsCodes } from "@/constants/booking" import { getBreakfastPackages, @@ -20,7 +22,6 @@ import EnterDetailsTrackingWrapper from "@/components/HotelReservation/EnterDeta import FnFNotAllowedAlert from "@/components/HotelReservation/FnFNotAllowedAlert/FnFNotAllowedAlert" import RoomProvider from "@/providers/Details/RoomProvider" import EnterDetailsProvider from "@/providers/EnterDetailsProvider" -import { parseDetailsSearchParams } from "@/utils/url" import styles from "./page.module.css" diff --git a/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-hotel/map/page.tsx b/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-hotel/map/page.tsx index a83533e80..331d11752 100644 --- a/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-hotel/map/page.tsx +++ b/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-hotel/map/page.tsx @@ -2,10 +2,11 @@ import stringify from "json-stable-stringify-without-jsonify" import { notFound } from "next/navigation" import { Suspense } from "react" +import { parseSelectHotelSearchParams } from "@scandic-hotels/booking-flow/utils/url" + import { SelectHotelMapContainer } from "@/components/HotelReservation/SelectHotel/SelectHotelMap/SelectHotelMapContainer" import { SelectHotelMapContainerSkeleton } from "@/components/HotelReservation/SelectHotel/SelectHotelMap/SelectHotelMapContainerSkeleton" import { MapContainer } from "@/components/MapContainer" -import { parseSelectHotelSearchParams } from "@/utils/url" import styles from "./page.module.css" diff --git a/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-hotel/page.tsx b/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-hotel/page.tsx index d7accb6f0..0eab92eff 100644 --- a/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-hotel/page.tsx +++ b/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-hotel/page.tsx @@ -3,8 +3,10 @@ import { cookies } from "next/headers" import { notFound } from "next/navigation" import { Suspense } from "react" +import { parseSelectHotelSearchParams } from "@scandic-hotels/booking-flow/utils/url" +import { selectHotelMap } from "@scandic-hotels/common/constants/routes/hotelReservation" + import { FamilyAndFriendsCodes } from "@/constants/booking" -import { selectHotelMap } from "@/constants/routes/hotelReservation" import FnFNotAllowedAlert from "@/components/HotelReservation/FnFNotAllowedAlert/FnFNotAllowedAlert" import SelectHotel from "@/components/HotelReservation/SelectHotel" @@ -12,7 +14,6 @@ import { getHotels } from "@/components/HotelReservation/SelectHotel/helpers" import { getTracking } from "@/components/HotelReservation/SelectHotel/tracking" import TrackingSDK from "@/components/TrackingSDK" import { getHotelSearchDetails } from "@/utils/hotelSearchDetails" -import { parseSelectHotelSearchParams } from "@/utils/url" import type { LangParams, NextSearchParams, PageArgs } from "@/types/params" diff --git a/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-rate/page.tsx b/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-rate/page.tsx index e4ee94763..45d483e4b 100644 --- a/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-rate/page.tsx +++ b/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-rate/page.tsx @@ -1,11 +1,11 @@ import { notFound } from "next/navigation" +import { parseSelectRateSearchParams } from "@scandic-hotels/booking-flow/utils/url" import { SEARCH_TYPE_REDEMPTION } from "@scandic-hotels/trpc/constants/booking" import { combineRegExps, rateTypeRegex } from "@/constants/booking" import SelectRate from "@/components/HotelReservation/SelectRate" -import { parseSelectRateSearchParams } from "@/utils/url" import type { LangParams, NextSearchParams, PageArgs } from "@/types/params" diff --git a/apps/scandic-web/app/[lang]/(live)/@bookingwidget/(contentTypes)/destination_city_page/[uid]/page.tsx b/apps/scandic-web/app/[lang]/(live)/@bookingwidget/(contentTypes)/destination_city_page/[uid]/page.tsx index fdaf11d35..6b64c1b80 100644 --- a/apps/scandic-web/app/[lang]/(live)/@bookingwidget/(contentTypes)/destination_city_page/[uid]/page.tsx +++ b/apps/scandic-web/app/[lang]/(live)/@bookingwidget/(contentTypes)/destination_city_page/[uid]/page.tsx @@ -1,7 +1,9 @@ +import { BookingWidget } from "@scandic-hotels/booking-flow/BookingWidget" +import { parseBookingWidgetSearchParams } from "@scandic-hotels/booking-flow/utils/url" + import { getDestinationCityPage } from "@/lib/trpc/memoizedRequests" -import { BookingWidget } from "@/components/BookingWidget" -import { parseBookingWidgetSearchParams } from "@/utils/url" +import { getLang } from "@/i18n/serverContext" import type { NextSearchParams, PageArgs } from "@/types/params" @@ -20,5 +22,7 @@ export default async function BookingWidgetDestinationCityPage( const booking = parseBookingWidgetSearchParams(bookingWidgetSearchParams) - return + const lang = await getLang() + + return } diff --git a/apps/scandic-web/app/[lang]/(live)/@bookingwidget/(contentTypes)/hotel_page/[uid]/page.tsx b/apps/scandic-web/app/[lang]/(live)/@bookingwidget/(contentTypes)/hotel_page/[uid]/page.tsx index b16b6644d..da4c72fec 100644 --- a/apps/scandic-web/app/[lang]/(live)/@bookingwidget/(contentTypes)/hotel_page/[uid]/page.tsx +++ b/apps/scandic-web/app/[lang]/(live)/@bookingwidget/(contentTypes)/hotel_page/[uid]/page.tsx @@ -1,8 +1,9 @@ +import { BookingWidget } from "@scandic-hotels/booking-flow/BookingWidget" +import { parseBookingWidgetSearchParams } from "@scandic-hotels/booking-flow/utils/url" + import { getHotel, getHotelPage } from "@/lib/trpc/memoizedRequests" -import { BookingWidget } from "@/components/BookingWidget" import { getLang } from "@/i18n/serverContext" -import { parseBookingWidgetSearchParams } from "@/utils/url" import type { NextSearchParams, PageArgs } from "@/types/params" @@ -12,9 +13,10 @@ export default async function BookingWidgetHotelPage( const searchParams = await props.searchParams const hotelPageData = await getHotelPage() + const lang = await getLang() const hotelData = await getHotel({ hotelId: hotelPageData?.hotel_page_id || "", - language: await getLang(), + language: lang, isCardOnlyPayment: false, }) @@ -34,5 +36,5 @@ export default async function BookingWidgetHotelPage( const booking = parseBookingWidgetSearchParams(bookingWidgetSearchParams) - return + return } diff --git a/apps/scandic-web/app/[lang]/(live)/@bookingwidget/hotelreservation/[...paths]/loading.tsx b/apps/scandic-web/app/[lang]/(live)/@bookingwidget/hotelreservation/[...paths]/loading.tsx index e49aa6721..59cbf2505 100644 --- a/apps/scandic-web/app/[lang]/(live)/@bookingwidget/hotelreservation/[...paths]/loading.tsx +++ b/apps/scandic-web/app/[lang]/(live)/@bookingwidget/hotelreservation/[...paths]/loading.tsx @@ -1,4 +1,4 @@ -import { BookingWidgetSkeleton } from "@/components/BookingWidget/Client" +import { BookingWidgetSkeleton } from "@scandic-hotels/booking-flow/BookingWidget/Skeleton" // This file is crucial for displaying a loading // state immediately in the booking flow. diff --git a/apps/scandic-web/app/[lang]/(live)/@bookingwidget/hotelreservation/page.tsx b/apps/scandic-web/app/[lang]/(live)/@bookingwidget/hotelreservation/page.tsx index 235081a69..2924e1e15 100644 --- a/apps/scandic-web/app/[lang]/(live)/@bookingwidget/hotelreservation/page.tsx +++ b/apps/scandic-web/app/[lang]/(live)/@bookingwidget/hotelreservation/page.tsx @@ -1,5 +1,7 @@ -import { BookingWidget } from "@/components/BookingWidget" -import { parseBookingWidgetSearchParams } from "@/utils/url" +import { BookingWidget } from "@scandic-hotels/booking-flow/BookingWidget" +import { parseBookingWidgetSearchParams } from "@scandic-hotels/booking-flow/utils/url" + +import { getLang } from "@/i18n/serverContext" import type { LangParams, NextSearchParams, PageArgs } from "@/types/params" @@ -10,5 +12,7 @@ export default async function BookingWidgetPage( const booking = parseBookingWidgetSearchParams(searchParams) - return + const lang = await getLang() + + return } diff --git a/apps/scandic-web/app/[lang]/(live)/@bookingwidget/page.tsx b/apps/scandic-web/app/[lang]/(live)/@bookingwidget/page.tsx index 235081a69..2924e1e15 100644 --- a/apps/scandic-web/app/[lang]/(live)/@bookingwidget/page.tsx +++ b/apps/scandic-web/app/[lang]/(live)/@bookingwidget/page.tsx @@ -1,5 +1,7 @@ -import { BookingWidget } from "@/components/BookingWidget" -import { parseBookingWidgetSearchParams } from "@/utils/url" +import { BookingWidget } from "@scandic-hotels/booking-flow/BookingWidget" +import { parseBookingWidgetSearchParams } from "@scandic-hotels/booking-flow/utils/url" + +import { getLang } from "@/i18n/serverContext" import type { LangParams, NextSearchParams, PageArgs } from "@/types/params" @@ -10,5 +12,7 @@ export default async function BookingWidgetPage( const booking = parseBookingWidgetSearchParams(searchParams) - return + const lang = await getLang() + + return } diff --git a/apps/scandic-web/app/[lang]/(live)/layout.tsx b/apps/scandic-web/app/[lang]/(live)/layout.tsx index 841176a7b..737e8285b 100644 --- a/apps/scandic-web/app/[lang]/(live)/layout.tsx +++ b/apps/scandic-web/app/[lang]/(live)/layout.tsx @@ -7,6 +7,7 @@ import { ReactQueryDevtools } from "@tanstack/react-query-devtools" import Script from "next/script" import { SessionProvider } from "next-auth/react" +import { BookingFlowTrackingProvider } from "@scandic-hotels/booking-flow/BookingFlowTrackingProvider" import { Lang } from "@scandic-hotels/common/constants/language" import TrpcProvider from "@/lib/trpc/Provider" @@ -26,6 +27,7 @@ import { FontPreload } from "@/fonts/font-preloading" import { getMessages } from "@/i18n" import ClientIntlProvider from "@/i18n/Provider" import { setLang } from "@/i18n/serverContext" +import { trackBookingSearchClick } from "@/utils/tracking/booking" import type { LangParams, LayoutArgs } from "@/types/params" @@ -65,17 +67,23 @@ export default async function RootLayout( > - - -

- {bookingwidget} - {children} -