From 94f97dffa994f916363e4d8309f7c4ab5d44e8db Mon Sep 17 00:00:00 2001 From: Pontus Dreij Date: Tue, 19 Nov 2024 09:50:08 +0100 Subject: [PATCH 01/21] fix(SW-565): Fixed that tooltip doesn't block anything. --- components/GuestsRoomsPicker/Form.tsx | 4 ++-- components/TempDesignSystem/Tooltip/index.tsx | 1 + components/TempDesignSystem/Tooltip/tooltip.module.css | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/components/GuestsRoomsPicker/Form.tsx b/components/GuestsRoomsPicker/Form.tsx index 01ded876a..062347761 100644 --- a/components/GuestsRoomsPicker/Form.tsx +++ b/components/GuestsRoomsPicker/Form.tsx @@ -99,7 +99,7 @@ export default function GuestsRoomsPickerDialog({ {rooms.length < 4 ? ( @@ -124,7 +124,7 @@ export default function GuestsRoomsPickerDialog({ {rooms.length < 4 ? ( diff --git a/components/TempDesignSystem/Tooltip/index.tsx b/components/TempDesignSystem/Tooltip/index.tsx index 033fc9a04..d73252161 100644 --- a/components/TempDesignSystem/Tooltip/index.tsx +++ b/components/TempDesignSystem/Tooltip/index.tsx @@ -28,6 +28,7 @@ export function Tooltip

