From eb5dd49981f3a571046bbc7167169b86ec5ddaf2 Mon Sep 17 00:00:00 2001 From: Bianca Widstam Date: Wed, 20 Nov 2024 13:39:52 +0000 Subject: [PATCH 01/16] Merged in fix/SW-955-restaurantsOverviewPage-attributes-optional (pull request #943) fix(SW-955): restaurantsOverviewPage atttributes optional * fix(SW-955): restaurantsOverviewPage atttributes optional Approved-by: Pontus Dreij --- server/routers/hotels/output.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/server/routers/hotels/output.ts b/server/routers/hotels/output.ts index 41f9a6b52..d383d5628 100644 --- a/server/routers/hotels/output.ts +++ b/server/routers/hotels/output.ts @@ -112,10 +112,10 @@ const hotelContentSchema = z.object({ }), }), restaurantsOverviewPage: z.object({ - restaurantsOverviewPageLinkText: z.string(), - restaurantsOverviewPageLink: z.string(), - restaurantsContentDescriptionShort: z.string(), - restaurantsContentDescriptionMedium: z.string(), + restaurantsOverviewPageLinkText: z.string().optional(), + restaurantsOverviewPageLink: z.string().optional(), + restaurantsContentDescriptionShort: z.string().optional(), + restaurantsContentDescriptionMedium: z.string().optional(), }), }) From a1f1531fc2496bdd6dd106239a80fed469e27dea Mon Sep 17 00:00:00 2001 From: Pontus Dreij Date: Tue, 19 Nov 2024 14:25:48 +0100 Subject: [PATCH 02/16] fix(SW-925): Don't throw error if api for packages throws error --- server/routers/hotels/output.ts | 38 +++++++++++++++++---------------- server/routers/hotels/query.ts | 3 +-- 2 files changed, 21 insertions(+), 20 deletions(-) diff --git a/server/routers/hotels/output.ts b/server/routers/hotels/output.ts index d383d5628..f9a5710de 100644 --- a/server/routers/hotels/output.ts +++ b/server/routers/hotels/output.ts @@ -864,22 +864,24 @@ export const packagesSchema = z.object({ export const getRoomPackagesSchema = z .object({ - data: z.object({ - attributes: z.object({ - hotelId: z.number(), - packages: z.array(packagesSchema).optional().default([]), - }), - relationships: z - .object({ - links: z.array( - z.object({ - url: z.string(), - type: z.string(), - }) - ), - }) - .optional(), - type: z.string(), - }), + data: z + .object({ + attributes: z.object({ + hotelId: z.number(), + packages: z.array(packagesSchema).optional().default([]), + }), + relationships: z + .object({ + links: z.array( + z.object({ + url: z.string(), + type: z.string(), + }) + ), + }) + .optional(), + type: z.string(), + }) + .optional(), }) - .transform((data) => data.data.attributes.packages) + .transform((data) => data.data?.attributes?.packages ?? []) diff --git a/server/routers/hotels/query.ts b/server/routers/hotels/query.ts index 34a1b3722..ddb2b3a31 100644 --- a/server/routers/hotels/query.ts +++ b/server/routers/hotels/query.ts @@ -939,12 +939,11 @@ export const hotelQueryRouter = router({ "api.hotels.packages error", JSON.stringify({ query: { hotelId, params } }) ) - throw serverErrorByStatus(apiResponse.status, apiResponse) } const apiJson = await apiResponse.json() const validatedPackagesData = getRoomPackagesSchema.safeParse(apiJson) - + console.log("validatedPackagesData", validatedPackagesData) if (!validatedPackagesData.success) { getHotelFailCounter.add(1, { hotelId, From a0627b9ac521037a504eb28acc3cd5f22a445a5c Mon Sep 17 00:00:00 2001 From: Pontus Dreij Date: Tue, 19 Nov 2024 14:28:00 +0100 Subject: [PATCH 03/16] fix(SW-925) remove log --- server/routers/hotels/query.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/server/routers/hotels/query.ts b/server/routers/hotels/query.ts index ddb2b3a31..eb31aacb6 100644 --- a/server/routers/hotels/query.ts +++ b/server/routers/hotels/query.ts @@ -943,7 +943,6 @@ export const hotelQueryRouter = router({ const apiJson = await apiResponse.json() const validatedPackagesData = getRoomPackagesSchema.safeParse(apiJson) - console.log("validatedPackagesData", validatedPackagesData) if (!validatedPackagesData.success) { getHotelFailCounter.add(1, { hotelId, From 10d2e094e4784e2f45f000eb3e22788d45506a37 Mon Sep 17 00:00:00 2001 From: Pontus Dreij Date: Wed, 20 Nov 2024 09:46:44 +0100 Subject: [PATCH 04/16] fix(SW-925) Fix default packages --- .../(standard)/select-rate/page.tsx | 2 +- .../SelectRate/RoomFilter/index.tsx | 1 + .../SelectRate/RoomSelection/index.tsx | 6 ++--- .../SelectRate/Rooms/index.tsx | 23 +++++++++++++++---- .../hotelReservation/selectRate/roomFilter.ts | 12 ++++++---- .../selectRate/roomSelection.ts | 4 ++-- 6 files changed, 32 insertions(+), 16 deletions(-) diff --git a/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-rate/page.tsx b/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-rate/page.tsx index fd9db4d6c..f8632f938 100644 --- a/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-rate/page.tsx +++ b/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-rate/page.tsx @@ -108,7 +108,7 @@ export default async function SelectRatePage({ roomsAvailability={roomsAvailability} roomCategories={roomCategories ?? []} user={user} - packages={packages ?? []} + availablePackages={packages ?? []} /> ) diff --git a/components/HotelReservation/SelectRate/RoomFilter/index.tsx b/components/HotelReservation/SelectRate/RoomFilter/index.tsx index a07e8353f..2620d3efe 100644 --- a/components/HotelReservation/SelectRate/RoomFilter/index.tsx +++ b/components/HotelReservation/SelectRate/RoomFilter/index.tsx @@ -26,6 +26,7 @@ export default function RoomFilter({ onFilter, filterOptions, }: RoomFilterProps) { + console.log(filterOptions) const initialFilterValues = useMemo( () => filterOptions.reduce( diff --git a/components/HotelReservation/SelectRate/RoomSelection/index.tsx b/components/HotelReservation/SelectRate/RoomSelection/index.tsx index b3624552f..75759459f 100644 --- a/components/HotelReservation/SelectRate/RoomSelection/index.tsx +++ b/components/HotelReservation/SelectRate/RoomSelection/index.tsx @@ -14,7 +14,7 @@ export default function RoomSelection({ roomsAvailability, roomCategories, user, - packages, + availablePackages, selectedPackages, setRateSummary, rateSummary, @@ -72,7 +72,7 @@ export default function RoomSelection({ roomCategories={roomCategories} handleSelectRate={setRateSummary} selectedPackages={selectedPackages} - packages={packages} + packages={availablePackages} /> ))} @@ -81,7 +81,7 @@ export default function RoomSelection({ )} diff --git a/components/HotelReservation/SelectRate/Rooms/index.tsx b/components/HotelReservation/SelectRate/Rooms/index.tsx index 626664988..06e0d954d 100644 --- a/components/HotelReservation/SelectRate/Rooms/index.tsx +++ b/components/HotelReservation/SelectRate/Rooms/index.tsx @@ -11,6 +11,7 @@ import { filterDuplicateRoomTypesByLowestPrice } from "./utils" import styles from "./rooms.module.css" import { + DefaultFilterOptions, RoomPackageCodeEnum, type RoomPackageCodes, } from "@/types/components/hotelReservation/selectRate/roomFilter" @@ -25,8 +26,9 @@ export default function Rooms({ roomsAvailability, roomCategories = [], user, - packages, + availablePackages, }: SelectRateProps) { + console.log(availablePackages) const visibleRooms: RoomConfiguration[] = filterDuplicateRoomTypesByLowestPrice(roomsAvailability.roomConfigurations) const [rateSummary, setRateSummary] = useState(null) @@ -47,6 +49,15 @@ export default function Rooms({ (state) => state.setRoomsAvailable ) + const defaultPackages: DefaultFilterOptions[] = [ + { code: RoomPackageCodeEnum.PET_ROOM, description: "Pet friendly" }, + { code: RoomPackageCodeEnum.ALLERGY_ROOM, description: "Allergy friendly" }, + { + code: RoomPackageCodeEnum.ACCESSIBILITY_ROOM, + description: "Accessibility", + }, + ] + const handleFilter = useCallback( (filter: Record) => { const filteredPackages = Object.keys(filter).filter( @@ -104,7 +115,9 @@ export default function Rooms({ const petRoomPackage = (filteredPackages.includes(RoomPackageCodeEnum.PET_ROOM) && - packages.find((pkg) => pkg.code === RoomPackageCodeEnum.PET_ROOM)) || + availablePackages.find( + (pkg) => pkg.code === RoomPackageCodeEnum.PET_ROOM + )) || undefined const features = filteredRooms.find((room) => @@ -124,7 +137,7 @@ export default function Rooms({ roomsAvailability, visibleRooms, rateSummary, - packages, + availablePackages, noRoomsAvailable, setNoRoomsAvailable, setRoomsAvailable, @@ -136,13 +149,13 @@ export default function Rooms({ ) => void - filterOptions: RoomPackageData + filterOptions: DefaultFilterOptions[] } export type RoomPackage = z.output diff --git a/types/components/hotelReservation/selectRate/roomSelection.ts b/types/components/hotelReservation/selectRate/roomSelection.ts index 163bfd6fa..cd1e48775 100644 --- a/types/components/hotelReservation/selectRate/roomSelection.ts +++ b/types/components/hotelReservation/selectRate/roomSelection.ts @@ -8,7 +8,7 @@ export interface RoomSelectionProps { roomsAvailability: RoomsAvailability roomCategories: RoomData[] user: SafeUser - packages: RoomPackageData | undefined + availablePackages: RoomPackageData | undefined selectedPackages: RoomPackageCodes[] setRateSummary: (rateSummary: Rate) => void rateSummary: Rate | null @@ -18,5 +18,5 @@ export interface SelectRateProps { roomsAvailability: RoomsAvailability roomCategories: RoomData[] user: SafeUser - packages: RoomPackageData + availablePackages: RoomPackageData } From 37098d23cf187de63e4ed73362fd6dc9eed02336 Mon Sep 17 00:00:00 2001 From: Pontus Dreij Date: Wed, 20 Nov 2024 10:14:06 +0100 Subject: [PATCH 05/16] fix(SW-925) disable filter if there are no availablePackages --- .../SelectRate/RoomFilter/index.tsx | 7 +++--- .../SelectRate/Rooms/index.tsx | 23 +++++++++++++++---- .../Form/FilterChip/_Chip/chip.module.css | 9 +++++--- .../hotelReservation/selectRate/roomFilter.ts | 1 + 4 files changed, 30 insertions(+), 10 deletions(-) diff --git a/components/HotelReservation/SelectRate/RoomFilter/index.tsx b/components/HotelReservation/SelectRate/RoomFilter/index.tsx index 2620d3efe..48c73cac2 100644 --- a/components/HotelReservation/SelectRate/RoomFilter/index.tsx +++ b/components/HotelReservation/SelectRate/RoomFilter/index.tsx @@ -26,7 +26,6 @@ export default function RoomFilter({ onFilter, filterOptions, }: RoomFilterProps) { - console.log(filterOptions) const initialFilterValues = useMemo( () => filterOptions.reduce( @@ -100,11 +99,13 @@ export default function RoomFilter({
{filterOptions.map((option) => { - const { code, description } = option + const { code, description, itemCode } = option const isPetRoom = code === RoomPackageCodeEnum.PET_ROOM const isAllergyRoom = code === RoomPackageCodeEnum.ALLERGY_ROOM const isDisabled = - (isAllergyRoom && petFriendly) || (isPetRoom && allergyFriendly) + (isAllergyRoom && petFriendly) || + (isPetRoom && allergyFriendly) || + !itemCode const checkboxChip = ( (null) @@ -50,11 +49,26 @@ export default function Rooms({ ) const defaultPackages: DefaultFilterOptions[] = [ - { code: RoomPackageCodeEnum.PET_ROOM, description: "Pet friendly" }, - { code: RoomPackageCodeEnum.ALLERGY_ROOM, description: "Allergy friendly" }, { code: RoomPackageCodeEnum.ACCESSIBILITY_ROOM, - description: "Accessibility", + description: "Accessible Room", + itemCode: availablePackages.find( + (pkg) => pkg.code === RoomPackageCodeEnum.ACCESSIBILITY_ROOM + )?.itemCode, + }, + { + code: RoomPackageCodeEnum.ALLERGY_ROOM, + description: "Allergy Room", + itemCode: availablePackages.find( + (pkg) => pkg.code === RoomPackageCodeEnum.ALLERGY_ROOM + )?.itemCode, + }, + { + code: RoomPackageCodeEnum.PET_ROOM, + description: "Pet Room", + itemCode: availablePackages.find( + (pkg) => pkg.code === RoomPackageCodeEnum.PET_ROOM + )?.itemCode, }, ] @@ -102,6 +116,7 @@ export default function Rooms({ notAvailableRooms.forEach((room) => { room.status = "NotAvailable" }) + setRooms({ ...roomsAvailability, roomConfigurations: [...filteredRooms, ...notAvailableRooms], diff --git a/components/TempDesignSystem/Form/FilterChip/_Chip/chip.module.css b/components/TempDesignSystem/Form/FilterChip/_Chip/chip.module.css index 44fa78a14..fa029bb47 100644 --- a/components/TempDesignSystem/Form/FilterChip/_Chip/chip.module.css +++ b/components/TempDesignSystem/Form/FilterChip/_Chip/chip.module.css @@ -2,11 +2,13 @@ display: flex; align-items: center; gap: var(--Spacing-x-half); - padding: var(--Spacing-x1) var(--Spacing-x-one-and-half); + padding: calc(var(--Spacing-x1) - 2px) var(--Spacing-x-one-and-half); border: 1px solid var(--Base-Border-Subtle); border-radius: var(--Corner-radius-Small); background-color: var(--Base-Surface-Secondary-light-Normal); cursor: pointer; + height: 32px; + background-color: var(--Base-Surface-Secondary-light-Normal); } .label[data-selected="true"], @@ -21,8 +23,9 @@ } .label[data-disabled="true"] { - background-color: var(--Base-Button-Primary-Fill-Disabled); - border-color: var(--Base-Button-Primary-Fill-Disabled); + background-color: var(--UI-Input-Controls-Surface-Disabled); + border-color: var(--UI-Input-Controls-Border-Disabled); + color: var(--Base-Text-Disabled); cursor: not-allowed; } diff --git a/types/components/hotelReservation/selectRate/roomFilter.ts b/types/components/hotelReservation/selectRate/roomFilter.ts index 239c6fa70..2bdd501b1 100644 --- a/types/components/hotelReservation/selectRate/roomFilter.ts +++ b/types/components/hotelReservation/selectRate/roomFilter.ts @@ -11,6 +11,7 @@ export enum RoomPackageCodeEnum { export interface DefaultFilterOptions { code: RoomPackageCodeEnum description: string + itemCode: string | undefined } export interface RoomFilterProps { numberOfRooms: number From f5a215b27f089fb16cf51d0079e799e4ea970244 Mon Sep 17 00:00:00 2001 From: Pontus Dreij Date: Wed, 20 Nov 2024 10:52:41 +0100 Subject: [PATCH 06/16] fix(SW-925) Removed adding of rooms not in filter --- .../HotelReservation/SelectRate/Rooms/index.tsx | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/components/HotelReservation/SelectRate/Rooms/index.tsx b/components/HotelReservation/SelectRate/Rooms/index.tsx index 58f5727f3..854b5b940 100644 --- a/components/HotelReservation/SelectRate/Rooms/index.tsx +++ b/components/HotelReservation/SelectRate/Rooms/index.tsx @@ -28,6 +28,7 @@ export default function Rooms({ user, availablePackages, }: SelectRateProps) { + console.log(roomsAvailability) const visibleRooms: RoomConfiguration[] = filterDuplicateRoomTypesByLowestPrice(roomsAvailability.roomConfigurations) const [rateSummary, setRateSummary] = useState(null) @@ -105,21 +106,12 @@ export default function Rooms({ room.features.some((feature) => feature.code === filteredPackage) ) ) - let notAvailableRooms = visibleRooms.filter((room) => - filteredPackages.every( - (filteredPackage) => - !room.features.some((feature) => feature.code === filteredPackage) - ) - ) - // Clone nested object to keep original object intact and not messup the room data - notAvailableRooms = JSON.parse(JSON.stringify(notAvailableRooms)) - notAvailableRooms.forEach((room) => { - room.status = "NotAvailable" - }) + console.log("filteredRooms", filteredRooms) + console.log("visibleRooms", visibleRooms) setRooms({ ...roomsAvailability, - roomConfigurations: [...filteredRooms, ...notAvailableRooms], + roomConfigurations: [...filteredRooms], }) if (filteredRooms.length == 0) { From f2de6f103e7e706046267d80e07628eadee90b0e Mon Sep 17 00:00:00 2001 From: Pontus Dreij Date: Wed, 20 Nov 2024 10:57:20 +0100 Subject: [PATCH 07/16] fix(SW-925) remove log --- components/HotelReservation/SelectRate/Rooms/index.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/components/HotelReservation/SelectRate/Rooms/index.tsx b/components/HotelReservation/SelectRate/Rooms/index.tsx index 854b5b940..bdf69ec7a 100644 --- a/components/HotelReservation/SelectRate/Rooms/index.tsx +++ b/components/HotelReservation/SelectRate/Rooms/index.tsx @@ -28,7 +28,6 @@ export default function Rooms({ user, availablePackages, }: SelectRateProps) { - console.log(roomsAvailability) const visibleRooms: RoomConfiguration[] = filterDuplicateRoomTypesByLowestPrice(roomsAvailability.roomConfigurations) const [rateSummary, setRateSummary] = useState(null) From a12fad1a4518ab82fe1ce87809bf821e670a06ce Mon Sep 17 00:00:00 2001 From: Pontus Dreij Date: Wed, 20 Nov 2024 10:58:00 +0100 Subject: [PATCH 08/16] fix(SW-925) remove log --- components/HotelReservation/SelectRate/Rooms/index.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/components/HotelReservation/SelectRate/Rooms/index.tsx b/components/HotelReservation/SelectRate/Rooms/index.tsx index bdf69ec7a..2c3570a95 100644 --- a/components/HotelReservation/SelectRate/Rooms/index.tsx +++ b/components/HotelReservation/SelectRate/Rooms/index.tsx @@ -105,8 +105,6 @@ export default function Rooms({ room.features.some((feature) => feature.code === filteredPackage) ) ) - console.log("filteredRooms", filteredRooms) - console.log("visibleRooms", visibleRooms) setRooms({ ...roomsAvailability, From 9ce56203ccd2032e4eb8e8e6eece002168dafdc8 Mon Sep 17 00:00:00 2001 From: Hrishikesh Vaipurkar Date: Wed, 20 Nov 2024 14:24:59 +0100 Subject: [PATCH 09/16] Fix: SW-943 LightBox responsive view update --- components/Lightbox/Lightbox.module.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/Lightbox/Lightbox.module.css b/components/Lightbox/Lightbox.module.css index 4c62a90dc..80901eabd 100644 --- a/components/Lightbox/Lightbox.module.css +++ b/components/Lightbox/Lightbox.module.css @@ -227,7 +227,7 @@ .galleryContent { width: 1090px; - height: 725px; + height: min(725px, 85dvh); } .fullViewContent { From 55bf718045357fb5b7900e817def58071b812b0d Mon Sep 17 00:00:00 2001 From: Bianca Widstam Date: Wed, 20 Nov 2024 15:09:24 +0000 Subject: [PATCH 10/16] Merged in fix/add-translation-no-prices-available (pull request #949) fix: add translation for no prices available * fix: add translation for no prices available Approved-by: Pontus Dreij Approved-by: Christian Andolf --- .../SelectRate/RoomSelection/FlexibilityOption/index.tsx | 2 +- i18n/dictionaries/da.json | 1 + i18n/dictionaries/de.json | 1 + i18n/dictionaries/en.json | 1 + i18n/dictionaries/fi.json | 1 + i18n/dictionaries/no.json | 1 + i18n/dictionaries/sv.json | 1 + 7 files changed, 7 insertions(+), 1 deletion(-) diff --git a/components/HotelReservation/SelectRate/RoomSelection/FlexibilityOption/index.tsx b/components/HotelReservation/SelectRate/RoomSelection/FlexibilityOption/index.tsx index 941d6257d..b17a2bedc 100644 --- a/components/HotelReservation/SelectRate/RoomSelection/FlexibilityOption/index.tsx +++ b/components/HotelReservation/SelectRate/RoomSelection/FlexibilityOption/index.tsx @@ -36,7 +36,7 @@ export default function FlexibilityOption({
diff --git a/i18n/dictionaries/da.json b/i18n/dictionaries/da.json index a9fdcfae4..a0bc269bd 100644 --- a/i18n/dictionaries/da.json +++ b/i18n/dictionaries/da.json @@ -227,6 +227,7 @@ "No breakfast": "Ingen morgenmad", "No content published": "Intet indhold offentliggjort", "No matching location found": "Der blev ikke fundet nogen matchende placering", + "No prices available": "Ingen tilgængelige priser", "No results": "Ingen resultater", "No transactions available": "Ingen tilgængelige transaktioner", "No, keep card": "Nej, behold kortet", diff --git a/i18n/dictionaries/de.json b/i18n/dictionaries/de.json index 96bcef2de..228f08007 100644 --- a/i18n/dictionaries/de.json +++ b/i18n/dictionaries/de.json @@ -225,6 +225,7 @@ "No breakfast": "Kein Frühstück", "No content published": "Kein Inhalt veröffentlicht", "No matching location found": "Kein passender Standort gefunden", + "No prices available": "Keine Preise verfügbar", "No results": "Keine Ergebnisse", "No transactions available": "Keine Transaktionen verfügbar", "No, keep card": "Nein, Karte behalten", diff --git a/i18n/dictionaries/en.json b/i18n/dictionaries/en.json index 385861316..c4870959c 100644 --- a/i18n/dictionaries/en.json +++ b/i18n/dictionaries/en.json @@ -244,6 +244,7 @@ "No breakfast": "No breakfast", "No content published": "No content published", "No matching location found": "No matching location found", + "No prices available": "No prices available", "No results": "No results", "No transactions available": "No transactions available", "No, keep card": "No, keep card", diff --git a/i18n/dictionaries/fi.json b/i18n/dictionaries/fi.json index 09fb8a403..e6f40b19f 100644 --- a/i18n/dictionaries/fi.json +++ b/i18n/dictionaries/fi.json @@ -227,6 +227,7 @@ "No breakfast": "Ei aamiaista", "No content published": "Ei julkaistua sisältöä", "No matching location found": "Vastaavaa sijaintia ei löytynyt", + "No prices available": "Hintoja ei ole saatavilla", "No results": "Ei tuloksia", "No transactions available": "Ei tapahtumia saatavilla", "No, keep card": "Ei, pidä kortti", diff --git a/i18n/dictionaries/no.json b/i18n/dictionaries/no.json index dcbcdddf4..c7d7dc1ed 100644 --- a/i18n/dictionaries/no.json +++ b/i18n/dictionaries/no.json @@ -225,6 +225,7 @@ "No breakfast": "Ingen frokost", "No content published": "Ingen innhold publisert", "No matching location found": "Fant ingen samsvarende plassering", + "No prices available": "Ingen priser tilgjengelig", "No results": "Ingen resultater", "No transactions available": "Ingen transaksjoner tilgjengelig", "No, keep card": "Nei, behold kortet", diff --git a/i18n/dictionaries/sv.json b/i18n/dictionaries/sv.json index 404896e15..7b89c06c1 100644 --- a/i18n/dictionaries/sv.json +++ b/i18n/dictionaries/sv.json @@ -225,6 +225,7 @@ "No breakfast": "Ingen frukost", "No content published": "Inget innehåll publicerat", "No matching location found": "Ingen matchande plats hittades", + "No prices available": "Inga priser tillgängliga", "No results": "Inga resultat", "No transactions available": "Inga transaktioner tillgängliga", "No, keep card": "Nej, behåll kortet", From 8b66c16e17db2beea1388bff0fa7ee841b1f3ac3 Mon Sep 17 00:00:00 2001 From: Bianca Widstam Date: Thu, 21 Nov 2024 07:28:39 +0000 Subject: [PATCH 11/16] Merged in feat/SW-903-breadcrumbs-select-hotel (pull request #924) Feat/SW-903 breadcrumbs select hotel * feat(SW-903): break out breadcrumbs component and add on select-hotel page * feat(903): updated paths * feat(903): fix padding and remove translations * feat(903): fix type * feat(903): refactor padding * feat(903): refactor padding again * feat(903): refactor * feat(903): fix comments * feat(903): rename content breadcrumbs back Approved-by: Pontus Dreij Approved-by: Erik Tiekstra --- .../my-pages/@breadcrumbs/[...path]/page.tsx | 2 +- .../[contentType]/[uid]/@breadcrumbs/page.tsx | 2 +- .../(standard)/select-hotel/page.module.css | 12 +++- .../(standard)/select-hotel/page.tsx | 32 +++++++++- components/Breadcrumbs/index.tsx | 53 +--------------- .../BreadcrumbsSkeleton/index.tsx} | 3 +- .../Breadcrumbs/breadcrumbs.module.css | 4 +- .../Breadcrumbs/breadcrumbs.ts | 9 +++ .../TempDesignSystem/Breadcrumbs/index.tsx | 61 +++++++++++++++++++ i18n/dictionaries/da.json | 3 + i18n/dictionaries/de.json | 3 + i18n/dictionaries/en.json | 3 + i18n/dictionaries/fi.json | 3 + i18n/dictionaries/no.json | 3 + i18n/dictionaries/sv.json | 3 + 15 files changed, 137 insertions(+), 59 deletions(-) rename components/{Breadcrumbs/BreadcrumbsSkeleton.tsx => TempDesignSystem/Breadcrumbs/BreadcrumbsSkeleton/index.tsx} (89%) rename components/{ => TempDesignSystem}/Breadcrumbs/breadcrumbs.module.css (82%) create mode 100644 components/TempDesignSystem/Breadcrumbs/breadcrumbs.ts create mode 100644 components/TempDesignSystem/Breadcrumbs/index.tsx diff --git a/app/[lang]/(live)/(protected)/my-pages/@breadcrumbs/[...path]/page.tsx b/app/[lang]/(live)/(protected)/my-pages/@breadcrumbs/[...path]/page.tsx index 6775fd188..048cf9e5f 100644 --- a/app/[lang]/(live)/(protected)/my-pages/@breadcrumbs/[...path]/page.tsx +++ b/app/[lang]/(live)/(protected)/my-pages/@breadcrumbs/[...path]/page.tsx @@ -1,7 +1,7 @@ import { Suspense } from "react" import Breadcrumbs from "@/components/Breadcrumbs" -import BreadcrumbsSkeleton from "@/components/Breadcrumbs/BreadcrumbsSkeleton" +import BreadcrumbsSkeleton from "@/components/TempDesignSystem/Breadcrumbs/BreadcrumbsSkeleton" import { setLang } from "@/i18n/serverContext" import { LangParams, PageArgs } from "@/types/params" diff --git a/app/[lang]/(live)/(public)/[contentType]/[uid]/@breadcrumbs/page.tsx b/app/[lang]/(live)/(public)/[contentType]/[uid]/@breadcrumbs/page.tsx index ec8f14553..f8024a816 100644 --- a/app/[lang]/(live)/(public)/[contentType]/[uid]/@breadcrumbs/page.tsx +++ b/app/[lang]/(live)/(public)/[contentType]/[uid]/@breadcrumbs/page.tsx @@ -1,7 +1,7 @@ import { Suspense } from "react" import Breadcrumbs from "@/components/Breadcrumbs" -import BreadcrumbsSkeleton from "@/components/Breadcrumbs/BreadcrumbsSkeleton" +import BreadcrumbsSkeleton from "@/components/TempDesignSystem/Breadcrumbs/BreadcrumbsSkeleton" import { setLang } from "@/i18n/serverContext" import { LangParams, PageArgs } from "@/types/params" diff --git a/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-hotel/page.module.css b/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-hotel/page.module.css index e42544196..cb7245753 100644 --- a/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-hotel/page.module.css +++ b/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-hotel/page.module.css @@ -14,6 +14,10 @@ padding: var(--Spacing-x3) var(--Spacing-x2) 0 var(--Spacing-x2); } +.header nav { + display: none; +} + .cityInformation { display: flex; flex-wrap: wrap; @@ -65,13 +69,19 @@ var(--Spacing-x5); } + .header nav { + display: block; + max-width: var(--max-width-navigation); + padding-left: 0; + } + .sorter { display: block; width: 339px; } .title { - margin: 0 auto; + margin: var(--Spacing-x3) auto 0; display: flex; max-width: var(--max-width-navigation); align-items: center; diff --git a/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-hotel/page.tsx b/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-hotel/page.tsx index 62cab6b85..49893c54d 100644 --- a/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-hotel/page.tsx +++ b/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-hotel/page.tsx @@ -1,6 +1,10 @@ import { notFound } from "next/navigation" +import { Suspense } from "react" -import { selectHotelMap } from "@/constants/routes/hotelReservation" +import { + selectHotel, + selectHotelMap, +} from "@/constants/routes/hotelReservation" import { getLocations } from "@/lib/trpc/memoizedRequests" import { @@ -19,6 +23,8 @@ import { import { ChevronRightIcon } from "@/components/Icons" import StaticMap from "@/components/Maps/StaticMap" import Alert from "@/components/TempDesignSystem/Alert" +import Breadcrumbs from "@/components/TempDesignSystem/Breadcrumbs" +import BreadcrumbsSkeleton from "@/components/TempDesignSystem/Breadcrumbs/BreadcrumbsSkeleton" import Button from "@/components/TempDesignSystem/Button" import Link from "@/components/TempDesignSystem/Link" import Subtitle from "@/components/TempDesignSystem/Text/Subtitle" @@ -65,12 +71,36 @@ export default async function SelectHotelPage({ }) const filterList = getFiltersFromHotels(hotels) + const breadcrumbs = [ + { + title: intl.formatMessage({ id: "Home" }), + href: `/${params.lang}`, + uid: "home-page", + }, + { + title: intl.formatMessage({ id: "Hotel reservation" }), + href: `/${params.lang}/hotelreservation`, + uid: "hotel-reservation", + }, + { + title: intl.formatMessage({ id: "Select hotel" }), + href: `${selectHotel(params.lang)}/?${selectHotelParams}`, + uid: "select-hotel", + }, + { + title: city.name, + uid: city.id, + }, + ] const isAllUnavailable = hotels.every((hotel) => hotel.price === undefined) return ( <>
+ }> + +
{city.name} diff --git a/components/Breadcrumbs/index.tsx b/components/Breadcrumbs/index.tsx index a3244fab8..31a4d445a 100644 --- a/components/Breadcrumbs/index.tsx +++ b/components/Breadcrumbs/index.tsx @@ -1,60 +1,13 @@ import { serverClient } from "@/lib/trpc/server" -import { ChevronRightSmallIcon,HouseIcon } from "@/components/Icons" -import Link from "@/components/TempDesignSystem/Link" -import Footnote from "@/components/TempDesignSystem/Text/Footnote" - -import styles from "./breadcrumbs.module.css" +import BreadcrumbsComp from "@/components/TempDesignSystem/Breadcrumbs" export default async function Breadcrumbs() { const breadcrumbs = await serverClient().contentstack.breadcrumbs.get() + if (!breadcrumbs?.length) { return null } - const homeBreadcrumb = breadcrumbs.shift() - return ( - - ) + return } diff --git a/components/Breadcrumbs/BreadcrumbsSkeleton.tsx b/components/TempDesignSystem/Breadcrumbs/BreadcrumbsSkeleton/index.tsx similarity index 89% rename from components/Breadcrumbs/BreadcrumbsSkeleton.tsx rename to components/TempDesignSystem/Breadcrumbs/BreadcrumbsSkeleton/index.tsx index 68004a81e..a72f1d1a2 100644 --- a/components/Breadcrumbs/BreadcrumbsSkeleton.tsx +++ b/components/TempDesignSystem/Breadcrumbs/BreadcrumbsSkeleton/index.tsx @@ -1,8 +1,7 @@ import { ChevronRightIcon, HouseIcon } from "@/components/Icons" +import styles from "@/components/TempDesignSystem/Breadcrumbs/breadcrumbs.module.css" import Footnote from "@/components/TempDesignSystem/Text/Footnote" -import styles from "./breadcrumbs.module.css" - export default function BreadcrumbsSkeleton() { return (
- - {intl.formatMessage( - { id: "{amount} {currency}" }, - { - amount: intl.formatNumber(totalPrice.local.price), - currency: totalPrice.local.currency, - } - )} - - {totalPrice.euro && ( + {totalPrice.local.amount > 0 && ( + + {intl.formatMessage( + { id: "{amount} {currency}" }, + { + amount: intl.formatNumber(totalPrice.local.amount), + currency: totalPrice.local.currency, + } + )} + + )} + {totalPrice.euro && totalPrice.euro.amount > 0 && ( {intl.formatMessage({ id: "Approx." })}{" "} {intl.formatMessage( { id: "{amount} {currency}" }, { - amount: intl.formatNumber(totalPrice.euro.price), + amount: intl.formatNumber(totalPrice.euro.amount), currency: totalPrice.euro.currency, } )} diff --git a/components/HotelReservation/SelectRate/RoomSelection/utils.ts b/components/HotelReservation/SelectRate/RoomSelection/utils.ts index 43af470e3..d6c54450a 100644 --- a/components/HotelReservation/SelectRate/RoomSelection/utils.ts +++ b/components/HotelReservation/SelectRate/RoomSelection/utils.ts @@ -50,6 +50,7 @@ export function getQueryParamsForEnterDetails( roomTypeCode: room.roomtype, rateCode: room.ratecode, packages: room.packages?.split(",") as RoomPackageCodeEnum[], + counterRateCode: room.counterratecode, })), } } diff --git a/stores/details.ts b/stores/details.ts index a382ad7d7..52e6d41a8 100644 --- a/stores/details.ts +++ b/stores/details.ts @@ -135,8 +135,8 @@ export function createDetailsStore( }, totalPrice: { - euro: { currency: "", price: 0 }, - local: { currency: "", price: 0 }, + euro: { currency: "", amount: 0 }, + local: { currency: "", amount: 0 }, }, }), { diff --git a/types/components/hotelReservation/enterDetails/bookingData.ts b/types/components/hotelReservation/enterDetails/bookingData.ts index 0afabf91a..0683c4739 100644 --- a/types/components/hotelReservation/enterDetails/bookingData.ts +++ b/types/components/hotelReservation/enterDetails/bookingData.ts @@ -7,6 +7,7 @@ interface Room { adults: number roomTypeCode: string rateCode: string + counterRateCode: string children?: Child[] packages?: RoomPackageCodeEnum[] } @@ -18,14 +19,24 @@ export interface BookingData { } type Price = { - price: number + amount: number currency: string } export type RoomsData = { roomType: string - localPrice: Price - euroPrice: Price | undefined + prices: { + public: { + local: Price + euro: Price | undefined + } + member: + | { + local: Price + euro: Price | undefined + } + | undefined + } adults: number children?: Child[] rateDetails?: string[] diff --git a/types/components/hotelReservation/selectRate/section.ts b/types/components/hotelReservation/selectRate/section.ts index 05d86ff6c..eaea36f2e 100644 --- a/types/components/hotelReservation/selectRate/section.ts +++ b/types/components/hotelReservation/selectRate/section.ts @@ -1,4 +1,4 @@ -import { CreditCard } from "@/types/user" +import { CreditCard, SafeUser } from "@/types/user" export interface SectionProps { nextPath: string @@ -28,6 +28,7 @@ export interface BreakfastSelectionProps extends SectionProps { export interface DetailsProps extends SectionProps {} export interface PaymentProps { + user: SafeUser roomPrice: { publicPrice: number; memberPrice: number | undefined } otherPaymentOptions: string[] savedCreditCards: CreditCard[] | null diff --git a/types/components/hotelReservation/selectRate/selectRate.ts b/types/components/hotelReservation/selectRate/selectRate.ts index a1da31b84..12eb83eb1 100644 --- a/types/components/hotelReservation/selectRate/selectRate.ts +++ b/types/components/hotelReservation/selectRate/selectRate.ts @@ -11,7 +11,7 @@ interface Room { adults: number roomtype: string ratecode: string - counterratecode?: string + counterratecode: string child?: Child[] packages?: string } diff --git a/types/stores/details.ts b/types/stores/details.ts index ef6d101dc..d10bb0d61 100644 --- a/types/stores/details.ts +++ b/types/stores/details.ts @@ -8,7 +8,7 @@ export interface DetailsState { actions: { setIsSubmittingDisabled: (isSubmittingDisabled: boolean) => void setTotalPrice: (totalPrice: TotalPrice) => void - toggleSummaryOpen: () => void, + toggleSummaryOpen: () => void updateBedType: (data: BedTypeSchema) => void updateBreakfast: (data: BreakfastPackage | false) => void updateDetails: (data: DetailsSchema) => void @@ -31,10 +31,10 @@ export interface InitialState extends Partial { interface Price { currency: string - price: number + amount: number } export interface TotalPrice { euro: Price | undefined local: Price -} \ No newline at end of file +} From 3a6cfcfe5c485f4c6f37867edee1e17612f8e185 Mon Sep 17 00:00:00 2001 From: Christel Westerberg Date: Tue, 19 Nov 2024 09:57:54 +0100 Subject: [PATCH 13/16] fix: avoid sending query params to planet --- .../payment-callback/layout.module.css | 3 + .../payment-callback/layout.tsx | 16 ++++ .../payment-callback/page.tsx | 70 +++++++++++++++++ .../payment-callback/[lang]/[status]/route.ts | 75 ------------------- .../EnterDetails/Details/schema.ts | 4 + .../Payment/PaymentCallback/index.tsx | 42 +++++++++++ .../EnterDetails/Payment/index.tsx | 12 ++- .../SelectRate/RoomSelection/utils.ts | 47 ++++++++++++ env/client.ts | 4 - lib/graphql/batchRequest.ts | 20 +---- next-env.d.ts | 2 +- next.config.js | 5 ++ server/routers/booking/output.ts | 9 ++- stores/details.ts | 11 ++- stores/steps.ts | 2 +- utils/merge.ts | 19 +++++ 16 files changed, 227 insertions(+), 114 deletions(-) create mode 100644 app/[lang]/(live)/(public)/hotelreservation/(payment-callback)/payment-callback/layout.module.css create mode 100644 app/[lang]/(live)/(public)/hotelreservation/(payment-callback)/payment-callback/layout.tsx create mode 100644 app/[lang]/(live)/(public)/hotelreservation/(payment-callback)/payment-callback/page.tsx delete mode 100644 app/api/web/payment-callback/[lang]/[status]/route.ts create mode 100644 components/HotelReservation/EnterDetails/Payment/PaymentCallback/index.tsx create mode 100644 utils/merge.ts diff --git a/app/[lang]/(live)/(public)/hotelreservation/(payment-callback)/payment-callback/layout.module.css b/app/[lang]/(live)/(public)/hotelreservation/(payment-callback)/payment-callback/layout.module.css new file mode 100644 index 000000000..1730ffa68 --- /dev/null +++ b/app/[lang]/(live)/(public)/hotelreservation/(payment-callback)/payment-callback/layout.module.css @@ -0,0 +1,3 @@ +.layout { + background-color: var(--Base-Background-Primary-Normal); +} diff --git a/app/[lang]/(live)/(public)/hotelreservation/(payment-callback)/payment-callback/layout.tsx b/app/[lang]/(live)/(public)/hotelreservation/(payment-callback)/payment-callback/layout.tsx new file mode 100644 index 000000000..b9ad3b13c --- /dev/null +++ b/app/[lang]/(live)/(public)/hotelreservation/(payment-callback)/payment-callback/layout.tsx @@ -0,0 +1,16 @@ +import { notFound } from "next/navigation" + +import { env } from "@/env/server" + +import styles from "./layout.module.css" + +import { LangParams, LayoutArgs } from "@/types/params" + +export default function PaymentCallbackLayout({ + children, +}: React.PropsWithChildren>) { + if (env.HIDE_FOR_NEXT_RELEASE) { + return notFound() + } + return
{children}
+} diff --git a/app/[lang]/(live)/(public)/hotelreservation/(payment-callback)/payment-callback/page.tsx b/app/[lang]/(live)/(public)/hotelreservation/(payment-callback)/payment-callback/page.tsx new file mode 100644 index 000000000..0e4e716f2 --- /dev/null +++ b/app/[lang]/(live)/(public)/hotelreservation/(payment-callback)/payment-callback/page.tsx @@ -0,0 +1,70 @@ +import { redirect } from "next/navigation" + +import { + BOOKING_CONFIRMATION_NUMBER, + PaymentErrorCodeEnum, +} from "@/constants/booking" +import { Lang } from "@/constants/languages" +import { + bookingConfirmation, + payment, +} from "@/constants/routes/hotelReservation" +import { serverClient } from "@/lib/trpc/server" + +import PaymentCallback from "@/components/HotelReservation/EnterDetails/Payment/PaymentCallback" + +import { LangParams, PageArgs } from "@/types/params" + +export default async function PaymentCallbackPage({ + params, + searchParams, +}: PageArgs< + LangParams, + { status: "error" | "success" | "cancel"; confirmationNumber?: string } +>) { + console.log(`[payment-callback] callback started`) + const lang = params.lang + const status = searchParams.status + const confirmationNumber = searchParams.confirmationNumber + + if (status === "success" && confirmationNumber) { + const confirmationUrl = `${bookingConfirmation(lang)}?${BOOKING_CONFIRMATION_NUMBER}=${confirmationNumber}` + + console.log(`[payment-callback] redirecting to: ${confirmationUrl}`) + redirect(confirmationUrl) + } + + const returnUrl = payment(lang) + const searchObject = new URLSearchParams() + + if (confirmationNumber) { + try { + const bookingStatus = await serverClient().booking.status({ + confirmationNumber, + }) + if (bookingStatus.metadata) { + searchObject.set( + "errorCode", + bookingStatus.metadata.errorCode?.toString() ?? "" + ) + } + } catch (error) { + console.error( + `[payment-callback] failed to get booking status for ${confirmationNumber}, status: ${status}` + ) + if (status === "cancel") { + searchObject.set("errorCode", PaymentErrorCodeEnum.Cancelled.toString()) + } + if (status === "error") { + searchObject.set("errorCode", PaymentErrorCodeEnum.Failed.toString()) + } + } + } + + return ( + + ) +} diff --git a/app/api/web/payment-callback/[lang]/[status]/route.ts b/app/api/web/payment-callback/[lang]/[status]/route.ts deleted file mode 100644 index 5884d63f9..000000000 --- a/app/api/web/payment-callback/[lang]/[status]/route.ts +++ /dev/null @@ -1,75 +0,0 @@ -import { NextRequest, NextResponse } from "next/server" - -import { - BOOKING_CONFIRMATION_NUMBER, - PaymentErrorCodeEnum, -} from "@/constants/booking" -import { Lang } from "@/constants/languages" -import { - bookingConfirmation, - payment, -} from "@/constants/routes/hotelReservation" -import { serverClient } from "@/lib/trpc/server" -import { getPublicURL } from "@/server/utils" - -export async function GET( - request: NextRequest, - { params }: { params: { lang: string; status: string } } -): Promise { - const publicURL = getPublicURL(request) - - console.log(`[payment-callback] callback started`) - const lang = params.lang as Lang - const status = params.status - - const queryParams = request.nextUrl.searchParams - const confirmationNumber = queryParams.get(BOOKING_CONFIRMATION_NUMBER) - - if (status === "success" && confirmationNumber) { - const confirmationUrl = new URL(`${publicURL}/${bookingConfirmation(lang)}`) - confirmationUrl.searchParams.set( - BOOKING_CONFIRMATION_NUMBER, - confirmationNumber - ) - - console.log(`[payment-callback] redirecting to: ${confirmationUrl}`) - return NextResponse.redirect(confirmationUrl) - } - - const returnUrl = new URL(`${publicURL}/${payment(lang)}`) - returnUrl.search = queryParams.toString() - - if (confirmationNumber) { - try { - const bookingStatus = await serverClient().booking.status({ - confirmationNumber, - }) - if (bookingStatus.metadata) { - returnUrl.searchParams.set( - "errorCode", - bookingStatus.metadata.errorCode?.toString() ?? "" - ) - } - } catch (error) { - console.error( - `[payment-callback] failed to get booking status for ${confirmationNumber}, status: ${status}` - ) - - if (status === "cancel") { - returnUrl.searchParams.set( - "errorCode", - PaymentErrorCodeEnum.Cancelled.toString() - ) - } - if (status === "error") { - returnUrl.searchParams.set( - "errorCode", - PaymentErrorCodeEnum.Failed.toString() - ) - } - } - } - - console.log(`[payment-callback] redirecting to: ${returnUrl}`) - return NextResponse.redirect(returnUrl) -} diff --git a/components/HotelReservation/EnterDetails/Details/schema.ts b/components/HotelReservation/EnterDetails/Details/schema.ts index abb29ac2b..b3e161dc9 100644 --- a/components/HotelReservation/EnterDetails/Details/schema.ts +++ b/components/HotelReservation/EnterDetails/Details/schema.ts @@ -55,4 +55,8 @@ export const signedInDetailsSchema = z.object({ firstName: z.string().optional(), lastName: z.string().optional(), phoneNumber: z.string().optional(), + join: z + .boolean() + .optional() + .transform((_) => false), }) diff --git a/components/HotelReservation/EnterDetails/Payment/PaymentCallback/index.tsx b/components/HotelReservation/EnterDetails/Payment/PaymentCallback/index.tsx new file mode 100644 index 000000000..1c303dfbe --- /dev/null +++ b/components/HotelReservation/EnterDetails/Payment/PaymentCallback/index.tsx @@ -0,0 +1,42 @@ +"use client" + +import { useRouter } from "next/navigation" +import { useEffect } from "react" + +import { detailsStorageName } from "@/stores/details" + +import { createQueryParamsForEnterDetails } from "@/components/HotelReservation/SelectRate/RoomSelection/utils" +import LoadingSpinner from "@/components/LoadingSpinner" + +import { DetailsState } from "@/types/stores/details" + +export default function PaymentCallback({ + returnUrl, + searchObject, +}: { + returnUrl: string + searchObject: URLSearchParams +}) { + const router = useRouter() + + useEffect(() => { + const bookingData = window.sessionStorage.getItem(detailsStorageName) + + if (bookingData) { + const detailsStorage: Record< + "state", + Pick + > = JSON.parse(bookingData) + const searchParams = createQueryParamsForEnterDetails( + detailsStorage.state.data.booking, + searchObject + ) + + if (searchParams.size > 0) { + router.replace(`${returnUrl}?${searchParams.toString()}`) + } + } + }, [returnUrl, router, searchObject]) + + return +} diff --git a/components/HotelReservation/EnterDetails/Payment/index.tsx b/components/HotelReservation/EnterDetails/Payment/index.tsx index 6a2f8877b..ab1f78807 100644 --- a/components/HotelReservation/EnterDetails/Payment/index.tsx +++ b/components/HotelReservation/EnterDetails/Payment/index.tsx @@ -60,7 +60,6 @@ export default function Payment({ const router = useRouter() const lang = useLang() const intl = useIntl() - const queryParams = useSearchParams() const { booking, ...userData } = useDetailsStore((state) => state.data) const setIsSubmittingDisabled = useDetailsStore( (state) => state.actions.setIsSubmittingDisabled @@ -164,9 +163,6 @@ export default function Payment({ ]) function handleSubmit(data: PaymentFormData) { - const allQueryParams = - queryParams.size > 0 ? `?${queryParams.toString()}` : "" - // set payment method to card if saved card is submitted const paymentMethod = isPaymentMethodEnum(data.paymentMethod) ? data.paymentMethod @@ -176,6 +172,8 @@ export default function Payment({ (card) => card.id === data.paymentMethod ) + const paymentRedirectUrl = `${env.NEXT_PUBLIC_NODE_ENV === "development" ? `http://localhost:${env.NEXT_PUBLIC_PORT}` : ""}/${lang}/hotelreservation/payment-callback` + initiateBooking.mutate({ hotelId: hotel, checkInDate: fromDate, @@ -224,9 +222,9 @@ export default function Payment({ } : undefined, - success: `${env.NEXT_PUBLIC_PAYMENT_CALLBACK_URL}/${lang}/success`, - error: `${env.NEXT_PUBLIC_PAYMENT_CALLBACK_URL}/${lang}/error${allQueryParams}`, - cancel: `${env.NEXT_PUBLIC_PAYMENT_CALLBACK_URL}/${lang}/cancel${allQueryParams}`, + success: `${paymentRedirectUrl}/success`, + error: `${paymentRedirectUrl}/error`, + cancel: `${paymentRedirectUrl}/cancel`, }, }) } diff --git a/components/HotelReservation/SelectRate/RoomSelection/utils.ts b/components/HotelReservation/SelectRate/RoomSelection/utils.ts index d6c54450a..c47841708 100644 --- a/components/HotelReservation/SelectRate/RoomSelection/utils.ts +++ b/components/HotelReservation/SelectRate/RoomSelection/utils.ts @@ -54,3 +54,50 @@ export function getQueryParamsForEnterDetails( })), } } + +export function createQueryParamsForEnterDetails( + bookingData: BookingData, + intitalSearchParams: URLSearchParams +) { + const { hotel, fromDate, toDate, rooms } = bookingData + + const bookingSearchParams = new URLSearchParams({ hotel, fromDate, toDate }) + const searchParams = new URLSearchParams([ + ...intitalSearchParams, + ...bookingSearchParams, + ]) + + rooms.forEach((item, index) => { + if (item?.adults) { + searchParams.set(`room[${index}].adults`, item.adults.toString()) + } + if (item?.children) { + item.children.forEach((child, childIndex) => { + searchParams.set( + `room[${index}].child[${childIndex}].age`, + child.age.toString() + ) + searchParams.set( + `room[${index}].child[${childIndex}].bed`, + child.bed.toString() + ) + }) + } + if (item?.roomTypeCode) { + searchParams.set(`room[${index}].roomtype`, item.roomTypeCode) + } + if (item?.rateCode) { + searchParams.set(`room[${index}].ratecode`, item.rateCode) + } + + if (item?.counterRateCode) { + searchParams.set(`room[${index}].counterratecode`, item.counterRateCode) + } + + if (item.packages && item.packages.length > 0) { + searchParams.set(`room[${index}].packages`, item.packages.join(",")) + } + }) + + return searchParams +} diff --git a/env/client.ts b/env/client.ts index 4eafd5592..467100c01 100644 --- a/env/client.ts +++ b/env/client.ts @@ -5,14 +5,10 @@ export const env = createEnv({ client: { NEXT_PUBLIC_NODE_ENV: z.enum(["development", "test", "production"]), NEXT_PUBLIC_PORT: z.string().default("3000"), - NEXT_PUBLIC_PAYMENT_CALLBACK_URL: z - .string() - .default("/api/web/payment-callback"), }, emptyStringAsUndefined: true, runtimeEnv: { NEXT_PUBLIC_NODE_ENV: process.env.NODE_ENV, NEXT_PUBLIC_PORT: process.env.NEXT_PUBLIC_PORT, - NEXT_PUBLIC_PAYMENT_CALLBACK_URL: `${process.env.NODE_ENV === "development" ? `http://localhost:${process.env.NEXT_PUBLIC_PORT}` : ""}/api/web/payment-callback`, }, }) diff --git a/lib/graphql/batchRequest.ts b/lib/graphql/batchRequest.ts index b6b5dbe3f..86361d527 100644 --- a/lib/graphql/batchRequest.ts +++ b/lib/graphql/batchRequest.ts @@ -2,30 +2,14 @@ import "server-only" import deepmerge from "deepmerge" +import { arrayMerge } from "@/utils/merge" + import { request } from "./request" import type { BatchRequestDocument } from "graphql-request" import type { Data } from "@/types/request" -function arrayMerge( - target: any[], - source: any[], - options: deepmerge.ArrayMergeOptions | undefined -) { - const destination = target.slice() - source.forEach((item, index) => { - if (typeof destination[index] === "undefined") { - destination[index] = options?.cloneUnlessOtherwiseSpecified(item, options) - } else if (options?.isMergeableObject(item)) { - destination[index] = deepmerge(target[index], item, options) - } else if (target.indexOf(item) === -1) { - destination.push(item) - } - }) - return destination -} - export async function batchRequest( queries: (BatchRequestDocument & { options?: RequestInit })[] ): Promise> { diff --git a/next-env.d.ts b/next-env.d.ts index 40c3d6809..4f11a03dc 100644 --- a/next-env.d.ts +++ b/next-env.d.ts @@ -2,4 +2,4 @@ /// // NOTE: This file should not be edited -// see https://nextjs.org/docs/app/building-your-application/configuring/typescript for more information. +// see https://nextjs.org/docs/basic-features/typescript for more information. diff --git a/next.config.js b/next.config.js index 222f085ac..34616f754 100644 --- a/next.config.js +++ b/next.config.js @@ -282,6 +282,11 @@ const nextConfig = { "/:lang/hotelreservation/:step(breakfast|details|payment|select-bed)", destination: "/:lang/hotelreservation/step?step=:step", }, + { + source: "/:lang/hotelreservation/payment-callback/:status", + destination: + "/:lang/hotelreservation/payment-callback?status=:status", + }, ], } }, diff --git a/server/routers/booking/output.ts b/server/routers/booking/output.ts index ae2e14cf4..5c8879c00 100644 --- a/server/routers/booking/output.ts +++ b/server/routers/booking/output.ts @@ -17,13 +17,14 @@ export const createBookingSchema = z paymentUrl: z.string().nullable(), metadata: z .object({ - errorCode: z.number().optional(), - errorMessage: z.string().optional(), + errorCode: z.number().nullable().optional(), + errorMessage: z.string().nullable().optional(), priceChangedMetadata: z .object({ - roomPrice: z.number().optional(), - totalPrice: z.number().optional(), + roomPrice: z.number().nullable().optional(), + totalPrice: z.number().nullable().optional(), }) + .nullable() .optional(), }) .nullable(), diff --git a/stores/details.ts b/stores/details.ts index 52e6d41a8..f8698e54c 100644 --- a/stores/details.ts +++ b/stores/details.ts @@ -11,11 +11,12 @@ import { signedInDetailsSchema, } from "@/components/HotelReservation/EnterDetails/Details/schema" import { DetailsContext } from "@/contexts/Details" +import { arrayMerge } from "@/utils/merge" import { StepEnum } from "@/types/enums/step" import type { DetailsState, InitialState } from "@/types/stores/details" -export const storageName = "details-storage" +export const detailsStorageName = "details-storage" export function createDetailsStore( initialState: InitialState, isMember: boolean @@ -27,13 +28,15 @@ export function createDetailsStore( * we cannot use the data as `defaultValues` for our forms. * RHF caches defaultValues on mount. */ - const detailsStorageUnparsed = sessionStorage.getItem(storageName) + const detailsStorageUnparsed = sessionStorage.getItem(detailsStorageName) if (detailsStorageUnparsed) { const detailsStorage: Record< "state", Pick > = JSON.parse(detailsStorageUnparsed) - initialState = merge(initialState, detailsStorage.state.data) + initialState = merge(detailsStorage.state.data, initialState, { + arrayMerge, + }) } } return create()( @@ -140,7 +143,7 @@ export function createDetailsStore( }, }), { - name: storageName, + name: detailsStorageName, onRehydrateStorage() { return function (state) { if (state) { diff --git a/stores/steps.ts b/stores/steps.ts index cf14f6768..efa356c8b 100644 --- a/stores/steps.ts +++ b/stores/steps.ts @@ -13,7 +13,7 @@ import { } from "@/components/HotelReservation/EnterDetails/Details/schema" import { StepsContext } from "@/contexts/Steps" -import { storageName as detailsStorageName } from "./details" +import { detailsStorageName as detailsStorageName } from "./details" import { StepEnum } from "@/types/enums/step" import type { DetailsState } from "@/types/stores/details" diff --git a/utils/merge.ts b/utils/merge.ts new file mode 100644 index 000000000..84aaae145 --- /dev/null +++ b/utils/merge.ts @@ -0,0 +1,19 @@ +import merge from "deepmerge" + +export function arrayMerge( + target: any[], + source: any[], + options: merge.ArrayMergeOptions +) { + const destination = target.slice() + source.forEach((item, index) => { + if (typeof destination[index] === "undefined") { + destination[index] = options.cloneUnlessOtherwiseSpecified(item, options) + } else if (options?.isMergeableObject(item)) { + destination[index] = merge(target[index], item, options) + } else if (target.indexOf(item) === -1) { + destination.push(item) + } + }) + return destination +} From 92b0ec9c84052787e1025884f12557c26c8a238c Mon Sep 17 00:00:00 2001 From: Christel Westerberg Date: Thu, 21 Nov 2024 11:14:28 +0100 Subject: [PATCH 14/16] fix: hydrate store with updated values --- stores/details.ts | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/stores/details.ts b/stores/details.ts index f8698e54c..30bf1ed81 100644 --- a/stores/details.ts +++ b/stores/details.ts @@ -144,34 +144,33 @@ export function createDetailsStore( }), { name: detailsStorageName, - onRehydrateStorage() { + onRehydrateStorage(prevState) { return function (state) { if (state) { const validatedBedType = bedTypeSchema.safeParse(state.data) - if (validatedBedType.success) { - state.actions.updateValidity(StepEnum.selectBed, true) - } else { - state.actions.updateValidity(StepEnum.selectBed, false) + if (validatedBedType.success !== state.isValid["select-bed"]) { + state.isValid["select-bed"] = validatedBedType.success } const validatedBreakfast = breakfastStoreSchema.safeParse( state.data ) - if (validatedBreakfast.success) { - state.actions.updateValidity(StepEnum.breakfast, true) - } else { - state.actions.updateValidity(StepEnum.breakfast, false) + if (validatedBreakfast.success !== state.isValid.breakfast) { + state.isValid.breakfast = validatedBreakfast.success } const detailsSchema = isMember ? signedInDetailsSchema : guestDetailsSchema const validatedDetails = detailsSchema.safeParse(state.data) - if (validatedDetails.success) { - state.actions.updateValidity(StepEnum.details, true) - } else { - state.actions.updateValidity(StepEnum.details, false) + if (validatedDetails.success !== state.isValid.details) { + state.isValid.details = validatedDetails.success } + + const mergedState = merge(state.data, prevState.data, { + arrayMerge, + }) + state.data = mergedState } } }, From de2057b41c93d622fa5abdc5d9b3a67c88b67b5b Mon Sep 17 00:00:00 2001 From: Hrishikesh Vaipurkar Date: Thu, 21 Nov 2024 11:11:31 +0100 Subject: [PATCH 15/16] fix: SW-967 Alert showing no hotels with filters --- .../HotelCardListing/index.tsx | 32 ++++++++++++------- i18n/dictionaries/en.json | 2 ++ 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/components/HotelReservation/HotelCardListing/index.tsx b/components/HotelReservation/HotelCardListing/index.tsx index 6ceb9aa85..3e96a6cac 100644 --- a/components/HotelReservation/HotelCardListing/index.tsx +++ b/components/HotelReservation/HotelCardListing/index.tsx @@ -1,9 +1,11 @@ "use client" import { useSearchParams } from "next/navigation" import { useEffect, useMemo, useState } from "react" +import { useIntl } from "react-intl" import { useHotelFilterStore } from "@/stores/hotel-filters" +import Alert from "@/components/TempDesignSystem/Alert" import { BackToTopButton } from "@/components/TempDesignSystem/BackToTopButton" import HotelCard from "../HotelCard" @@ -17,6 +19,7 @@ import { type HotelData, } from "@/types/components/hotelReservation/selectHotel/hotelCardListingProps" import { SortOrder } from "@/types/components/hotelReservation/selectHotel/hotelSorter" +import { AlertTypeEnum } from "@/types/enums/alert" export default function HotelCardListing({ hotelData, @@ -28,6 +31,7 @@ export default function HotelCardListing({ const activeFilters = useHotelFilterStore((state) => state.activeFilters) const setResultCount = useHotelFilterStore((state) => state.setResultCount) const [showBackToTop, setShowBackToTop] = useState(false) + const intl = useIntl() const sortBy = useMemo( () => searchParams.get("sort") ?? DEFAULT_SORT, @@ -101,17 +105,23 @@ export default function HotelCardListing({ return (
- {hotels?.length - ? hotels.map((hotel) => ( - - )) - : null} + {hotels?.length ? ( + hotels.map((hotel) => ( + + )) + ) : activeFilters ? ( + + ) : null} {showBackToTop && }
) diff --git a/i18n/dictionaries/en.json b/i18n/dictionaries/en.json index 950bbb36e..4abc07ea7 100644 --- a/i18n/dictionaries/en.json +++ b/i18n/dictionaries/en.json @@ -473,6 +473,8 @@ "breakfast.price.free": "{amount} {currency} 0 {currency}/night", "by": "by", "characters": "characters", + "filters.nohotel.heading": "No hotels match your filters", + "filters.nohotel.text": "It looks like no hotels match your filters. Try adjusting your search to find the perfect stay.", "from": "from", "guaranteeing": "guaranteeing", "guest": "guest", From 01638f4dd73df61799bb562b4c102ae8748b2930 Mon Sep 17 00:00:00 2001 From: Hrishikesh Vaipurkar Date: Thu, 21 Nov 2024 11:18:02 +0100 Subject: [PATCH 16/16] fix: SW-967 Fixed bad setState call error --- components/HotelReservation/HotelCardListing/index.tsx | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/components/HotelReservation/HotelCardListing/index.tsx b/components/HotelReservation/HotelCardListing/index.tsx index 3e96a6cac..f666c5ba2 100644 --- a/components/HotelReservation/HotelCardListing/index.tsx +++ b/components/HotelReservation/HotelCardListing/index.tsx @@ -73,7 +73,6 @@ export default function HotelCardListing({ const hotels = useMemo(() => { if (activeFilters.length === 0) { - setResultCount(sortedHotels.length) return sortedHotels } @@ -85,9 +84,8 @@ export default function HotelCardListing({ ) ) - setResultCount(filteredHotels.length) return filteredHotels - }, [activeFilters, sortedHotels, setResultCount]) + }, [activeFilters, sortedHotels]) useEffect(() => { const handleScroll = () => { @@ -99,6 +97,10 @@ export default function HotelCardListing({ return () => window.removeEventListener("scroll", handleScroll) }, []) + useEffect(() => { + setResultCount(hotels ? hotels.length : 0) + }, [hotels, setResultCount]) + function scrollToTop() { window.scrollTo({ top: 0, behavior: "smooth" }) }