From 0fe4a7c42cbedd9e857d9c7d00f40746e38dfede Mon Sep 17 00:00:00 2001 From: Erik Tiekstra Date: Thu, 17 Oct 2024 11:23:50 +0200 Subject: [PATCH 01/18] feat(SW-498): added sitewide alert --- app/[lang]/(live)/@sitewidealert/page.tsx | 10 ++------ components/SitewideAlert/index.tsx | 28 +++++++++++++---------- 2 files changed, 18 insertions(+), 20 deletions(-) diff --git a/app/[lang]/(live)/@sitewidealert/page.tsx b/app/[lang]/(live)/@sitewidealert/page.tsx index be7ae2256..0f0c75eba 100644 --- a/app/[lang]/(live)/@sitewidealert/page.tsx +++ b/app/[lang]/(live)/@sitewidealert/page.tsx @@ -1,11 +1,9 @@ -import { Suspense } from "react" - import { env } from "@/env/server" import SitewideAlert, { preload } from "@/components/SitewideAlert" import { setLang } from "@/i18n/serverContext" -import type { LangParams, PageArgs } from "@/types/params" +import { LangParams, PageArgs } from "@/types/params" export default function SitewideAlertPage({ params }: PageArgs) { if (env.HIDE_FOR_NEXT_RELEASE) { @@ -15,9 +13,5 @@ export default function SitewideAlertPage({ params }: PageArgs) { setLang(params.lang) preload() - return ( - - - - ) + return } diff --git a/components/SitewideAlert/index.tsx b/components/SitewideAlert/index.tsx index 2ce624119..c2cb6e728 100644 --- a/components/SitewideAlert/index.tsx +++ b/components/SitewideAlert/index.tsx @@ -1,3 +1,5 @@ +import { Suspense } from "react" + import { getSiteConfig } from "@/lib/trpc/memoizedRequests" import Alert from "../TempDesignSystem/Alert" @@ -17,17 +19,19 @@ export default async function SitewideAlert() { const { sitewideAlert } = siteConfig return ( -
- -
+ +
+ +
+
) } From a29657a6b20488fe495f96f82392047ca61803a9 Mon Sep 17 00:00:00 2001 From: Erik Tiekstra Date: Tue, 22 Oct 2024 10:49:01 +0200 Subject: [PATCH 02/18] feat(SW-508): Added hotel alerts --- app/[lang]/(live)/@sitewidealert/page.tsx | 9 +++-- .../HotelPage/hotelPage.module.css | 16 +++++---- components/ContentType/HotelPage/index.tsx | 34 ++++++++++++++----- components/SitewideAlert/index.tsx | 28 +++++++-------- components/TempDesignSystem/Alert/alert.ts | 4 +-- components/TempDesignSystem/Alert/index.tsx | 4 +++ server/routers/hotels/output.ts | 21 +++++++++++- server/routers/hotels/query.ts | 2 ++ 8 files changed, 82 insertions(+), 36 deletions(-) diff --git a/app/[lang]/(live)/@sitewidealert/page.tsx b/app/[lang]/(live)/@sitewidealert/page.tsx index 0f0c75eba..b0bbf8765 100644 --- a/app/[lang]/(live)/@sitewidealert/page.tsx +++ b/app/[lang]/(live)/@sitewidealert/page.tsx @@ -1,9 +1,10 @@ import { env } from "@/env/server" +import { Suspense } from "react" import SitewideAlert, { preload } from "@/components/SitewideAlert" import { setLang } from "@/i18n/serverContext" -import { LangParams, PageArgs } from "@/types/params" +import type { LangParams, PageArgs } from "@/types/params" export default function SitewideAlertPage({ params }: PageArgs) { if (env.HIDE_FOR_NEXT_RELEASE) { @@ -13,5 +14,9 @@ export default function SitewideAlertPage({ params }: PageArgs) { setLang(params.lang) preload() - return + return ( + + + + ) } diff --git a/components/ContentType/HotelPage/hotelPage.module.css b/components/ContentType/HotelPage/hotelPage.module.css index 771c4e76e..091444fe2 100644 --- a/components/ContentType/HotelPage/hotelPage.module.css +++ b/components/ContentType/HotelPage/hotelPage.module.css @@ -29,6 +29,11 @@ display: none; } +.overview { + display: grid; + gap: var(--Spacing-x3); +} + .introContainer { display: flex; flex-wrap: wrap; @@ -37,6 +42,11 @@ scroll-margin-top: var(--hotel-page-scroll-margin-top); } +.alertsContainer { + display: grid; + gap: var(--Spacing-x2); +} + @media screen and (min-width: 1367px) { .pageContainer { grid-template-areas: @@ -76,10 +86,4 @@ padding-left: var(--Spacing-x5); padding-right: var(--Spacing-x5); } - .introContainer { - grid-template-columns: 38rem minmax(max-content, 16rem); - justify-content: space-between; - gap: var(--Spacing-x2); - align-items: end; - } } diff --git a/components/ContentType/HotelPage/index.tsx b/components/ContentType/HotelPage/index.tsx index 5b0139d6f..d10244040 100644 --- a/components/ContentType/HotelPage/index.tsx +++ b/components/ContentType/HotelPage/index.tsx @@ -4,6 +4,7 @@ import { serverClient } from "@/lib/trpc/server" import AccordionSection from "@/components/Blocks/Accordion" import SidePeekProvider from "@/components/SidePeekProvider" +import Alert from "@/components/TempDesignSystem/Alert" import SidePeek from "@/components/TempDesignSystem/SidePeek" import { getIntl } from "@/i18n" import { getLang } from "@/i18n/serverContext" @@ -49,6 +50,7 @@ export default async function HotelPage() { pointsOfInterest, facilities, faq, + alerts, } = hotelData const topThreePois = pointsOfInterest.slice(0, 3) @@ -69,16 +71,30 @@ export default async function HotelPage() { hasFAQ={!!faq} />
-
- +
+
+ - + +
+ {alerts.length ? ( +
+ {alerts.map((alert) => ( + + ))} +
+ ) : null}
diff --git a/components/SitewideAlert/index.tsx b/components/SitewideAlert/index.tsx index c2cb6e728..2ce624119 100644 --- a/components/SitewideAlert/index.tsx +++ b/components/SitewideAlert/index.tsx @@ -1,5 +1,3 @@ -import { Suspense } from "react" - import { getSiteConfig } from "@/lib/trpc/memoizedRequests" import Alert from "../TempDesignSystem/Alert" @@ -19,19 +17,17 @@ export default async function SitewideAlert() { const { sitewideAlert } = siteConfig return ( - -
- -
-
+
+ +
) } diff --git a/components/TempDesignSystem/Alert/alert.ts b/components/TempDesignSystem/Alert/alert.ts index 20927d7fc..e63873c66 100644 --- a/components/TempDesignSystem/Alert/alert.ts +++ b/components/TempDesignSystem/Alert/alert.ts @@ -8,8 +8,8 @@ import type { SidepeekContent } from "@/types/trpc/routers/contentstack/siteConf export interface AlertProps extends VariantProps { className?: string type: AlertTypeEnum - heading?: string - text: string + heading?: string | null + text?: string | null phoneContact?: { displayText: string phoneNumber?: string diff --git a/components/TempDesignSystem/Alert/index.tsx b/components/TempDesignSystem/Alert/index.tsx index 6499c7126..2f1e97b6a 100644 --- a/components/TempDesignSystem/Alert/index.tsx +++ b/components/TempDesignSystem/Alert/index.tsx @@ -27,6 +27,10 @@ export default function Alert({ }) const Icon = getIconByAlertType(type) + if (!text && !heading) { + return null + } + return (
diff --git a/server/routers/hotels/output.ts b/server/routers/hotels/output.ts index 89e286185..803ae012f 100644 --- a/server/routers/hotels/output.ts +++ b/server/routers/hotels/output.ts @@ -1,11 +1,13 @@ import { z } from "zod" +import { dt } from "@/lib/dt" import { toLang } from "@/server/utils" import { imageMetaDataSchema, imageSizesSchema } from "./schemas/image" import { roomSchema } from "./schemas/room" import { getPoiGroupByCategoryName } from "./utils" +import { AlertTypeEnum } from "@/types/enums/alert" import { FacilityEnum } from "@/types/enums/facilities" import { PointOfInterestCategoryNameEnum } from "@/types/hotel" @@ -321,6 +323,7 @@ const socialMediaSchema = z.object({ const metaSpecialAlertSchema = z.object({ type: z.string(), + title: z.string().optional(), description: z.string().optional(), displayInBookingFlow: z.boolean(), startDate: z.string(), @@ -328,7 +331,23 @@ const metaSpecialAlertSchema = z.object({ }) const metaSchema = z.object({ - specialAlerts: z.array(metaSpecialAlertSchema), + specialAlerts: z + .array(metaSpecialAlertSchema) + .transform((data) => { + const now = dt().utc().format("YYYY-MM-DD") + const filteredAlerts = data.filter((alert) => { + const shouldShowNow = alert.startDate <= now && alert.endDate >= now + const hasText = alert.description || alert.title + return shouldShowNow && hasText + }) + return filteredAlerts.map((alert, idx) => ({ + id: `alert-${alert.type}-${idx}`, + type: AlertTypeEnum.Info, + heading: alert.title || null, + text: alert.description || null, + })) + }) + .default([]), }) const relationshipsSchema = z.object({ diff --git a/server/routers/hotels/query.ts b/server/routers/hotels/query.ts index 2fa4cfbe8..b5b5ff34b 100644 --- a/server/routers/hotels/query.ts +++ b/server/routers/hotels/query.ts @@ -219,6 +219,7 @@ export const hotelQueryRouter = router({ const hotelAttributes = validatedHotelData.data.data.attributes const images = extractHotelImages(hotelAttributes) + const hotelAlerts = hotelAttributes.meta?.specialAlerts || [] const roomCategories = included ? included.filter((item) => item.type === "roomcategories") @@ -262,6 +263,7 @@ export const hotelQueryRouter = router({ roomCategories, activitiesCard: activities?.upcoming_activities_card, facilities, + alerts: hotelAlerts, faq: contentstackData?.faq, } }), From d94c55a46daead7c320c97e40cec02994cca649c Mon Sep 17 00:00:00 2001 From: Erik Tiekstra Date: Thu, 24 Oct 2024 10:24:57 +0200 Subject: [PATCH 03/18] fix: import order fix --- app/[lang]/(live)/@sitewidealert/page.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/[lang]/(live)/@sitewidealert/page.tsx b/app/[lang]/(live)/@sitewidealert/page.tsx index b0bbf8765..be7ae2256 100644 --- a/app/[lang]/(live)/@sitewidealert/page.tsx +++ b/app/[lang]/(live)/@sitewidealert/page.tsx @@ -1,6 +1,7 @@ -import { env } from "@/env/server" import { Suspense } from "react" +import { env } from "@/env/server" + import SitewideAlert, { preload } from "@/components/SitewideAlert" import { setLang } from "@/i18n/serverContext" From 748021cdabcfb2e042ea740e1340c3810f4af16d Mon Sep 17 00:00:00 2001 From: Bianca Widstam Date: Thu, 24 Oct 2024 08:41:26 +0000 Subject: [PATCH 04/18] Merged in feat/SW-673-galleryicon-hotel-lightbox (pull request #734) Feat/SW-673 galleryicon hotel lightbox * feat(SW-673): add galleryChip to trigger lightbox * feat(SW-673): add updated design galleryIcon * feat(SW-673): add first image from hotelContent and heroImages * feat(SW-673): fix import type * feat(SW-673): fix css variables * feat(SW-673): change component to include image that trigger lightbox * feat(SW-673): refactor name to imageGallery Approved-by: Niclas Edenvin --- .../HotelCard/hotelCard.module.css | 13 ++++--- .../HotelReservation/HotelCard/index.tsx | 19 +++++----- .../HotelInfoCard/hotelInfoCard.module.css | 8 ++--- .../SelectRate/HotelInfoCard/index.tsx | 17 +++++---- .../ImageGallery/imageGallery.module.css | 17 +++++++++ .../SelectRate/ImageGallery/index.tsx | 36 +++++++++++++++++++ .../RoomSelection/RoomCard/index.tsx | 29 +++------------ .../RoomCard/roomCard.module.css | 14 -------- server/routers/hotels/output.ts | 16 +++++++++ .../selectRate/imageGallery.ts | 3 ++ types/hotel.ts | 4 ++- 11 files changed, 111 insertions(+), 65 deletions(-) create mode 100644 components/HotelReservation/SelectRate/ImageGallery/imageGallery.module.css create mode 100644 components/HotelReservation/SelectRate/ImageGallery/index.tsx create mode 100644 types/components/hotelReservation/selectRate/imageGallery.ts diff --git a/components/HotelReservation/HotelCard/hotelCard.module.css b/components/HotelReservation/HotelCard/hotelCard.module.css index 0ffa5b150..587feb29a 100644 --- a/components/HotelReservation/HotelCard/hotelCard.module.css +++ b/components/HotelReservation/HotelCard/hotelCard.module.css @@ -14,15 +14,16 @@ .imageContainer { grid-area: image; + position: relative; + height: 100%; + width: 116px; } .tripAdvisor { display: none; } -.image { - height: 100%; - width: 116px; +.imageContainer img { object-fit: cover; } @@ -77,6 +78,8 @@ .imageContainer { position: relative; + min-height: 200px; + width: 518px; } .tripAdvisor { @@ -86,10 +89,6 @@ top: 7px; } - .image { - width: 518px; - } - .hotelInformation { padding-top: var(--Spacing-x2); padding-right: var(--Spacing-x2); diff --git a/components/HotelReservation/HotelCard/index.tsx b/components/HotelReservation/HotelCard/index.tsx index 67ce49f17..9300771e9 100644 --- a/components/HotelReservation/HotelCard/index.tsx +++ b/components/HotelReservation/HotelCard/index.tsx @@ -11,10 +11,11 @@ import Title from "@/components/TempDesignSystem/Text/Title" import { getIntl } from "@/i18n" import ReadMore from "../ReadMore" +import ImageGallery from "../SelectRate/ImageGallery" import styles from "./hotelCard.module.css" -import { HotelCardProps } from "@/types/components/hotelReservation/selectHotel/hotelCardProps" +import type { HotelCardProps } from "@/types/components/hotelReservation/selectHotel/hotelCardProps" export default async function HotelCard({ hotel }: HotelCardProps) { const intl = await getIntl() @@ -27,13 +28,15 @@ export default async function HotelCard({ hotel }: HotelCardProps) { return (
- {hotelData.hotelContent.images.metaData.altText} + {hotelData.gallery && ( + + )}
diff --git a/components/HotelReservation/SelectRate/HotelInfoCard/hotelInfoCard.module.css b/components/HotelReservation/SelectRate/HotelInfoCard/hotelInfoCard.module.css index 1482bf4c9..aacdf0449 100644 --- a/components/HotelReservation/SelectRate/HotelInfoCard/hotelInfoCard.module.css +++ b/components/HotelReservation/SelectRate/HotelInfoCard/hotelInfoCard.module.css @@ -12,10 +12,6 @@ gap: var(--Spacing-x2); } -.image { - border-radius: var(--Corner-radius-Medium); -} - .imageWrapper { position: relative; overflow: hidden; @@ -24,6 +20,10 @@ width: 100%; } +.imageWrapper img { + border-radius: var(--Corner-radius-Medium); +} + .tripAdvisor { display: flex; align-items: center; diff --git a/components/HotelReservation/SelectRate/HotelInfoCard/index.tsx b/components/HotelReservation/SelectRate/HotelInfoCard/index.tsx index 1ec58dd07..120c0385d 100644 --- a/components/HotelReservation/SelectRate/HotelInfoCard/index.tsx +++ b/components/HotelReservation/SelectRate/HotelInfoCard/index.tsx @@ -10,6 +10,7 @@ import Caption from "@/components/TempDesignSystem/Text/Caption" import Title from "@/components/TempDesignSystem/Text/Title" import ReadMore from "../../ReadMore" +import ImageGallery from "../ImageGallery" import styles from "./hotelInfoCard.module.css" @@ -28,12 +29,6 @@ export default function HotelInfoCard({ hotelData }: HotelInfoCardProps) { {hotelAttributes && (
- {hotelAttributes.hotelContent.images.metaData.altText} {hotelAttributes.ratings?.tripAdvisor && (
@@ -42,7 +37,15 @@ export default function HotelInfoCard({ hotelData }: HotelInfoCardProps) {
)} - {/* TODO: gallery icon and image carousel */} + {hotelAttributes.gallery && ( + + )}
diff --git a/components/HotelReservation/SelectRate/ImageGallery/imageGallery.module.css b/components/HotelReservation/SelectRate/ImageGallery/imageGallery.module.css new file mode 100644 index 000000000..5d156f77a --- /dev/null +++ b/components/HotelReservation/SelectRate/ImageGallery/imageGallery.module.css @@ -0,0 +1,17 @@ +.galleryIcon { + position: absolute; + bottom: 16px; + right: 16px; + max-height: 32px; + width: 48px; + background-color: rgba(0, 0, 0, 0.6); + padding: var(--Spacing-x-quarter) var(--Spacing-x-half); + border-radius: var(--Corner-radius-Small); + display: flex; + align-items: center; + gap: var(--Spacing-x-quarter); +} + +.triggerArea { + cursor: pointer; +} diff --git a/components/HotelReservation/SelectRate/ImageGallery/index.tsx b/components/HotelReservation/SelectRate/ImageGallery/index.tsx new file mode 100644 index 000000000..778c2d45e --- /dev/null +++ b/components/HotelReservation/SelectRate/ImageGallery/index.tsx @@ -0,0 +1,36 @@ +import { GalleryIcon } from "@/components/Icons" +import Image from "@/components/Image" +import Lightbox from "@/components/Lightbox" +import Footnote from "@/components/TempDesignSystem/Text/Footnote" + +import styles from "./imageGallery.module.css" + +import type { ImageGalleryProps } from "@/types/components/hotelReservation/selectRate/imageGallery" + +export default function ImageGallery({ images, title }: ImageGalleryProps) { + return ( + ({ + url: image.imageSizes.small, + alt: image.metaData.altText, + title: image.metaData.title, + }))} + dialogTitle={title} + > +
+ {images[0].metaData.altText} +
+ + + {images.length} + +
+
+
+ ) +} diff --git a/components/HotelReservation/SelectRate/RoomSelection/RoomCard/index.tsx b/components/HotelReservation/SelectRate/RoomSelection/RoomCard/index.tsx index 87b0143b5..444968ce1 100644 --- a/components/HotelReservation/SelectRate/RoomSelection/RoomCard/index.tsx +++ b/components/HotelReservation/SelectRate/RoomSelection/RoomCard/index.tsx @@ -5,18 +5,18 @@ import { useIntl } from "react-intl" import { RateDefinition } from "@/server/routers/hotels/output" import FlexibilityOption from "@/components/HotelReservation/SelectRate/RoomSelection/FlexibilityOption" -import { ChevronRightSmallIcon, GalleryIcon } from "@/components/Icons" -import Image from "@/components/Image" -import Lightbox from "@/components/Lightbox" +import { ChevronRightSmallIcon } from "@/components/Icons" import Button from "@/components/TempDesignSystem/Button" import Body from "@/components/TempDesignSystem/Text/Body" import Caption from "@/components/TempDesignSystem/Text/Caption" import Footnote from "@/components/TempDesignSystem/Text/Footnote" import Subtitle from "@/components/TempDesignSystem/Text/Subtitle" +import ImageGallery from "../../ImageGallery" + import styles from "./roomCard.module.css" -import { RoomCardProps } from "@/types/components/hotelReservation/selectRate/roomCard" +import type { RoomCardProps } from "@/types/components/hotelReservation/selectRate/roomCard" export default function RoomCard({ rateDefinitions, @@ -25,7 +25,6 @@ export default function RoomCard({ handleSelectRate, }: RoomCardProps) { const intl = useIntl() - const saveRate = rateDefinitions.find( // TODO: Update string when API has decided (rate) => rate.cancellationRule === "NonCancellable" @@ -153,26 +152,8 @@ export default function RoomCard({ )} {/*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. */} - {mainImage.metaData.altText} {images && ( - ({ - url: image.imageSizes.small, - alt: image.metaData.altText, - title: image.metaData.title, - }))} - dialogTitle={roomConfiguration.roomType} - > -
- - {images.length} -
-
+ )}
)} diff --git a/components/HotelReservation/SelectRate/RoomSelection/RoomCard/roomCard.module.css b/components/HotelReservation/SelectRate/RoomSelection/RoomCard/roomCard.module.css index 25add23b5..ef5d9b8fc 100644 --- a/components/HotelReservation/SelectRate/RoomSelection/RoomCard/roomCard.module.css +++ b/components/HotelReservation/SelectRate/RoomSelection/RoomCard/roomCard.module.css @@ -77,17 +77,3 @@ min-height: 185px; position: relative; } - -.galleryIcon { - position: absolute; - bottom: 16px; - right: 16px; - height: 24px; - background-color: rgba(64, 57, 55, 0.9); - padding: 0 var(--Spacing-x-half); - border-radius: var(--Corner-radius-Small); - cursor: pointer; - display: flex; - align-items: center; - gap: var(--Spacing-x-quarter); -} diff --git a/server/routers/hotels/output.ts b/server/routers/hotels/output.ts index 803ae012f..0f545d673 100644 --- a/server/routers/hotels/output.ts +++ b/server/routers/hotels/output.ts @@ -162,6 +162,21 @@ export const facilitySchema = z.object({ ), }) +export const gallerySchema = z.object({ + heroImages: z.array( + z.object({ + metaData: imageMetaDataSchema, + imageSizes: imageSizesSchema, + }) + ), + smallerImages: z.array( + z.object({ + metaData: imageMetaDataSchema, + imageSizes: imageSizesSchema, + }) + ), +}) + const healthFacilitySchema = z.object({ type: z.string(), content: z.object({ @@ -441,6 +456,7 @@ export const getHotelDataSchema = z.object({ conferencesAndMeetings: facilitySchema.optional(), healthAndWellness: facilitySchema.optional(), restaurantImages: facilitySchema.optional(), + gallery: gallerySchema.optional(), }), relationships: relationshipsSchema, }), diff --git a/types/components/hotelReservation/selectRate/imageGallery.ts b/types/components/hotelReservation/selectRate/imageGallery.ts new file mode 100644 index 000000000..333ff2d94 --- /dev/null +++ b/types/components/hotelReservation/selectRate/imageGallery.ts @@ -0,0 +1,3 @@ +import type { GalleryImages } from "@/types/hotel" + +export type ImageGalleryProps = { images: GalleryImages; title: string } diff --git a/types/hotel.ts b/types/hotel.ts index a60204720..972c6459e 100644 --- a/types/hotel.ts +++ b/types/hotel.ts @@ -2,6 +2,7 @@ import { z } from "zod" import { facilitySchema, + gallerySchema, getHotelDataSchema, parkingSchema, pointOfInterestSchema, @@ -13,7 +14,6 @@ export type HotelData = z.infer export type Hotel = HotelData["data"]["attributes"] export type HotelAddress = HotelData["data"]["attributes"]["address"] export type HotelLocation = HotelData["data"]["attributes"]["location"] - export type Amenities = HotelData["data"]["attributes"]["detailedFacilities"] type HotelRatings = HotelData["data"]["attributes"]["ratings"] @@ -22,6 +22,8 @@ export type HotelTripAdvisor = | undefined export type RoomData = z.infer +export type GallerySchema = z.infer +export type GalleryImages = GallerySchema["heroImages"] export type PointOfInterest = z.output From 8d490e14f2ed757d85b8b9a4f2ec52bd6e1ebb7a Mon Sep 17 00:00:00 2001 From: Niclas Edenvin Date: Thu, 24 Oct 2024 08:49:06 +0000 Subject: [PATCH 05/18] fix(SW-690): use correct naming of search params in booking Approved-by: Bianca Widstam Approved-by: Linus Flood --- .../(standard)/select-rate/page.tsx | 14 +++++------ components/BookingWidget/Client.tsx | 4 ++-- components/DatePicker/index.tsx | 24 +++++++++---------- .../Forms/BookingWidget/FormContent/index.tsx | 2 +- components/Forms/BookingWidget/schema.ts | 4 ++-- .../HotelReservation/HotelCard/index.tsx | 6 ++++- components/TempDesignSystem/Link/index.tsx | 7 +++--- .../hotelReservation/selectRate/selectRate.ts | 6 ++--- 8 files changed, 36 insertions(+), 31 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 532228434..2d80356ac 100644 --- a/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-rate/page.tsx +++ b/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-rate/page.tsx @@ -17,11 +17,11 @@ export default async function SelectRatePage({ }: PageArgs) { setLang(params.lang) - const selecetRoomParams = new URLSearchParams(searchParams) - const selecetRoomParamsObject = - getHotelReservationQueryParams(selecetRoomParams) - const adults = selecetRoomParamsObject.room[0].adults // TODO: Handle multiple rooms - const children = selecetRoomParamsObject.room[0].child.length // TODO: Handle multiple rooms + const selectRoomParams = new URLSearchParams(searchParams) + const selectRoomParamsObject = + getHotelReservationQueryParams(selectRoomParams) + const adults = selectRoomParamsObject.room[0].adults // TODO: Handle multiple rooms + const children = selectRoomParamsObject.room[0].child?.length // TODO: Handle multiple rooms const [hotelData, roomConfigurations, user] = await Promise.all([ serverClient().hotel.hotelData.get({ @@ -33,8 +33,8 @@ export default async function SelectRatePage({ hotelId: parseInt(searchParams.hotel, 10), roomStayStartDate: searchParams.fromDate, roomStayEndDate: searchParams.toDate, - adults: adults, - children: children, + adults, + children, }), getProfileSafely(), ]) diff --git a/components/BookingWidget/Client.tsx b/components/BookingWidget/Client.tsx index eded233f0..68a6a1fc2 100644 --- a/components/BookingWidget/Client.tsx +++ b/components/BookingWidget/Client.tsx @@ -42,8 +42,8 @@ export default function BookingWidgetClient({ date: { // UTC is required to handle requests from far away timezones https://scandichotels.atlassian.net/browse/SWAP-6375 & PET-507 // This is specifically to handle timezones falling in different dates. - from: dt().utc().format("YYYY-MM-DD"), - to: dt().utc().add(1, "day").format("YYYY-MM-DD"), + fromDate: dt().utc().format("YYYY-MM-DD"), + toDate: dt().utc().add(1, "day").format("YYYY-MM-DD"), }, bookingCode: "", redemption: false, diff --git a/components/DatePicker/index.tsx b/components/DatePicker/index.tsx index 503c0c6ac..b07b1a0d8 100644 --- a/components/DatePicker/index.tsx +++ b/components/DatePicker/index.tsx @@ -44,22 +44,22 @@ export default function DatePickerForm({ name = "date" }: DatePickerFormProps) { function handleSelectDate(selected: Date) { if (isSelectingFrom) { setValue(name, { - from: dt(selected).format("YYYY-MM-DD"), - to: undefined, + fromDate: dt(selected).format("YYYY-MM-DD"), + toDate: undefined, }) setIsSelectingFrom(false) } else { - const fromDate = dt(selectedDate.from) + const fromDate = dt(selectedDate.fromDate) const toDate = dt(selected) if (toDate.isAfter(fromDate)) { setValue(name, { - from: selectedDate.from, - to: toDate.format("YYYY-MM-DD"), + fromDate: selectedDate.fromDate, + toDate: toDate.format("YYYY-MM-DD"), }) } else { setValue(name, { - from: toDate.format("YYYY-MM-DD"), - to: selectedDate.from, + fromDate: toDate.format("YYYY-MM-DD"), + toDate: selectedDate.fromDate, }) } setIsSelectingFrom(true) @@ -79,11 +79,11 @@ export default function DatePickerForm({ name = "date" }: DatePickerFormProps) { } }, [setIsOpen]) - const selectedFromDate = dt(selectedDate.from) + const selectedFromDate = dt(selectedDate.fromDate) .locale(lang) .format("ddd D MMM") - const selectedToDate = !!selectedDate.to - ? dt(selectedDate.to).locale(lang).format("ddd D MMM") + const selectedToDate = !!selectedDate.toDate + ? dt(selectedDate.toDate).locale(lang).format("ddd D MMM") : "" return ( @@ -93,8 +93,8 @@ export default function DatePickerForm({ name = "date" }: DatePickerFormProps) { {selectedFromDate} - {selectedToDate} - - + +
diff --git a/components/Forms/BookingWidget/schema.ts b/components/Forms/BookingWidget/schema.ts index cfa3cb03f..aa42b542d 100644 --- a/components/Forms/BookingWidget/schema.ts +++ b/components/Forms/BookingWidget/schema.ts @@ -18,8 +18,8 @@ export const bookingWidgetSchema = z.object({ bookingCode: z.string(), // Update this as required when working with booking codes component date: z.object({ // Update this as required once started working with Date picker in Nights component - from: z.string(), - to: z.string(), + fromDate: z.string(), + toDate: z.string(), }), location: z.string().refine( (value) => { diff --git a/components/HotelReservation/HotelCard/index.tsx b/components/HotelReservation/HotelCard/index.tsx index 9300771e9..2bea7c895 100644 --- a/components/HotelReservation/HotelCard/index.tsx +++ b/components/HotelReservation/HotelCard/index.tsx @@ -105,7 +105,11 @@ export default async function HotelCard({ hotel }: HotelCardProps) { className={styles.button} > {/* TODO: Localize link and also use correct search params */} - + {intl.formatMessage({ id: "See rooms" })} diff --git a/components/TempDesignSystem/Link/index.tsx b/components/TempDesignSystem/Link/index.tsx index 716221b5b..2c46c8b6f 100644 --- a/components/TempDesignSystem/Link/index.tsx +++ b/components/TempDesignSystem/Link/index.tsx @@ -51,9 +51,10 @@ export default function Link({ const router = useRouter() const fullUrl = useMemo(() => { - const search = - keepSearchParams && searchParams.size ? `?${searchParams}` : "" - return `${href}${search}` + if (!keepSearchParams || !searchParams.size) return href + + const delimiter = href.includes("?") ? "&" : "?" + return `${href}${delimiter}${searchParams}` }, [href, searchParams, keepSearchParams]) // TODO: Remove this check (and hook) and only return when current web is deleted diff --git a/types/components/hotelReservation/selectRate/selectRate.ts b/types/components/hotelReservation/selectRate/selectRate.ts index 58aa6fbbe..16b3f5dcf 100644 --- a/types/components/hotelReservation/selectRate/selectRate.ts +++ b/types/components/hotelReservation/selectRate/selectRate.ts @@ -7,9 +7,9 @@ interface Child { interface Room { adults: number - roomtypecode: string - ratecode: string - child: Child[] + roomcode?: string + ratecode?: string + child?: Child[] } export interface SelectRateSearchParams { From 12d4be59d574224389d8f567e294dbb421a727c8 Mon Sep 17 00:00:00 2001 From: Chuma McPhoy Date: Tue, 15 Oct 2024 09:05:20 +0200 Subject: [PATCH 06/18] chore: add a commit to enable pr for testing --- constants/routes/signup.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/constants/routes/signup.ts b/constants/routes/signup.ts index 82a39ee41..9ef09c4a0 100644 --- a/constants/routes/signup.ts +++ b/constants/routes/signup.ts @@ -17,3 +17,11 @@ export const signupVerify: LangRoute = { da: `${signup.da}/bekraeft`, de: `${signup.de}/verifizieren`, } + +export const isSignupPage = (path: string): boolean => { + return Object.values(signup).includes(path) +} + +export const isSignupVerifyPage = (path: string): boolean => { + return Object.values(signupVerify).includes(path) +} From 19049ce22c119c51ab452db4f8e7eef9a21e99cf Mon Sep 17 00:00:00 2001 From: Chuma McPhoy Date: Tue, 22 Oct 2024 10:46:11 +0200 Subject: [PATCH 07/18] fix(SW-360): signup cta ui + name lable formatting --- components/Forms/Register/form.module.css | 4 ++++ components/Forms/Register/index.tsx | 6 ++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/components/Forms/Register/form.module.css b/components/Forms/Register/form.module.css index 612cbc8f8..dc913b792 100644 --- a/components/Forms/Register/form.module.css +++ b/components/Forms/Register/form.module.css @@ -46,4 +46,8 @@ .nameInputs { grid-template-columns: 1fr 1fr; } + + .signUpButton { + width: fit-content; + } } diff --git a/components/Forms/Register/index.tsx b/components/Forms/Register/index.tsx index ed82617b0..a8f3f6524 100644 --- a/components/Forms/Register/index.tsx +++ b/components/Forms/Register/index.tsx @@ -94,12 +94,12 @@ export default function Form({ link, subtitle, title }: RegisterFormProps) {
@@ -171,7 +171,9 @@ export default function Form({ link, subtitle, title }: RegisterFormProps) {
From eaf9c2f5f2231c539700703e0e5940b1aab1e328 Mon Sep 17 00:00:00 2001 From: Chuma McPhoy Date: Thu, 24 Oct 2024 08:46:14 +0200 Subject: [PATCH 13/18] refactor(SW-360): trigger validation on submnission --- components/Forms/Signup/index.tsx | 55 +++++++++++++++++-------------- 1 file changed, 30 insertions(+), 25 deletions(-) diff --git a/components/Forms/Signup/index.tsx b/components/Forms/Signup/index.tsx index d9a273560..39d389e91 100644 --- a/components/Forms/Signup/index.tsx +++ b/components/Forms/Signup/index.tsx @@ -1,7 +1,6 @@ "use client" import { zodResolver } from "@hookform/resolvers/zod" -import { useEffect, useState } from "react" import { FormProvider, useForm } from "react-hook-form" import { useIntl } from "react-intl" @@ -37,15 +36,13 @@ export default function SignupForm({ link, subtitle, title }: SignUpFormProps) { const phoneNumber = intl.formatMessage({ id: "Phone number" }) const zipCode = intl.formatMessage({ id: "Zip code" }) - const [isSubmitAttempted, setIsSubmitAttempted] = useState(false) - const methods = useForm({ defaultValues: { firstName: "", lastName: "", email: "", phoneNumber: "", - dateOfBirth: "", + dateOfBirth: "1995-01-01", address: { countryCode: "", zipCode: "", @@ -59,16 +56,6 @@ export default function SignupForm({ link, subtitle, title }: SignUpFormProps) { reValidateMode: "onChange", }) - // Trigger validation for all fields upon invalid submissions. - useEffect(() => { - if ( - isSubmitAttempted && - (!methods.formState.isValid || !methods.formState.isSubmitting) - ) { - methods.trigger() - } - }, [isSubmitAttempted, methods]) - async function onSubmit(data: SignUpSchema) { try { const result = await registerUser(data) @@ -184,17 +171,35 @@ export default function SignupForm({ link, subtitle, title }: SignUpFormProps) {
- + + {/* + We use this approach to trigger validation for all invalid inputs upon submission. + To handle this programmatically in the future, we would need some major refactoring + of the Input component, which is out of scope for now. + */} + {!methods.formState.isValid ? ( + + ) : ( + + )}
From 62eb5a9bb5dd2a94c86a1f2e4df51c58bac0a57c Mon Sep 17 00:00:00 2001 From: Chuma McPhoy Date: Thu, 24 Oct 2024 08:49:53 +0200 Subject: [PATCH 14/18] fix(SW-360): remove default date --- components/Forms/Signup/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/Forms/Signup/index.tsx b/components/Forms/Signup/index.tsx index 39d389e91..a64569f80 100644 --- a/components/Forms/Signup/index.tsx +++ b/components/Forms/Signup/index.tsx @@ -42,7 +42,7 @@ export default function SignupForm({ link, subtitle, title }: SignUpFormProps) { lastName: "", email: "", phoneNumber: "", - dateOfBirth: "1995-01-01", + dateOfBirth: "", address: { countryCode: "", zipCode: "", From e25a974426cbb9a4befb85468a6fe584ae9fb7d3 Mon Sep 17 00:00:00 2001 From: Chuma McPhoy Date: Thu, 24 Oct 2024 09:19:14 +0200 Subject: [PATCH 15/18] fix(SW-360): more context to how we handle triggers --- components/Forms/Signup/index.tsx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/components/Forms/Signup/index.tsx b/components/Forms/Signup/index.tsx index a64569f80..9f061f614 100644 --- a/components/Forms/Signup/index.tsx +++ b/components/Forms/Signup/index.tsx @@ -173,9 +173,10 @@ export default function SignupForm({ link, subtitle, title }: SignUpFormProps) { {/* - We use this approach to trigger validation for all invalid inputs upon submission. - To handle this programmatically in the future, we would need some major refactoring - of the Input component, which is out of scope for now. + This is a manual validation trigger workaround: + - The Controller component (which Input uses) doesn't re-render on submit, + which prevents automatic error display. + - Future fix requires Input component refactoring (out of scope for now). */} {!methods.formState.isValid ? (