({ role="tooltip" aria-label={text} onClick={handleToggle} + onTouchStart={handleToggle} data-active={isActive} >

diff --git a/components/TempDesignSystem/Tooltip/tooltip.module.css b/components/TempDesignSystem/Tooltip/tooltip.module.css index e25433f7c..b0ae8cf4f 100644 --- a/components/TempDesignSystem/Tooltip/tooltip.module.css +++ b/components/TempDesignSystem/Tooltip/tooltip.module.css @@ -16,6 +16,7 @@ transition: opacity 0.3s; max-width: 200px; min-width: 150px; + height: fit-content; } .tooltipContainer:hover .tooltip { From ebbdecf8d8cb92c7d042d6c9b8d5d2dad001c993 Mon Sep 17 00:00:00 2001 From: Pontus Dreij Date: Tue, 19 Nov 2024 10:34:21 +0100 Subject: [PATCH 02/21] fix(SW-565) fix select hight to see its scrollable --- .../GuestsRoomsPicker/ChildSelector/ChildInfoSelector.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/GuestsRoomsPicker/ChildSelector/ChildInfoSelector.tsx b/components/GuestsRoomsPicker/ChildSelector/ChildInfoSelector.tsx index 8252f2d2a..b39821483 100644 --- a/components/GuestsRoomsPicker/ChildSelector/ChildInfoSelector.tsx +++ b/components/GuestsRoomsPicker/ChildSelector/ChildInfoSelector.tsx @@ -94,7 +94,7 @@ export default function ChildInfoSelector({ updateSelectedAge(key as number) }} placeholder={ageLabel} - maxHeight={150} + maxHeight={180} {...register(ageFieldName, { required: true, })} From 602e7ea2ce9b5beeadaa3126c67e528de5cba630 Mon Sep 17 00:00:00 2001 From: Christel Westerberg Date: Tue, 19 Nov 2024 13:25:47 +0100 Subject: [PATCH 03/21] fix: handle undefined pricing --- components/HotelReservation/SelectRate/Rooms/utils.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/HotelReservation/SelectRate/Rooms/utils.ts b/components/HotelReservation/SelectRate/Rooms/utils.ts index 71b2149cc..96d8a8488 100644 --- a/components/HotelReservation/SelectRate/Rooms/utils.ts +++ b/components/HotelReservation/SelectRate/Rooms/utils.ts @@ -66,7 +66,7 @@ export function filterDuplicateRoomTypesByLowestPrice( Math.min( Number( previousLowest.products[0].productType.public.requestedPrice - .pricePerNight + ?.pricePerNight ) ?? Infinity, Number( previousLowest.products[0].productType.member?.requestedPrice @@ -77,7 +77,7 @@ export function filterDuplicateRoomTypesByLowestPrice( Math.min( Number( previousLowest.products[0].productType.public.requestedPrice - .pricePerNight + ?.pricePerNight ) ?? Infinity, Number( previousLowest.products[0].productType.member?.requestedPrice From c2ef7f70746a8957045efb654a980ab267e6f47d Mon Sep 17 00:00:00 2001 From: Christel Westerberg Date: Tue, 19 Nov 2024 13:41:08 +0100 Subject: [PATCH 04/21] fix: padding issues --- .../EnterDetails/Details/details.module.css | 1 - .../SectionAccordion/sectionAccordion.module.css | 7 +++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/components/HotelReservation/EnterDetails/Details/details.module.css b/components/HotelReservation/EnterDetails/Details/details.module.css index c6571ea9e..8781a9be2 100644 --- a/components/HotelReservation/EnterDetails/Details/details.module.css +++ b/components/HotelReservation/EnterDetails/Details/details.module.css @@ -1,7 +1,6 @@ .form { display: grid; gap: var(--Spacing-x3); - margin-bottom: var(--Spacing-x3); } .container { diff --git a/components/HotelReservation/EnterDetails/SectionAccordion/sectionAccordion.module.css b/components/HotelReservation/EnterDetails/SectionAccordion/sectionAccordion.module.css index 0bbcf851c..48d387add 100644 --- a/components/HotelReservation/EnterDetails/SectionAccordion/sectionAccordion.module.css +++ b/components/HotelReservation/EnterDetails/SectionAccordion/sectionAccordion.module.css @@ -79,7 +79,10 @@ .accordion[data-open="true"] { grid-template-rows: var(--header-height) 1fr; - gap: var(--Spacing-x3); +} + +.accordion[data-open="true"] .content { + padding-bottom: var(--Spacing-x3); } .content { @@ -90,7 +93,7 @@ @media screen and (min-width: 768px) { .accordion { - gap: var(--Spacing-x3); + column-gap: var(--Spacing-x3); grid-template-areas: "circle header" "circle content"; } From d43c29e394489329d80e43af35e17a8c52029090 Mon Sep 17 00:00:00 2001 From: Christel Westerberg Date: Tue, 19 Nov 2024 14:06:09 +0100 Subject: [PATCH 05/21] fix: disable button on not isComplete --- .../EnterDetails/SectionAccordion/index.tsx | 10 ++++++++-- .../SectionAccordion/sectionAccordion.module.css | 6 +++++- components/HotelReservation/SelectRate/Rooms/utils.ts | 2 +- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/components/HotelReservation/EnterDetails/SectionAccordion/index.tsx b/components/HotelReservation/EnterDetails/SectionAccordion/index.tsx index b96ef8ef8..488d941b5 100644 --- a/components/HotelReservation/EnterDetails/SectionAccordion/index.tsx +++ b/components/HotelReservation/EnterDetails/SectionAccordion/index.tsx @@ -75,7 +75,11 @@ export default function SectionAccordion({
-
-
{children}
+
+
{children}
+
) } diff --git a/components/HotelReservation/EnterDetails/SectionAccordion/sectionAccordion.module.css b/components/HotelReservation/EnterDetails/SectionAccordion/sectionAccordion.module.css index 48d387add..125905317 100644 --- a/components/HotelReservation/EnterDetails/SectionAccordion/sectionAccordion.module.css +++ b/components/HotelReservation/EnterDetails/SectionAccordion/sectionAccordion.module.css @@ -33,6 +33,10 @@ padding: 0; } +.modifyButton:disabled { + cursor: default; +} + .title { grid-area: title; text-align: start; @@ -81,7 +85,7 @@ grid-template-rows: var(--header-height) 1fr; } -.accordion[data-open="true"] .content { +.contentWrapper { padding-bottom: var(--Spacing-x3); } diff --git a/components/HotelReservation/SelectRate/Rooms/utils.ts b/components/HotelReservation/SelectRate/Rooms/utils.ts index 96d8a8488..fbd353aa1 100644 --- a/components/HotelReservation/SelectRate/Rooms/utils.ts +++ b/components/HotelReservation/SelectRate/Rooms/utils.ts @@ -88,7 +88,7 @@ export function filterDuplicateRoomTypesByLowestPrice( Math.min( Number( previousLowest.products[0].productType.public.localPrice - .pricePerNight + ?.pricePerNight ) ?? Infinity, Number( previousLowest.products[0].productType.member?.localPrice From ef2860dd8ece3e4a4f0d66b400e50de697b75266 Mon Sep 17 00:00:00 2001 From: Pontus Dreij Date: Tue, 19 Nov 2024 15:11:13 +0100 Subject: [PATCH 06/21] fix: hide occupancy and roomSize if undefined --- .../RoomSelection/RoomCard/index.tsx | 97 ++++++++++--------- .../RoomCard/roomCard.module.css | 1 + 2 files changed, 52 insertions(+), 46 deletions(-) diff --git a/components/HotelReservation/SelectRate/RoomSelection/RoomCard/index.tsx b/components/HotelReservation/SelectRate/RoomSelection/RoomCard/index.tsx index d69391122..6c477d39f 100644 --- a/components/HotelReservation/SelectRate/RoomSelection/RoomCard/index.tsx +++ b/components/HotelReservation/SelectRate/RoomSelection/RoomCard/index.tsx @@ -112,56 +112,61 @@ export default function RoomCard({ : "default", }) + console.log(occupancy) + return (
- {mainImage && ( -
-
- {roomConfiguration.roomsLeft < 5 && ( - - {`${roomConfiguration.roomsLeft} ${intl.formatMessage({ id: "Left" })}`} - - )} - {roomConfiguration.features - .filter((feature) => selectedPackages.includes(feature.code)) - .map((feature) => ( - - {createElement(getIconForFeatureCode(feature.code), { - width: 16, - height: 16, - color: "burgundy", - })} - - ))} -
- {/*NOTE: images from the test API are hosted on test3.scandichotels.com, - which can't be accessed unless on Scandic's Wifi or using Citrix. */} - -
- )} -
- - {intl.formatMessage( - { - id: "booking.guests", - }, - { nrOfGuests: occupancy?.total } +
+
+ {roomConfiguration.roomsLeft < 5 && ( + + {`${roomConfiguration.roomsLeft} ${intl.formatMessage({ id: "Left" })}`} + )} - - - {roomSize?.min === roomSize?.max - ? roomSize?.min - : `${roomSize?.min}-${roomSize?.max}`} - m² - + {roomConfiguration.features + .filter((feature) => selectedPackages.includes(feature.code)) + .map((feature) => ( + + {createElement(getIconForFeatureCode(feature.code), { + width: 16, + height: 16, + color: "burgundy", + })} + + ))} +
+ {/*NOTE: images from the test API are hosted on test3.scandichotels.com, + which can't be accessed unless on Scandic's Wifi or using Citrix. */} + +
+ +
+ {occupancy && ( + + {intl.formatMessage( + { + id: "booking.guests", + }, + { nrOfGuests: occupancy?.total } + )} + + )} + {roomSize && ( + + {roomSize.min === roomSize.max + ? roomSize.min + : `${roomSize.min}-${roomSize.max}`} + m² + + )}
{roomConfiguration.roomTypeCode && ( Date: Tue, 19 Nov 2024 15:11:55 +0100 Subject: [PATCH 07/21] fix: remove log --- .../SelectRate/RoomSelection/RoomCard/index.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/components/HotelReservation/SelectRate/RoomSelection/RoomCard/index.tsx b/components/HotelReservation/SelectRate/RoomSelection/RoomCard/index.tsx index 6c477d39f..2a374b17c 100644 --- a/components/HotelReservation/SelectRate/RoomSelection/RoomCard/index.tsx +++ b/components/HotelReservation/SelectRate/RoomSelection/RoomCard/index.tsx @@ -112,8 +112,6 @@ export default function RoomCard({ : "default", }) - console.log(occupancy) - return (
From 14b1610d4c6108480b148879d32a86d69f7af01a Mon Sep 17 00:00:00 2001 From: Pontus Dreij Date: Tue, 19 Nov 2024 15:17:39 +0100 Subject: [PATCH 08/21] fix: removed unused code --- .../SelectRate/RoomSelection/RoomCard/index.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/components/HotelReservation/SelectRate/RoomSelection/RoomCard/index.tsx b/components/HotelReservation/SelectRate/RoomSelection/RoomCard/index.tsx index 2a374b17c..d8a37179b 100644 --- a/components/HotelReservation/SelectRate/RoomSelection/RoomCard/index.tsx +++ b/components/HotelReservation/SelectRate/RoomSelection/RoomCard/index.tsx @@ -60,7 +60,6 @@ export default function RoomCard({ const getBreakfastMessage = (rate: RateDefinition | undefined) => { const breakfastIncluded = getRateDefinitionForRate(rate)?.breakfastIncluded - switch (breakfastIncluded) { case true: return intl.formatMessage({ id: "Breakfast is included." }) @@ -83,7 +82,6 @@ export default function RoomCard({ ) const { roomSize, occupancy, images } = selectedRoom || {} - const mainImage = images?.[0] const freeCancelation = intl.formatMessage({ id: "Free cancellation" }) const nonRefundable = intl.formatMessage({ id: "Non-refundable" }) From ea3aff5dcdc7254cc12a749cca8c5f27a779cc4f Mon Sep 17 00:00:00 2001 From: Bianca Widstam Date: Tue, 19 Nov 2024 14:34:45 +0000 Subject: [PATCH 09/21] Merged in fix/translation-hotelpage-header (pull request #934) Fix/SW-932-translation hotelpage header * fix: add translation for hotel page header * fix: add hotel translation * fix: add translation where to when loading * fix: update hotel(s) count if filtered * fix(SW-932): update hotel(s) count Approved-by: Pontus Dreij Approved-by: Niclas Edenvin --- .../(standard)/select-hotel/page.tsx | 4 ++-- .../FormContent/Search/index.tsx | 3 ++- .../SelectHotel/HotelCount/index.tsx | 22 +++++++++++++++++++ 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 + 9 files changed, 32 insertions(+), 3 deletions(-) create mode 100644 components/HotelReservation/SelectHotel/HotelCount/index.tsx 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 a12639acf..70696a689 100644 --- a/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-hotel/page.tsx +++ b/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-hotel/page.tsx @@ -8,6 +8,7 @@ import { getFiltersFromHotels, } from "@/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-hotel/utils" import HotelCardListing from "@/components/HotelReservation/HotelCardListing" +import HotelCount from "@/components/HotelReservation/SelectHotel/HotelCount" import HotelFilter from "@/components/HotelReservation/SelectHotel/HotelFilter" import HotelSorter from "@/components/HotelReservation/SelectHotel/HotelSorter" import MobileMapButtonContainer from "@/components/HotelReservation/SelectHotel/MobileMapButtonContainer" @@ -20,7 +21,6 @@ import StaticMap from "@/components/Maps/StaticMap" import Alert from "@/components/TempDesignSystem/Alert" import Button from "@/components/TempDesignSystem/Button" import Link from "@/components/TempDesignSystem/Link" -import Preamble from "@/components/TempDesignSystem/Text/Preamble" import Subtitle from "@/components/TempDesignSystem/Text/Subtitle" import { getIntl } from "@/i18n" import { setLang } from "@/i18n/serverContext" @@ -72,7 +72,7 @@ export default async function SelectHotelPage({
{city.name} - {hotels.length} hotels +
diff --git a/components/Forms/BookingWidget/FormContent/Search/index.tsx b/components/Forms/BookingWidget/FormContent/Search/index.tsx index abbb28112..0d1ee36d4 100644 --- a/components/Forms/BookingWidget/FormContent/Search/index.tsx +++ b/components/Forms/BookingWidget/FormContent/Search/index.tsx @@ -206,11 +206,12 @@ export default function Search({ locations }: SearchProps) { } export function SearchSkeleton() { + const intl = useIntl() return (
- Where to + {intl.formatMessage({ id: "Where to" })}
diff --git a/components/HotelReservation/SelectHotel/HotelCount/index.tsx b/components/HotelReservation/SelectHotel/HotelCount/index.tsx new file mode 100644 index 000000000..1556dcf30 --- /dev/null +++ b/components/HotelReservation/SelectHotel/HotelCount/index.tsx @@ -0,0 +1,22 @@ +"use client" +import { useIntl } from "react-intl" + +import { useHotelFilterStore } from "@/stores/hotel-filters" + +import Preamble from "@/components/TempDesignSystem/Text/Preamble" + +export default function HotelCount() { + const intl = useIntl() + const resultCount = useHotelFilterStore((state) => state.resultCount) + + return ( + + {intl.formatMessage( + { + id: "Hotel(s)", + }, + { amount: resultCount } + )} + + ) +} diff --git a/i18n/dictionaries/da.json b/i18n/dictionaries/da.json index 7ec920d05..0ad5dce97 100644 --- a/i18n/dictionaries/da.json +++ b/i18n/dictionaries/da.json @@ -154,6 +154,7 @@ "Hotel": "Hotel", "Hotel facilities": "Hotel faciliteter", "Hotel surroundings": "Hotel omgivelser", + "Hotel(s)": "{amount} {amount, plural, one {hotel} other {hoteller}}", "Hotels": "Hoteller", "How do you want to sleep?": "Hvordan vil du sove?", "How it works": "Hvordan det virker", diff --git a/i18n/dictionaries/de.json b/i18n/dictionaries/de.json index 80b3b6116..bd094f4d5 100644 --- a/i18n/dictionaries/de.json +++ b/i18n/dictionaries/de.json @@ -154,6 +154,7 @@ "Hotel": "Hotel", "Hotel facilities": "Hotel-Infos", "Hotel surroundings": "Umgebung des Hotels", + "Hotel(s)": "{amount} {amount, plural, one {hotel} other {hotels}}", "Hotels": "Hotels", "How do you want to sleep?": "Wie möchtest du schlafen?", "How it works": "Wie es funktioniert", diff --git a/i18n/dictionaries/en.json b/i18n/dictionaries/en.json index 6080fc36b..afea03c06 100644 --- a/i18n/dictionaries/en.json +++ b/i18n/dictionaries/en.json @@ -166,6 +166,7 @@ "Hotel": "Hotel", "Hotel facilities": "Hotel facilities", "Hotel surroundings": "Hotel surroundings", + "Hotel(s)": "{amount} {amount, plural, one {hotel} other {hotels}}", "Hotels": "Hotels", "How do you want to sleep?": "How do you want to sleep?", "How it works": "How it works", diff --git a/i18n/dictionaries/fi.json b/i18n/dictionaries/fi.json index 0c1a08d35..57f137e94 100644 --- a/i18n/dictionaries/fi.json +++ b/i18n/dictionaries/fi.json @@ -154,6 +154,7 @@ "Hotel": "Hotelli", "Hotel facilities": "Hotellin palvelut", "Hotel surroundings": "Hotellin ympäristö", + "Hotel(s)": "{amount} {amount, plural, one {hotelli} other {hotellit}}", "Hotels": "Hotellit", "How do you want to sleep?": "Kuinka haluat nukkua?", "How it works": "Kuinka se toimii", diff --git a/i18n/dictionaries/no.json b/i18n/dictionaries/no.json index 2aca61a85..1ee68eb82 100644 --- a/i18n/dictionaries/no.json +++ b/i18n/dictionaries/no.json @@ -153,6 +153,7 @@ "Hotel": "Hotel", "Hotel facilities": "Hotelfaciliteter", "Hotel surroundings": "Hotellomgivelser", + "Hotel(s)": "{amount} {amount, plural, one {hotell} other {hoteller}}", "Hotels": "Hoteller", "How do you want to sleep?": "Hvordan vil du sove?", "How it works": "Hvordan det fungerer", diff --git a/i18n/dictionaries/sv.json b/i18n/dictionaries/sv.json index db300b7c2..3177903d2 100644 --- a/i18n/dictionaries/sv.json +++ b/i18n/dictionaries/sv.json @@ -153,6 +153,7 @@ "Hotel": "Hotell", "Hotel facilities": "Hotellfaciliteter", "Hotel surroundings": "Hotellomgivning", + "Hotel(s)": "{amount} hotell", "Hotels": "Hotell", "How do you want to sleep?": "Hur vill du sova?", "How it works": "Hur det fungerar", From ab9c8012c91670a2fa78ed6d2c82d19bdc06cdf2 Mon Sep 17 00:00:00 2001 From: Pontus Dreij Date: Tue, 19 Nov 2024 15:36:20 +0100 Subject: [PATCH 10/21] fix(SW-934): Change logic to isAllUnavailable instad of hotels.length --- .../hotelreservation/(standard)/select-hotel/page.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) 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 a12639acf..c76e6b7b6 100644 --- a/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-hotel/page.tsx +++ b/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-hotel/page.tsx @@ -66,6 +66,8 @@ export default async function SelectHotelPage({ const filterList = getFiltersFromHotels(hotels) + const isAllUnavailable = hotels.every((hotel) => hotel.price === undefined) + return ( <>
@@ -123,7 +125,7 @@ export default async function SelectHotelPage({
- {!hotels.length && ( + {isAllUnavailable && ( Date: Tue, 19 Nov 2024 14:39:25 +0000 Subject: [PATCH 11/21] Merged in feat/SW-863-remove-filters (pull request #935) feat(SW-863): remove filters without a type * feat(SW-863): remove filters without a type Approved-by: Pontus Dreij --- .../(standard)/select-hotel/utils.ts | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-hotel/utils.ts b/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-hotel/utils.ts index 58b18a25d..bd41510ce 100644 --- a/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-hotel/utils.ts +++ b/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-hotel/utils.ts @@ -19,6 +19,15 @@ const hotelSurroundingsFilterNames = [ "Omgivningar", ] +const hotelFacilitiesFilterNames = [ + "Hotel facilities", + "Hotellfaciliteter", + "Hotelfaciliteter", + "Hotel faciliteter", + "Hotel-Infos", + "Hotellin palvelut", +] + export async function fetchAvailableHotels( input: AvailabilityInput ): Promise { @@ -52,6 +61,7 @@ export function getFiltersFromHotels(hotels: HotelData[]): CategorizedFilters { const filterList: Filter[] = uniqueFilterIds .map((filterId) => filters.find((filter) => filter.id === filterId)) .filter((filter): filter is Filter => filter !== undefined) + .sort((a, b) => b.sortOrder - a.sortOrder) return filterList.reduce( (acc, filter) => { @@ -61,10 +71,13 @@ export function getFiltersFromHotels(hotels: HotelData[]): CategorizedFilters { surroundingsFilters: [...acc.surroundingsFilters, filter], } - return { - facilityFilters: [...acc.facilityFilters, filter], - surroundingsFilters: acc.surroundingsFilters, - } + if (filter.filter && hotelFacilitiesFilterNames.includes(filter.filter)) + return { + facilityFilters: [...acc.facilityFilters, filter], + surroundingsFilters: acc.surroundingsFilters, + } + + return acc }, { facilityFilters: [], surroundingsFilters: [] } ) From 6958db3ca576b4cc3360c4fdc8c938643cac2ee1 Mon Sep 17 00:00:00 2001 From: Chuma McPhoy Date: Fri, 15 Nov 2024 08:30:52 +0100 Subject: [PATCH 12/21] refactor(SW-898): replace signup server action with TRPC --- actions/registerUser.ts | 89 ------------------------------- components/Forms/Signup/index.tsx | 37 ++++++------- server/routers/user/input.ts | 8 +++ server/routers/user/mutation.ts | 72 ++++++++++++++++++++++++- server/routers/user/output.ts | 19 +++++++ server/trpc.ts | 2 +- 6 files changed, 116 insertions(+), 111 deletions(-) delete mode 100644 actions/registerUser.ts diff --git a/actions/registerUser.ts b/actions/registerUser.ts deleted file mode 100644 index 8def69ec3..000000000 --- a/actions/registerUser.ts +++ /dev/null @@ -1,89 +0,0 @@ -"use server" - -import { parsePhoneNumber } from "libphonenumber-js" -import { redirect } from "next/navigation" -import { z } from "zod" - -import { signupVerify } from "@/constants/routes/signup" -import * as api from "@/lib/api" -import { serviceServerActionProcedure } from "@/server/trpc" - -import { signUpSchema } from "@/components/Forms/Signup/schema" -import { passwordValidator } from "@/utils/passwordValidator" -import { phoneValidator } from "@/utils/phoneValidator" - -const registerUserPayload = z.object({ - language: z.string(), - firstName: z.string(), - lastName: z.string(), - email: z.string(), - phoneNumber: phoneValidator("Phone is required"), - dateOfBirth: z.string(), - address: z.object({ - city: z.string().default(""), - country: z.string().default(""), - countryCode: z.string().default(""), - zipCode: z.string().default(""), - streetAddress: z.string().default(""), - }), - password: passwordValidator("Password is required"), -}) - -export const registerUser = serviceServerActionProcedure - .input(signUpSchema) - .mutation(async function ({ ctx, input }) { - const payload = { - ...input, - language: ctx.lang, - phoneNumber: input.phoneNumber.replace(/\s+/g, ""), - } - - const parsedPayload = registerUserPayload.safeParse(payload) - if (!parsedPayload.success) { - console.error( - "registerUser payload validation error", - JSON.stringify({ - query: input, - error: parsedPayload.error, - }) - ) - - return { success: false, error: "Validation error" } - } - - let apiResponse - try { - apiResponse = await api.post(api.endpoints.v1.Profile.profile, { - body: parsedPayload.data, - headers: { - Authorization: `Bearer ${ctx.serviceToken}`, - }, - }) - } catch (error) { - console.error("Unexpected error", error) - return { success: false, error: "Unexpected error" } - } - - if (!apiResponse.ok) { - const text = await apiResponse.text() - console.error( - "registerUser api error", - JSON.stringify({ - query: input, - error: { - status: apiResponse.status, - statusText: apiResponse.statusText, - error: text, - }, - }) - ) - return { success: false, error: "API error" } - } - - const json = await apiResponse.json() - console.log("registerUser: json", json) - - // Note: The redirect needs to be called after the try/catch block. - // See: https://nextjs.org/docs/app/api-reference/functions/redirect - redirect(signupVerify[ctx.lang]) - }) diff --git a/components/Forms/Signup/index.tsx b/components/Forms/Signup/index.tsx index d6d5fc7da..d1e2727e0 100644 --- a/components/Forms/Signup/index.tsx +++ b/components/Forms/Signup/index.tsx @@ -1,12 +1,13 @@ "use client" import { zodResolver } from "@hookform/resolvers/zod" +import { useRouter } from "next/navigation" import { FormProvider, useForm } from "react-hook-form" import { useIntl } from "react-intl" import { privacyPolicy } from "@/constants/currentWebHrefs" +import { trpc } from "@/lib/trpc/client" -import { registerUser } from "@/actions/registerUser" import Button from "@/components/TempDesignSystem/Button" import Checkbox from "@/components/TempDesignSystem/Form/Checkbox" import CountrySelect from "@/components/TempDesignSystem/Form/Country" @@ -30,12 +31,25 @@ import type { SignUpFormProps } from "@/types/components/form/signupForm" export default function SignupForm({ link, subtitle, title }: SignUpFormProps) { const intl = useIntl() + const router = useRouter() const lang = useLang() const country = intl.formatMessage({ id: "Country" }) const email = intl.formatMessage({ id: "Email address" }) const phoneNumber = intl.formatMessage({ id: "Phone number" }) const zipCode = intl.formatMessage({ id: "Zip code" }) + const signup = trpc.user.signup.useMutation({ + onSuccess: (data) => { + if (data.success && data.redirectUrl) { + router.push(data.redirectUrl) + } + }, + onError: (error) => { + toast.error(intl.formatMessage({ id: "Something went wrong!" })) + console.error("Component Signup error:", error) + }, + }) + const methods = useForm({ defaultValues: { firstName: "", @@ -56,19 +70,7 @@ export default function SignupForm({ link, subtitle, title }: SignUpFormProps) { }) async function onSubmit(data: SignUpSchema) { - try { - const result = await registerUser(data) - if (result && !result.success) { - toast.error(intl.formatMessage({ id: "Something went wrong!" })) - } - } catch (error) { - // The server-side redirect will throw an error, which we can ignore - // as it's handled by Next.js. - if (error instanceof Error && error.message.includes("NEXT_REDIRECT")) { - return - } - toast.error(intl.formatMessage({ id: "Something went wrong!" })) - } + signup.mutate({ ...data, language: lang }) } return ( @@ -79,11 +81,6 @@ export default function SignupForm({ link, subtitle, title }: SignUpFormProps) { className={styles.form} id="register" onSubmit={methods.handleSubmit(onSubmit)} - /** - * Ignoring since ts doesn't recognize that tRPC - * parses FormData before reaching the route - * @ts-ignore */ - action={registerUser} >
@@ -194,7 +191,7 @@ export default function SignupForm({ link, subtitle, title }: SignUpFormProps) { type="submit" theme="base" intent="primary" - disabled={methods.formState.isSubmitting} + disabled={methods.formState.isSubmitting || signup.isPending} data-testid="submit" > {intl.formatMessage({ id: "Sign up to Scandic Friends" })} diff --git a/server/routers/user/input.ts b/server/routers/user/input.ts index d84875ea3..1d279c2ef 100644 --- a/server/routers/user/input.ts +++ b/server/routers/user/input.ts @@ -1,5 +1,9 @@ import { z } from "zod" +import { Lang } from "@/constants/languages" + +import { signUpSchema } from "@/components/Forms/Signup/schema" + // Query export const staysInput = z .object({ @@ -35,3 +39,7 @@ export const saveCreditCardInput = z.object({ transactionId: z.string(), merchantId: z.string().optional(), }) + +export const signupInput = signUpSchema.extend({ + language: z.nativeEnum(Lang), +}) diff --git a/server/routers/user/mutation.ts b/server/routers/user/mutation.ts index b03e6a68e..e233814ee 100644 --- a/server/routers/user/mutation.ts +++ b/server/routers/user/mutation.ts @@ -1,17 +1,21 @@ import { metrics } from "@opentelemetry/api" +import { signupVerify } from "@/constants/routes/signup" import { env } from "@/env/server" import * as api from "@/lib/api" +import { badRequestError, serverErrorByStatus } from "@/server/errors/trpc" import { initiateSaveCardSchema, + signupPayloadSchema, subscriberIdSchema, } from "@/server/routers/user/output" -import { protectedProcedure, router } from "@/server/trpc" +import { protectedProcedure, router,serviceProcedure } from "@/server/trpc" import { addCreditCardInput, deleteCreditCardInput, saveCreditCardInput, + signupInput, } from "./input" const meter = metrics.getMeter("trpc.user") @@ -24,6 +28,9 @@ const generatePreferencesLinkSuccessCounter = meter.createCounter( const generatePreferencesLinkFailCounter = meter.createCounter( "trpc.user.generatePreferencesLink-fail" ) +const signupCounter = meter.createCounter("trpc.user.signup") +const signupSuccessCounter = meter.createCounter("trpc.user.signup-success") +const signupFailCounter = meter.createCounter("trpc.user.signup-fail") export const userMutationRouter = router({ creditCard: router({ @@ -208,4 +215,67 @@ export const userMutationRouter = router({ generatePreferencesLinkSuccessCounter.add(1) return preferencesLink.toString() }), + signup: serviceProcedure.input(signupInput).mutation(async function ({ + ctx, + input, + }) { + const payload = { + ...input, + language: input.language, + phoneNumber: input.phoneNumber.replace(/\s+/g, ""), + } + signupCounter.add(1) + + const parsedPayload = signupPayloadSchema.safeParse(payload) + if (!parsedPayload.success) { + signupFailCounter.add(1, { + error_type: "validation_error", + error: JSON.stringify(parsedPayload.error), + }) + console.error( + "api.user.signup validation error", + JSON.stringify({ + query: input, + error: parsedPayload.error, + }) + ) + throw badRequestError(parsedPayload.error) + } + + const apiResponse = await api.post(api.endpoints.v1.Profile.profile, { + body: parsedPayload.data, + headers: { + Authorization: `Bearer ${ctx.serviceToken}`, + }, + }) + + if (!apiResponse.ok) { + const text = await apiResponse.text() + signupFailCounter.add(1, { + error_type: "http_error", + error: JSON.stringify({ + status: apiResponse.status, + statusText: apiResponse.statusText, + error: text, + }), + }) + console.error( + "api.user.signup api error", + JSON.stringify({ + error: { + status: apiResponse.status, + statusText: apiResponse.statusText, + error: text, + }, + }) + ) + throw serverErrorByStatus(apiResponse.status, text) + } + signupSuccessCounter.add(1) + console.info("api.user.signup success", JSON.stringify({})) + return { + success: true, + redirectUrl: signupVerify[input.language], + } + }), }) diff --git a/server/routers/user/output.ts b/server/routers/user/output.ts index a9e7a0416..4dadd467f 100644 --- a/server/routers/user/output.ts +++ b/server/routers/user/output.ts @@ -1,6 +1,8 @@ import { z } from "zod" import { countriesMap } from "@/components/TempDesignSystem/Form/Country/countries" +import { passwordValidator } from "@/utils/passwordValidator" +import { phoneValidator } from "@/utils/phoneValidator" import { getMembership } from "@/utils/user" export const membershipSchema = z.object({ @@ -244,3 +246,20 @@ export const initiateSaveCardSchema = z.object({ export const subscriberIdSchema = z.object({ subscriberId: z.string(), }) + +export const signupPayloadSchema = z.object({ + language: z.string(), + firstName: z.string(), + lastName: z.string(), + email: z.string(), + phoneNumber: phoneValidator("Phone is required"), + dateOfBirth: z.string(), + address: z.object({ + city: z.string().default(""), + country: z.string().default(""), + countryCode: z.string().default(""), + zipCode: z.string().default(""), + streetAddress: z.string().default(""), + }), + password: passwordValidator("Password is required"), +}) diff --git a/server/trpc.ts b/server/trpc.ts index 688ea01cf..3fc3a10a6 100644 --- a/server/trpc.ts +++ b/server/trpc.ts @@ -121,7 +121,7 @@ export const safeProtectedProcedure = t.procedure.use(async function (opts) { }) }) -export const serviceProcedure = t.procedure.use(async (opts) => { +export const serviceProcedure = t.procedure.use(async function (opts) { const { access_token } = await getServiceToken() if (!access_token) { throw internalServerError(`[serviceProcedure] No service token`) From bc5a01fdf4010f45bac5660224e080b6dca84378 Mon Sep 17 00:00:00 2001 From: Chuma McPhoy Date: Mon, 18 Nov 2024 10:13:05 +0100 Subject: [PATCH 13/21] fix(SW-898): formatting --- server/routers/user/mutation.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/routers/user/mutation.ts b/server/routers/user/mutation.ts index e233814ee..fd8fe0d41 100644 --- a/server/routers/user/mutation.ts +++ b/server/routers/user/mutation.ts @@ -9,7 +9,7 @@ import { signupPayloadSchema, subscriberIdSchema, } from "@/server/routers/user/output" -import { protectedProcedure, router,serviceProcedure } from "@/server/trpc" +import { protectedProcedure, router, serviceProcedure } from "@/server/trpc" import { addCreditCardInput, From cfaa92260a3d31ccf7dd6f4e2324edf69098eff5 Mon Sep 17 00:00:00 2001 From: Chuma McPhoy Date: Mon, 18 Nov 2024 10:35:27 +0100 Subject: [PATCH 14/21] chore(SW-898): pr comments --- server/routers/user/mutation.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/routers/user/mutation.ts b/server/routers/user/mutation.ts index fd8fe0d41..17fc39adf 100644 --- a/server/routers/user/mutation.ts +++ b/server/routers/user/mutation.ts @@ -272,7 +272,7 @@ export const userMutationRouter = router({ throw serverErrorByStatus(apiResponse.status, text) } signupSuccessCounter.add(1) - console.info("api.user.signup success", JSON.stringify({})) + console.info("api.user.signup success") return { success: true, redirectUrl: signupVerify[input.language], From 5c571c3c0c30b248d48b8eb9c45ffa2021cf1fa6 Mon Sep 17 00:00:00 2001 From: Chuma McPhoy Date: Mon, 18 Nov 2024 11:18:55 +0100 Subject: [PATCH 15/21] feat(SW-898): add pending ui text to signup button --- components/Forms/Signup/index.tsx | 10 ++++++++-- 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, 14 insertions(+), 2 deletions(-) diff --git a/components/Forms/Signup/index.tsx b/components/Forms/Signup/index.tsx index d1e2727e0..24fe2bd95 100644 --- a/components/Forms/Signup/index.tsx +++ b/components/Forms/Signup/index.tsx @@ -37,6 +37,10 @@ export default function SignupForm({ link, subtitle, title }: SignUpFormProps) { const email = intl.formatMessage({ id: "Email address" }) const phoneNumber = intl.formatMessage({ id: "Phone number" }) const zipCode = intl.formatMessage({ id: "Zip code" }) + const signupButtonText = intl.formatMessage({ + id: "Sign up to Scandic Friends", + }) + const signingUpPendingText = intl.formatMessage({ id: "Signing up..." }) const signup = trpc.user.signup.useMutation({ onSuccess: (data) => { @@ -183,7 +187,7 @@ export default function SignupForm({ link, subtitle, title }: SignUpFormProps) { onClick={() => methods.trigger()} data-testid="trigger-validation" > - {intl.formatMessage({ id: "Sign up to Scandic Friends" })} + {signupButtonText} ) : ( )} diff --git a/i18n/dictionaries/da.json b/i18n/dictionaries/da.json index 0ad5dce97..a9fdcfae4 100644 --- a/i18n/dictionaries/da.json +++ b/i18n/dictionaries/da.json @@ -337,6 +337,7 @@ "Show wellness & exercise": "Vis velvære og motion", "Sign up bonus": "Velkomstbonus", "Sign up to Scandic Friends": "Tilmeld dig Scandic Friends", + "Signing up...": "Tilmelder...", "Skip to main content": "Spring over og gå til hovedindhold", "Something went wrong and we couldn't add your card. Please try again later.": "Noget gik galt, og vi kunne ikke tilføje dit kort. Prøv venligst igen senere.", "Something went wrong and we couldn't remove your card. Please try again later.": "Noget gik galt, og vi kunne ikke fjerne dit kort. Prøv venligst igen senere.", diff --git a/i18n/dictionaries/de.json b/i18n/dictionaries/de.json index bd094f4d5..96bcef2de 100644 --- a/i18n/dictionaries/de.json +++ b/i18n/dictionaries/de.json @@ -336,6 +336,7 @@ "Show wellness & exercise": "Zeige Wellness und Bewegung", "Sign up bonus": "Anmelde-Bonus", "Sign up to Scandic Friends": "Treten Sie Scandic Friends bei", + "Signing up...": "Registrierung läuft...", "Skip to main content": "Direkt zum Inhalt", "Something went wrong and we couldn't add your card. Please try again later.": "Ein Fehler ist aufgetreten und wir konnten Ihre Karte nicht hinzufügen. Bitte versuchen Sie es später erneut.", "Something went wrong and we couldn't remove your card. Please try again later.": "Ein Fehler ist aufgetreten und wir konnten Ihre Karte nicht entfernen. Bitte versuchen Sie es später noch einmal.", diff --git a/i18n/dictionaries/en.json b/i18n/dictionaries/en.json index afea03c06..385861316 100644 --- a/i18n/dictionaries/en.json +++ b/i18n/dictionaries/en.json @@ -366,6 +366,7 @@ "Show wellness & exercise": "Show wellness & exercise", "Sign up bonus": "Sign up bonus", "Sign up to Scandic Friends": "Sign up to Scandic Friends", + "Signing up...": "Signing up...", "Skip to main content": "Skip to main content", "Something went wrong and we couldn't add your card. Please try again later.": "Something went wrong and we couldn't add your card. Please try again later.", "Something went wrong and we couldn't remove your card. Please try again later.": "Something went wrong and we couldn't remove your card. Please try again later.", diff --git a/i18n/dictionaries/fi.json b/i18n/dictionaries/fi.json index 57f137e94..09fb8a403 100644 --- a/i18n/dictionaries/fi.json +++ b/i18n/dictionaries/fi.json @@ -338,6 +338,7 @@ "Show wellness & exercise": "Näytä hyvinvointi ja liikunta", "Sign up bonus": "Liittymisbonus", "Sign up to Scandic Friends": "Liity Scandic Friends -jäseneksi", + "Signing up...": "Rekisteröidytään...", "Skip to main content": "Siirry pääsisältöön", "Something went wrong and we couldn't add your card. Please try again later.": "Jotain meni pieleen, emmekä voineet lisätä korttiasi. Yritä myöhemmin uudelleen.", "Something went wrong and we couldn't remove your card. Please try again later.": "Jotain meni pieleen, emmekä voineet poistaa korttiasi. Yritä myöhemmin uudelleen.", diff --git a/i18n/dictionaries/no.json b/i18n/dictionaries/no.json index 1ee68eb82..dcbcdddf4 100644 --- a/i18n/dictionaries/no.json +++ b/i18n/dictionaries/no.json @@ -335,6 +335,7 @@ "Show wellness & exercise": "Vis velvære og trening", "Sign up bonus": "Velkomstbonus", "Sign up to Scandic Friends": "Bli med i Scandic Friends", + "Signing up...": "Registrerer...", "Skip to main content": "Gå videre til hovedsiden", "Something went wrong and we couldn't add your card. Please try again later.": "Noe gikk galt, og vi kunne ikke legge til kortet ditt. Prøv igjen senere.", "Something went wrong and we couldn't remove your card. Please try again later.": "Noe gikk galt, og vi kunne ikke fjerne kortet ditt. Vennligst prøv igjen senere.", diff --git a/i18n/dictionaries/sv.json b/i18n/dictionaries/sv.json index 3177903d2..404896e15 100644 --- a/i18n/dictionaries/sv.json +++ b/i18n/dictionaries/sv.json @@ -335,6 +335,7 @@ "Show wellness & exercise": "Visa välbefinnande och träning", "Sign up bonus": "Välkomstbonus", "Sign up to Scandic Friends": "Bli medlem i Scandic Friends", + "Signing up...": "Registrerar...", "Skip to main content": "Fortsätt till huvudinnehåll", "Something went wrong and we couldn't add your card. Please try again later.": "Något gick fel och vi kunde inte lägga till ditt kort. Försök igen senare.", "Something went wrong and we couldn't remove your card. Please try again later.": "Något gick fel och vi kunde inte ta bort ditt kort. Försök igen senare.", From a68e37c26fc65c71c06ae6eda6032f297abbe16c Mon Sep 17 00:00:00 2001 From: Chuma McPhoy Date: Mon, 18 Nov 2024 15:47:13 +0100 Subject: [PATCH 16/21] fix(SW-898): remove redundant schema and add transform in signupInput --- server/routers/user/input.ts | 18 +++++++++++++++--- server/routers/user/mutation.ts | 26 ++------------------------ server/routers/user/output.ts | 17 ----------------- 3 files changed, 17 insertions(+), 44 deletions(-) diff --git a/server/routers/user/input.ts b/server/routers/user/input.ts index 1d279c2ef..1e9fee267 100644 --- a/server/routers/user/input.ts +++ b/server/routers/user/input.ts @@ -40,6 +40,18 @@ export const saveCreditCardInput = z.object({ merchantId: z.string().optional(), }) -export const signupInput = signUpSchema.extend({ - language: z.nativeEnum(Lang), -}) +export const signupInput = signUpSchema + .extend({ + language: z.nativeEnum(Lang), + }) + .omit({ termsAccepted: true }) + .transform((data) => ({ + ...data, + phoneNumber: data.phoneNumber.replace(/\s+/g, ""), + address: { + ...data.address, + city: "", + country: "", + streetAddress: "", + }, + })) diff --git a/server/routers/user/mutation.ts b/server/routers/user/mutation.ts index 17fc39adf..689c43a26 100644 --- a/server/routers/user/mutation.ts +++ b/server/routers/user/mutation.ts @@ -3,10 +3,9 @@ import { metrics } from "@opentelemetry/api" import { signupVerify } from "@/constants/routes/signup" import { env } from "@/env/server" import * as api from "@/lib/api" -import { badRequestError, serverErrorByStatus } from "@/server/errors/trpc" +import { serverErrorByStatus } from "@/server/errors/trpc" import { initiateSaveCardSchema, - signupPayloadSchema, subscriberIdSchema, } from "@/server/routers/user/output" import { protectedProcedure, router, serviceProcedure } from "@/server/trpc" @@ -219,31 +218,10 @@ export const userMutationRouter = router({ ctx, input, }) { - const payload = { - ...input, - language: input.language, - phoneNumber: input.phoneNumber.replace(/\s+/g, ""), - } signupCounter.add(1) - const parsedPayload = signupPayloadSchema.safeParse(payload) - if (!parsedPayload.success) { - signupFailCounter.add(1, { - error_type: "validation_error", - error: JSON.stringify(parsedPayload.error), - }) - console.error( - "api.user.signup validation error", - JSON.stringify({ - query: input, - error: parsedPayload.error, - }) - ) - throw badRequestError(parsedPayload.error) - } - const apiResponse = await api.post(api.endpoints.v1.Profile.profile, { - body: parsedPayload.data, + body: input, headers: { Authorization: `Bearer ${ctx.serviceToken}`, }, diff --git a/server/routers/user/output.ts b/server/routers/user/output.ts index 4dadd467f..616419047 100644 --- a/server/routers/user/output.ts +++ b/server/routers/user/output.ts @@ -246,20 +246,3 @@ export const initiateSaveCardSchema = z.object({ export const subscriberIdSchema = z.object({ subscriberId: z.string(), }) - -export const signupPayloadSchema = z.object({ - language: z.string(), - firstName: z.string(), - lastName: z.string(), - email: z.string(), - phoneNumber: phoneValidator("Phone is required"), - dateOfBirth: z.string(), - address: z.object({ - city: z.string().default(""), - country: z.string().default(""), - countryCode: z.string().default(""), - zipCode: z.string().default(""), - streetAddress: z.string().default(""), - }), - password: passwordValidator("Password is required"), -}) From bc344e64cf713041eb64e8234996e3143a9502ab Mon Sep 17 00:00:00 2001 From: Hrishikesh Vaipurkar Date: Tue, 19 Nov 2024 14:54:11 +0100 Subject: [PATCH 17/21] feat: SW-601 Implement filters and sort in map view --- .../select-hotel/@modal/(.)map/page.tsx | 4 +- .../filterAndSortModal.module.css | 70 +++++++++++++++++++ .../SelectHotel/FilterAndSortModal/index.tsx | 12 +++- .../HotelFilter/hotelFilter.module.css | 14 ++++ .../SelectHotel/HotelFilter/index.tsx | 10 ++- .../SelectHotel/SelectHotelMap/index.tsx | 5 +- .../SelectHotelMap/selectHotelMap.module.css | 5 ++ .../selectHotel/hotelFilters.ts | 5 ++ .../hotelReservation/selectHotel/map.ts | 3 +- 9 files changed, 120 insertions(+), 8 deletions(-) diff --git a/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-hotel/@modal/(.)map/page.tsx b/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-hotel/@modal/(.)map/page.tsx index fd9cc33c5..7c5573536 100644 --- a/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-hotel/@modal/(.)map/page.tsx +++ b/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-hotel/@modal/(.)map/page.tsx @@ -12,7 +12,7 @@ import { import { MapModal } from "@/components/MapModal" import { setLang } from "@/i18n/serverContext" -import { fetchAvailableHotels } from "../../utils" +import { fetchAvailableHotels, getFiltersFromHotels } from "../../utils" import type { SelectHotelSearchParams } from "@/types/components/hotelReservation/selectHotel/selectHotelSearchParams" import type { LangParams, PageArgs } from "@/types/params" @@ -57,6 +57,7 @@ export default async function SelectHotelMapPage({ }) const hotelPins = getHotelPins(hotels) + const filterList = getFiltersFromHotels(hotels) return ( @@ -65,6 +66,7 @@ export default async function SelectHotelMapPage({ hotelPins={hotelPins} mapId={googleMapId} hotels={hotels} + filterList={filterList} /> ) diff --git a/components/HotelReservation/SelectHotel/FilterAndSortModal/filterAndSortModal.module.css b/components/HotelReservation/SelectHotel/FilterAndSortModal/filterAndSortModal.module.css index 6768d2c56..299527ad0 100644 --- a/components/HotelReservation/SelectHotel/FilterAndSortModal/filterAndSortModal.module.css +++ b/components/HotelReservation/SelectHotel/FilterAndSortModal/filterAndSortModal.module.css @@ -81,6 +81,10 @@ flex: 0 0 auto; } +.title { + display: none; +} + .close { background: none; border: none; @@ -97,3 +101,69 @@ flex: 0 0 auto; border-top: 1px solid var(--Base-Border-Subtle); } + +@media screen and (min-width: 768px) { + .modal { + left: 50%; + bottom: 50%; + height: min(80dvh, 680px); + width: min(80dvw, 960px); + translate: -50% 50%; + overflow-y: auto; + } + + .header { + display: grid; + grid-template-columns: auto 1fr; + padding: var(--Spacing-x2) var(--Spacing-x3); + align-items: center; + border-bottom: 1px solid var(--Base-Border-Subtle); + position: sticky; + top: 0; + background: var(--Base-Surface-Primary-light-Normal); + z-index: 1; + border-top-left-radius: var(--Corner-radius-large); + border-top-right-radius: var(--Corner-radius-large); + } + + .title { + display: block; + } + + .content { + gap: var(--Spacing-x4); + height: auto; + } + + .filters { + overflow-y: unset; + } + + .sorter, + .filters, + .footer, + .divider { + padding: 0 var(--Spacing-x3); + } + + .footer { + flex-direction: row-reverse; + justify-content: space-between; + position: sticky; + bottom: 0; + background: var(--Base-Surface-Primary-light-Normal); + z-index: 1; + border-bottom-left-radius: var(--Corner-radius-large); + border-bottom-right-radius: var(--Corner-radius-large); + padding: var(--Spacing-x2) var(--Spacing-x3); + } + + .filters aside h1 { + margin-bottom: var(--Spacing-x2); + } + + .filters aside > div:last-child { + margin-top: var(--Spacing-x4); + padding-bottom: 0; + } +} diff --git a/components/HotelReservation/SelectHotel/FilterAndSortModal/index.tsx b/components/HotelReservation/SelectHotel/FilterAndSortModal/index.tsx index be1a1bc9c..40dd606fb 100644 --- a/components/HotelReservation/SelectHotel/FilterAndSortModal/index.tsx +++ b/components/HotelReservation/SelectHotel/FilterAndSortModal/index.tsx @@ -12,6 +12,8 @@ import { useHotelFilterStore } from "@/stores/hotel-filters" import { CloseLargeIcon, FilterIcon } from "@/components/Icons" import Button from "@/components/TempDesignSystem/Button" +import Divider from "@/components/TempDesignSystem/Divider" +import Subtitle from "@/components/TempDesignSystem/Text/Subtitle" import HotelFilter from "../HotelFilter" import HotelSorter from "../HotelSorter" @@ -47,12 +49,20 @@ export default function FilterAndSortModal({ > + + {intl.formatMessage({ id: "Filter and sort" })} +
+
- +
- Filter and sort - {/* TODO: Add filter and sort button */} +
From ebd60d9789b6924c0d51d49c14432e5e3b0b7e98 Mon Sep 17 00:00:00 2001 From: Hrishikesh Vaipurkar Date: Tue, 19 Nov 2024 17:18:12 +0100 Subject: [PATCH 18/21] feat: SW-601 Removed autoclose of map view in desktop --- components/MapModal/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/MapModal/index.tsx b/components/MapModal/index.tsx index 2c06a08cc..3f9e3b4b6 100644 --- a/components/MapModal/index.tsx +++ b/components/MapModal/index.tsx @@ -66,7 +66,7 @@ export function MapModal({ children }: { children: React.ReactNode }) { return (
- + Date: Tue, 19 Nov 2024 17:19:04 +0100 Subject: [PATCH 19/21] feat: SW-601 Optimized css --- .../filterAndSortModal.module.css | 11 +++++++++++ .../SelectHotel/HotelFilter/hotelFilter.module.css | 14 -------------- 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/components/HotelReservation/SelectHotel/FilterAndSortModal/filterAndSortModal.module.css b/components/HotelReservation/SelectHotel/FilterAndSortModal/filterAndSortModal.module.css index 299527ad0..eab6a1c1d 100644 --- a/components/HotelReservation/SelectHotel/FilterAndSortModal/filterAndSortModal.module.css +++ b/components/HotelReservation/SelectHotel/FilterAndSortModal/filterAndSortModal.module.css @@ -166,4 +166,15 @@ margin-top: var(--Spacing-x4); padding-bottom: 0; } + + .filters aside ul { + display: grid; + grid-template-columns: 1fr 1fr; + margin-top: var(--Spacing-x3); + } +} +@media screen and (min-width: 1024) { + .facilities ul { + grid-template-columns: 1fr 1fr 1fr; + } } diff --git a/components/HotelReservation/SelectHotel/HotelFilter/hotelFilter.module.css b/components/HotelReservation/SelectHotel/HotelFilter/hotelFilter.module.css index 0e204c144..8a4fcebff 100644 --- a/components/HotelReservation/SelectHotel/HotelFilter/hotelFilter.module.css +++ b/components/HotelReservation/SelectHotel/HotelFilter/hotelFilter.module.css @@ -38,17 +38,3 @@ height: 1.25rem; margin: 0; } - -@media screen and (min-width: 768px) { - .facilities ul.modal { - display: grid; - grid-template-columns: auto auto auto; - margin-top: var(--Spacing-x3); - } -} - -@media screen and (min-width: 768px) and (max-width: 1023) { - .facilities ul.modal { - grid-template-columns: auto auto; - } -} From 1330c8b537adb4424b54169d32bfebcaed5dbfe2 Mon Sep 17 00:00:00 2001 From: Hrishikesh Vaipurkar Date: Tue, 19 Nov 2024 17:31:34 +0100 Subject: [PATCH 20/21] feat: SW-601 Optimized code --- .../SelectHotel/FilterAndSortModal/index.tsx | 2 +- .../HotelReservation/SelectHotel/HotelFilter/index.tsx | 10 +++------- .../hotelReservation/selectHotel/hotelFilters.ts | 1 - 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/components/HotelReservation/SelectHotel/FilterAndSortModal/index.tsx b/components/HotelReservation/SelectHotel/FilterAndSortModal/index.tsx index 40dd606fb..286042ca0 100644 --- a/components/HotelReservation/SelectHotel/FilterAndSortModal/index.tsx +++ b/components/HotelReservation/SelectHotel/FilterAndSortModal/index.tsx @@ -62,7 +62,7 @@ export default function FilterAndSortModal({
- +