From cbf9e7b7c205b2c998cbfe15368df395f5d45ffb Mon Sep 17 00:00:00 2001 From: Anton Gunnarsson Date: Mon, 2 Jun 2025 11:11:50 +0000 Subject: [PATCH] Merged in chore/next15 (pull request #1999) chore (SW-834): Upgrade to Next 15 * wip: apply codemod and upgrade swc plugin * wip: design-system to react 19, fix issues from async (search)params * wip: fix remaining issues from codemod serverClient is now async because context use headers() getLang is now async because it uses headers() * Minor cleanup * Inline react-material-symbols package Package is seemingly not maintained any more and doesn't support React 19. This copies the package source into `design-system`, makes the necessary changes for 19 and export it for others to use. * Fix missing awaits * Disable modal exit animations Enabling modal exit animations via isExiting prop is causing modals to be rendered in "hidden" state and never unmount. Seems to be an issue with react-aria-components, see https://github.com/adobe/react-spectrum/issues/7563. Can probably be fixed by rewriting to a solution similar to https://react-spectrum.adobe.com/react-aria/examples/framer-modal-sheet.html * Remove unstable cache implementation and use in memory cache locally * Fix ref type in SelectFilter * Use cloneElement to add key prop to element Approved-by: Linus Flood --- .../[lang]/(live)/(protected)/logout/route.ts | 5 +- .../(protected)/my-pages/[...path]/page.tsx | 3 +- .../my-pages/profile/edit/page.tsx | 3 +- .../(protected)/my-pages/profile/page.tsx | 3 +- .../(public)/(contentTypes)/@preview/page.tsx | 9 +- .../content_page/[uid]/page.tsx | 5 +- .../destination_city_page/[uid]/page.tsx | 7 +- .../(contentTypes)/hotel_page/[uid]/page.tsx | 7 +- .../(contentTypes)/start_page/[uid]/page.tsx | 7 +- .../booking-confirmation/page.tsx | 17 +- .../gla-payment-callback/page.tsx | 28 +- .../payment-callback/page.tsx | 26 +- .../alternative-hotels/map/page.tsx | 17 +- .../(standard)/alternative-hotels/page.tsx | 23 +- .../(standard)/details/page.tsx | 14 +- .../hotelreservation/(standard)/page.tsx | 6 +- .../(standard)/select-hotel/map/page.tsx | 13 +- .../(standard)/select-hotel/page.tsx | 20 +- .../(standard)/select-rate/page.tsx | 11 +- .../(public)/hotelreservation/layout.tsx | 3 +- .../hotelreservation/my-stay/page.tsx | 12 +- .../hotelreservation/my-stay/tracking.tsx | 4 +- .../app/[lang]/(live)/(public)/login/route.ts | 7 +- .../(live)/(public)/verifymagiclink/route.ts | 5 +- .../destination_city_page/[uid]/page.tsx | 5 +- .../(contentTypes)/hotel_page/[uid]/page.tsx | 9 +- .../@bookingwidget/hotelreservation/page.tsx | 8 +- .../app/[lang]/(live)/@bookingwidget/page.tsx | 7 +- apps/scandic-web/app/[lang]/(live)/error.tsx | 2 +- apps/scandic-web/app/[lang]/(live)/layout.tsx | 23 +- .../(live)/middleware-error/[status]/page.tsx | 10 +- .../current-content-page/page.tsx | 7 +- .../app/[lang]/(live-current)/layout.tsx | 19 +- .../hotelreservation/my-stay/receipt/page.tsx | 5 +- .../app/[lang]/(no-layout)/layout.tsx | 11 +- .../sas-x-scandic/callback/route.ts | 8 +- .../(protected)/sas-x-scandic/error/page.tsx | 7 +- .../(protected)/sas-x-scandic/layout.tsx | 11 +- .../(protected)/sas-x-scandic/link/page.tsx | 5 +- .../sas-x-scandic/link/success/page.tsx | 5 +- .../(protected)/sas-x-scandic/login/page.tsx | 7 +- .../(protected)/sas-x-scandic/otp/page.tsx | 27 +- .../sas-x-scandic/transfer/success/page.tsx | 7 +- .../sas-x-scandic/unlink/success/page.tsx | 5 +- .../app/[lang]/(partner)/layout.tsx | 11 +- .../webview/[contentType]/[uid]/page.tsx | 11 +- .../webview/hotelreservation/layout.tsx | 3 +- .../webview/hotelreservation/my-stay/page.tsx | 12 +- .../hotelreservation/my-stay/tracking.tsx | 4 +- .../scandic-web/app/[lang]/webview/layout.tsx | 11 +- apps/scandic-web/app/api/hoteldata/route.ts | 3 +- .../api/web/add-card-callback/[lang]/route.ts | 6 +- .../app/api/web/revalidate/hotel/route.ts | 2 +- .../api/web/revalidate/loyaltyConfig/route.ts | 2 +- .../app/api/web/revalidate/manually/route.ts | 2 +- .../app/api/web/revalidate/route.ts | 2 +- .../app/sitemap/[sitemapId]/route.ts | 5 +- .../components/Auth/TokenRefresher.tsx | 2 +- .../DynamicContent/LoyaltyLevels/index.tsx | 3 +- .../Overview/Stats/ExpiringPoints/index.tsx | 3 +- .../Overview/Stats/Points/index.tsx | 3 +- .../DynamicContent/OverviewTable/index.tsx | 3 +- .../Rewards/NextLevel/index.tsx | 3 +- .../SAS/TransferPoints/index.tsx | 2 +- .../SASTierComparison/index.tsx | 3 +- .../DynamicContent/Stays/Previous/index.tsx | 3 +- .../Soonest/EmptyUpcomingStays/index.tsx | 2 +- .../DynamicContent/Stays/Soonest/index.tsx | 3 +- .../Upcoming/EmptyUpcomingStays/index.tsx | 2 +- .../DynamicContent/Stays/Upcoming/index.tsx | 3 +- .../components/Breadcrumbs/index.tsx | 3 +- .../ContentType/HotelMapPage/index.tsx | 2 +- .../IntroSection/TripAdvisorLink/index.tsx | 2 +- .../ContactInformation/index.tsx | 2 +- .../HotelPage/SidePeeks/Amenities/index.tsx | 4 +- .../MeetingsAndConferences/index.tsx | 2 +- .../RestaurantBar/RestaurantBarItem/index.tsx | 2 +- .../HotelPage/SidePeeks/Room/index.tsx | 2 +- .../SidePeeks/WellnessAndExercise/index.tsx | 4 +- .../components/ContentType/HotelPage/data.tsx | 2 + .../ContentType/HotelPage/index.tsx | 2 +- .../HotelSubpage/MeetingsSubpage/index.tsx | 2 +- .../ContentType/HotelSubpage/index.tsx | 2 +- .../ContentType/LoyaltyPage/index.tsx | 3 +- .../StaticPages/CollectionPage/index.tsx | 4 +- .../StaticPages/ContentPage/index.tsx | 3 +- .../components/Current/Footer/index.tsx | 3 +- .../Current/Header/TopMenu/index.tsx | 6 +- .../components/Current/Header/index.tsx | 4 +- .../components/Current/LangPopup/index.tsx | 7 +- .../components/Current/NotFound/index.tsx | 4 +- .../components/DeprecatedJsonToHtml/utils.tsx | 8 +- .../EmployeeBenefits/AuthCard/index.tsx | 2 +- .../EmployeeBenefits/CallToActions/index.tsx | 2 +- .../components/Footer/Details/index.tsx | 4 +- apps/scandic-web/components/Footer/index.tsx | 4 +- .../components/Header/TopMenu/index.tsx | 2 +- apps/scandic-web/components/Header/index.tsx | 4 +- .../MyStay/Receipt/Footer/index.tsx | 2 +- .../HotelReservation/MyStay/Receipt/index.tsx | 3 +- .../MyStay/Receipt/tracking.tsx | 4 +- .../SelectHotel/NoAvailabilityAlert.tsx | 2 +- .../SelectHotelMapContainer.tsx | 14 +- .../HotelReservation/SelectHotel/helpers.ts | 20 +- .../HotelReservation/SelectHotel/index.tsx | 16 +- .../RoomsHeader/RoomPackageFilter/utils.ts | 2 +- .../HotelReservation/SelectRate/index.tsx | 20 +- .../HotelReservation/utils/index.tsx | 2 + .../components/Icons/IconByIconName.tsx | 2 + .../components/JsonToHtml/utils.tsx | 8 +- apps/scandic-web/components/Modal/index.tsx | 6 +- apps/scandic-web/components/Modal/modal.ts | 2 +- .../MyPages/Profile/CreditCards/index.tsx | 3 +- .../components/MyPages/Profile/index.tsx | 2 +- .../components/MyPages/Sidebar/index.tsx | 8 +- .../components/MyPages/Surprises/index.tsx | 3 +- .../components/ProtectedLayout.tsx | 7 +- .../SidePeeks/RoomSidePeek/bedIcon.ts | 2 +- .../SidePeeks/RoomSidePeek/facilityIcon.tsx | 4 +- .../JoinLoyalty/Contact/ContactRow/index.tsx | 3 +- .../TempDesignSystem/Alert/utils.tsx | 2 + .../TempDesignSystem/Form/RadioCard/types.ts | 2 + .../TempDesignSystem/Select/select.ts | 2 +- .../Webviews/AccountPage/Blocks.tsx | 90 +- .../components/Webviews/AccountPage/index.tsx | 7 +- .../Webviews/LinkToOverview/index.tsx | 5 +- .../Webviews/LoyaltyPage/Blocks.tsx | 118 +- .../components/Webviews/LoyaltyPage/index.tsx | 3 +- apps/scandic-web/constants/booking.ts | 2 + apps/scandic-web/hooks/useClickOutside.ts | 2 +- apps/scandic-web/hooks/useScrollToTop.ts | 2 +- apps/scandic-web/hooks/useStickyPosition.ts | 2 +- apps/scandic-web/i18n/index.ts | 2 +- apps/scandic-web/i18n/serverContext.ts | 5 +- .../lib/trpc/memoizedRequests/index.ts | 128 +- apps/scandic-web/lib/trpc/server.ts | 5 +- apps/scandic-web/middlewares/authRequired.ts | 2 +- apps/scandic-web/next.config.js | 3 +- apps/scandic-web/package.json | 21 +- .../providers/AddAncillaryProvider.tsx | 2 +- .../providers/BookingConfirmationProvider.tsx | 2 +- .../DestinationDataProvider/index.tsx | 2 +- .../providers/EnterDetailsProvider.tsx | 2 +- apps/scandic-web/providers/MyStay.tsx | 2 +- apps/scandic-web/server/context.ts | 20 +- .../routers/partners/sas/getSasToken.ts | 4 +- .../routers/partners/sas/linkAccount.ts | 4 +- .../routers/partners/sas/otp/getOTPState.ts | 5 +- .../partners/sas/otp/request/requestOtp.ts | 7 +- .../partners/sas/otp/verify/verifyOtp.ts | 6 +- .../partners/sas/performLevelUpgrade.ts | 2 +- .../routers/partners/sas/transferPoints.ts | 2 +- .../routers/partners/sas/unlinkAccount.ts | 4 +- .../MemoryCache/UnstableCache/cacheOrGet.ts | 43 - .../MemoryCache/UnstableCache/deleteKey.ts | 5 - .../MemoryCache/UnstableCache/get.ts | 14 - .../MemoryCache/UnstableCache/index.ts | 10 - .../MemoryCache/UnstableCache/set.ts | 15 - .../MemoryCache/createMemoryCache.ts | 12 +- .../services/warmup/warmupHotelData.ts | 3 +- apps/scandic-web/stores/sticky-position.ts | 6 +- .../types/components/bookingWidget/index.ts | 8 +- .../hotelPage/map/interactiveMap.ts | 2 +- .../hotelReservation/selectHotel/map.ts | 5 +- .../selectHotel/selectHotel.ts | 12 +- .../types/components/overviewTable.ts | 2 + apps/scandic-web/types/params.ts | 4 +- apps/scandic-web/types/rte/node.ts | 2 + .../types/transitionTypes/rte/node.ts | 2 + .../scandic-web/utils/appendSlugToPathname.ts | 7 +- apps/scandic-web/utils/generateMetadata.ts | 23 +- apps/scandic-web/utils/hotelSearchDetails.ts | 12 +- apps/scandic-web/utils/isLoggedInUser.ts | 4 +- apps/scandic-web/utils/url.ts | 2 +- apps/scandic-web/utils/webviews.ts | 11 +- package.json | 4 +- .../ChipButton/ChipButton.stories.tsx | 2 - .../Icons/MaterialIcon/MaterialIcon.tsx | 5 +- .../MaterialSymbol/MaterialSymbol.tsx | 101 + .../MaterialIcon/MaterialSymbol/consts.ts | 3463 +++++++++++++++++ .../MaterialIcon/MaterialSymbol/index.tsx | 1 + .../MaterialIcon/MaterialSymbol/types.ts | 55 + .../components/Loading/Loading.stories.tsx | 2 - .../lib/components/RateCard/Modal/modal.ts | 2 +- .../lib/components/Select/Select.stories.tsx | 2 - .../lib/components/Select/SelectFilter.tsx | 2 +- packages/design-system/package.json | 18 +- yarn.lock | 800 ++-- 188 files changed, 4883 insertions(+), 1023 deletions(-) delete mode 100644 apps/scandic-web/services/dataCache/MemoryCache/UnstableCache/cacheOrGet.ts delete mode 100644 apps/scandic-web/services/dataCache/MemoryCache/UnstableCache/deleteKey.ts delete mode 100644 apps/scandic-web/services/dataCache/MemoryCache/UnstableCache/get.ts delete mode 100644 apps/scandic-web/services/dataCache/MemoryCache/UnstableCache/index.ts delete mode 100644 apps/scandic-web/services/dataCache/MemoryCache/UnstableCache/set.ts create mode 100644 packages/design-system/lib/components/Icons/MaterialIcon/MaterialSymbol/MaterialSymbol.tsx create mode 100644 packages/design-system/lib/components/Icons/MaterialIcon/MaterialSymbol/consts.ts create mode 100644 packages/design-system/lib/components/Icons/MaterialIcon/MaterialSymbol/index.tsx create mode 100644 packages/design-system/lib/components/Icons/MaterialIcon/MaterialSymbol/types.ts diff --git a/apps/scandic-web/app/[lang]/(live)/(protected)/logout/route.ts b/apps/scandic-web/app/[lang]/(live)/(protected)/logout/route.ts index 3d9038b28..8adfe8d98 100644 --- a/apps/scandic-web/app/[lang]/(live)/(protected)/logout/route.ts +++ b/apps/scandic-web/app/[lang]/(live)/(protected)/logout/route.ts @@ -10,7 +10,7 @@ import { signOut } from "@/auth" export async function GET( request: NextRequest, - context: { params: { lang: Lang } } + context: { params: Promise<{ lang: Lang }> } ) { const publicURL = getPublicURL(request) @@ -49,7 +49,8 @@ export async function GET( try { // Initiate the seamless logout flow let redirectUrlValue - switch (context.params.lang) { + const params = await context.params + switch (params.lang) { case Lang.da: redirectUrlValue = env.SEAMLESS_LOGOUT_DA break diff --git a/apps/scandic-web/app/[lang]/(live)/(protected)/my-pages/[...path]/page.tsx b/apps/scandic-web/app/[lang]/(live)/(protected)/my-pages/[...path]/page.tsx index 82ca57deb..e51798f28 100644 --- a/apps/scandic-web/app/[lang]/(live)/(protected)/my-pages/[...path]/page.tsx +++ b/apps/scandic-web/app/[lang]/(live)/(protected)/my-pages/[...path]/page.tsx @@ -14,7 +14,8 @@ export { generateMetadata } from "@/utils/generateMetadata" export default async function MyPages({}: PageArgs< LangParams & { path: string[] } >) { - const accountPageRes = await serverClient().contentstack.accountPage.get() + const caller = await serverClient() + const accountPageRes = await caller.contentstack.accountPage.get() const intl = await getIntl() if (!accountPageRes) { diff --git a/apps/scandic-web/app/[lang]/(live)/(protected)/my-pages/profile/edit/page.tsx b/apps/scandic-web/app/[lang]/(live)/(protected)/my-pages/profile/edit/page.tsx index 881bc602e..a78449883 100644 --- a/apps/scandic-web/app/[lang]/(live)/(protected)/my-pages/profile/edit/page.tsx +++ b/apps/scandic-web/app/[lang]/(live)/(protected)/my-pages/profile/edit/page.tsx @@ -7,7 +7,8 @@ import TrackingSDK from "@/components/TrackingSDK" import styles from "./page.module.css" export default async function EditProfileSlot() { - const accountPage = await serverClient().contentstack.accountPage.get() + const caller = await serverClient() + const accountPage = await caller.contentstack.accountPage.get() const user = await getProfile() if (!user || "error" in user) { diff --git a/apps/scandic-web/app/[lang]/(live)/(protected)/my-pages/profile/page.tsx b/apps/scandic-web/app/[lang]/(live)/(protected)/my-pages/profile/page.tsx index 7b4e4e67e..af1d431db 100644 --- a/apps/scandic-web/app/[lang]/(live)/(protected)/my-pages/profile/page.tsx +++ b/apps/scandic-web/app/[lang]/(live)/(protected)/my-pages/profile/page.tsx @@ -8,7 +8,8 @@ import type { LangParams, PageArgs } from "@/types/params" export { generateMetadata } from "@/utils/generateMetadata" export default async function ProfilePage({}: PageArgs) { - const accountPage = await serverClient().contentstack.accountPage.get() + const caller = await serverClient() + const accountPage = await caller.contentstack.accountPage.get() return ( <> diff --git a/apps/scandic-web/app/[lang]/(live)/(public)/(contentTypes)/@preview/page.tsx b/apps/scandic-web/app/[lang]/(live)/(public)/(contentTypes)/@preview/page.tsx index 3c6e14e9e..fd52de064 100644 --- a/apps/scandic-web/app/[lang]/(live)/(public)/(contentTypes)/@preview/page.tsx +++ b/apps/scandic-web/app/[lang]/(live)/(public)/(contentTypes)/@preview/page.tsx @@ -4,10 +4,11 @@ import InitLivePreview from "@/components/LivePreview" import type { PageArgs, UIDParams } from "@/types/params" -export default function PreviewPage({ - searchParams, - params, -}: PageArgs) { +export default async function PreviewPage( + props: PageArgs +) { + const params = await props.params + const searchParams = await props.searchParams const shouldInitializePreview = searchParams.isPreview === "true" if (searchParams.live_preview) { diff --git a/apps/scandic-web/app/[lang]/(live)/(public)/(contentTypes)/content_page/[uid]/page.tsx b/apps/scandic-web/app/[lang]/(live)/(public)/(contentTypes)/content_page/[uid]/page.tsx index 88fc958f7..52d5af945 100644 --- a/apps/scandic-web/app/[lang]/(live)/(public)/(contentTypes)/content_page/[uid]/page.tsx +++ b/apps/scandic-web/app/[lang]/(live)/(public)/(contentTypes)/content_page/[uid]/page.tsx @@ -12,8 +12,9 @@ import { isLoggedInUser } from "@/utils/isLoggedInUser" export { generateMetadata } from "@/utils/generateMetadata" export default async function ContentPagePage() { - const lang = getLang() - const pathname = headers().get("x-pathname") || "" + const lang = await getLang() + const headersList = await headers() + const pathname = headersList.get("x-pathname") || "" const isSignupRoute = isSignupPage(pathname) if (isSignupRoute) { diff --git a/apps/scandic-web/app/[lang]/(live)/(public)/(contentTypes)/destination_city_page/[uid]/page.tsx b/apps/scandic-web/app/[lang]/(live)/(public)/(contentTypes)/destination_city_page/[uid]/page.tsx index 6eb9da134..2689807ec 100644 --- a/apps/scandic-web/app/[lang]/(live)/(public)/(contentTypes)/destination_city_page/[uid]/page.tsx +++ b/apps/scandic-web/app/[lang]/(live)/(public)/(contentTypes)/destination_city_page/[uid]/page.tsx @@ -10,9 +10,10 @@ import type { PageArgs } from "@/types/params" export { generateMetadata } from "@/utils/generateMetadata" -export default function DestinationCityPagePage({ - searchParams, -}: PageArgs<{}, { view?: "map" }>) { +export default async function DestinationCityPagePage( + props: PageArgs<{}, { view?: "map" }> +) { + const searchParams = await props.searchParams if (env.NEW_SITE_LIVE_STATUS === "NOT_LIVE") { return notFound() } diff --git a/apps/scandic-web/app/[lang]/(live)/(public)/(contentTypes)/hotel_page/[uid]/page.tsx b/apps/scandic-web/app/[lang]/(live)/(public)/(contentTypes)/hotel_page/[uid]/page.tsx index 5ef1f9dc6..569b66961 100644 --- a/apps/scandic-web/app/[lang]/(live)/(public)/(contentTypes)/hotel_page/[uid]/page.tsx +++ b/apps/scandic-web/app/[lang]/(live)/(public)/(contentTypes)/hotel_page/[uid]/page.tsx @@ -11,9 +11,10 @@ import type { PageArgs } from "@/types/params" export { generateMetadata } from "@/utils/generateMetadata" -export default async function HotelPagePage({ - searchParams, -}: PageArgs<{}, { subpage?: string; view?: "map" }>) { +export default async function HotelPagePage( + props: PageArgs<{}, { subpage?: string; view?: "map" }> +) { + const searchParams = await props.searchParams if (env.NEW_SITE_LIVE_STATUS === "NOT_LIVE") { return notFound() } diff --git a/apps/scandic-web/app/[lang]/(live)/(public)/(contentTypes)/start_page/[uid]/page.tsx b/apps/scandic-web/app/[lang]/(live)/(public)/(contentTypes)/start_page/[uid]/page.tsx index 987a47ae9..b8496a7bb 100644 --- a/apps/scandic-web/app/[lang]/(live)/(public)/(contentTypes)/start_page/[uid]/page.tsx +++ b/apps/scandic-web/app/[lang]/(live)/(public)/(contentTypes)/start_page/[uid]/page.tsx @@ -9,9 +9,10 @@ import type { PageArgs } from "@/types/params" export { generateMetadata } from "@/utils/generateMetadata" -export default function StartPagePage({ - searchParams, -}: PageArgs<{}, BookingWidgetSearchData>) { +export default async function StartPagePage( + props: PageArgs<{}, BookingWidgetSearchData> +) { + const searchParams = await props.searchParams if (env.NEW_SITE_LIVE_STATUS === "NOT_LIVE") { return notFound() } diff --git a/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(confirmation)/booking-confirmation/page.tsx b/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(confirmation)/booking-confirmation/page.tsx index 743c398f6..51b60cacc 100644 --- a/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(confirmation)/booking-confirmation/page.tsx +++ b/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(confirmation)/booking-confirmation/page.tsx @@ -9,22 +9,19 @@ import { decrypt } from "@/utils/encryption" import type { LangParams, PageArgs } from "@/types/params" -export default async function BookingConfirmationPage({ - params, - searchParams, -}: PageArgs< - LangParams, - { - RefId?: string - } ->) { +export default async function BookingConfirmationPage( + props: PageArgs +) { + const searchParams = await props.searchParams + const params = await props.params const refId = searchParams.RefId if (!refId) { notFound() } - const sig = cookies().get("bcsig")?.value + const cookieStore = await cookies() + const sig = cookieStore.get("bcsig")?.value if (!sig) { redirect(`/${params.lang}`) diff --git a/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(payment-callback)/gla-payment-callback/page.tsx b/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(payment-callback)/gla-payment-callback/page.tsx index 12e48a763..48fc6d6f1 100644 --- a/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(payment-callback)/gla-payment-callback/page.tsx +++ b/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(payment-callback)/gla-payment-callback/page.tsx @@ -13,18 +13,19 @@ import LoadingSpinner from "@/components/LoadingSpinner" import type { LangParams, PageArgs } from "@/types/params" -export default async function GuaranteePaymentCallbackPage({ - params, - searchParams, -}: PageArgs< - LangParams, - { - status?: PaymentCallbackStatusEnum - RefId?: string - confirmationNumber?: string - ancillary?: string - } ->) { +export default async function GuaranteePaymentCallbackPage( + props: PageArgs< + LangParams, + { + status?: PaymentCallbackStatusEnum + RefId?: string + confirmationNumber?: string + ancillary?: string + } + > +) { + const searchParams = await props.searchParams + const params = await props.params console.log(`[gla-payment-callback] callback started`) const lang = params.lang const status = searchParams.status @@ -57,7 +58,8 @@ export default async function GuaranteePaymentCallbackPage({ if (refId) { try { - const bookingStatus = await serverClient().booking.status({ + const caller = await serverClient() + const bookingStatus = await caller.booking.status({ refId, }) diff --git a/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(payment-callback)/payment-callback/page.tsx b/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(payment-callback)/payment-callback/page.tsx index f7d9b7b31..32f596254 100644 --- a/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(payment-callback)/payment-callback/page.tsx +++ b/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(payment-callback)/payment-callback/page.tsx @@ -20,17 +20,18 @@ import { isValidSession } from "@/utils/session" import type { LangParams, PageArgs } from "@/types/params" -export default async function PaymentCallbackPage({ - params, - searchParams, -}: PageArgs< - LangParams, - { - status?: PaymentCallbackStatusEnum - confirmationNumber?: string - hotel?: string - } ->) { +export default async function PaymentCallbackPage( + props: PageArgs< + LangParams, + { + status?: PaymentCallbackStatusEnum + confirmationNumber?: string + hotel?: string + } + > +) { + const searchParams = await props.searchParams + const params = await props.params console.log(`[payment-callback] callback started`) const lang = params.lang const status = searchParams.status @@ -87,7 +88,8 @@ export default async function PaymentCallbackPage({ if (refId) { try { - const bookingStatus = await serverClient().booking.status({ + const caller = await serverClient() + const bookingStatus = await caller.booking.status({ refId, }) diff --git a/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/alternative-hotels/map/page.tsx b/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/alternative-hotels/map/page.tsx index 0c0b61f56..22bd28fd2 100644 --- a/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/alternative-hotels/map/page.tsx +++ b/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/alternative-hotels/map/page.tsx @@ -3,15 +3,21 @@ import { Suspense } from "react" import { SelectHotelMapContainer } from "@/components/HotelReservation/SelectHotel/SelectHotelMap/SelectHotelMapContainer" import { SelectHotelMapContainerSkeleton } from "@/components/HotelReservation/SelectHotel/SelectHotelMap/SelectHotelMapContainerSkeleton" import { MapContainer } from "@/components/MapContainer" +import { convertSearchParamsToObj } from "@/utils/url" import styles from "./page.module.css" import type { AlternativeHotelsSearchParams } from "@/types/components/hotelReservation/selectHotel/selectHotelSearchParams" import type { LangParams, PageArgs } from "@/types/params" -export default async function SelectHotelMapPage({ - searchParams, -}: PageArgs) { +export default async function SelectHotelMapPage( + props: PageArgs +) { + const searchParams = await props.searchParams + + const booking = + convertSearchParamsToObj(searchParams) + return (
@@ -19,10 +25,7 @@ export default async function SelectHotelMapPage({ key={searchParams.hotel} fallback={} > - +
diff --git a/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/alternative-hotels/page.tsx b/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/alternative-hotels/page.tsx index 8f416be53..38d210df6 100644 --- a/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/alternative-hotels/page.tsx +++ b/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/alternative-hotels/page.tsx @@ -12,21 +12,26 @@ import { getHotels } from "@/components/HotelReservation/SelectHotel/helpers" import { getTracking } from "@/components/HotelReservation/SelectHotel/tracking" import TrackingSDK from "@/components/TrackingSDK" import { getIntl } from "@/i18n" -import { setLang } from "@/i18n/serverContext" import { getHotelSearchDetails } from "@/utils/hotelSearchDetails" +import { convertSearchParamsToObj } from "@/utils/url" import type { AlternativeHotelsSearchParams, SelectHotelSearchParams, } from "@/types/components/hotelReservation/selectHotel/selectHotelSearchParams" +import { SelectRateSearchParams } from "@/types/components/hotelReservation/selectRate/selectRate" import type { LangParams, PageArgs } from "@/types/params" -export default async function AlternativeHotelsPage({ - params, - searchParams, -}: PageArgs) { - setLang(params.lang) - const searchDetails = await getHotelSearchDetails({ searchParams }, true) +export default async function AlternativeHotelsPage( + props: PageArgs +) { + const searchParams = await props.searchParams + const params = await props.params + + const booking = + convertSearchParamsToObj(searchParams) + + const searchDetails = await getHotelSearchDetails(booking, true) if (!searchDetails || !searchDetails.hotel || !searchDetails.city) { return notFound() @@ -44,7 +49,7 @@ export default async function AlternativeHotelsPage({ } = searchDetails if (bookingCode && FamilyAndFriendsCodes.includes(bookingCode)) { - const cookieStore = cookies() + const cookieStore = await cookies() const isInvalidFNF = cookieStore.get("sc")?.value !== "1" if (isInvalidFNF) { @@ -55,7 +60,7 @@ export default async function AlternativeHotelsPage({ // TODO: This needs to be refactored into its // own functions const hotels = await getHotels( - selectHotelParams as SelectHotelSearchParams, + selectHotelParams, isAlternativeFor, bookingCode, city, diff --git a/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/details/page.tsx b/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/details/page.tsx index 506c71d28..23f5bbc64 100644 --- a/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/details/page.tsx +++ b/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/details/page.tsx @@ -27,10 +27,14 @@ import styles from "./page.module.css" import type { SelectRateSearchParams } from "@/types/components/hotelReservation/selectRate/selectRate" import type { LangParams, PageArgs } from "@/types/params" -export default async function DetailsPage({ - params: { lang }, - searchParams, -}: PageArgs) { +export default async function DetailsPage( + props: PageArgs +) { + const searchParams = await props.searchParams + const params = await props.params + + const { lang } = params + const selectRoomParams = new URLSearchParams(searchParams) const { errorCode, ...booking } = @@ -44,7 +48,7 @@ export default async function DetailsPage({ booking.bookingCode && FamilyAndFriendsCodes.includes(booking.bookingCode) ) { - const cookieStore = cookies() + const cookieStore = await cookies() const isInValidFNF = cookieStore.get("sc")?.value !== "1" if (isInValidFNF) { diff --git a/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/page.tsx b/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/page.tsx index ea2c9305b..0ac06cd77 100644 --- a/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/page.tsx +++ b/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/page.tsx @@ -8,7 +8,11 @@ import { } from "@/types/components/tracking" import type { LangParams, PageArgs } from "@/types/params" -export default function HotelReservationPage({ params }: PageArgs) { +export default async function HotelReservationPage( + props: PageArgs +) { + const params = await props.params + const pageTrackingData: TrackingSDKPageData = { pageId: "hotelreservation", domainLanguage: params.lang, diff --git a/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-hotel/map/page.tsx b/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-hotel/map/page.tsx index 536438828..e5908f347 100644 --- a/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-hotel/map/page.tsx +++ b/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-hotel/map/page.tsx @@ -4,17 +4,22 @@ import { Suspense } from "react" import { SelectHotelMapContainer } from "@/components/HotelReservation/SelectHotel/SelectHotelMap/SelectHotelMapContainer" import { SelectHotelMapContainerSkeleton } from "@/components/HotelReservation/SelectHotel/SelectHotelMap/SelectHotelMapContainerSkeleton" import { MapContainer } from "@/components/MapContainer" +import { convertSearchParamsToObj } from "@/utils/url" import styles from "./page.module.css" import type { SelectHotelSearchParams } from "@/types/components/hotelReservation/selectHotel/selectHotelSearchParams" import type { LangParams, PageArgs } from "@/types/params" -export default async function SelectHotelMapPage({ - searchParams, -}: PageArgs) { +export default async function SelectHotelMapPage( + props: PageArgs +) { + const searchParams = await props.searchParams const suspenseKey = stringify(searchParams) + const booking = + convertSearchParamsToObj(searchParams) + return (
@@ -22,7 +27,7 @@ export default async function SelectHotelMapPage({ key={suspenseKey} fallback={} > - +
diff --git a/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-hotel/page.tsx b/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-hotel/page.tsx index ad5d55f7c..e564c1dc8 100644 --- a/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-hotel/page.tsx +++ b/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-hotel/page.tsx @@ -11,18 +11,22 @@ import SelectHotel from "@/components/HotelReservation/SelectHotel" import { getHotels } from "@/components/HotelReservation/SelectHotel/helpers" import { getTracking } from "@/components/HotelReservation/SelectHotel/tracking" import TrackingSDK from "@/components/TrackingSDK" -import { setLang } from "@/i18n/serverContext" import { getHotelSearchDetails } from "@/utils/hotelSearchDetails" +import { convertSearchParamsToObj } from "@/utils/url" import type { SelectHotelSearchParams } from "@/types/components/hotelReservation/selectHotel/selectHotelSearchParams" import type { LangParams, PageArgs } from "@/types/params" -export default async function SelectHotelPage({ - params, - searchParams, -}: PageArgs) { - setLang(params.lang) - const searchDetails = await getHotelSearchDetails({ searchParams }) +export default async function SelectHotelPage( + props: PageArgs +) { + const searchParams = await props.searchParams + const params = await props.params + + const booking = + convertSearchParamsToObj(searchParams) + + const searchDetails = await getHotelSearchDetails(booking) if (!searchDetails || !searchDetails.city) return notFound() @@ -37,7 +41,7 @@ export default async function SelectHotelPage({ } = searchDetails if (bookingCode && FamilyAndFriendsCodes.includes(bookingCode)) { - const cookieStore = cookies() + const cookieStore = await cookies() const isInvalidFNF = cookieStore.get("sc")?.value !== "1" if (isInvalidFNF) { diff --git a/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-rate/page.tsx b/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-rate/page.tsx index 41bdbf733..1d8eef18e 100644 --- a/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-rate/page.tsx +++ b/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-rate/page.tsx @@ -13,10 +13,11 @@ const singleRoomRateTypes = combineRegExps( "i" ) -export default async function SelectRatePage({ - params, - searchParams, -}: PageArgs) { +export default async function SelectRatePage( + props: PageArgs +) { + const params = await props.params + const searchParams = await props.searchParams const booking = convertSearchParamsToObj(searchParams) const isMultiRoom = booking.rooms.length > 1 @@ -35,5 +36,5 @@ export default async function SelectRatePage({ delete searchParams.bookingCode } - return + return } diff --git a/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/layout.tsx b/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/layout.tsx index 6de8a694f..785aa448b 100644 --- a/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/layout.tsx +++ b/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/layout.tsx @@ -2,7 +2,8 @@ import { env } from "@/env/server" import type { LangParams, PageArgs } from "@/types/params" -export async function generateMetadata({ params }: PageArgs) { +export async function generateMetadata(props: PageArgs) { + const params = await props.params; return { robots: { index: env.isLangLive(params.lang), diff --git a/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/my-stay/page.tsx b/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/my-stay/page.tsx index 963d3c70e..1da0008ce 100644 --- a/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/my-stay/page.tsx +++ b/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/my-stay/page.tsx @@ -47,10 +47,11 @@ import type { LangParams, PageArgs } from "@/types/params" import type { BookingConfirmation } from "@/types/trpc/routers/booking/confirmation" import type { SafeUser } from "@/types/user" -export default async function MyStay({ - params, - searchParams, -}: PageArgs) { +export default async function MyStay( + props: PageArgs +) { + const searchParams = await props.searchParams + const params = await props.params setLang(params.lang) const refId = searchParams.RefId @@ -65,7 +66,8 @@ export default async function MyStay({ const isLoggedIn = await isLoggedInUser() - const bv = cookies().get("bv")?.value + const cookieStore = await cookies() + const bv = cookieStore.get("bv")?.value let bookingConfirmation if (isLoggedIn) { bookingConfirmation = await getBookingConfirmation(refId) diff --git a/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/my-stay/tracking.tsx b/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/my-stay/tracking.tsx index 4b18e6af7..757acd92e 100644 --- a/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/my-stay/tracking.tsx +++ b/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/my-stay/tracking.tsx @@ -6,8 +6,8 @@ import { type TrackingSDKPageData, } from "@/types/components/tracking" -export default function Tracking() { - const lang = getLang() +export default async function Tracking() { + const lang = await getLang() const pageTrackingData: TrackingSDKPageData = { channel: TrackingChannelEnum.hotels, diff --git a/apps/scandic-web/app/[lang]/(live)/(public)/login/route.ts b/apps/scandic-web/app/[lang]/(live)/(public)/login/route.ts index a44df7ada..608777608 100644 --- a/apps/scandic-web/app/[lang]/(live)/(public)/login/route.ts +++ b/apps/scandic-web/app/[lang]/(live)/(public)/login/route.ts @@ -10,8 +10,9 @@ import { signIn } from "@/auth" export async function GET( request: NextRequest, - context: { params: { lang: Lang } } + context: { params: Promise<{ lang: Lang }> } ) { + const contextParams = await context.params const publicURL = getPublicURL(request) let redirectHeaders: Headers | undefined = undefined @@ -67,7 +68,7 @@ export async function GET( try { // Initiate the seamless login flow let redirectUrlValue - switch (context.params.lang) { + switch (contextParams.lang) { case Lang.da: redirectUrlValue = env.SEAMLESS_LOGIN_DA break @@ -115,7 +116,7 @@ export async function GET( /** Record is next-auth typings */ const params: Record = { - ui_locales: context.params.lang, + ui_locales: contextParams.lang, scope: [ "openid", "profile", diff --git a/apps/scandic-web/app/[lang]/(live)/(public)/verifymagiclink/route.ts b/apps/scandic-web/app/[lang]/(live)/(public)/verifymagiclink/route.ts index b6283d1f0..2795a15ef 100644 --- a/apps/scandic-web/app/[lang]/(live)/(public)/verifymagiclink/route.ts +++ b/apps/scandic-web/app/[lang]/(live)/(public)/verifymagiclink/route.ts @@ -10,7 +10,7 @@ import type { Lang } from "@/constants/languages" export async function GET( request: NextRequest, - context: { params: { lang: Lang } } + context: { params: Promise<{ lang: Lang }> } ) { const publicURL = getPublicURL(request) @@ -52,6 +52,7 @@ export async function GET( try { console.log(`[verifymagiclink] final redirectUrl: ${redirectTo}`) + const params = await context.params /** * Passing `redirect: false` to `signIn` will return the URL instead of * automatically redirecting to it inside of `signIn`. @@ -64,7 +65,7 @@ export async function GET( redirect: false, }, { - ui_locales: context.params.lang, + ui_locales: params.lang, scope: [ "openid", "profile", diff --git a/apps/scandic-web/app/[lang]/(live)/@bookingwidget/(contentTypes)/destination_city_page/[uid]/page.tsx b/apps/scandic-web/app/[lang]/(live)/@bookingwidget/(contentTypes)/destination_city_page/[uid]/page.tsx index e7207bd0c..508b0c034 100644 --- a/apps/scandic-web/app/[lang]/(live)/@bookingwidget/(contentTypes)/destination_city_page/[uid]/page.tsx +++ b/apps/scandic-web/app/[lang]/(live)/@bookingwidget/(contentTypes)/destination_city_page/[uid]/page.tsx @@ -6,9 +6,8 @@ import { BookingWidget } from "@/components/BookingWidget" import type { BookingWidgetSearchData } from "@/types/components/bookingWidget" import type { PageArgs } from "@/types/params" -export default async function BookingWidgetDestinationCityPage({ - searchParams, -}: PageArgs<{}, BookingWidgetSearchData>) { +export default async function BookingWidgetDestinationCityPage(props: PageArgs<{}, BookingWidgetSearchData>) { + const searchParams = await props.searchParams; if (env.NEW_SITE_LIVE_STATUS === "NOT_LIVE") { return null } diff --git a/apps/scandic-web/app/[lang]/(live)/@bookingwidget/(contentTypes)/hotel_page/[uid]/page.tsx b/apps/scandic-web/app/[lang]/(live)/@bookingwidget/(contentTypes)/hotel_page/[uid]/page.tsx index d67cc018a..efdde751a 100644 --- a/apps/scandic-web/app/[lang]/(live)/@bookingwidget/(contentTypes)/hotel_page/[uid]/page.tsx +++ b/apps/scandic-web/app/[lang]/(live)/@bookingwidget/(contentTypes)/hotel_page/[uid]/page.tsx @@ -7,9 +7,10 @@ import { getLang } from "@/i18n/serverContext" import type { BookingWidgetSearchData } from "@/types/components/bookingWidget" import type { PageArgs } from "@/types/params" -export default async function BookingWidgetHotelPage({ - searchParams, -}: PageArgs<{}, BookingWidgetSearchData & { subpage?: string }>) { +export default async function BookingWidgetHotelPage( + props: PageArgs<{}, BookingWidgetSearchData & { subpage?: string }> +) { + const searchParams = await props.searchParams if (env.NEW_SITE_LIVE_STATUS === "NOT_LIVE") { return null } @@ -19,7 +20,7 @@ export default async function BookingWidgetHotelPage({ const hotelPageData = await getHotelPage() const hotelData = await getHotel({ hotelId: hotelPageData?.hotel_page_id || "", - language: getLang(), + language: await getLang(), isCardOnlyPayment: false, }) diff --git a/apps/scandic-web/app/[lang]/(live)/@bookingwidget/hotelreservation/page.tsx b/apps/scandic-web/app/[lang]/(live)/@bookingwidget/hotelreservation/page.tsx index 68de93f90..8e2cc6038 100644 --- a/apps/scandic-web/app/[lang]/(live)/@bookingwidget/hotelreservation/page.tsx +++ b/apps/scandic-web/app/[lang]/(live)/@bookingwidget/hotelreservation/page.tsx @@ -3,8 +3,10 @@ import { BookingWidget } from "@/components/BookingWidget" import type { BookingWidgetSearchData } from "@/types/components/bookingWidget" import type { LangParams, PageArgs } from "@/types/params" -export default async function BookingWidgetPage({ - searchParams, -}: PageArgs) { +export default async function BookingWidgetPage( + props: PageArgs +) { + const searchParams = await props.searchParams + return } diff --git a/apps/scandic-web/app/[lang]/(live)/@bookingwidget/page.tsx b/apps/scandic-web/app/[lang]/(live)/@bookingwidget/page.tsx index 95b79464d..3cc112ee9 100644 --- a/apps/scandic-web/app/[lang]/(live)/@bookingwidget/page.tsx +++ b/apps/scandic-web/app/[lang]/(live)/@bookingwidget/page.tsx @@ -5,10 +5,9 @@ import { BookingWidget } from "@/components/BookingWidget" import type { BookingWidgetSearchData } from "@/types/components/bookingWidget" import type { LangParams, PageArgs } from "@/types/params" -export default async function BookingWidgetPage({ - searchParams, - params, -}: PageArgs) { +export default async function BookingWidgetPage(props: PageArgs) { + const params = await props.params; + const searchParams = await props.searchParams; if (!env.isLangLive(params.lang)) { return null } diff --git a/apps/scandic-web/app/[lang]/(live)/error.tsx b/apps/scandic-web/app/[lang]/(live)/error.tsx index cd593e9e2..0dad8ad60 100644 --- a/apps/scandic-web/app/[lang]/(live)/error.tsx +++ b/apps/scandic-web/app/[lang]/(live)/error.tsx @@ -24,7 +24,7 @@ export default function Error({ const params = useParams() const router = useRouter() const searchParams = useSearchParams() - const currentSearchParamsRef = useRef() + const currentSearchParamsRef = useRef(undefined) const isFirstLoadRef = useRef(true) useEffect(() => { diff --git a/apps/scandic-web/app/[lang]/(live)/layout.tsx b/apps/scandic-web/app/[lang]/(live)/layout.tsx index 248545bb8..f32f02fd9 100644 --- a/apps/scandic-web/app/[lang]/(live)/layout.tsx +++ b/apps/scandic-web/app/[lang]/(live)/layout.tsx @@ -27,15 +27,20 @@ import { setLang } from "@/i18n/serverContext" import type { LangParams, LayoutArgs } from "@/types/params" -export default async function RootLayout({ - bookingwidget, - children, - params, -}: React.PropsWithChildren< - LayoutArgs & { - bookingwidget: React.ReactNode - } ->) { +export default async function RootLayout( + props: React.PropsWithChildren< + LayoutArgs & { + bookingwidget: React.ReactNode + } + > +) { + const params = await props.params; + + const { + bookingwidget, + children + } = props; + setLang(params.lang) const messages = await getMessages(params.lang) diff --git a/apps/scandic-web/app/[lang]/(live)/middleware-error/[status]/page.tsx b/apps/scandic-web/app/[lang]/(live)/middleware-error/[status]/page.tsx index e48580a6a..6bcefcd30 100644 --- a/apps/scandic-web/app/[lang]/(live)/middleware-error/[status]/page.tsx +++ b/apps/scandic-web/app/[lang]/(live)/middleware-error/[status]/page.tsx @@ -2,13 +2,11 @@ import styles from "./page.module.css" import type { LangParams, LayoutArgs, StatusParams } from "@/types/params" -export default async function MiddlewareError({ - params, -}: LayoutArgs) { +export default async function MiddlewareError(props: LayoutArgs) { + const params = await props.params; return ( // eslint-disable-next-line formatjs/no-literal-string-in-jsx -
- Middleware error {params.lang} {params.status} +
Middleware error {params.lang} {params.status}
- ) + ); } diff --git a/apps/scandic-web/app/[lang]/(live-current)/current-content-page/page.tsx b/apps/scandic-web/app/[lang]/(live-current)/current-content-page/page.tsx index 07a8c685c..7c3a8d4f0 100644 --- a/apps/scandic-web/app/[lang]/(live-current)/current-content-page/page.tsx +++ b/apps/scandic-web/app/[lang]/(live-current)/current-content-page/page.tsx @@ -11,10 +11,9 @@ import type { LangParams, PageArgs, UriParams } from "@/types/params" import type { GetCurrentBlockPageData } from "@/types/requests/currentBlockPage" import type { TrackingData } from "@/types/requests/trackingData" -export default async function CurrentContentPage({ - params, - searchParams, -}: PageArgs) { +export default async function CurrentContentPage(props: PageArgs) { + const searchParams = await props.searchParams; + const params = await props.params; try { if (!searchParams.uri) { throw new Error("Bad URI") diff --git a/apps/scandic-web/app/[lang]/(live-current)/layout.tsx b/apps/scandic-web/app/[lang]/(live-current)/layout.tsx index a289f3461..126810ccf 100644 --- a/apps/scandic-web/app/[lang]/(live-current)/layout.tsx +++ b/apps/scandic-web/app/[lang]/(live-current)/layout.tsx @@ -30,13 +30,18 @@ export const metadata: Metadata = { title: "Scandic Hotels", } -export default async function RootLayout({ - children, - params, - header, -}: React.PropsWithChildren< - LayoutArgs & { header: React.ReactNode } ->) { +export default async function RootLayout( + props: React.PropsWithChildren< + LayoutArgs & { header: React.ReactNode } + > +) { + const params = await props.params; + + const { + children, + header + } = props; + setLang(params.lang) const messages = await getMessages(params.lang) diff --git a/apps/scandic-web/app/[lang]/(no-layout)/hotelreservation/my-stay/receipt/page.tsx b/apps/scandic-web/app/[lang]/(no-layout)/hotelreservation/my-stay/receipt/page.tsx index a5a66c0e0..6d931f287 100644 --- a/apps/scandic-web/app/[lang]/(no-layout)/hotelreservation/my-stay/receipt/page.tsx +++ b/apps/scandic-web/app/[lang]/(no-layout)/hotelreservation/my-stay/receipt/page.tsx @@ -6,9 +6,8 @@ import { Receipt } from "@/components/HotelReservation/MyStay/Receipt" import type { LangParams, PageArgs } from "@/types/params" -export default async function ReceiptPage({ - searchParams, -}: PageArgs) { +export default async function ReceiptPage(props: PageArgs) { + const searchParams = await props.searchParams; if (!searchParams.RefId) { notFound() } diff --git a/apps/scandic-web/app/[lang]/(no-layout)/layout.tsx b/apps/scandic-web/app/[lang]/(no-layout)/layout.tsx index eb6e5abbe..8bb303798 100644 --- a/apps/scandic-web/app/[lang]/(no-layout)/layout.tsx +++ b/apps/scandic-web/app/[lang]/(no-layout)/layout.tsx @@ -23,10 +23,13 @@ import { setLang } from "@/i18n/serverContext" import type { LangParams, LayoutArgs } from "@/types/params" -export default async function RootLayout({ - children, - params, -}: React.PropsWithChildren>) { +export default async function RootLayout(props: React.PropsWithChildren>) { + const params = await props.params; + + const { + children + } = props; + setLang(params.lang) const messages = await getMessages(params.lang) diff --git a/apps/scandic-web/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/callback/route.ts b/apps/scandic-web/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/callback/route.ts index 5100fa919..11bc9f268 100644 --- a/apps/scandic-web/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/callback/route.ts +++ b/apps/scandic-web/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/callback/route.ts @@ -23,8 +23,9 @@ const tokenResponseSchema = z.object({ export async function GET( request: NextRequest, - { params }: { params: { lang: string } } + props: { params: Promise<{ lang: string }> } ) { + const params = await props.params const { lang } = params const result = searchParamsSchema.safeParse({ @@ -72,7 +73,7 @@ export async function GET( redirect(`/${lang}/sas-x-scandic/error?errorCode=invalid_state`) } - const cookieStore = cookies() + const cookieStore = await cookies() cookieStore.set(SAS_TOKEN_STORAGE_KEY, tokenData.access_token, { maxAge: 3600, httpOnly: true, @@ -83,7 +84,8 @@ export async function GET( stateResult.data.intent === "unlink" || stateResult.data.intent === "transfer" ) { - const [data, error] = await safeTry(serverClient().partner.sas.requestOtp()) + const caller = await serverClient() + const [data, error] = await safeTry(caller.partner.sas.requestOtp()) if (!data || error) { console.error("[SAS] Failed to request OTP", error) redirect(`/${lang}/sas-x-scandic/error`) diff --git a/apps/scandic-web/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/error/page.tsx b/apps/scandic-web/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/error/page.tsx index 56bc38eed..8609c8d59 100644 --- a/apps/scandic-web/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/error/page.tsx +++ b/apps/scandic-web/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/error/page.tsx @@ -12,9 +12,10 @@ import { UnlinkError } from "../components/UnlinkError" import type { LangParams, PageArgs, SearchParams } from "@/types/params" -export default async function Page({ - searchParams, -}: PageArgs & SearchParams<{ errorCode?: "dateOfBirthMismatch" }>) { +export default async function Page( + props: PageArgs & SearchParams<{ errorCode?: "dateOfBirthMismatch" }> +) { + const searchParams = await props.searchParams; const intl = await getIntl() const { errorCode } = searchParams diff --git a/apps/scandic-web/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/layout.tsx b/apps/scandic-web/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/layout.tsx index 7709ea884..b850a7abb 100644 --- a/apps/scandic-web/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/layout.tsx +++ b/apps/scandic-web/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/layout.tsx @@ -13,10 +13,13 @@ import type { PropsWithChildren } from "react" import type { LangParams, LayoutArgs } from "@/types/params" -export default async function SasXScandicLayout({ - children, - params, -}: PropsWithChildren>) { +export default async function SasXScandicLayout(props: PropsWithChildren>) { + const params = await props.params; + + const { + children + } = props; + const intl = await getIntl() return ( diff --git a/apps/scandic-web/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/link/page.tsx b/apps/scandic-web/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/link/page.tsx index 1f724963b..97f5bf801 100644 --- a/apps/scandic-web/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/link/page.tsx +++ b/apps/scandic-web/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/link/page.tsx @@ -10,9 +10,8 @@ import { LinkAccountForm } from "./LinkAccountForm" import type { LangParams, PageArgs } from "@/types/params" -export default async function SASxScandicLinkPage({ - params, -}: PageArgs) { +export default async function SASxScandicLinkPage(props: PageArgs) { + const params = await props.params; const profile = await getProfileSafely() if (!profile || !profile.loyalty) return null diff --git a/apps/scandic-web/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/link/success/page.tsx b/apps/scandic-web/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/link/success/page.tsx index c8005c526..7c3813c22 100644 --- a/apps/scandic-web/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/link/success/page.tsx +++ b/apps/scandic-web/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/link/success/page.tsx @@ -12,9 +12,8 @@ import { SASModal } from "../../components/SASModal" import type { LangParams, PageArgs } from "@/types/params" -export default async function SASxScandicLinkPage({ - params, -}: PageArgs) { +export default async function SASxScandicLinkPage(props: PageArgs) { + const params = await props.params; const intl = await getIntl() return ( diff --git a/apps/scandic-web/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/login/page.tsx b/apps/scandic-web/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/login/page.tsx index 725e70f70..8ce0db21e 100644 --- a/apps/scandic-web/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/login/page.tsx +++ b/apps/scandic-web/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/login/page.tsx @@ -24,10 +24,9 @@ const searchParamsSchema = z.object({ type Intent = z.infer["intent"] -export default async function SASxScandicLoginPage({ - searchParams, - params, -}: PageArgs & SearchParams) { +export default async function SASxScandicLoginPage(props: PageArgs & SearchParams) { + const params = await props.params; + const searchParams = await props.searchParams; const result = searchParamsSchema.safeParse(searchParams) if (!result.success) { // TOOD where to redirect? diff --git a/apps/scandic-web/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/otp/page.tsx b/apps/scandic-web/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/otp/page.tsx index e1cfbb8f6..9760274d3 100644 --- a/apps/scandic-web/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/otp/page.tsx +++ b/apps/scandic-web/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/otp/page.tsx @@ -29,12 +29,13 @@ const searchParamsSchema = z.object({ export type OtpError = z.infer type Intent = z.infer -export default async function SASxScandicOneTimePasswordPage({ - searchParams, - params, -}: PageArgs & SearchParams) { +export default async function SASxScandicOneTimePasswordPage( + props: PageArgs & SearchParams +) { + const params = await props.params + const searchParams = await props.searchParams const intl = await getIntl() - const cookieStore = cookies() + const cookieStore = await cookies() const tokenCookie = cookieStore.get(SAS_TOKEN_STORAGE_KEY) const result = searchParamsSchema.safeParse(searchParams) @@ -49,9 +50,8 @@ export default async function SASxScandicOneTimePasswordPage({ const handleOtpVerified: OnSubmitHandler = async ({ otp }) => { "use server" - const [data, error] = await safeTry( - serverClient().partner.sas.verifyOtp({ otp }) - ) + const caller = await serverClient() + const [data, error] = await safeTry(caller.partner.sas.verifyOtp({ otp })) if (error || !data) { throw error || new Error("OTP verification failed") @@ -166,7 +166,8 @@ async function handleLinkAccount({ }: { lang: Lang }): ReturnType { - const [res, error] = await safeTry(serverClient().partner.sas.linkAccount()) + const caller = await serverClient() + const [res, error] = await safeTry(caller.partner.sas.linkAccount()) if (!res || error) { console.error("[SAS] link account error", error) return { @@ -208,7 +209,8 @@ async function handleUnlinkAccount({ }: { lang: Lang }): ReturnType { - const [res, error] = await safeTry(serverClient().partner.sas.unlinkAccount()) + const caller = await serverClient() + const [res, error] = await safeTry(caller.partner.sas.unlinkAccount()) if (!res || error) { console.error("[SAS] unlink account error", error) return { @@ -239,7 +241,7 @@ async function handleTransferPoints({ }: { lang: Lang }): ReturnType { - const cookieStore = cookies() + const cookieStore = await cookies() const pointsCookie = cookieStore.get(SAS_TRANSFER_POINT_KEY) const points = Number(pointsCookie?.value) @@ -252,8 +254,9 @@ async function handleTransferPoints({ } } + const caller = await serverClient() const [res, error] = await safeTry( - serverClient().partner.sas.transferPoints({ + caller.partner.sas.transferPoints({ points, }) ) diff --git a/apps/scandic-web/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/transfer/success/page.tsx b/apps/scandic-web/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/transfer/success/page.tsx index bd746a466..1ad62886a 100644 --- a/apps/scandic-web/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/transfer/success/page.tsx +++ b/apps/scandic-web/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/transfer/success/page.tsx @@ -20,10 +20,9 @@ import styles from "./transferSuccess.module.css" import type { LangParams, PageArgs, SearchParams } from "@/types/params" import type { Lang } from "@/constants/languages" -export default async function SASxScandicTransferSuccessPage({ - params, - searchParams, -}: PageArgs & SearchParams<{ p?: string }>) { +export default async function SASxScandicTransferSuccessPage(props: PageArgs & SearchParams<{ p?: string }>) { + const searchParams = await props.searchParams; + const params = await props.params; const intl = await getIntl() const { lang } = params const addedPoints = Number(searchParams.p) || 0 diff --git a/apps/scandic-web/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/unlink/success/page.tsx b/apps/scandic-web/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/unlink/success/page.tsx index d1cbc4521..8f94e367a 100644 --- a/apps/scandic-web/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/unlink/success/page.tsx +++ b/apps/scandic-web/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/unlink/success/page.tsx @@ -12,9 +12,8 @@ import { SASModal } from "../../components/SASModal" import type { LangParams, PageArgs } from "@/types/params" -export default async function SASxScandicUnlinkSuccessPage({ - params, -}: PageArgs) { +export default async function SASxScandicUnlinkSuccessPage(props: PageArgs) { + const params = await props.params; const intl = await getIntl() return ( diff --git a/apps/scandic-web/app/[lang]/(partner)/layout.tsx b/apps/scandic-web/app/[lang]/(partner)/layout.tsx index 70ab21123..18ca50b75 100644 --- a/apps/scandic-web/app/[lang]/(partner)/layout.tsx +++ b/apps/scandic-web/app/[lang]/(partner)/layout.tsx @@ -23,10 +23,13 @@ import { setLang } from "@/i18n/serverContext" import type { LangParams, LayoutArgs } from "@/types/params" -export default async function RootLayout({ - children, - params, -}: React.PropsWithChildren>) { +export default async function RootLayout(props: React.PropsWithChildren>) { + const params = await props.params; + + const { + children + } = props; + if (!env.SAS_ENABLED) { return null } diff --git a/apps/scandic-web/app/[lang]/webview/[contentType]/[uid]/page.tsx b/apps/scandic-web/app/[lang]/webview/[contentType]/[uid]/page.tsx index a6b341c2b..3b1d48cff 100644 --- a/apps/scandic-web/app/[lang]/webview/[contentType]/[uid]/page.tsx +++ b/apps/scandic-web/app/[lang]/webview/[contentType]/[uid]/page.tsx @@ -14,9 +14,10 @@ import type { UIDParams, } from "@/types/params" -export default async function ContentTypePage({ - params, -}: PageArgs) { +export default async function ContentTypePage( + props: PageArgs +) { + const params = await props.params const intl = await getIntl() const user = await getProfile() @@ -36,8 +37,8 @@ export default async function ContentTypePage({ case "unauthorized": // fall through case "forbidden": // fall through case "token_expired": - const h = headers() - const returnURL = `/${params.lang}/webview${h.get("x-pathname")!}` + const headersList = await headers() + const returnURL = `/${params.lang}/webview${headersList.get("x-pathname")!}` const redirectURL = `/${params.lang}/webview/refresh?returnUrl=${encodeURIComponent(returnURL)}` console.log(`[webview:page] user error, redirecting to: ${redirectURL}`) redirect(redirectURL) diff --git a/apps/scandic-web/app/[lang]/webview/hotelreservation/layout.tsx b/apps/scandic-web/app/[lang]/webview/hotelreservation/layout.tsx index ffee19a76..1b3f9ee9f 100644 --- a/apps/scandic-web/app/[lang]/webview/hotelreservation/layout.tsx +++ b/apps/scandic-web/app/[lang]/webview/hotelreservation/layout.tsx @@ -2,7 +2,8 @@ import { env } from "@/env/server" import type { LangParams, PageArgs } from "@/types/params" -export async function generateMetadata({ params }: PageArgs) { +export async function generateMetadata(props: PageArgs) { + const params = await props.params; return { robots: { index: env.isLangLive(params.lang), diff --git a/apps/scandic-web/app/[lang]/webview/hotelreservation/my-stay/page.tsx b/apps/scandic-web/app/[lang]/webview/hotelreservation/my-stay/page.tsx index 4594c48b4..702cba673 100644 --- a/apps/scandic-web/app/[lang]/webview/hotelreservation/my-stay/page.tsx +++ b/apps/scandic-web/app/[lang]/webview/hotelreservation/my-stay/page.tsx @@ -47,10 +47,11 @@ import type { LangParams, PageArgs } from "@/types/params" import type { BookingConfirmation } from "@/types/trpc/routers/booking/confirmation" import type { SafeUser } from "@/types/user" -export default async function MyStay({ - params, - searchParams, -}: PageArgs) { +export default async function MyStay( + props: PageArgs +) { + const searchParams = await props.searchParams + const params = await props.params setLang(params.lang) const refId = searchParams.RefId @@ -66,7 +67,8 @@ export default async function MyStay({ const isLoggedIn = await isLoggedInUser() - const bv = cookies().get("bv")?.value + const cookieStore = await cookies() + const bv = cookieStore.get("bv")?.value let bookingConfirmation if (isLoggedIn) { bookingConfirmation = await getBookingConfirmation(refId) diff --git a/apps/scandic-web/app/[lang]/webview/hotelreservation/my-stay/tracking.tsx b/apps/scandic-web/app/[lang]/webview/hotelreservation/my-stay/tracking.tsx index 4684e901c..df8447e94 100644 --- a/apps/scandic-web/app/[lang]/webview/hotelreservation/my-stay/tracking.tsx +++ b/apps/scandic-web/app/[lang]/webview/hotelreservation/my-stay/tracking.tsx @@ -6,8 +6,8 @@ import { type TrackingSDKPageData, } from "@/types/components/tracking" -export default function Tracking() { - const lang = getLang() +export default async function Tracking() { + const lang = await getLang() const pageTrackingData: TrackingSDKPageData = { channel: TrackingChannelEnum.hotels, diff --git a/apps/scandic-web/app/[lang]/webview/layout.tsx b/apps/scandic-web/app/[lang]/webview/layout.tsx index 25f10b216..36e5b7f37 100644 --- a/apps/scandic-web/app/[lang]/webview/layout.tsx +++ b/apps/scandic-web/app/[lang]/webview/layout.tsx @@ -26,10 +26,13 @@ export const metadata: Metadata = { title: "Webview", } -export default async function RootLayout({ - children, - params, -}: React.PropsWithChildren>) { +export default async function RootLayout(props: React.PropsWithChildren>) { + const params = await props.params; + + const { + children + } = props; + setLang(params.lang) const messages = await getMessages(params.lang) diff --git a/apps/scandic-web/app/api/hoteldata/route.ts b/apps/scandic-web/app/api/hoteldata/route.ts index cc07fbe74..e88202729 100644 --- a/apps/scandic-web/app/api/hoteldata/route.ts +++ b/apps/scandic-web/app/api/hoteldata/route.ts @@ -25,7 +25,8 @@ export async function GET(request: NextRequest) { throw new Error("[WARMUP] Invalid language provided") } - const hotels = await serverClient().hotel.hotels.getDestinationsMapData({ + const caller = await serverClient() + const hotels = await caller.hotel.hotels.getDestinationsMapData({ lang: parsedLang.data, warmup: true, }) diff --git a/apps/scandic-web/app/api/web/add-card-callback/[lang]/route.ts b/apps/scandic-web/app/api/web/add-card-callback/[lang]/route.ts index 22c8361ff..72b18c93b 100644 --- a/apps/scandic-web/app/api/web/add-card-callback/[lang]/route.ts +++ b/apps/scandic-web/app/api/web/add-card-callback/[lang]/route.ts @@ -7,8 +7,9 @@ import type { NextRequest } from "next/server" export async function GET( request: NextRequest, - { params }: { params: { lang: string } } + props: { params: Promise<{ lang: string }> } ) { + const params = await props.params const publicURL = getPublicURL(request) console.log(`[add-card] callback started`) @@ -24,7 +25,8 @@ export async function GET( if (success) { if (trxId) { - const saveCardSuccess = await serverClient().user.creditCard.save({ + const caller = await serverClient() + const saveCardSuccess = await caller.user.creditCard.save({ transactionId: trxId, }) diff --git a/apps/scandic-web/app/api/web/revalidate/hotel/route.ts b/apps/scandic-web/app/api/web/revalidate/hotel/route.ts index 97147963f..08190c46d 100644 --- a/apps/scandic-web/app/api/web/revalidate/hotel/route.ts +++ b/apps/scandic-web/app/api/web/revalidate/hotel/route.ts @@ -26,7 +26,7 @@ const validateJsonBody = z.object({ export async function POST(request: NextRequest) { try { - const headersList = headers() + const headersList = await headers() const secret = headersList.get("x-revalidate-secret") if (secret !== env.REVALIDATE_SECRET) { diff --git a/apps/scandic-web/app/api/web/revalidate/loyaltyConfig/route.ts b/apps/scandic-web/app/api/web/revalidate/loyaltyConfig/route.ts index 869b4774a..5ee04b948 100644 --- a/apps/scandic-web/app/api/web/revalidate/loyaltyConfig/route.ts +++ b/apps/scandic-web/app/api/web/revalidate/loyaltyConfig/route.ts @@ -31,7 +31,7 @@ const validateJsonBody = z.object({ export async function POST(request: NextRequest) { try { - const headersList = headers() + const headersList = await headers() const secret = headersList.get("x-revalidate-secret") if (secret !== env.REVALIDATE_SECRET) { diff --git a/apps/scandic-web/app/api/web/revalidate/manually/route.ts b/apps/scandic-web/app/api/web/revalidate/manually/route.ts index 906f75020..c17b0e98d 100644 --- a/apps/scandic-web/app/api/web/revalidate/manually/route.ts +++ b/apps/scandic-web/app/api/web/revalidate/manually/route.ts @@ -13,7 +13,7 @@ import type { Lang } from "@/constants/languages" // purging your cache for new (and old) requests export async function POST() { try { - const headersList = headers() + const headersList = await headers() const secret = headersList.get("x-revalidate-secret") if (secret !== env.REVALIDATE_SECRET) { diff --git a/apps/scandic-web/app/api/web/revalidate/route.ts b/apps/scandic-web/app/api/web/revalidate/route.ts index 078735faa..f641b0c41 100644 --- a/apps/scandic-web/app/api/web/revalidate/route.ts +++ b/apps/scandic-web/app/api/web/revalidate/route.ts @@ -45,7 +45,7 @@ const validateJsonBody = z.object({ export async function POST(request: NextRequest) { try { - const headersList = headers() + const headersList = await headers() const secret = headersList.get("x-revalidate-secret") if (secret !== env.REVALIDATE_SECRET) { diff --git a/apps/scandic-web/app/sitemap/[sitemapId]/route.ts b/apps/scandic-web/app/sitemap/[sitemapId]/route.ts index dbc810c7f..cf6ffb511 100644 --- a/apps/scandic-web/app/sitemap/[sitemapId]/route.ts +++ b/apps/scandic-web/app/sitemap/[sitemapId]/route.ts @@ -10,13 +10,14 @@ export const dynamic = "force-dynamic" export async function GET( _request: NextRequest, - context: { params: { sitemapId: string } } + context: { params: Promise<{ sitemapId: string }> } ) { if (env.NEW_SITE_LIVE_STATUS !== "ALL_LANGUAGES_LIVE") { return notFound() } - const sitemapId = context.params.sitemapId + const params = await context.params + const sitemapId = params.sitemapId console.log("[SITEMAP] Fetching sitemap by ID", sitemapId) diff --git a/apps/scandic-web/components/Auth/TokenRefresher.tsx b/apps/scandic-web/components/Auth/TokenRefresher.tsx index 30caaa7c5..23b271bc9 100644 --- a/apps/scandic-web/components/Auth/TokenRefresher.tsx +++ b/apps/scandic-web/components/Auth/TokenRefresher.tsx @@ -24,7 +24,7 @@ export function SessionRefresher() { const session = useSession() const pathname = usePathname() const searchParams = useSearchParams() - const timeoutId = useRef>() + const timeoutId = useRef>(undefined) // Simple inactivity control. Reset when the URL changes. const stopPreRefreshAt = useMemo( diff --git a/apps/scandic-web/components/Blocks/DynamicContent/LoyaltyLevels/index.tsx b/apps/scandic-web/components/Blocks/DynamicContent/LoyaltyLevels/index.tsx index 26f82cd4d..77b4b5e77 100644 --- a/apps/scandic-web/components/Blocks/DynamicContent/LoyaltyLevels/index.tsx +++ b/apps/scandic-web/components/Blocks/DynamicContent/LoyaltyLevels/index.tsx @@ -18,7 +18,8 @@ import type { LevelCardProps } from "@/types/components/overviewTable" export default async function LoyaltyLevels({ dynamic_content, }: LoyaltyLevelsProps) { - const uniqueLevels = await serverClient().contentstack.rewards.all({ + const caller = await serverClient() + const uniqueLevels = await caller.contentstack.rewards.all({ unique: true, }) diff --git a/apps/scandic-web/components/Blocks/DynamicContent/Overview/Stats/ExpiringPoints/index.tsx b/apps/scandic-web/components/Blocks/DynamicContent/Overview/Stats/ExpiringPoints/index.tsx index b0e4c3b40..8e26c79be 100644 --- a/apps/scandic-web/components/Blocks/DynamicContent/Overview/Stats/ExpiringPoints/index.tsx +++ b/apps/scandic-web/components/Blocks/DynamicContent/Overview/Stats/ExpiringPoints/index.tsx @@ -18,7 +18,8 @@ export default async function ExpiringPoints({ user }: UserProps) { } const d = dt(membership.pointsExpiryDate) - const dateFormat = getLang() == Lang.fi ? "DD.MM.YYYY" : "YYYY-MM-DD" + const lang = await getLang() + const dateFormat = lang == Lang.fi ? "DD.MM.YYYY" : "YYYY-MM-DD" return (
diff --git a/apps/scandic-web/components/Blocks/DynamicContent/Overview/Stats/Points/index.tsx b/apps/scandic-web/components/Blocks/DynamicContent/Overview/Stats/Points/index.tsx index 1742b05f1..26f2a7da9 100644 --- a/apps/scandic-web/components/Blocks/DynamicContent/Overview/Stats/Points/index.tsx +++ b/apps/scandic-web/components/Blocks/DynamicContent/Overview/Stats/Points/index.tsx @@ -14,9 +14,10 @@ export default async function Points({ user }: UserProps) { const membership = user.loyalty ? getFriendsMembership(user.loyalty) : null + const caller = await serverClient() const nextLevel = membership?.nextLevel && MembershipLevelEnum[membership.nextLevel] - ? await serverClient().contentstack.loyaltyLevels.byLevel({ + ? await caller.contentstack.loyaltyLevels.byLevel({ level: MembershipLevelEnum[membership.nextLevel], }) : null diff --git a/apps/scandic-web/components/Blocks/DynamicContent/OverviewTable/index.tsx b/apps/scandic-web/components/Blocks/DynamicContent/OverviewTable/index.tsx index 1f3e5cf33..50fa7f889 100644 --- a/apps/scandic-web/components/Blocks/DynamicContent/OverviewTable/index.tsx +++ b/apps/scandic-web/components/Blocks/DynamicContent/OverviewTable/index.tsx @@ -9,8 +9,9 @@ import type { OverviewTableProps } from "@/types/components/blocks/dynamicConten export default async function OverviewTable({ dynamic_content, }: OverviewTableProps) { + const caller = await serverClient() const [levels, membershipLevel] = await Promise.all([ - serverClient().contentstack.rewards.all(), + caller.contentstack.rewards.all(), getMembershipLevelSafely(), ]) diff --git a/apps/scandic-web/components/Blocks/DynamicContent/Rewards/NextLevel/index.tsx b/apps/scandic-web/components/Blocks/DynamicContent/Rewards/NextLevel/index.tsx index 68c5b1d9d..49c4b9442 100644 --- a/apps/scandic-web/components/Blocks/DynamicContent/Rewards/NextLevel/index.tsx +++ b/apps/scandic-web/components/Blocks/DynamicContent/Rewards/NextLevel/index.tsx @@ -29,7 +29,8 @@ export default async function NextLevelRewardsBlock({ return null } - const nextLevelRewards = await serverClient().contentstack.rewards.byLevel({ + const caller = await serverClient() + const nextLevelRewards = await caller.contentstack.rewards.byLevel({ level_id: MembershipLevelEnum[membershipLevel?.nextLevel], unique: true, }) diff --git a/apps/scandic-web/components/Blocks/DynamicContent/SAS/TransferPoints/index.tsx b/apps/scandic-web/components/Blocks/DynamicContent/SAS/TransferPoints/index.tsx index 21cd4b5ab..752ef97ea 100644 --- a/apps/scandic-web/components/Blocks/DynamicContent/SAS/TransferPoints/index.tsx +++ b/apps/scandic-web/components/Blocks/DynamicContent/SAS/TransferPoints/index.tsx @@ -27,7 +27,7 @@ export default async function SASTransferPoints({ return null } - const lang = getLang() + const lang = await getLang() return ( diff --git a/apps/scandic-web/components/Blocks/DynamicContent/SASTierComparison/index.tsx b/apps/scandic-web/components/Blocks/DynamicContent/SASTierComparison/index.tsx index e0438e598..c3c725a39 100644 --- a/apps/scandic-web/components/Blocks/DynamicContent/SASTierComparison/index.tsx +++ b/apps/scandic-web/components/Blocks/DynamicContent/SASTierComparison/index.tsx @@ -10,8 +10,9 @@ export default async function SASTierComparisonBlock({ title, preamble, }: SASTierComparisonBlockProps) { + const caller = await serverClient() const tierComparison = - await serverClient().contentstack.partner.getSasTierComparison() + await caller.contentstack.partner.getSasTierComparison() if (!tierComparison) return null diff --git a/apps/scandic-web/components/Blocks/DynamicContent/Stays/Previous/index.tsx b/apps/scandic-web/components/Blocks/DynamicContent/Stays/Previous/index.tsx index 8f8ddd5bc..3c5efd087 100644 --- a/apps/scandic-web/components/Blocks/DynamicContent/Stays/Previous/index.tsx +++ b/apps/scandic-web/components/Blocks/DynamicContent/Stays/Previous/index.tsx @@ -13,7 +13,8 @@ export default async function PreviousStays({ subtitle, link, }: AccountPageComponentProps) { - const initialPreviousStays = await serverClient().user.stays.previous({ + const caller = await serverClient() + const initialPreviousStays = await caller.user.stays.previous({ limit: 6, }) diff --git a/apps/scandic-web/components/Blocks/DynamicContent/Stays/Soonest/EmptyUpcomingStays/index.tsx b/apps/scandic-web/components/Blocks/DynamicContent/Stays/Soonest/EmptyUpcomingStays/index.tsx index 4bad747dd..c54bb55e6 100644 --- a/apps/scandic-web/components/Blocks/DynamicContent/Stays/Soonest/EmptyUpcomingStays/index.tsx +++ b/apps/scandic-web/components/Blocks/DynamicContent/Stays/Soonest/EmptyUpcomingStays/index.tsx @@ -12,7 +12,7 @@ import styles from "./emptyUpcomingStays.module.css" export default async function EmptyUpcomingStaysBlock() { const intl = await getIntl() - const lang = getLang() + const lang = await getLang() const baseUrl = env.PUBLIC_URL || "https://www.scandichotels.com" const href = !env.isLangLive(lang) diff --git a/apps/scandic-web/components/Blocks/DynamicContent/Stays/Soonest/index.tsx b/apps/scandic-web/components/Blocks/DynamicContent/Stays/Soonest/index.tsx index c0a16f04a..6aa38ad71 100644 --- a/apps/scandic-web/components/Blocks/DynamicContent/Stays/Soonest/index.tsx +++ b/apps/scandic-web/components/Blocks/DynamicContent/Stays/Soonest/index.tsx @@ -15,7 +15,8 @@ export default async function SoonestStays({ subtitle, link, }: AccountPageComponentProps) { - const upcomingStays = await serverClient().user.stays.upcoming({ limit: 3 }) + const caller = await serverClient() + const upcomingStays = await caller.user.stays.upcoming({ limit: 3 }) if (!upcomingStays?.data) { return null } diff --git a/apps/scandic-web/components/Blocks/DynamicContent/Stays/Upcoming/EmptyUpcomingStays/index.tsx b/apps/scandic-web/components/Blocks/DynamicContent/Stays/Upcoming/EmptyUpcomingStays/index.tsx index 4bad747dd..c54bb55e6 100644 --- a/apps/scandic-web/components/Blocks/DynamicContent/Stays/Upcoming/EmptyUpcomingStays/index.tsx +++ b/apps/scandic-web/components/Blocks/DynamicContent/Stays/Upcoming/EmptyUpcomingStays/index.tsx @@ -12,7 +12,7 @@ import styles from "./emptyUpcomingStays.module.css" export default async function EmptyUpcomingStaysBlock() { const intl = await getIntl() - const lang = getLang() + const lang = await getLang() const baseUrl = env.PUBLIC_URL || "https://www.scandichotels.com" const href = !env.isLangLive(lang) diff --git a/apps/scandic-web/components/Blocks/DynamicContent/Stays/Upcoming/index.tsx b/apps/scandic-web/components/Blocks/DynamicContent/Stays/Upcoming/index.tsx index 6c3e91b71..fe2f5add4 100644 --- a/apps/scandic-web/components/Blocks/DynamicContent/Stays/Upcoming/index.tsx +++ b/apps/scandic-web/components/Blocks/DynamicContent/Stays/Upcoming/index.tsx @@ -16,7 +16,8 @@ export default async function UpcomingStays({ subtitle, link, }: AccountPageComponentProps) { - const initialUpcomingStays = await serverClient().user.stays.upcoming({ + const caller = await serverClient() + const initialUpcomingStays = await caller.user.stays.upcoming({ limit: 6, }) diff --git a/apps/scandic-web/components/Breadcrumbs/index.tsx b/apps/scandic-web/components/Breadcrumbs/index.tsx index f9295f75c..fefd3a96b 100644 --- a/apps/scandic-web/components/Breadcrumbs/index.tsx +++ b/apps/scandic-web/components/Breadcrumbs/index.tsx @@ -14,7 +14,8 @@ export default async function Breadcrumbs({ size, subpageTitle, }: Props) { - const breadcrumbs = await serverClient().contentstack.breadcrumbs.get() + const caller = await serverClient() + const breadcrumbs = await caller.contentstack.breadcrumbs.get() if (!breadcrumbs?.length) { return null } diff --git a/apps/scandic-web/components/ContentType/HotelMapPage/index.tsx b/apps/scandic-web/components/ContentType/HotelMapPage/index.tsx index ea65b140b..3f18d6a39 100644 --- a/apps/scandic-web/components/ContentType/HotelMapPage/index.tsx +++ b/apps/scandic-web/components/ContentType/HotelMapPage/index.tsx @@ -12,7 +12,7 @@ interface HotelMapPageProps { } export default async function HotelMapPage({ hotelId }: HotelMapPageProps) { - const lang = getLang() + const lang = await getLang() const hotelPageData = await getHotelPage() const hotelData = await getHotel({ hotelId, diff --git a/apps/scandic-web/components/ContentType/HotelPage/IntroSection/TripAdvisorLink/index.tsx b/apps/scandic-web/components/ContentType/HotelPage/IntroSection/TripAdvisorLink/index.tsx index c96d91e95..dc42589f9 100644 --- a/apps/scandic-web/components/ContentType/HotelPage/IntroSection/TripAdvisorLink/index.tsx +++ b/apps/scandic-web/components/ContentType/HotelPage/IntroSection/TripAdvisorLink/index.tsx @@ -32,7 +32,7 @@ export default async function TripAdvisorLink({ const hasTripAdvisorIframeSrc = !!reviews.widgetScriptEmbedUrlIframe const tripAdvisorHref = hasTripAdvisorIframeSrc - ? appendSlugToPathname("reviews") + ? await appendSlugToPathname("reviews") : null if (!tripAdvisorHref) { diff --git a/apps/scandic-web/components/ContentType/HotelPage/SidePeeks/AboutTheHotel/ContactInformation/index.tsx b/apps/scandic-web/components/ContentType/HotelPage/SidePeeks/AboutTheHotel/ContactInformation/index.tsx index a092bd3f6..aa58baea4 100644 --- a/apps/scandic-web/components/ContentType/HotelPage/SidePeeks/AboutTheHotel/ContactInformation/index.tsx +++ b/apps/scandic-web/components/ContentType/HotelPage/SidePeeks/AboutTheHotel/ContactInformation/index.tsx @@ -23,7 +23,7 @@ export default async function ContactInformation({ ecoLabels, }: ContactInformationProps) { const intl = await getIntl() - const lang = getLang() + const lang = await getLang() const { latitude, longitude } = coordinates const directionsUrl = `https://www.google.com/maps/dir/?api=1&destination=${latitude},${longitude}` diff --git a/apps/scandic-web/components/ContentType/HotelPage/SidePeeks/Amenities/index.tsx b/apps/scandic-web/components/ContentType/HotelPage/SidePeeks/Amenities/index.tsx index 52d7b4887..b5ac7c3c9 100644 --- a/apps/scandic-web/components/ContentType/HotelPage/SidePeeks/Amenities/index.tsx +++ b/apps/scandic-web/components/ContentType/HotelPage/SidePeeks/Amenities/index.tsx @@ -21,8 +21,8 @@ export default async function AmenitiesSidePeek({ }: AmenitiesSidePeekProps) { const intl = await getIntl() - const parkingPageHref = appendSlugToPathname(parking.parkingPageUrl) - const accessibilityPageHref = appendSlugToPathname( + const parkingPageHref = await appendSlugToPathname(parking.parkingPageUrl) + const accessibilityPageHref = await appendSlugToPathname( accessibility.accessibilityPageUrl ) diff --git a/apps/scandic-web/components/ContentType/HotelPage/SidePeeks/MeetingsAndConferences/index.tsx b/apps/scandic-web/components/ContentType/HotelPage/SidePeeks/MeetingsAndConferences/index.tsx index bf241e215..14365f3f5 100644 --- a/apps/scandic-web/components/ContentType/HotelPage/SidePeeks/MeetingsAndConferences/index.tsx +++ b/apps/scandic-web/components/ContentType/HotelPage/SidePeeks/MeetingsAndConferences/index.tsx @@ -23,7 +23,7 @@ export default async function MeetingsAndConferencesSidePeek({ const intl = await getIntl() const { seatingText, roomText } = await getConferenceRoomTexts(meetingRooms) const visibleImages = meetingFacilities?.heroImages.slice(0, 2) - const meetingPageHref = appendSlugToPathname(meetingPageUrl) + const meetingPageHref = await appendSlugToPathname(meetingPageUrl) return ( = { [FacilityEnum.AccessibleBathingControls]: IconName.StarFilled, [FacilityEnum.AccessibleBathtubs]: IconName.StarFilled, diff --git a/apps/scandic-web/components/ContentType/HotelPage/index.tsx b/apps/scandic-web/components/ContentType/HotelPage/index.tsx index b1e856254..be585d0a6 100644 --- a/apps/scandic-web/components/ContentType/HotelPage/index.tsx +++ b/apps/scandic-web/components/ContentType/HotelPage/index.tsx @@ -43,7 +43,7 @@ import type { HotelPageProps } from "@/types/components/hotelPage/hotelPage" import { HotelHashValues } from "@/types/components/hotelPage/tabNavigation" export default async function HotelPage({ hotelId }: HotelPageProps) { - const lang = getLang() + const lang = await getLang() void getHotelPage() void getHotel({ diff --git a/apps/scandic-web/components/ContentType/HotelSubpage/MeetingsSubpage/index.tsx b/apps/scandic-web/components/ContentType/HotelSubpage/MeetingsSubpage/index.tsx index d2e8a79fb..8a00186ff 100644 --- a/apps/scandic-web/components/ContentType/HotelSubpage/MeetingsSubpage/index.tsx +++ b/apps/scandic-web/components/ContentType/HotelSubpage/MeetingsSubpage/index.tsx @@ -30,7 +30,7 @@ export default async function MeetingsSubpage({ additionalData, }: MeetingsSubpageProps) { const intl = await getIntl() - const lang = getLang() + const lang = await getLang() const heading = intl.formatMessage({ defaultMessage: "Meetings, Conferences & Events", }) diff --git a/apps/scandic-web/components/ContentType/HotelSubpage/index.tsx b/apps/scandic-web/components/ContentType/HotelSubpage/index.tsx index 565e362d3..ef2af6b6f 100644 --- a/apps/scandic-web/components/ContentType/HotelSubpage/index.tsx +++ b/apps/scandic-web/components/ContentType/HotelSubpage/index.tsx @@ -18,7 +18,7 @@ export default async function HotelSubpage({ hotelId, subpage, }: HotelSubpageProps) { - const lang = getLang() + const lang = await getLang() const [hotelPageData, hotelData] = await Promise.all([ getHotelPage(), getHotel({ hotelId, language: lang, isCardOnlyPayment: false }), diff --git a/apps/scandic-web/components/ContentType/LoyaltyPage/index.tsx b/apps/scandic-web/components/ContentType/LoyaltyPage/index.tsx index 334b6b2f3..2a78f473d 100644 --- a/apps/scandic-web/components/ContentType/LoyaltyPage/index.tsx +++ b/apps/scandic-web/components/ContentType/LoyaltyPage/index.tsx @@ -14,7 +14,8 @@ import TrackingSDK from "@/components/TrackingSDK" import styles from "./loyaltyPage.module.css" export default async function LoyaltyPage() { - const loyaltyPageRes = await serverClient().contentstack.loyaltyPage.get() + const caller = await serverClient() + const loyaltyPageRes = await caller.contentstack.loyaltyPage.get() if (!loyaltyPageRes) { return null diff --git a/apps/scandic-web/components/ContentType/StaticPages/CollectionPage/index.tsx b/apps/scandic-web/components/ContentType/StaticPages/CollectionPage/index.tsx index 41a06391c..4dad567a3 100644 --- a/apps/scandic-web/components/ContentType/StaticPages/CollectionPage/index.tsx +++ b/apps/scandic-web/components/ContentType/StaticPages/CollectionPage/index.tsx @@ -3,8 +3,8 @@ import { serverClient } from "@/lib/trpc/server" import StaticPage from ".." export default async function CollectionPage() { - const collectionPageRes = - await serverClient().contentstack.collectionPage.get() + const caller = await serverClient() + const collectionPageRes = await caller.contentstack.collectionPage.get() if (!collectionPageRes) { return null diff --git a/apps/scandic-web/components/ContentType/StaticPages/ContentPage/index.tsx b/apps/scandic-web/components/ContentType/StaticPages/ContentPage/index.tsx index dcb715738..ea0f10380 100644 --- a/apps/scandic-web/components/ContentType/StaticPages/ContentPage/index.tsx +++ b/apps/scandic-web/components/ContentType/StaticPages/ContentPage/index.tsx @@ -9,7 +9,8 @@ import BreadcrumbsSkeleton from "@/components/TempDesignSystem/Breadcrumbs/Bread import StaticPage from ".." export default async function ContentPage() { - const contentPageRes = await serverClient().contentstack.contentPage.get() + const caller = await serverClient() + const contentPageRes = await caller.contentstack.contentPage.get() if (!contentPageRes) { return null diff --git a/apps/scandic-web/components/Current/Footer/index.tsx b/apps/scandic-web/components/Current/Footer/index.tsx index a9e9b0d64..ad8613995 100644 --- a/apps/scandic-web/components/Current/Footer/index.tsx +++ b/apps/scandic-web/components/Current/Footer/index.tsx @@ -10,7 +10,8 @@ import Navigation from "./Navigation" import styles from "./footer.module.css" export default async function Footer() { - const footerData = await getCurrentFooter(getLang()) + const lang = await getLang() + const footerData = await getCurrentFooter(lang) if (!footerData) { return null } diff --git a/apps/scandic-web/components/Current/Header/TopMenu/index.tsx b/apps/scandic-web/components/Current/Header/TopMenu/index.tsx index 10d159e8c..853cd1eae 100644 --- a/apps/scandic-web/components/Current/Header/TopMenu/index.tsx +++ b/apps/scandic-web/components/Current/Header/TopMenu/index.tsx @@ -24,6 +24,8 @@ export default async function TopMenu({ }: TopMenuProps) { const intl = await getIntl() const user = await getName() + const lang = await getLang() + return (
@@ -48,7 +50,7 @@ export default async function TopMenu({ <> {user ? ( @@ -57,7 +59,7 @@ export default async function TopMenu({ ) : null}
diff --git a/apps/scandic-web/components/Current/Header/index.tsx b/apps/scandic-web/components/Current/Header/index.tsx index f66f2a1d7..1d455246d 100644 --- a/apps/scandic-web/components/Current/Header/index.tsx +++ b/apps/scandic-web/components/Current/Header/index.tsx @@ -13,14 +13,14 @@ import TopMenu from "./TopMenu" import styles from "./header.module.css" export default async function Header() { - const lang = getLang() + const lang = await getLang() const [data, user] = await Promise.all([getCurrentHeader(lang), getName()]) if (!data?.header) { return null } - const homeHref = homeHrefs[env.NODE_ENV][getLang()] + const homeHref = homeHrefs[env.NODE_ENV][lang] const { frontpageLinkText, logo, menu, topMenu } = data.header const topMenuMobileLinks = topMenu.links diff --git a/apps/scandic-web/components/Current/LangPopup/index.tsx b/apps/scandic-web/components/Current/LangPopup/index.tsx index 423f6bb11..108548730 100644 --- a/apps/scandic-web/components/Current/LangPopup/index.tsx +++ b/apps/scandic-web/components/Current/LangPopup/index.tsx @@ -6,8 +6,8 @@ import { Lang, localeToLang } from "@/constants/languages" import { getLang } from "@/i18n/serverContext" -export default function LangPopup() { - const headersList = headers() +export default async function LangPopup() { + const headersList = await headers() const preferedLang = headersList.get("Accept-Language") ?? "" const possibleLangs = Object.keys(localeToLang) @@ -18,7 +18,8 @@ export default function LangPopup() { const langOfChoice: Lang = localeToLang[preferedLang as Lang] - if (langOfChoice === getLang()) { + const lang = await getLang() + if (langOfChoice === lang) { return null } diff --git a/apps/scandic-web/components/Current/NotFound/index.tsx b/apps/scandic-web/components/Current/NotFound/index.tsx index ddb4c3fe8..7d485928f 100644 --- a/apps/scandic-web/components/Current/NotFound/index.tsx +++ b/apps/scandic-web/components/Current/NotFound/index.tsx @@ -6,8 +6,8 @@ import { texts } from "./Texts" import styles from "./notFound.module.css" -export default function NotFound() { - const lang = getLang() +export default async function NotFound() { + const lang = await getLang() const infoTexts = texts[lang] return ( diff --git a/apps/scandic-web/components/DeprecatedJsonToHtml/utils.tsx b/apps/scandic-web/components/DeprecatedJsonToHtml/utils.tsx index c3fb6e3b8..20db82776 100644 --- a/apps/scandic-web/components/DeprecatedJsonToHtml/utils.tsx +++ b/apps/scandic-web/components/DeprecatedJsonToHtml/utils.tsx @@ -1,3 +1,5 @@ +import { cloneElement } from "react" + import { renderOptions } from "./renderOptions" import type { EmbedByUid } from "@/types/components/deprecatedjsontohtml" @@ -40,10 +42,10 @@ export function nodeChildrenToHtml( if (!element) { return null } - return { - ...element, + + return cloneElement(element, { key: `child-rte-${i}`, - } + }) }) .filter(Boolean) } diff --git a/apps/scandic-web/components/DigitalTeamMemberCard/EmployeeBenefits/AuthCard/index.tsx b/apps/scandic-web/components/DigitalTeamMemberCard/EmployeeBenefits/AuthCard/index.tsx index b7282ee1c..0a5b5aa0d 100644 --- a/apps/scandic-web/components/DigitalTeamMemberCard/EmployeeBenefits/AuthCard/index.tsx +++ b/apps/scandic-web/components/DigitalTeamMemberCard/EmployeeBenefits/AuthCard/index.tsx @@ -11,7 +11,7 @@ import styles from "./authCard.module.css" export default async function EmployeeBenefitsAuthCard() { const intl = await getIntl() - const lang = getLang() + const lang = await getLang() const isLoggedIn = await isLoggedInUser() diff --git a/apps/scandic-web/components/DigitalTeamMemberCard/EmployeeBenefits/CallToActions/index.tsx b/apps/scandic-web/components/DigitalTeamMemberCard/EmployeeBenefits/CallToActions/index.tsx index 0c1d85d0c..344a22735 100644 --- a/apps/scandic-web/components/DigitalTeamMemberCard/EmployeeBenefits/CallToActions/index.tsx +++ b/apps/scandic-web/components/DigitalTeamMemberCard/EmployeeBenefits/CallToActions/index.tsx @@ -17,7 +17,7 @@ import styles from "./callToActions.module.css" export default async function EmployeeBenefitsCallToActions() { const session = await auth() const intl = await getIntl() - const lang = getLang() + const lang = await getLang() if (!isValidSession(session)) { return ( diff --git a/apps/scandic-web/components/Footer/Details/index.tsx b/apps/scandic-web/components/Footer/Details/index.tsx index f2980fc9b..137f4dca7 100644 --- a/apps/scandic-web/components/Footer/Details/index.tsx +++ b/apps/scandic-web/components/Footer/Details/index.tsx @@ -14,7 +14,7 @@ import SocialLink from "./SocialLink" import styles from "./details.module.css" export default async function FooterDetails() { - const lang = getLang() + const lang = await getLang() const intl = await getIntl() // preloaded const footer = await getFooter() @@ -72,7 +72,7 @@ export default async function FooterDetails() { } export async function FooterDetailsSkeleton() { - const lang = getLang() + const lang = await getLang() const intl = await getIntl() const currentYear = new Date().getFullYear() diff --git a/apps/scandic-web/components/Footer/index.tsx b/apps/scandic-web/components/Footer/index.tsx index ad0b5b014..4cff8bff9 100644 --- a/apps/scandic-web/components/Footer/index.tsx +++ b/apps/scandic-web/components/Footer/index.tsx @@ -13,8 +13,8 @@ export function preload() { void getFooter() } -export default function Footer() { - const lang = getLang() +export default async function Footer() { + const lang = await getLang() if (!env.isLangLive(lang)) { return } diff --git a/apps/scandic-web/components/Header/TopMenu/index.tsx b/apps/scandic-web/components/Header/TopMenu/index.tsx index 857be6aad..cd141a7d8 100644 --- a/apps/scandic-web/components/Header/TopMenu/index.tsx +++ b/apps/scandic-web/components/Header/TopMenu/index.tsx @@ -29,7 +29,7 @@ export default async function TopMenu() { return null } - const lang = getLang() + const lang = await getLang() const baseUrl = env.PUBLIC_URL || "https://www.scandichotels.com" const findMyBookingUrl = !env.isLangLive(lang) ? getCurrentWebUrl({ diff --git a/apps/scandic-web/components/Header/index.tsx b/apps/scandic-web/components/Header/index.tsx index 481e53851..9f989cc41 100644 --- a/apps/scandic-web/components/Header/index.tsx +++ b/apps/scandic-web/components/Header/index.tsx @@ -12,10 +12,10 @@ import TopMenu, { TopMenuSkeleton } from "./TopMenu" import styles from "./header.module.css" -export default function Header() { +export default async function Header() { void getName() - const lang = getLang() + const lang = await getLang() if (!env.isLangLive(lang)) { return ( }> diff --git a/apps/scandic-web/components/HotelReservation/MyStay/Receipt/Footer/index.tsx b/apps/scandic-web/components/HotelReservation/MyStay/Receipt/Footer/index.tsx index 9c81428a9..28f99d13a 100644 --- a/apps/scandic-web/components/HotelReservation/MyStay/Receipt/Footer/index.tsx +++ b/apps/scandic-web/components/HotelReservation/MyStay/Receipt/Footer/index.tsx @@ -13,7 +13,7 @@ import { RoomPackageCodeEnum } from "@/types/components/hotelReservation/selectR export default async function Footer({ booking, room }: FooterProps) { const intl = await getIntl() - const lang = getLang() + const lang = await getLang() const petRoomPackage = booking.packages.find( (p) => p.code === RoomPackageCodeEnum.PET_ROOM diff --git a/apps/scandic-web/components/HotelReservation/MyStay/Receipt/index.tsx b/apps/scandic-web/components/HotelReservation/MyStay/Receipt/index.tsx index c2ab4be6e..50cf9f20f 100644 --- a/apps/scandic-web/components/HotelReservation/MyStay/Receipt/index.tsx +++ b/apps/scandic-web/components/HotelReservation/MyStay/Receipt/index.tsx @@ -42,7 +42,8 @@ export async function Receipt({ refId }: { refId: string }) { const isLoggedIn = await isLoggedInUser() - const bv = cookies().get("bv")?.value + const cookieStore = await cookies() + const bv = cookieStore.get("bv")?.value let bookingConfirmation if (isLoggedIn) { bookingConfirmation = await getBookingConfirmation(refId) diff --git a/apps/scandic-web/components/HotelReservation/MyStay/Receipt/tracking.tsx b/apps/scandic-web/components/HotelReservation/MyStay/Receipt/tracking.tsx index 1093f9a97..8cd0b222f 100644 --- a/apps/scandic-web/components/HotelReservation/MyStay/Receipt/tracking.tsx +++ b/apps/scandic-web/components/HotelReservation/MyStay/Receipt/tracking.tsx @@ -6,8 +6,8 @@ import { type TrackingSDKPageData, } from "@/types/components/tracking" -export default function Tracking() { - const lang = getLang() +export default async function Tracking() { + const lang = await getLang() const pageTrackingData: TrackingSDKPageData = { channel: TrackingChannelEnum.hotels, diff --git a/apps/scandic-web/components/HotelReservation/SelectHotel/NoAvailabilityAlert.tsx b/apps/scandic-web/components/HotelReservation/SelectHotel/NoAvailabilityAlert.tsx index c5566efbd..770b5f5a0 100644 --- a/apps/scandic-web/components/HotelReservation/SelectHotel/NoAvailabilityAlert.tsx +++ b/apps/scandic-web/components/HotelReservation/SelectHotel/NoAvailabilityAlert.tsx @@ -16,7 +16,7 @@ export default async function NoAvailabilityAlert({ operaId, }: NoAvailabilityAlertProp) { const intl = await getIntl() - const lang = getLang() + const lang = await getLang() if (bookingCode && isBookingCodeRateNotAvailable) { const bookingCodeText = intl.formatMessage( diff --git a/apps/scandic-web/components/HotelReservation/SelectHotel/SelectHotelMap/SelectHotelMapContainer.tsx b/apps/scandic-web/components/HotelReservation/SelectHotel/SelectHotelMap/SelectHotelMapContainer.tsx index ad9e7b8ad..964f65980 100644 --- a/apps/scandic-web/components/HotelReservation/SelectHotel/SelectHotelMap/SelectHotelMapContainer.tsx +++ b/apps/scandic-web/components/HotelReservation/SelectHotel/SelectHotelMap/SelectHotelMapContainer.tsx @@ -14,24 +14,16 @@ import { getTracking } from "./tracking" import SelectHotelMap from "." import type { SelectHotelMapContainerProps } from "@/types/components/hotelReservation/selectHotel/map" -import type { SelectHotelSearchParams } from "@/types/components/hotelReservation/selectHotel/selectHotelSearchParams" export async function SelectHotelMapContainer({ - searchParams, + booking, isAlternativeHotels, }: SelectHotelMapContainerProps) { - const lang = getLang() + const lang = await getLang() const googleMapId = env.GOOGLE_DYNAMIC_MAP_ID const googleMapsApiKey = env.GOOGLE_STATIC_MAP_KEY const getHotelSearchDetailsPromise = safeTry( - getHotelSearchDetails( - { - searchParams: searchParams as SelectHotelSearchParams & { - [key: string]: string - }, - }, - isAlternativeHotels - ) + getHotelSearchDetails(booking, isAlternativeHotels) ) const [searchDetails] = await getHotelSearchDetailsPromise diff --git a/apps/scandic-web/components/HotelReservation/SelectHotel/helpers.ts b/apps/scandic-web/components/HotelReservation/SelectHotel/helpers.ts index 5716a28dc..75f017abb 100644 --- a/apps/scandic-web/components/HotelReservation/SelectHotel/helpers.ts +++ b/apps/scandic-web/components/HotelReservation/SelectHotel/helpers.ts @@ -24,6 +24,7 @@ import type { HotelLocation, Location, } from "@/types/trpc/routers/hotel/locations" +import type { SelectHotelParams } from "@/utils/url" interface AvailabilityResponse { availability: HotelsAvailabilityItem[] @@ -39,7 +40,7 @@ type Result = AvailabilityResponse | null type SettledResult = PromiseSettledResult[] async function enhanceHotels(hotels: HotelsAvailabilityItem[]) { - const language = getLang() + const language = await getLang() return await Promise.allSettled( hotels.map(async (availability) => { const hotelData = await getHotel({ @@ -65,7 +66,8 @@ async function fetchAlternativeHotels( hotelId: string, input: AlternativeHotelsAvailabilityInput ) { - const alternativeHotelIds = await serverClient().hotel.nearbyHotelIds({ + const caller = await serverClient() + const alternativeHotelIds = await caller.hotel.nearbyHotelIds({ hotelId, }) @@ -73,20 +75,20 @@ async function fetchAlternativeHotels( return null } - return await serverClient().hotel.availability.hotelsByHotelIds({ + return await caller.hotel.availability.hotelsByHotelIds({ ...input, hotelIds: alternativeHotelIds, }) } async function fetchAvailableHotels(input: AvailabilityInput) { - return await serverClient().hotel.availability.hotelsByCity(input) + const caller = await serverClient() + return await caller.hotel.availability.hotelsByCity(input) } async function fetchBookingCodeAvailableHotels(input: AvailabilityInput) { - return await serverClient().hotel.availability.hotelsByCityWithBookingCode( - input - ) + const caller = await serverClient() + return await caller.hotel.availability.hotelsByCityWithBookingCode(input) } function getFulfilledResponses(result: PromiseSettledResult[]) { @@ -161,7 +163,9 @@ function sortAndFilterHotelsByAvailability( } export async function getHotels( - booking: SelectHotelSearchParams | AlternativeHotelsSearchParams, + booking: SelectHotelParams< + SelectHotelSearchParams | AlternativeHotelsSearchParams + >, isAlternativeFor: HotelLocation | null, bookingCode: string | undefined, city: Location, diff --git a/apps/scandic-web/components/HotelReservation/SelectHotel/index.tsx b/apps/scandic-web/components/HotelReservation/SelectHotel/index.tsx index 4fcc454e2..29c538504 100644 --- a/apps/scandic-web/components/HotelReservation/SelectHotel/index.tsx +++ b/apps/scandic-web/components/HotelReservation/SelectHotel/index.tsx @@ -43,18 +43,18 @@ export default async function SelectHotel({ const isBookingCodeRateAvailable = bookingCode ? hotels.some( - (hotel) => - hotel.availability.bookingCode && - hotel.availability.status === "Available" - ) + (hotel) => + hotel.availability.bookingCode && + hotel.availability.status === "Available" + ) : false const isFullPriceHotelAvailable = bookingCode ? hotels?.some( - (hotel) => - !hotel.availability.bookingCode && - hotel.availability.status === "Available" - ) + (hotel) => + !hotel.availability.bookingCode && + hotel.availability.status === "Available" + ) : false // Special rates (corporate cheque, voucher and reward nights) will not have regular rate hotels availability diff --git a/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/RoomsHeader/RoomPackageFilter/utils.ts b/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/RoomsHeader/RoomPackageFilter/utils.ts index 10348e855..f153b7068 100644 --- a/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/RoomsHeader/RoomPackageFilter/utils.ts +++ b/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/RoomsHeader/RoomPackageFilter/utils.ts @@ -1,4 +1,4 @@ -import type { MaterialSymbolProps } from "react-material-symbols" +import type { MaterialSymbolProps } from "@scandic-hotels/design-system/Icons/MaterialIcon/MaterialSymbol" import { RoomPackageCodeEnum } from "@/types/components/hotelReservation/selectRate/roomFilter" import type { PackageEnum } from "@/types/requests/packages" diff --git a/apps/scandic-web/components/HotelReservation/SelectRate/index.tsx b/apps/scandic-web/components/HotelReservation/SelectRate/index.tsx index e033aafed..d594f8509 100644 --- a/apps/scandic-web/components/HotelReservation/SelectRate/index.tsx +++ b/apps/scandic-web/components/HotelReservation/SelectRate/index.tsx @@ -6,7 +6,6 @@ import { getHotel } from "@/lib/trpc/memoizedRequests" import HotelInfoCard from "@/components/HotelReservation/SelectRate/HotelInfoCard" import { RoomsContainer } from "@/components/HotelReservation/SelectRate/RoomsContainer" -import { setLang } from "@/i18n/serverContext" import { getHotelSearchDetails } from "@/utils/hotelSearchDetails" import FnFNotAllowedAlert from "../FnFNotAllowedAlert/FnFNotAllowedAlert" @@ -14,14 +13,17 @@ import AvailabilityError from "./AvailabilityError" import Tracking from "./Tracking" import type { SelectRateSearchParams } from "@/types/components/hotelReservation/selectRate/selectRate" -import type { LangParams, PageArgs } from "@/types/params" +import type { Lang } from "@/constants/languages" +import type { SelectHotelParams } from "@/utils/url" export default async function SelectRatePage({ - params, - searchParams, -}: PageArgs) { - setLang(params.lang) - const searchDetails = await getHotelSearchDetails({ searchParams }) + lang, + booking, +}: { + lang: Lang + booking: SelectHotelParams +}) { + const searchDetails = await getHotelSearchDetails(booking) if (!searchDetails?.hotel) { return notFound() } @@ -31,7 +33,7 @@ export default async function SelectRatePage({ const hotelData = await getHotel({ hotelId: hotel.id, isCardOnlyPayment: false, - language: params.lang, + language: lang, }) if (!hotelData) { @@ -40,7 +42,7 @@ export default async function SelectRatePage({ let isInValidFNF = false if (bookingCode && FamilyAndFriendsCodes.includes(bookingCode)) { - const cookieStore = cookies() + const cookieStore = await cookies() isInValidFNF = cookieStore.get("sc")?.value !== "1" } return ( diff --git a/apps/scandic-web/components/HotelReservation/utils/index.tsx b/apps/scandic-web/components/HotelReservation/utils/index.tsx index a25c7b6f5..4a00c021a 100644 --- a/apps/scandic-web/components/HotelReservation/utils/index.tsx +++ b/apps/scandic-web/components/HotelReservation/utils/index.tsx @@ -13,6 +13,8 @@ import { import type { Child } from "@/types/components/hotelReservation/selectRate/selectRate" import type { Packages } from "@/types/requests/packages" +import type { JSX } from "react"; + interface IconForFeatureCodeProps { featureCode: RoomPackageCodes } diff --git a/apps/scandic-web/components/Icons/IconByIconName.tsx b/apps/scandic-web/components/Icons/IconByIconName.tsx index 0e849784b..76b878a0f 100644 --- a/apps/scandic-web/components/Icons/IconByIconName.tsx +++ b/apps/scandic-web/components/Icons/IconByIconName.tsx @@ -31,6 +31,8 @@ import type { NucleoIconProps, } from "@scandic-hotels/design-system/Icons" +import type { JSX } from "react"; + interface IconByIconNameProps { iconName: IconName | null } diff --git a/apps/scandic-web/components/JsonToHtml/utils.tsx b/apps/scandic-web/components/JsonToHtml/utils.tsx index c7786c37e..1e9ef3bec 100644 --- a/apps/scandic-web/components/JsonToHtml/utils.tsx +++ b/apps/scandic-web/components/JsonToHtml/utils.tsx @@ -1,4 +1,4 @@ -import React from "react" +import React, { cloneElement } from "react" import { renderOptions } from "./renderOptions" @@ -44,10 +44,10 @@ export function nodeChildrenToHtml( if (!element) { return null } - return { - ...element, + + return cloneElement(element, { key: `child-rte-${i}`, - } + }) }) .filter(Boolean) } diff --git a/apps/scandic-web/components/Modal/index.tsx b/apps/scandic-web/components/Modal/index.tsx index af1b005ff..d4632dac1 100644 --- a/apps/scandic-web/components/Modal/index.tsx +++ b/apps/scandic-web/components/Modal/index.tsx @@ -71,7 +71,11 @@ function InnerModal({ className={styles.overlay} initial="hidden" isDismissable - isExiting={animation === AnimationStateEnum.hidden} + // TODO: Enabling this causes the modal to never unmount. + // Seems to be an issue with react-aria-components, see https://github.com/adobe/react-spectrum/issues/7563. + // Exit animations can probably be fixed by rewriting to a solution similar to + // https://react-spectrum.adobe.com/react-aria/examples/framer-modal-sheet.html. + // isExiting={animation === AnimationStateEnum.hidden} onAnimationComplete={modalStateHandler} variants={fade} isOpen={isOpen} diff --git a/apps/scandic-web/components/Modal/modal.ts b/apps/scandic-web/components/Modal/modal.ts index 48e7d2dde..eef41378c 100644 --- a/apps/scandic-web/components/Modal/modal.ts +++ b/apps/scandic-web/components/Modal/modal.ts @@ -1,4 +1,4 @@ -import type { Dispatch, SetStateAction } from "react" +import type { Dispatch, SetStateAction, JSX } from "react"; export enum AnimationStateEnum { unmounted = "unmounted", diff --git a/apps/scandic-web/components/MyPages/Profile/CreditCards/index.tsx b/apps/scandic-web/components/MyPages/Profile/CreditCards/index.tsx index 2f4d21bd7..3f5f38a4e 100644 --- a/apps/scandic-web/components/MyPages/Profile/CreditCards/index.tsx +++ b/apps/scandic-web/components/MyPages/Profile/CreditCards/index.tsx @@ -10,7 +10,8 @@ import styles from "./creditCards.module.css" export default async function CreditCardSlot() { const intl = await getIntl() - const creditCards = await serverClient().user.creditCards() + const caller = await serverClient() + const creditCards = await caller.user.creditCards() return (
diff --git a/apps/scandic-web/components/MyPages/Profile/index.tsx b/apps/scandic-web/components/MyPages/Profile/index.tsx index 9d56080ad..23a7eded4 100644 --- a/apps/scandic-web/components/MyPages/Profile/index.tsx +++ b/apps/scandic-web/components/MyPages/Profile/index.tsx @@ -25,7 +25,7 @@ export default async function Profile() { } const intl = await getIntl() - const lang = getLang() + const lang = await getLang() const addressParts = [] if (user.address.streetAddress) { diff --git a/apps/scandic-web/components/MyPages/Sidebar/index.tsx b/apps/scandic-web/components/MyPages/Sidebar/index.tsx index 1a530ad77..b14d81cc3 100644 --- a/apps/scandic-web/components/MyPages/Sidebar/index.tsx +++ b/apps/scandic-web/components/MyPages/Sidebar/index.tsx @@ -40,7 +40,8 @@ export default async function SidebarMyPages() { } async function PrimaryLinks() { - const nav = await serverClient().navigation.myPages({}) + const caller = await serverClient() + const nav = await caller.navigation.myPages({}) return ( <> @@ -66,9 +67,10 @@ async function PrimaryLinks() { } async function SecondaryLinks() { - const lang = getLang() + const lang = await getLang() - const nav = await serverClient().navigation.myPages({}) + const caller = await serverClient() + const nav = await caller.navigation.myPages({}) const intl = await getIntl() return ( diff --git a/apps/scandic-web/components/MyPages/Surprises/index.tsx b/apps/scandic-web/components/MyPages/Surprises/index.tsx index a8c28b16b..772a1014c 100644 --- a/apps/scandic-web/components/MyPages/Surprises/index.tsx +++ b/apps/scandic-web/components/MyPages/Surprises/index.tsx @@ -8,7 +8,8 @@ export default async function Surprises() { return null } - const surprises = await serverClient().contentstack.rewards.surprises() + const caller = await serverClient() + const surprises = await caller.contentstack.rewards.surprises() if (!surprises) { return null diff --git a/apps/scandic-web/components/ProtectedLayout.tsx b/apps/scandic-web/components/ProtectedLayout.tsx index 1e3d73be5..15ebffc35 100644 --- a/apps/scandic-web/components/ProtectedLayout.tsx +++ b/apps/scandic-web/components/ProtectedLayout.tsx @@ -16,12 +16,13 @@ export async function ProtectedLayout({ children }: React.PropsWithChildren) { * Fallback to make sure every route nested in the * protected route group is actually protected. */ - const h = headers() + const headersList = await headers() + const lang = await getLang() const redirectTo = encodeURIComponent( - h.get("x-url") ?? h.get("x-pathname") ?? overview[getLang()] + headersList.get("x-url") ?? headersList.get("x-pathname") ?? overview[lang] ) - const redirectURL = `/${getLang()}/login?redirectTo=${redirectTo}` + const redirectURL = `/${lang}/login?redirectTo=${redirectTo}` if (!isValidSession(session)) { console.log(`[layout:protected] no session, redirecting to: ${redirectURL}`) diff --git a/apps/scandic-web/components/SidePeeks/RoomSidePeek/bedIcon.ts b/apps/scandic-web/components/SidePeeks/RoomSidePeek/bedIcon.ts index b87a12bb1..703cf77f1 100644 --- a/apps/scandic-web/components/SidePeeks/RoomSidePeek/bedIcon.ts +++ b/apps/scandic-web/components/SidePeeks/RoomSidePeek/bedIcon.ts @@ -1,4 +1,4 @@ -import type { MaterialSymbolProps } from "react-material-symbols" +import type { MaterialSymbolProps } from "@scandic-hotels/design-system/Icons/MaterialIcon/MaterialSymbol" export function getBedIconName(name: string): MaterialSymbolProps["icon"] { const iconMappings = [ diff --git a/apps/scandic-web/components/SidePeeks/RoomSidePeek/facilityIcon.tsx b/apps/scandic-web/components/SidePeeks/RoomSidePeek/facilityIcon.tsx index 388194d20..c058e421a 100644 --- a/apps/scandic-web/components/SidePeeks/RoomSidePeek/facilityIcon.tsx +++ b/apps/scandic-web/components/SidePeeks/RoomSidePeek/facilityIcon.tsx @@ -35,7 +35,9 @@ import type { IconProps, NucleoIconProps, } from "@scandic-hotels/design-system/Icons" -import type { MaterialSymbolProps } from "react-material-symbols" +import type { MaterialSymbolProps } from "@scandic-hotels/design-system/Icons/MaterialIcon/MaterialSymbol" + +import type { JSX } from "react" interface FacilityIconProps { name: string | undefined diff --git a/apps/scandic-web/components/Sidebar/JoinLoyalty/Contact/ContactRow/index.tsx b/apps/scandic-web/components/Sidebar/JoinLoyalty/Contact/ContactRow/index.tsx index dfcc86609..6e481ef01 100644 --- a/apps/scandic-web/components/Sidebar/JoinLoyalty/Contact/ContactRow/index.tsx +++ b/apps/scandic-web/components/Sidebar/JoinLoyalty/Contact/ContactRow/index.tsx @@ -15,7 +15,8 @@ import styles from "./contactRow.module.css" import type { ContactRowProps } from "@/types/components/sidebar/joinLoyaltyContact" export default async function ContactRow({ contact }: ContactRowProps) { - const data = await serverClient().contentstack.base.contact() + const caller = await serverClient() + const data = await caller.contentstack.base.contact() if (!data) { return null } diff --git a/apps/scandic-web/components/TempDesignSystem/Alert/utils.tsx b/apps/scandic-web/components/TempDesignSystem/Alert/utils.tsx index bf96fb4f8..205d0f53b 100644 --- a/apps/scandic-web/components/TempDesignSystem/Alert/utils.tsx +++ b/apps/scandic-web/components/TempDesignSystem/Alert/utils.tsx @@ -6,6 +6,8 @@ import { import { AlertTypeEnum } from "@/types/enums/alert" import type { AlertProps } from "./alert" +import type { JSX } from "react"; + interface IconByAlertProps { alertType: AlertTypeEnum variant?: AlertProps["variant"] diff --git a/apps/scandic-web/components/TempDesignSystem/Form/RadioCard/types.ts b/apps/scandic-web/components/TempDesignSystem/Form/RadioCard/types.ts index 571cc8318..02feee74d 100644 --- a/apps/scandic-web/components/TempDesignSystem/Form/RadioCard/types.ts +++ b/apps/scandic-web/components/TempDesignSystem/Form/RadioCard/types.ts @@ -1,5 +1,7 @@ import type { IconProps } from "@scandic-hotels/design-system/Icons" +import type { JSX } from "react"; + export interface RadioCardProps extends Omit, "title"> { Icon?: (props: IconProps) => JSX.Element diff --git a/apps/scandic-web/components/TempDesignSystem/Select/select.ts b/apps/scandic-web/components/TempDesignSystem/Select/select.ts index 671e96cf2..08bd55efa 100644 --- a/apps/scandic-web/components/TempDesignSystem/Select/select.ts +++ b/apps/scandic-web/components/TempDesignSystem/Select/select.ts @@ -13,7 +13,7 @@ export interface SelectProps showRadioButton?: boolean discreet?: boolean isNestedInModal?: boolean - optionsIcon?: ReactElement + optionsIcon?: ReactElement } export type SelectPortalContainer = HTMLDivElement | undefined diff --git a/apps/scandic-web/components/Webviews/AccountPage/Blocks.tsx b/apps/scandic-web/components/Webviews/AccountPage/Blocks.tsx index db03a614e..18e03eb39 100644 --- a/apps/scandic-web/components/Webviews/AccountPage/Blocks.tsx +++ b/apps/scandic-web/components/Webviews/AccountPage/Blocks.tsx @@ -15,13 +15,14 @@ import type { import { BlocksEnums } from "@/types/enums/blocks" import { DynamicContentEnum } from "@/types/enums/dynamicContent" -function DynamicComponent({ dynamic_content }: AccountPageContentProps) { +async function DynamicComponent({ dynamic_content }: AccountPageContentProps) { + const lang = await getLang() const dynamicContent = { ...dynamic_content, link: dynamic_content.link ? { ...dynamic_content.link, - href: modWebviewLink(dynamic_content.link.href, getLang()), + href: await modWebviewLink(dynamic_content.link.href, lang), } : undefined, } @@ -45,49 +46,54 @@ function DynamicComponent({ dynamic_content }: AccountPageContentProps) { } } -export default function Content({ content }: ContentProps) { +export default async function Content({ content }: ContentProps) { + const lang = await getLang() return ( <> - {content.map((item, idx) => { - switch (item.typename) { - case BlocksEnums.block.DynamicContent: - return ( - - ) - case BlocksEnums.block.Shortcuts: - const shortcuts = item.shortcuts.shortcuts.map((shortcut) => { - return { - ...shortcut, - url: modWebviewLink(shortcut.url, getLang()), - } - }) - return ( - - ) - case BlocksEnums.block.TextContent: - return ( -
- { + switch (item.typename) { + case BlocksEnums.block.DynamicContent: + return ( + -
- ) - default: - return null - } - })} + ) + case BlocksEnums.block.Shortcuts: + const shortcuts = await Promise.all( + item.shortcuts.shortcuts.map(async (shortcut) => { + return { + ...shortcut, + url: await modWebviewLink(shortcut.url, lang), + } + }) + ) + return ( + + ) + case BlocksEnums.block.TextContent: + return ( +
+ +
+ ) + default: + return null + } + }) + )} ) } diff --git a/apps/scandic-web/components/Webviews/AccountPage/index.tsx b/apps/scandic-web/components/Webviews/AccountPage/index.tsx index 9637491ce..573c1425e 100644 --- a/apps/scandic-web/components/Webviews/AccountPage/index.tsx +++ b/apps/scandic-web/components/Webviews/AccountPage/index.tsx @@ -11,7 +11,8 @@ import { getLang } from "@/i18n/serverContext" import styles from "./accountPage.module.css" export default async function AccountPage() { - const accountPageRes = await serverClient().contentstack.accountPage.get() + const caller = await serverClient() + const accountPageRes = await caller.contentstack.accountPage.get() if (!accountPageRes) { return null @@ -19,8 +20,8 @@ export default async function AccountPage() { const { tracking, accountPage } = accountPageRes - const linkToOverview = - `/${getLang()}/webview${accountPage.url}` !== overview[getLang()] + const lang = await getLang() + const linkToOverview = `/${lang}/webview${accountPage.url}` !== overview[lang] return ( <> diff --git a/apps/scandic-web/components/Webviews/LinkToOverview/index.tsx b/apps/scandic-web/components/Webviews/LinkToOverview/index.tsx index 77d268dbf..bdf6eeced 100644 --- a/apps/scandic-web/components/Webviews/LinkToOverview/index.tsx +++ b/apps/scandic-web/components/Webviews/LinkToOverview/index.tsx @@ -11,9 +11,10 @@ import styles from "./linkToOverview.module.css" export default async function LinkToOverview() { const intl = await getIntl() - const searchParams = webviewSearchParams() + const searchParams = await webviewSearchParams() - const overviewHref = `${overview[getLang()]}?${searchParams.toString()}` + const lang = await getLang() + const overviewHref = `${overview[lang]}?${searchParams.toString()}` return ( diff --git a/apps/scandic-web/components/Webviews/LoyaltyPage/Blocks.tsx b/apps/scandic-web/components/Webviews/LoyaltyPage/Blocks.tsx index 6a06bf156..6b5c54b53 100644 --- a/apps/scandic-web/components/Webviews/LoyaltyPage/Blocks.tsx +++ b/apps/scandic-web/components/Webviews/LoyaltyPage/Blocks.tsx @@ -8,61 +8,67 @@ import { modWebviewLink } from "@/utils/webviews" import type { BlocksProps } from "@/types/components/blocks" import { BlocksEnums } from "@/types/enums/blocks" -export default function Blocks({ blocks }: BlocksProps) { - return blocks.map((block, idx) => { - switch (block.typename) { - case BlocksEnums.block.CardsGrid: - return ( - - ) - case BlocksEnums.block.Content: - return ( -
- -
- ) - case BlocksEnums.block.DynamicContent: - const dynamicContent = { - ...block.dynamic_content, - link: block.dynamic_content.link - ? { - ...block.dynamic_content.link, - href: modWebviewLink( - block.dynamic_content.link.href, - getLang() - ), - } - : undefined, - } +export default async function Blocks({ blocks }: BlocksProps) { + const lang = await getLang() - return ( - - ) - case BlocksEnums.block.Shortcuts: - const shortcuts = block.shortcuts.shortcuts.map((shortcut) => ({ - ...shortcut, - url: modWebviewLink(shortcut.url, getLang()), - })) - return ( - - ) - default: - return null - } - }) + return Promise.all( + blocks.map(async (block, idx) => { + switch (block.typename) { + case BlocksEnums.block.CardsGrid: + return ( + + ) + case BlocksEnums.block.Content: + return ( +
+ +
+ ) + case BlocksEnums.block.DynamicContent: + const dynamicContent = { + ...block.dynamic_content, + link: block.dynamic_content.link + ? { + ...block.dynamic_content.link, + href: await modWebviewLink( + block.dynamic_content.link.href, + lang + ), + } + : undefined, + } + + return ( + + ) + case BlocksEnums.block.Shortcuts: + const shortcuts = await Promise.all( + block.shortcuts.shortcuts.map(async (shortcut) => ({ + ...shortcut, + url: await modWebviewLink(shortcut.url, lang), + })) + ) + return ( + + ) + default: + return null + } + }) + ) } diff --git a/apps/scandic-web/components/Webviews/LoyaltyPage/index.tsx b/apps/scandic-web/components/Webviews/LoyaltyPage/index.tsx index b14563772..9203e16ed 100644 --- a/apps/scandic-web/components/Webviews/LoyaltyPage/index.tsx +++ b/apps/scandic-web/components/Webviews/LoyaltyPage/index.tsx @@ -10,7 +10,8 @@ import Blocks from "./Blocks" import styles from "./loyaltyPage.module.css" export default async function AboutScandicFriends() { - const loyaltyPageRes = await serverClient().contentstack.loyaltyPage.get() + const caller = await serverClient() + const loyaltyPageRes = await caller.contentstack.loyaltyPage.get() if (!loyaltyPageRes) { return null diff --git a/apps/scandic-web/constants/booking.ts b/apps/scandic-web/constants/booking.ts index f99aa687e..4d125050d 100644 --- a/apps/scandic-web/constants/booking.ts +++ b/apps/scandic-web/constants/booking.ts @@ -10,6 +10,8 @@ import BedWallExtraIcon from "@scandic-hotels/design-system/Icons/BedWallExtraIc import type { IconProps } from "@scandic-hotels/design-system/Icons" +import type { JSX } from "react"; + export enum BookingStatusEnum { BookingCompleted = "BookingCompleted", Cancelled = "Cancelled", diff --git a/apps/scandic-web/hooks/useClickOutside.ts b/apps/scandic-web/hooks/useClickOutside.ts index b9862c059..e0bf1d7f1 100644 --- a/apps/scandic-web/hooks/useClickOutside.ts +++ b/apps/scandic-web/hooks/useClickOutside.ts @@ -1,7 +1,7 @@ import { useEffect } from "react" export default function useClickOutside( - ref: React.RefObject, + ref: React.RefObject, isOpen: boolean, callback: () => void ) { diff --git a/apps/scandic-web/hooks/useScrollToTop.ts b/apps/scandic-web/hooks/useScrollToTop.ts index a39dbac9e..60ca9dfac 100644 --- a/apps/scandic-web/hooks/useScrollToTop.ts +++ b/apps/scandic-web/hooks/useScrollToTop.ts @@ -2,7 +2,7 @@ import { type RefObject, useEffect, useState } from "react" interface UseScrollToTopProps { threshold: number - elementRef?: RefObject + elementRef?: RefObject refScrollable?: boolean } diff --git a/apps/scandic-web/hooks/useStickyPosition.ts b/apps/scandic-web/hooks/useStickyPosition.ts index f86ef54a4..483e11fca 100644 --- a/apps/scandic-web/hooks/useStickyPosition.ts +++ b/apps/scandic-web/hooks/useStickyPosition.ts @@ -12,7 +12,7 @@ import { debounce } from "@/utils/debounce" import { useIsLangLive } from "./useIsLangLive" interface UseStickyPositionProps { - ref?: React.RefObject + ref?: React.RefObject name?: StickyElementNameEnum group?: string } diff --git a/apps/scandic-web/i18n/index.ts b/apps/scandic-web/i18n/index.ts index 078a48d76..150637622 100644 --- a/apps/scandic-web/i18n/index.ts +++ b/apps/scandic-web/i18n/index.ts @@ -17,7 +17,7 @@ export async function getMessages(lang: Lang): Promise> { } export async function getIntl(options?: { lang: Lang | undefined }) { - const lang = options?.lang || getLang() + const lang = options?.lang || (await getLang()) if (!instances[lang]) { const messages = await getMessages(lang) diff --git a/apps/scandic-web/i18n/serverContext.ts b/apps/scandic-web/i18n/serverContext.ts index c7103d552..e3ae3fa33 100644 --- a/apps/scandic-web/i18n/serverContext.ts +++ b/apps/scandic-web/i18n/serverContext.ts @@ -25,9 +25,10 @@ export function setLang(newLang: Lang) { /** * Get the global language set for the current request */ -export function getLang(): Lang { +export async function getLang(): Promise { const contextLang = getRef().current - const headerLang = headers().get("x-lang") as Lang + const headersList = await headers() + const headerLang = headersList.get("x-lang") as Lang const l = contextLang || headerLang || Lang.en return l diff --git a/apps/scandic-web/lib/trpc/memoizedRequests/index.ts b/apps/scandic-web/lib/trpc/memoizedRequests/index.ts index 2f894fb3a..f5047deed 100644 --- a/apps/scandic-web/lib/trpc/memoizedRequests/index.ts +++ b/apps/scandic-web/lib/trpc/memoizedRequests/index.ts @@ -23,27 +23,32 @@ import type { GetHotelsByCSFilterInput } from "@/server/routers/hotels/input" import type { GetSavedPaymentCardsInput } from "@/server/routers/user/input" export const getLocations = cache(async function getMemoizedLocations() { - const lang = getLang() - return serverClient().hotel.locations.get({ lang }) + const lang = await getLang() + const caller = await serverClient() + return caller.hotel.locations.get({ lang }) }) export const getProfile = cache(async function getMemoizedProfile() { - return serverClient().user.get() + const caller = await serverClient() + return caller.user.get() }) export const getName = cache(async function getMemoizedName() { - return serverClient().user.name() + const caller = await serverClient() + return caller.user.name() }) export const getProfileSafely = cache( async function getMemoizedProfileSafely() { - return serverClient().user.getSafely() + const caller = await serverClient() + return caller.user.getSafely() } ) export const getProfileWithExtendedPartnerData = cache( async function getMemoizedProfileWithPartnerData() { - return serverClient().user.getWithExtendedPartnerData() + const caller = await serverClient() + return caller.user.getWithExtendedPartnerData() } ) @@ -51,32 +56,37 @@ export const getSavedPaymentCardsSafely = cache( async function getMemoizedSavedPaymentCardsSafely( input: GetSavedPaymentCardsInput ) { - return serverClient().user.safePaymentCards(input) + const caller = await serverClient() + return caller.user.safePaymentCards(input) } ) export const getMembershipLevel = cache( async function getMemoizedMembershipLevel() { - return serverClient().user.membershipLevel() + const caller = await serverClient() + return caller.user.membershipLevel() } ) export const getMembershipLevelSafely = cache( async function getMemoizedMembershipLevelSafely() { - return serverClient().user.safeMembershipLevel() + const caller = await serverClient() + return caller.user.safeMembershipLevel() } ) export const getMembershipCards = cache( async function getMemoizedMembershipCards() { - return serverClient().user.membershipCards() + const caller = await serverClient() + return caller.user.membershipCards() } ) export const getHotelsByCSFilter = cache(async function getMemoizedHotels( input: GetHotelsByCSFilterInput ) { - return serverClient().hotel.hotels.byCSFilter.get(input) + const caller = await serverClient() + return caller.hotel.hotels.byCSFilter.get(input) }) export const getHotel = cache(async function getMemoizedHotelData( @@ -85,60 +95,71 @@ export const getHotel = cache(async function getMemoizedHotelData( if (!input.isCardOnlyPayment) { input.isCardOnlyPayment = false } - return serverClient().hotel.get(input) + const caller = await serverClient() + return caller.hotel.get(input) }) export const getHotelPage = cache(async function getMemoizedHotelPage() { - return serverClient().contentstack.hotelPage.get() + const caller = await serverClient() + return caller.contentstack.hotelPage.get() }) export const getFooter = cache(async function getMemoizedFooter() { - return serverClient().contentstack.base.footer() + const caller = await serverClient() + return caller.contentstack.base.footer() }) export const getHeader = cache(async function getMemoizedHeader() { - return serverClient().contentstack.base.header() + const caller = await serverClient() + return caller.contentstack.base.header() }) export const getCurrentHeader = cache(async function getMemoizedCurrentHeader( lang: Lang ) { - return serverClient().contentstack.base.currentHeader({ lang }) + const caller = await serverClient() + return caller.contentstack.base.currentHeader({ lang }) }) export const getCurrentFooter = cache(async function getMemoizedCurrentFooter( lang: Lang ) { - return serverClient().contentstack.base.currentFooter({ lang }) + const caller = await serverClient() + return caller.contentstack.base.currentFooter({ lang }) }) export const getSiteConfig = cache(async function getMemoizedSiteConfig( lang: Lang ) { - return serverClient().contentstack.base.siteConfig({ lang }) + const caller = await serverClient() + return caller.contentstack.base.siteConfig({ lang }) }) export const getBreakfastPackages = cache( async function getMemoizedBreakfastPackages(input: BreackfastPackagesInput) { - return serverClient().hotel.packages.breakfast(input) + const caller = await serverClient() + return caller.hotel.packages.breakfast(input) } ) export const getAncillaryPackages = cache( async function getMemoizedAncillaryPackages(input: AncillaryPackagesInput) { - return serverClient().hotel.packages.ancillary(input) + const caller = await serverClient() + return caller.hotel.packages.ancillary(input) } ) export const getPackages = cache(async function getMemoizedPackages( input: PackagesInput ) { - return serverClient().hotel.packages.get(input) + const caller = await serverClient() + return caller.hotel.packages.get(input) }) export const getBookingConfirmation = cache( async function getMemoizedBookingConfirmation(refId: string) { - return serverClient().booking.get({ refId }) + const caller = await serverClient() + return caller.booking.get({ refId }) } ) @@ -148,7 +169,8 @@ export const findBooking = cache(async function getMemoizedFindBooking( firstName: string, email: string ) { - return serverClient().booking.findBooking({ + const caller = await serverClient() + return caller.booking.findBooking({ confirmationNumber, lastName, firstName, @@ -158,7 +180,8 @@ export const findBooking = cache(async function getMemoizedFindBooking( export const getLinkedReservations = cache( async function getMemoizedLinkedReservations(refId: string) { - return serverClient().booking.linkedReservations({ + const caller = await serverClient() + return caller.booking.linkedReservations({ refId, }) } @@ -166,13 +189,15 @@ export const getLinkedReservations = cache( export const getCityCoordinates = cache( async function getMemoizedCityCoordinates(input: CityCoordinatesInput) { - return serverClient().hotel.map.city(input) + const caller = await serverClient() + return caller.hotel.map.city(input) } ) export const getCurrentRewards = cache( async function getMemoizedCurrentRewards() { - return serverClient().contentstack.rewards.current() + const caller = await serverClient() + return caller.contentstack.rewards.current() } ) @@ -181,7 +206,8 @@ export const getMeetingRooms = cache( hotelId: string language: Lang }) { - return serverClient().hotel.meetingRooms(input) + const caller = await serverClient() + return caller.hotel.meetingRooms(input) } ) @@ -190,71 +216,82 @@ export const getAdditionalData = cache( hotelId: string language: Lang }) { - return serverClient().hotel.additionalData(input) + const caller = await serverClient() + return caller.hotel.additionalData(input) } ) export const getDestinationOverviewPage = cache( async function getMemoizedDestinationOverviewPage() { - return serverClient().contentstack.destinationOverviewPage.get() + const caller = await serverClient() + return caller.contentstack.destinationOverviewPage.get() } ) export const getDestinationsList = cache( async function getMemoizedDestinationsList() { - return serverClient().contentstack.destinationOverviewPage.destinations.get() + const caller = await serverClient() + return caller.contentstack.destinationOverviewPage.destinations.get() } ) export const getDestinationCountryPage = cache( async function getMemoizedDestinationCountryPage() { - return serverClient().contentstack.destinationCountryPage.get() + const caller = await serverClient() + return caller.contentstack.destinationCountryPage.get() } ) export const getDestinationCityPagesByCountry = cache( async function getMemoizedDestinationCityPagesByCountry(country: Country) { - return serverClient().contentstack.destinationCountryPage.cityPages({ + const caller = await serverClient() + return caller.contentstack.destinationCountryPage.cityPages({ country, }) } ) export const getHotelsByCountry = cache( async function getMemoizedHotelsByCountry(country: Country) { - return serverClient().hotel.hotels.byCountry.get({ + const caller = await serverClient() + return caller.hotel.hotels.byCountry.get({ country, }) } ) export const getHotelsByCityIdentifier = cache( async function getMemoizedHotelsByCityIdentifier(cityIdentifier: string) { - return serverClient().hotel.hotels.byCityIdentifier.get({ + const caller = await serverClient() + return caller.hotel.hotels.byCityIdentifier.get({ cityIdentifier, }) } ) export const getDestinationsMapData = cache( async function getMemoizedDestinationsMapData() { - return serverClient().hotel.hotels.getDestinationsMapData() + const caller = await serverClient() + return caller.hotel.hotels.getDestinationsMapData() } ) export const getDestinationCityPage = cache( async function getMemoizedDestinationCityPage() { - return serverClient().contentstack.destinationCityPage.get() + const caller = await serverClient() + return caller.contentstack.destinationCityPage.get() } ) export const getStartPage = cache(async function getMemoizedStartPage() { - return serverClient().contentstack.startPage.get() + const caller = await serverClient() + return caller.contentstack.startPage.get() }) export const getPageSettings = cache(async function getMemoizedPageSettings( lang: Lang ) { - return serverClient().contentstack.pageSettings.get({ lang }) + const caller = await serverClient() + return caller.contentstack.pageSettings.get({ lang }) }) export const isBookingWidgetHidden = cache( async function isMemoizedBookingWidgetHidden() { - const lang = getLang() + const lang = await getLang() const [pageSettingsResult, siteConfigResults] = await Promise.allSettled([ getPageSettings(lang), getSiteConfig(lang), @@ -277,21 +314,23 @@ export const isBookingWidgetHidden = cache( export const getPageSettingsBookingCode = cache( async function getMemoizedPageSettingsBookingCode() { - const lang = getLang() + const lang = await getLang() const pageSettings = await getPageSettings(lang) return pageSettings?.page.settings.booking_code ?? "" } ) export const getJobylonFeed = cache(async function getMemoizedJobylonFeed() { - return serverClient().partner.jobylon.feed.get() + const caller = await serverClient() + return caller.partner.jobylon.feed.get() }) export const getJumpToData = cache(async function getMemoizedJumpToData() { - const lang = getLang() + const lang = await getLang() + const caller = await serverClient() const [locationsResults, urlsResults] = await Promise.allSettled([ getLocations(), - serverClient().hotel.locations.urls({ lang }), + caller.hotel.locations.urls({ lang }), ]) if ( @@ -367,7 +406,8 @@ export const getSelectedRoomsAvailabilityEnterDetails = cache( async function getMemoizedSelectedRoomsAvailability( input: RoomsAvailabilityExtendedInputSchema ) { - const result = await serverClient().hotel.availability.enterDetails(input) + const caller = await serverClient() + const result = await caller.hotel.availability.enterDetails(input) if (typeof result === "string") { redirect(result) diff --git a/apps/scandic-web/lib/trpc/server.ts b/apps/scandic-web/lib/trpc/server.ts index 70a417749..4ecd82813 100644 --- a/apps/scandic-web/lib/trpc/server.ts +++ b/apps/scandic-web/lib/trpc/server.ts @@ -11,8 +11,9 @@ import { createCallerFactory } from "@/server/trpc" const createCaller = createCallerFactory(appRouter) -export function serverClient() { - return createCaller(createContext(), { +export async function serverClient() { + const ctx = await createContext() + return createCaller(ctx, { onError: ({ ctx, error, input, path, type }) => { console.error(`[serverClient] error for ${type}: ${path}`, error) diff --git a/apps/scandic-web/middlewares/authRequired.ts b/apps/scandic-web/middlewares/authRequired.ts index 4384b1609..b663cc724 100644 --- a/apps/scandic-web/middlewares/authRequired.ts +++ b/apps/scandic-web/middlewares/authRequired.ts @@ -90,7 +90,7 @@ export const middleware = auth(async (request) => { } console.log(`[authRequired] redirecting to: ${redirectUrl}`, redirectOpts) return NextResponse.redirect(redirectUrl, redirectOpts) -}) as NextMiddleware // See comment above +}) as unknown as NextMiddleware // See comment above export const matcher: MiddlewareMatcher = (request) => { return authRequired.includes(request.nextUrl.pathname) diff --git a/apps/scandic-web/next.config.js b/apps/scandic-web/next.config.js index b8ebea407..6744e6688 100644 --- a/apps/scandic-web/next.config.js +++ b/apps/scandic-web/next.config.js @@ -22,7 +22,6 @@ const nextConfig = { eslint: { ignoreDuringBuilds: true }, trailingSlash: false, experimental: { - instrumentationHook: true, serverActions: { allowedOrigins: [ "*--web-scandic-hotels.netlify.app", @@ -35,7 +34,7 @@ const nextConfig = { }, swcPlugins: [ [ - "@formatjs/swc-plugin-experimental", + "@swc/plugin-formatjs", { ast: true, }, diff --git a/apps/scandic-web/package.json b/apps/scandic-web/package.json index 80139d05a..786a45580 100644 --- a/apps/scandic-web/package.json +++ b/apps/scandic-web/package.json @@ -50,6 +50,7 @@ "@react-aria/ssr": "^3.9.8", "@scandic-hotels/design-system": "workspace:*", "@sentry/nextjs": "^8.41.0", + "@swc/plugin-formatjs": "^3.2.2", "@t3-oss/env-nextjs": "^0.13.4", "@tanstack/react-query": "^5.75.5", "@tanstack/react-query-devtools": "^5.75.5", @@ -90,12 +91,12 @@ "md5": "^2.3.0", "motion": "^12.10.0", "nanoid": "^5.1.5", - "next": "^14.2.25", - "next-auth": "5.0.0-beta.19", - "react": "^18", + "next": "15.3.2", + "next-auth": "5.0.0-beta.27", + "react": "19.1.0", "react-aria-components": "^1.8.0", "react-day-picker": "^9.6.7", - "react-dom": "^18", + "react-dom": "19.1.0", "react-feather": "^2.0.10", "react-focus-lock": "^2.13.6", "react-hook-form": "^7.56.2", @@ -114,7 +115,6 @@ }, "devDependencies": { "@formatjs/cli": "^6.7.1", - "@formatjs/swc-plugin-experimental": "0.4.0", "@lokalise/node-api": "^14.0.0", "@scandic-hotels/typescript-config": "workspace:*", "@svgr/webpack": "^8.1.0", @@ -127,15 +127,15 @@ "@types/jsonwebtoken": "^9", "@types/lodash-es": "^4", "@types/node": "^20", - "@types/react": "^18", - "@types/react-dom": "^18", + "@types/react": "19.1.0", + "@types/react-dom": "19.1.0", "@typescript-eslint/eslint-plugin": "^8.32.0", "@typescript-eslint/parser": "^8.32.0", "adm-zip": "^0.5.16", "cypress": "^14.3.3", "dotenv": "^16.5.0", "eslint": "^8", - "eslint-config-next": "^14.0.4", + "eslint-config-next": "15.3.2", "eslint-plugin-formatjs": "^5.3.1", "eslint-plugin-import": "^2.31.0", "eslint-plugin-simple-import-sort": "^12.1.1", @@ -146,7 +146,6 @@ "lint-staged": "^15.5.2", "netlify-plugin-cypress": "^2.2.1", "prettier": "^3.5.3", - "react-material-symbols": "^4.4.0", "schema-dts": "^1.1.5", "start-server-and-test": "^2.0.11", "ts-jest": "^29.3.2", @@ -157,5 +156,9 @@ }, "engines": { "node": "22" + }, + "resolutions": { + "@types/react": "19.1.0", + "@types/react-dom": "19.1.0" } } diff --git a/apps/scandic-web/providers/AddAncillaryProvider.tsx b/apps/scandic-web/providers/AddAncillaryProvider.tsx index b67f9737d..349b3cb54 100644 --- a/apps/scandic-web/providers/AddAncillaryProvider.tsx +++ b/apps/scandic-web/providers/AddAncillaryProvider.tsx @@ -22,7 +22,7 @@ export function AddAncillaryProvider({ booking: Room children: React.ReactNode }) { - const storeRef = useRef() + const storeRef = useRef(undefined) if (!storeRef.current) { storeRef.current = createAddAncillaryStore(booking, ancillaries) } diff --git a/apps/scandic-web/providers/BookingConfirmationProvider.tsx b/apps/scandic-web/providers/BookingConfirmationProvider.tsx index c41877cf4..88928beb7 100644 --- a/apps/scandic-web/providers/BookingConfirmationProvider.tsx +++ b/apps/scandic-web/providers/BookingConfirmationProvider.tsx @@ -23,7 +23,7 @@ export default function BookingConfirmationProvider({ vat, }: BookingConfirmationProviderProps) { const intl = useIntl() - const storeRef = useRef() + const storeRef = useRef(undefined) if (!storeRef.current) { const totalBookingPrice = rooms.reduce((acc, room) => { diff --git a/apps/scandic-web/providers/DestinationDataProvider/index.tsx b/apps/scandic-web/providers/DestinationDataProvider/index.tsx index b920a7cab..feefc8f95 100644 --- a/apps/scandic-web/providers/DestinationDataProvider/index.tsx +++ b/apps/scandic-web/providers/DestinationDataProvider/index.tsx @@ -17,7 +17,7 @@ export default function DestinationDataProvider({ sortItems, children, }: DestinationDataProviderProps) { - const storeRef = useRef() + const storeRef = useRef(undefined) const pathname = usePathname() if (!storeRef.current) { diff --git a/apps/scandic-web/providers/EnterDetailsProvider.tsx b/apps/scandic-web/providers/EnterDetailsProvider.tsx index f86b27773..1cd1ee724 100644 --- a/apps/scandic-web/providers/EnterDetailsProvider.tsx +++ b/apps/scandic-web/providers/EnterDetailsProvider.tsx @@ -37,7 +37,7 @@ export default function EnterDetailsProvider({ // and since we read from SessionStorage we need to delay // rendering the form until that has been done. const [hasInitializedStore, setHasInitializedStore] = useState(false) - const storeRef = useRef() + const storeRef = useRef(undefined) if (!storeRef.current) { const initialData: InitialState = { booking, diff --git a/apps/scandic-web/providers/MyStay.tsx b/apps/scandic-web/providers/MyStay.tsx index e11c73543..5a256d680 100644 --- a/apps/scandic-web/providers/MyStay.tsx +++ b/apps/scandic-web/providers/MyStay.tsx @@ -39,7 +39,7 @@ export default function MyStayProvider({ roomCategories, savedCreditCards, }: React.PropsWithChildren) { - const storeRef = useRef() + const storeRef = useRef(undefined) const intl = useIntl() const { data, error, isFetching, isFetchedAfterMount } = diff --git a/apps/scandic-web/server/context.ts b/apps/scandic-web/server/context.ts index ddf7f762f..a81690365 100644 --- a/apps/scandic-web/server/context.ts +++ b/apps/scandic-web/server/context.ts @@ -38,12 +38,12 @@ export function createContextInner(opts: CreateContextOptions) { * This is the actual context you'll use in your router * @link https://trpc.io/docs/context **/ -export const createContext = cache(function () { - const h = headers() +export const createContext = cache(async function () { + const headersList = await headers() - const cookie = cookies() + const cookie = await cookies() const webviewTokenCookie = cookie.get("webviewToken") - const loginType = h.get("loginType") + const loginType = headersList.get("loginType") return createContextInner({ auth: async () => { @@ -60,13 +60,13 @@ export const createContext = cache(function () { } as Session) ) }, - lang: h.get("x-lang") as Lang, - pathname: h.get("x-pathname")!, - uid: h.get("x-uid"), - url: h.get("x-url")!, + lang: headersList.get("x-lang") as Lang, + pathname: headersList.get("x-pathname")!, + uid: headersList.get("x-uid"), + url: headersList.get("x-url")!, webToken: webviewTokenCookie?.value, - contentType: h.get("x-contenttype")!, + contentType: headersList.get("x-contenttype")!, }) }) -export type Context = ReturnType +export type Context = Awaited> diff --git a/apps/scandic-web/server/routers/partners/sas/getSasToken.ts b/apps/scandic-web/server/routers/partners/sas/getSasToken.ts index b6de657a5..f988422ec 100644 --- a/apps/scandic-web/server/routers/partners/sas/getSasToken.ts +++ b/apps/scandic-web/server/routers/partners/sas/getSasToken.ts @@ -2,8 +2,8 @@ import { cookies } from "next/headers" import { SAS_TOKEN_STORAGE_KEY } from "@/app/[lang]/(partner)/(sas)/(protected)/sas-x-scandic/sasUtils" -export function getSasToken() { - const cookieStore = cookies() +export async function getSasToken() { + const cookieStore = await cookies() const tokenCookie = cookieStore.get(SAS_TOKEN_STORAGE_KEY) const sasAuthToken = tokenCookie?.value diff --git a/apps/scandic-web/server/routers/partners/sas/linkAccount.ts b/apps/scandic-web/server/routers/partners/sas/linkAccount.ts index 8489bddb8..0eb732106 100644 --- a/apps/scandic-web/server/routers/partners/sas/linkAccount.ts +++ b/apps/scandic-web/server/routers/partners/sas/linkAccount.ts @@ -22,8 +22,8 @@ const outputSchema = z.object({ export const linkAccount = protectedProcedure .output(outputSchema) .mutation(async function ({ ctx }) { - const sasAuthToken = getSasToken() - const { referenceId } = getOTPState() + const sasAuthToken = await getSasToken() + const { referenceId } = await getOTPState() console.log("[SAS] link account") diff --git a/apps/scandic-web/server/routers/partners/sas/otp/getOTPState.ts b/apps/scandic-web/server/routers/partners/sas/otp/getOTPState.ts index fdf486afc..fa700519a 100644 --- a/apps/scandic-web/server/routers/partners/sas/otp/getOTPState.ts +++ b/apps/scandic-web/server/routers/partners/sas/otp/getOTPState.ts @@ -10,8 +10,9 @@ const otpStateSchema = z.object({ export type OtpState = z.infer -export function getOTPState() { - const otpState = cookies().get(SAS_REQUEST_OTP_STATE_STORAGE_COOKIE_NAME) +export async function getOTPState() { + const cookieStore = await cookies() + const otpState = cookieStore.get(SAS_REQUEST_OTP_STATE_STORAGE_COOKIE_NAME) return otpStateSchema.parse(JSON.parse(otpState?.value ?? "{}")) } diff --git a/apps/scandic-web/server/routers/partners/sas/otp/request/requestOtp.ts b/apps/scandic-web/server/routers/partners/sas/otp/request/requestOtp.ts index e3d2fad7b..54fce9dc2 100644 --- a/apps/scandic-web/server/routers/partners/sas/otp/request/requestOtp.ts +++ b/apps/scandic-web/server/routers/partners/sas/otp/request/requestOtp.ts @@ -41,7 +41,7 @@ const outputSchema = z.union([successSchema, failureSchema]) export const requestOtp = protectedProcedure .output(outputSchema) .mutation(async function () { - const sasAuthToken = getSasToken() + const sasAuthToken = await getSasToken() if (!sasAuthToken) { throw createError("AUTH_TOKEN_NOT_FOUND") @@ -113,14 +113,15 @@ async function fetchRequestOtp({ sasAuthToken }: { sasAuthToken: string }) { }) } -function setSASOtpCookie({ +async function setSASOtpCookie({ referenceId, databaseUUID, }: { referenceId: string databaseUUID: string }) { - cookies().set( + const cookieStore = await cookies() + cookieStore.set( SAS_REQUEST_OTP_STATE_STORAGE_COOKIE_NAME, JSON.stringify({ referenceId: referenceId, diff --git a/apps/scandic-web/server/routers/partners/sas/otp/verify/verifyOtp.ts b/apps/scandic-web/server/routers/partners/sas/otp/verify/verifyOtp.ts index c4c1caae3..9539479ba 100644 --- a/apps/scandic-web/server/routers/partners/sas/otp/verify/verifyOtp.ts +++ b/apps/scandic-web/server/routers/partners/sas/otp/verify/verifyOtp.ts @@ -34,7 +34,7 @@ export const verifyOtp = protectedProcedure .input(inputSchema) .output(outputSchema) .mutation(async function ({ input }) { - const sasAuthToken = getSasToken() + const sasAuthToken = await getSasToken() if (!sasAuthToken) { throw createError("AUTH_TOKEN_NOT_FOUND") @@ -70,8 +70,8 @@ export const verifyOtp = protectedProcedure }) async function fetchVerifyOtp(input: z.infer) { - const sasAuthToken = getSasToken() - const { referenceId, databaseUUID } = getOTPState() + const sasAuthToken = await getSasToken() + const { referenceId, databaseUUID } = await getOTPState() return await fetch( `${env.SAS_API_ENDPOINT}/api/scandic-partnership/customer/verify-otp`, diff --git a/apps/scandic-web/server/routers/partners/sas/performLevelUpgrade.ts b/apps/scandic-web/server/routers/partners/sas/performLevelUpgrade.ts index 128fe56c2..41c40db07 100644 --- a/apps/scandic-web/server/routers/partners/sas/performLevelUpgrade.ts +++ b/apps/scandic-web/server/routers/partners/sas/performLevelUpgrade.ts @@ -24,7 +24,7 @@ const outputSchema = z.union([matchedSchema, notMatchedSchema]) export const performLevelUpgrade = protectedProcedure .output(outputSchema) .mutation(async function ({ ctx }) { - const cookieStore = cookies() + const cookieStore = await cookies() const sasTierMatch = cookieStore.get("sasTierMatch") if (sasTierMatch) { return { tierMatchState: "cached" } diff --git a/apps/scandic-web/server/routers/partners/sas/transferPoints.ts b/apps/scandic-web/server/routers/partners/sas/transferPoints.ts index 4a3dabcd8..ac30bfb9e 100644 --- a/apps/scandic-web/server/routers/partners/sas/transferPoints.ts +++ b/apps/scandic-web/server/routers/partners/sas/transferPoints.ts @@ -17,7 +17,7 @@ export const transferPoints = protectedProcedure .output(outputSchema) .input(transferPointsInputSchema) .mutation(async function ({ ctx, input }) { - const sasAuthToken = getSasToken() + const sasAuthToken = await getSasToken() console.log("[SAS] transfer points") console.log({ sasAuthToken }) diff --git a/apps/scandic-web/server/routers/partners/sas/unlinkAccount.ts b/apps/scandic-web/server/routers/partners/sas/unlinkAccount.ts index 4b7108d83..7a5b6ddb0 100644 --- a/apps/scandic-web/server/routers/partners/sas/unlinkAccount.ts +++ b/apps/scandic-web/server/routers/partners/sas/unlinkAccount.ts @@ -13,8 +13,8 @@ const outputSchema = z.object({ export const unlinkAccount = protectedProcedure .output(outputSchema) .mutation(async function ({ ctx }) { - const sasAuthToken = getSasToken() - const { referenceId } = getOTPState() + const sasAuthToken = await getSasToken() + const { referenceId } = await getOTPState() const apiResponse = await api.post(api.endpoints.v1.Profile.unlink, { headers: { diff --git a/apps/scandic-web/services/dataCache/MemoryCache/UnstableCache/cacheOrGet.ts b/apps/scandic-web/services/dataCache/MemoryCache/UnstableCache/cacheOrGet.ts deleted file mode 100644 index cf5085289..000000000 --- a/apps/scandic-web/services/dataCache/MemoryCache/UnstableCache/cacheOrGet.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { revalidateTag, unstable_cache } from "next/cache" - -import { - type CacheTime, - type DataCache, - getCacheTimeInSeconds, -} from "@/services/dataCache/Cache" - -import { - type CacheOrGetOptions, - shouldGetFromCache, -} from "../../cacheOrGetOptions" -import { cacheLogger } from "../../logger" - -export const cacheOrGet: DataCache["cacheOrGet"] = async ( - key: string | string[], - callback: () => Promise, - ttl: CacheTime, - opts?: CacheOrGetOptions -): Promise => { - if (!Array.isArray(key)) { - key = [key] - } - - const perf = performance.now() - if (!shouldGetFromCache(opts)) { - revalidateTag(key[0]) - } - - const res = await unstable_cache(callback, key, { - revalidate: getCacheTimeInSeconds(ttl), - tags: key, - })() - - const size = JSON.stringify(res).length / (1024 * 1024) - cacheLogger.debug(`'${key}': ${size}mb`) - if (size > 5) { - cacheLogger.warn(`'${key}' is larger than 5mb!`) - } - cacheLogger.debug(`'${key}' took ${(performance.now() - perf).toFixed(2)}ms`) - - return res -} diff --git a/apps/scandic-web/services/dataCache/MemoryCache/UnstableCache/deleteKey.ts b/apps/scandic-web/services/dataCache/MemoryCache/UnstableCache/deleteKey.ts deleted file mode 100644 index 1624a4c15..000000000 --- a/apps/scandic-web/services/dataCache/MemoryCache/UnstableCache/deleteKey.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { revalidateTag } from "next/cache" - -export async function deleteKey(key: string) { - revalidateTag(key) -} diff --git a/apps/scandic-web/services/dataCache/MemoryCache/UnstableCache/get.ts b/apps/scandic-web/services/dataCache/MemoryCache/UnstableCache/get.ts deleted file mode 100644 index f2de1e01a..000000000 --- a/apps/scandic-web/services/dataCache/MemoryCache/UnstableCache/get.ts +++ /dev/null @@ -1,14 +0,0 @@ -import type { DataCache } from "@/services/dataCache/Cache" - -/** - * This function is not implemented for unstable_cache due to underlying cache implementation. - * @see cacheOrGet - * @param _key - * @returns - */ -export const get: DataCache["get"] = async ( - _key: string -): Promise => { - console.warn("UnstableCache.get is not implemented, use cacheOrGet") - return undefined -} diff --git a/apps/scandic-web/services/dataCache/MemoryCache/UnstableCache/index.ts b/apps/scandic-web/services/dataCache/MemoryCache/UnstableCache/index.ts deleted file mode 100644 index 7a25e367c..000000000 --- a/apps/scandic-web/services/dataCache/MemoryCache/UnstableCache/index.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { cacheOrGet } from "./cacheOrGet" -import { deleteKey } from "./deleteKey" -import { get } from "./get" -import { set } from "./set" - -import type { DataCache } from "@/services/dataCache/Cache" - -export async function createUnstableCache(): Promise { - return { type: "unstable-cache", cacheOrGet, deleteKey, get, set } -} diff --git a/apps/scandic-web/services/dataCache/MemoryCache/UnstableCache/set.ts b/apps/scandic-web/services/dataCache/MemoryCache/UnstableCache/set.ts deleted file mode 100644 index 7cb20f5ec..000000000 --- a/apps/scandic-web/services/dataCache/MemoryCache/UnstableCache/set.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { type CacheTime, type DataCache } from "@/services/dataCache/Cache" - -/** - * This function is not implemented for unstable_cache due to underlying cache implementation. - * @see cacheOrGet - * @param _key - * @returns - */ -export const set: DataCache["set"] = async ( - _key: string, - _data: T, - _ttl: CacheTime -): Promise => { - console.warn("UnstableCache.set is not implemented, use cacheOrGet") -} diff --git a/apps/scandic-web/services/dataCache/MemoryCache/createMemoryCache.ts b/apps/scandic-web/services/dataCache/MemoryCache/createMemoryCache.ts index 7612104b5..126ef13cc 100644 --- a/apps/scandic-web/services/dataCache/MemoryCache/createMemoryCache.ts +++ b/apps/scandic-web/services/dataCache/MemoryCache/createMemoryCache.ts @@ -1,17 +1,7 @@ -import { isEdge } from "@/utils/isEdge" - import { createInMemoryCache } from "./InMemoryCache" -import { createUnstableCache } from "./UnstableCache" import type { DataCache } from "@/services/dataCache/Cache" export function createMemoryCache(): Promise { - if (isEdge) { - /** - * unstable_cache is not available on the edge runtime - */ - return createInMemoryCache() - } - - return createUnstableCache() + return createInMemoryCache() } diff --git a/apps/scandic-web/services/warmup/warmupHotelData.ts b/apps/scandic-web/services/warmup/warmupHotelData.ts index 1c9698dc2..2853f2fcf 100644 --- a/apps/scandic-web/services/warmup/warmupHotelData.ts +++ b/apps/scandic-web/services/warmup/warmupHotelData.ts @@ -14,7 +14,8 @@ export const warmupHotelData = } try { - await serverClient().hotel.hotels.getDestinationsMapData({ + const caller = await serverClient() + await caller.hotel.hotels.getDestinationsMapData({ lang, warmup: true, }) diff --git a/apps/scandic-web/stores/sticky-position.ts b/apps/scandic-web/stores/sticky-position.ts index 243a358a1..5d558a297 100644 --- a/apps/scandic-web/stores/sticky-position.ts +++ b/apps/scandic-web/stores/sticky-position.ts @@ -11,7 +11,7 @@ export enum StickyElementNameEnum { export interface StickyElement { height: number - ref: React.RefObject + ref: React.RefObject group: string priority: number name: StickyElementNameEnum @@ -20,11 +20,11 @@ export interface StickyElement { interface StickyStore { stickyElements: StickyElement[] registerSticky: ( - ref: React.RefObject, + ref: React.RefObject, name: StickyElementNameEnum, group: string ) => void - unregisterSticky: (ref: React.RefObject) => void + unregisterSticky: (ref: React.RefObject) => void updateHeights: () => void getAllElements: () => Array } diff --git a/apps/scandic-web/types/components/bookingWidget/index.ts b/apps/scandic-web/types/components/bookingWidget/index.ts index 8172b5ff3..37eb32e6e 100644 --- a/apps/scandic-web/types/components/bookingWidget/index.ts +++ b/apps/scandic-web/types/components/bookingWidget/index.ts @@ -28,12 +28,16 @@ export type BookingWidgetType = VariantProps< export interface BookingWidgetProps { type?: BookingWidgetType - bookingWidgetSearchParams: SearchParams["searchParams"] + bookingWidgetSearchParams: Awaited< + SearchParams["searchParams"] + > } export interface BookingWidgetClientProps { type?: BookingWidgetType - bookingWidgetSearchParams: SearchParams["searchParams"] + bookingWidgetSearchParams: Awaited< + SearchParams["searchParams"] + > pageSettingsBookingCodePromise: Promise | null } diff --git a/apps/scandic-web/types/components/hotelPage/map/interactiveMap.ts b/apps/scandic-web/types/components/hotelPage/map/interactiveMap.ts index 77d3706e0..528ed9bf5 100644 --- a/apps/scandic-web/types/components/hotelPage/map/interactiveMap.ts +++ b/apps/scandic-web/types/components/hotelPage/map/interactiveMap.ts @@ -12,7 +12,7 @@ export interface InteractiveMapProps { pointsOfInterest?: PointOfInterest[] markerInfo?: MarkerInfo mapId: string - closeButton: ReactElement + closeButton: ReactElement fitBounds?: boolean onTilesLoaded?: () => void onActivePoiChange?: (poi: PointOfInterest["name"] | null) => void diff --git a/apps/scandic-web/types/components/hotelReservation/selectHotel/map.ts b/apps/scandic-web/types/components/hotelReservation/selectHotel/map.ts index 28ce1da1c..dfd841560 100644 --- a/apps/scandic-web/types/components/hotelReservation/selectHotel/map.ts +++ b/apps/scandic-web/types/components/hotelReservation/selectHotel/map.ts @@ -5,6 +5,7 @@ import type { Amenities } from "@/types/hotel" import type { ProductTypeCheque } from "@/types/trpc/routers/hotel/availability" import type { HotelResponse } from "@/components/HotelReservation/SelectHotel/helpers" import type { imageSchema } from "@/server/routers/hotels/schemas/image" +import type { SelectHotelParams } from "@/utils/url" import type { CategorizedFilters } from "./hotelFilters" import type { AlternativeHotelsSearchParams, @@ -75,6 +76,8 @@ export interface HotelCardDialogListingProps { } export type SelectHotelMapContainerProps = { - searchParams: SelectHotelSearchParams | AlternativeHotelsSearchParams + booking: SelectHotelParams< + SelectHotelSearchParams | AlternativeHotelsSearchParams + > isAlternativeHotels?: boolean } diff --git a/apps/scandic-web/types/components/hotelReservation/selectHotel/selectHotel.ts b/apps/scandic-web/types/components/hotelReservation/selectHotel/selectHotel.ts index 60273df24..9c05b4b25 100644 --- a/apps/scandic-web/types/components/hotelReservation/selectHotel/selectHotel.ts +++ b/apps/scandic-web/types/components/hotelReservation/selectHotel/selectHotel.ts @@ -1,10 +1,8 @@ import type { Hotel } from "@/types/hotel" import type { Lang } from "@/constants/languages" +import type { SelectHotelParams } from "@/utils/url" import type { SidePeekEnum } from "../sidePeek" -import type { - AlternativeHotelsSearchParams, - SelectHotelSearchParams, -} from "./selectHotelSearchParams" +import type { AlternativeHotelsSearchParams } from "./selectHotelSearchParams" export enum AvailabilityEnum { Available = "Available", @@ -23,9 +21,7 @@ export interface ContactProps { } export interface SelectHotelProps { - params: { - lang: Lang - } - searchParams: SelectHotelSearchParams | AlternativeHotelsSearchParams + booking: SelectHotelParams + lang: Lang isAlternativeHotels?: boolean } diff --git a/apps/scandic-web/types/components/overviewTable.ts b/apps/scandic-web/types/components/overviewTable.ts index 0a242021e..a5d56f54c 100644 --- a/apps/scandic-web/types/components/overviewTable.ts +++ b/apps/scandic-web/types/components/overviewTable.ts @@ -2,6 +2,8 @@ import type { MembershipLevel } from "@/constants/membershipLevels" import type { LoyaltyLevel } from "@/server/routers/contentstack/loyaltyLevel/output" import type { CMSReward } from "../trpc/routers/contentstack/reward" +import type { JSX } from "react"; + export type OverviewTableClientProps = { activeMembership: MembershipLevel | null levels: ComparisonLevel[] diff --git a/apps/scandic-web/types/params.ts b/apps/scandic-web/types/params.ts index ae2a69fcc..841f722ff 100644 --- a/apps/scandic-web/types/params.ts +++ b/apps/scandic-web/types/params.ts @@ -2,11 +2,11 @@ import type { Lang } from "@/constants/languages" import type { PageContentTypeEnum } from "./requests/contentType" export type SearchParams = { - searchParams: S & { [key: string]: string } + searchParams: Promise } export type Params

= { - params: P + params: Promise

} export type LangParams = { diff --git a/apps/scandic-web/types/rte/node.ts b/apps/scandic-web/types/rte/node.ts index 5625e282c..07f3aa5a8 100644 --- a/apps/scandic-web/types/rte/node.ts +++ b/apps/scandic-web/types/rte/node.ts @@ -10,6 +10,8 @@ import type { } from "./attrs" import type { RenderOptions } from "./option" +import type { JSX } from "react"; + export interface RTEDefaultNode { attrs: Attributes children: RTENode[] diff --git a/apps/scandic-web/types/transitionTypes/rte/node.ts b/apps/scandic-web/types/transitionTypes/rte/node.ts index 8dcc45adb..fcf96449b 100644 --- a/apps/scandic-web/types/transitionTypes/rte/node.ts +++ b/apps/scandic-web/types/transitionTypes/rte/node.ts @@ -9,6 +9,8 @@ import type { import type { RTETypeEnum } from "./enums" import type { RenderOptions } from "./option" +import type { JSX } from "react"; + export interface RTEDefaultNode { attrs: Attributes children: RTENode[] diff --git a/apps/scandic-web/utils/appendSlugToPathname.ts b/apps/scandic-web/utils/appendSlugToPathname.ts index 3c9d4119c..5cfd55f56 100644 --- a/apps/scandic-web/utils/appendSlugToPathname.ts +++ b/apps/scandic-web/utils/appendSlugToPathname.ts @@ -2,9 +2,10 @@ import { headers } from "next/headers" import { getLang } from "@/i18n/serverContext" -export function appendSlugToPathname(slug?: string) { - const pathname = headers().get("x-pathname") - const lang = getLang() +export async function appendSlugToPathname(slug?: string) { + const headersList = await headers() + const pathname = headersList.get("x-pathname") + const lang = await getLang() if (!pathname || !slug) { return null diff --git a/apps/scandic-web/utils/generateMetadata.ts b/apps/scandic-web/utils/generateMetadata.ts index 30b3cab2a..48833795b 100644 --- a/apps/scandic-web/utils/generateMetadata.ts +++ b/apps/scandic-web/utils/generateMetadata.ts @@ -18,22 +18,23 @@ export async function generateMetadata({ LangParams & ContentTypeParams & UIDParams, { subpage?: string; filterFromUrl?: string } >) { - const { subpage, filterFromUrl, ...otherSearchParams } = searchParams + const { lang } = await params + const { subpage, filterFromUrl, ...otherSearchParams } = await searchParams // If there are other (real) search params, we don't want to index the page as this will // cause duplicate content issues. const noIndexOnSearchParams = !!Object.keys(otherSearchParams).length - const { metadata, alternates } = - await serverClient().contentstack.metadata.get({ - subpage, - filterFromUrl, - noIndex: noIndexOnSearchParams, - }) + const caller = await serverClient() + const { metadata, alternates } = await caller.contentstack.metadata.get({ + subpage, + filterFromUrl, + noIndex: noIndexOnSearchParams, + }) if (!metadata) { return { robots: { - index: env.isLangLive(params.lang), - follow: env.isLangLive(params.lang), + index: env.isLangLive(lang), + follow: env.isLangLive(lang), }, } } @@ -46,8 +47,8 @@ export async function generateMetadata({ ...metadata, robots: { ...(metadata.robots ?? {}), - index: isIndexable(metadata.robots?.index, params.lang, alternates), - follow: isIndexable(metadata.robots?.follow, params.lang, alternates), + index: isIndexable(metadata.robots?.index, lang, alternates), + follow: isIndexable(metadata.robots?.follow, lang, alternates), }, } } diff --git a/apps/scandic-web/utils/hotelSearchDetails.ts b/apps/scandic-web/utils/hotelSearchDetails.ts index ce96b8714..b15b36253 100644 --- a/apps/scandic-web/utils/hotelSearchDetails.ts +++ b/apps/scandic-web/utils/hotelSearchDetails.ts @@ -5,7 +5,7 @@ import { getLocations } from "@/lib/trpc/memoizedRequests" import { generateChildrenString } from "@/components/HotelReservation/utils" import { safeTry } from "@/utils/safeTry" -import { convertSearchParamsToObj, type SelectHotelParams } from "@/utils/url" +import { type SelectHotelParams } from "@/utils/url" import type { AlternativeHotelsSearchParams, @@ -42,17 +42,9 @@ export async function getHotelSearchDetails< | SelectRateSearchParams | AlternativeHotelsSearchParams, >( - { - searchParams, - }: { - searchParams: T & { - [key: string]: string - } - }, + selectHotelParams: SelectHotelParams, isAlternativeHotels?: boolean ): Promise | null> { - const selectHotelParams = convertSearchParamsToObj(searchParams) - const [locations, error] = await safeTry(getLocations()) if (!locations || error) { return null diff --git a/apps/scandic-web/utils/isLoggedInUser.ts b/apps/scandic-web/utils/isLoggedInUser.ts index 7f5609154..d3b705205 100644 --- a/apps/scandic-web/utils/isLoggedInUser.ts +++ b/apps/scandic-web/utils/isLoggedInUser.ts @@ -8,8 +8,8 @@ import { isValidSession } from "./session" export async function isLoggedInUser(): Promise { const session = await auth() - const cookie = cookies() - const webviewTokenCookie = cookie.get("webviewToken") + const cookieStore = await cookies() + const webviewTokenCookie = cookieStore.get("webviewToken") // We assume we have a valid session if we have a webviewTokenCookie. return isValidSession(session) || !!webviewTokenCookie?.value diff --git a/apps/scandic-web/utils/url.ts b/apps/scandic-web/utils/url.ts index 4fa511a37..12edf4d81 100644 --- a/apps/scandic-web/utils/url.ts +++ b/apps/scandic-web/utils/url.ts @@ -55,7 +55,7 @@ export function searchParamsToRecord(searchParams: URLSearchParams) { export function convertSearchParamsToObj( searchParams: Record -) { +): SelectHotelParams { const searchParamsObject = Object.entries(searchParams).reduce< SelectHotelParams >((acc, [key, value]) => { diff --git a/apps/scandic-web/utils/webviews.ts b/apps/scandic-web/utils/webviews.ts index 7aebb4ca1..561e94162 100644 --- a/apps/scandic-web/utils/webviews.ts +++ b/apps/scandic-web/utils/webviews.ts @@ -6,22 +6,23 @@ import { webviews } from "@/constants/routes/webviews" import type { Lang } from "@/constants/languages" -export function webviewSearchParams() { +export async function webviewSearchParams() { const searchParams = new URLSearchParams() - const loginType = headers().get("loginType") + const headersList = await headers() + const loginType = headersList.get("loginType") if (loginType) { searchParams.set("loginType", loginType) } - const adobeMc = headers().get("adobe_mc") + const adobeMc = headersList.get("adobe_mc") if (adobeMc) { searchParams.set("adobe_mc", adobeMc) } return searchParams } -export function modWebviewLink(url: string, lang: Lang) { - const searchParams = webviewSearchParams() +export async function modWebviewLink(url: string, lang: Lang) { + const searchParams = await webviewSearchParams() const urlWithoutLang = url.replace(`/${lang}`, "") const webviewUrl = `/${lang}/webview${urlWithoutLang}` diff --git a/package.json b/package.json index 22dcee7c4..7bfe3b448 100644 --- a/package.json +++ b/package.json @@ -16,8 +16,8 @@ "packages/*" ], "devDependencies": { - "@types/react": "^18.2.0", - "@types/react-dom": "^18.2.0", + "@types/react": "19.1.0", + "@types/react-dom": "19.1.0", "husky": "^9.1.7", "lint-staged": "^15.2.2", "ts-node": "^10.9.2", diff --git a/packages/design-system/lib/components/ChipButton/ChipButton.stories.tsx b/packages/design-system/lib/components/ChipButton/ChipButton.stories.tsx index 112942e5c..84922bc3f 100644 --- a/packages/design-system/lib/components/ChipButton/ChipButton.stories.tsx +++ b/packages/design-system/lib/components/ChipButton/ChipButton.stories.tsx @@ -1,5 +1,3 @@ -import 'react-material-symbols/rounded' - import type { Meta, StoryObj } from '@storybook/react' import { fn } from '@storybook/test' diff --git a/packages/design-system/lib/components/Icons/MaterialIcon/MaterialIcon.tsx b/packages/design-system/lib/components/Icons/MaterialIcon/MaterialIcon.tsx index c744cf70d..bc7954be0 100644 --- a/packages/design-system/lib/components/Icons/MaterialIcon/MaterialIcon.tsx +++ b/packages/design-system/lib/components/Icons/MaterialIcon/MaterialIcon.tsx @@ -1,7 +1,4 @@ -import { - MaterialSymbol, - type MaterialSymbolProps, -} from 'react-material-symbols' +import { MaterialSymbol, type MaterialSymbolProps } from './MaterialSymbol' import { iconVariants } from '../variants' diff --git a/packages/design-system/lib/components/Icons/MaterialIcon/MaterialSymbol/MaterialSymbol.tsx b/packages/design-system/lib/components/Icons/MaterialIcon/MaterialSymbol/MaterialSymbol.tsx new file mode 100644 index 000000000..f94a0dc28 --- /dev/null +++ b/packages/design-system/lib/components/Icons/MaterialIcon/MaterialSymbol/MaterialSymbol.tsx @@ -0,0 +1,101 @@ +// This is adapted from https://github.com/edjonesdev/react-material-symbols +// since it doesn't support React 19 and is not maintained anymore. +// We should probably move to a different solution in the future. + +import type { ElementType, CSSProperties, ReactElement, Ref } from 'react' +import type { + MaterialSymbolWeight, + PolymorphicComponentProps, + SymbolCodepoints, +} from './types' +import { cx } from 'class-variance-authority' +export type { MaterialSymbolWeight, SymbolCodepoints } from './types' + +export type MaterialSymbolProps = { + /** Required. The name of the icon to render. */ + icon: SymbolCodepoints + /** Default `false`. + * + * Fill gives you the ability to modify the default icon style. A single icon can render both unfilled and filled states. */ + fill?: boolean + /** Weight defines the symbol’s stroke weight, with a range of weights between thin (100) and heavy (900). Weight can also affect the overall size of the symbol. */ + weight?: MaterialSymbolWeight + /** Weight and grade affect a symbol’s thickness. Adjustments to grade are more granular than adjustments to weight and have a small impact on the size of the symbol. */ + grade?: number + /** Default `'inherit'`. + * + * Size defines the icon width and height in pixels. For the image to look the same at different sizes, the stroke weight (thickness) changes as the icon size scales. */ + size?: number + /** Default `'inherit'` + * + * Color accepts key values (`'red'`, `'blue'`, `'indigo'`, etc.), ``, ``, `` and `` values. */ + color?: CSSProperties['color'] + className?: string + style?: CSSProperties +} + +export type PolymorphicMaterialSymbolProps = + PolymorphicComponentProps + +export const MaterialSymbol = (( + { + icon, + onClick, + as, + weight, + fill = false, + grade, + size, + style: propStyle, + color, + className, + ...props + }: PolymorphicMaterialSymbolProps, + ref: Ref +): ReactElement => { + const Component = + onClick !== undefined ? 'button' : ((as as ElementType) ?? 'span') + const style = { color, ...propStyle } + + if (fill) + style.fontVariationSettings = [style.fontVariationSettings, '"FILL" 1'] + .filter(Boolean) + .join(', ') + if (weight) + style.fontVariationSettings = [ + style.fontVariationSettings, + `"wght" ${weight}`, + ] + .filter(Boolean) + .join(', ') + if (grade) + style.fontVariationSettings = [ + style.fontVariationSettings, + `"GRAD" ${grade}`, + ] + .filter(Boolean) + .join(', ') + if (size) { + style.fontVariationSettings = [ + style.fontVariationSettings, + `"opsz" ${size}`, + ] + .filter(Boolean) + .join(', ') + style.fontSize = size + } + + return ( + + {icon} + + ) +}) as ( + props: PolymorphicMaterialSymbolProps +) => ReactElement diff --git a/packages/design-system/lib/components/Icons/MaterialIcon/MaterialSymbol/consts.ts b/packages/design-system/lib/components/Icons/MaterialIcon/MaterialSymbol/consts.ts new file mode 100644 index 000000000..c4f57dfec --- /dev/null +++ b/packages/design-system/lib/components/Icons/MaterialIcon/MaterialSymbol/consts.ts @@ -0,0 +1,3463 @@ +export const MaterialSymbolWeightArray = [ + 100, 200, 300, 400, 500, 600, 700, 800, 900, +] as const + +export const SymbolCodepointsArray = [ + '10k', + '10mp', + '11mp', + '123', + '12mp', + '13mp', + '14mp', + '15mp', + '16mp', + '17mp', + '18_up_rating', + '18mp', + '19mp', + '1k', + '1k_plus', + '1x_mobiledata', + '1x_mobiledata_badge', + '20mp', + '21mp', + '22mp', + '23mp', + '24mp', + '2d', + '2k', + '2k_plus', + '2mp', + '30fps', + '30fps_select', + '360', + '3d_rotation', + '3g_mobiledata', + '3g_mobiledata_badge', + '3k', + '3k_plus', + '3mp', + '3p', + '4g_mobiledata', + '4g_mobiledata_badge', + '4g_plus_mobiledata', + '4k', + '4k_plus', + '4mp', + '50mp', + '5g', + '5g_mobiledata_badge', + '5k', + '5k_plus', + '5mp', + '60fps', + '60fps_select', + '6_ft_apart', + '6k', + '6k_plus', + '6mp', + '7k', + '7k_plus', + '7mp', + '8k', + '8k_plus', + '8mp', + '9k', + '9k_plus', + '9mp', + 'abc', + 'ac_unit', + 'access_alarm', + 'access_alarms', + 'access_time', + 'access_time_filled', + 'accessibility', + 'accessibility_new', + 'accessible', + 'accessible_forward', + 'account_balance', + 'account_balance_wallet', + 'account_box', + 'account_child', + 'account_child_invert', + 'account_circle', + 'account_circle_filled', + 'account_circle_off', + 'account_tree', + 'action_key', + 'activity_zone', + 'acute', + 'ad', + 'ad_group', + 'ad_group_off', + 'ad_off', + 'ad_units', + 'adb', + 'add', + 'add_a_photo', + 'add_ad', + 'add_alarm', + 'add_alert', + 'add_box', + 'add_business', + 'add_call', + 'add_card', + 'add_chart', + 'add_circle', + 'add_circle_outline', + 'add_comment', + 'add_home', + 'add_home_work', + 'add_ic_call', + 'add_link', + 'add_location', + 'add_location_alt', + 'add_moderator', + 'add_notes', + 'add_photo_alternate', + 'add_reaction', + 'add_road', + 'add_shopping_cart', + 'add_task', + 'add_to_drive', + 'add_to_home_screen', + 'add_to_photos', + 'add_to_queue', + 'addchart', + 'adf_scanner', + 'adjust', + 'admin_meds', + 'admin_panel_settings', + 'ads_click', + 'agender', + 'agriculture', + 'air', + 'air_freshener', + 'air_purifier', + 'air_purifier_gen', + 'airline_seat_flat', + 'airline_seat_flat_angled', + 'airline_seat_individual_suite', + 'airline_seat_legroom_extra', + 'airline_seat_legroom_normal', + 'airline_seat_legroom_reduced', + 'airline_seat_recline_extra', + 'airline_seat_recline_normal', + 'airline_stops', + 'airlines', + 'airplane_ticket', + 'airplanemode_active', + 'airplanemode_inactive', + 'airplay', + 'airport_shuttle', + 'airware', + 'airwave', + 'alarm', + 'alarm_add', + 'alarm_off', + 'alarm_on', + 'alarm_smart_wake', + 'album', + 'align_center', + 'align_end', + 'align_flex_center', + 'align_flex_end', + 'align_flex_start', + 'align_horizontal_center', + 'align_horizontal_left', + 'align_horizontal_right', + 'align_items_stretch', + 'align_justify_center', + 'align_justify_flex_end', + 'align_justify_flex_start', + 'align_justify_space_around', + 'align_justify_space_between', + 'align_justify_space_even', + 'align_justify_stretch', + 'align_self_stretch', + 'align_space_around', + 'align_space_between', + 'align_space_even', + 'align_start', + 'align_stretch', + 'align_vertical_bottom', + 'align_vertical_center', + 'align_vertical_top', + 'all_inbox', + 'all_inclusive', + 'all_match', + 'all_out', + 'allergies', + 'allergy', + 'alt_route', + 'alternate_email', + 'altitude', + 'ambient_screen', + 'ambulance', + 'amend', + 'amp_stories', + 'analytics', + 'anchor', + 'android', + 'animation', + 'announcement', + 'aod', + 'aod_tablet', + 'aod_watch', + 'apartment', + 'api', + 'apk_document', + 'apk_install', + 'app_badging', + 'app_blocking', + 'app_promo', + 'app_registration', + 'app_settings_alt', + 'app_shortcut', + 'apparel', + 'approval', + 'approval_delegation', + 'apps', + 'apps_outage', + 'aq', + 'aq_indoor', + 'ar_on_you', + 'ar_stickers', + 'architecture', + 'archive', + 'area_chart', + 'arming_countdown', + 'arrow_and_edge', + 'arrow_back', + 'arrow_back_ios', + 'arrow_back_ios_new', + 'arrow_circle_down', + 'arrow_circle_left', + 'arrow_circle_right', + 'arrow_circle_up', + 'arrow_downward', + 'arrow_downward_alt', + 'arrow_drop_down', + 'arrow_drop_down_circle', + 'arrow_drop_up', + 'arrow_forward', + 'arrow_forward_ios', + 'arrow_insert', + 'arrow_left', + 'arrow_left_alt', + 'arrow_or_edge', + 'arrow_outward', + 'arrow_range', + 'arrow_right', + 'arrow_right_alt', + 'arrow_selector_tool', + 'arrow_split', + 'arrow_top_left', + 'arrow_top_right', + 'arrow_upward', + 'arrow_upward_alt', + 'arrows_more_down', + 'arrows_more_up', + 'arrows_outward', + 'art_track', + 'article', + 'article_shortcut', + 'artist', + 'aspect_ratio', + 'assessment', + 'assignment', + 'assignment_add', + 'assignment_ind', + 'assignment_late', + 'assignment_return', + 'assignment_returned', + 'assignment_turned_in', + 'assist_walker', + 'assistant', + 'assistant_device', + 'assistant_direction', + 'assistant_navigation', + 'assistant_on_hub', + 'assistant_photo', + 'assured_workload', + 'asterisk', + 'astrophotography_auto', + 'astrophotography_off', + 'atm', + 'atr', + 'attach_email', + 'attach_file', + 'attach_file_add', + 'attach_money', + 'attachment', + 'attractions', + 'attribution', + 'audio_description', + 'audio_file', + 'audio_video_receiver', + 'audiotrack', + 'auto_activity_zone', + 'auto_awesome', + 'auto_awesome_mosaic', + 'auto_awesome_motion', + 'auto_delete', + 'auto_detect_voice', + 'auto_draw_solid', + 'auto_fix', + 'auto_fix_high', + 'auto_fix_normal', + 'auto_fix_off', + 'auto_graph', + 'auto_label', + 'auto_meeting_room', + 'auto_mode', + 'auto_read_pause', + 'auto_read_play', + 'auto_schedule', + 'auto_stories', + 'auto_timer', + 'auto_towing', + 'auto_transmission', + 'auto_videocam', + 'autofps_select', + 'autopause', + 'autopay', + 'autoplay', + 'autorenew', + 'autostop', + 'av_timer', + 'avg_pace', + 'avg_time', + 'award_star', + 'azm', + 'baby_changing_station', + 'back_hand', + 'back_to_tab', + 'background_dot_large', + 'background_dot_small', + 'background_grid_small', + 'background_replace', + 'backlight_high', + 'backlight_low', + 'backpack', + 'backspace', + 'backup', + 'backup_table', + 'badge', + 'badge_critical_battery', + 'bakery_dining', + 'balance', + 'balcony', + 'ballot', + 'bar_chart', + 'bar_chart_4_bars', + 'barcode', + 'barcode_reader', + 'barcode_scanner', + 'barefoot', + 'batch_prediction', + 'bath_outdoor', + 'bath_private', + 'bath_public_large', + 'bathroom', + 'bathtub', + 'battery_0_bar', + 'battery_1_bar', + 'battery_20', + 'battery_2_bar', + 'battery_30', + 'battery_3_bar', + 'battery_4_bar', + 'battery_50', + 'battery_5_bar', + 'battery_60', + 'battery_6_bar', + 'battery_80', + 'battery_90', + 'battery_alert', + 'battery_change', + 'battery_charging_20', + 'battery_charging_30', + 'battery_charging_50', + 'battery_charging_60', + 'battery_charging_80', + 'battery_charging_90', + 'battery_charging_full', + 'battery_error', + 'battery_full', + 'battery_full_alt', + 'battery_horiz_000', + 'battery_horiz_050', + 'battery_horiz_075', + 'battery_low', + 'battery_plus', + 'battery_profile', + 'battery_saver', + 'battery_share', + 'battery_status_good', + 'battery_std', + 'battery_unknown', + 'battery_vert_005', + 'battery_vert_020', + 'battery_vert_050', + 'battery_very_low', + 'beach_access', + 'bed', + 'bedroom_baby', + 'bedroom_child', + 'bedroom_parent', + 'bedtime', + 'bedtime_off', + 'beenhere', + 'bento', + 'bia', + 'bid_landscape', + 'bid_landscape_disabled', + 'bigtop_updates', + 'bike_scooter', + 'biotech', + 'blanket', + 'blender', + 'blind', + 'blinds', + 'blinds_closed', + 'block', + 'blood_pressure', + 'bloodtype', + 'bluetooth', + 'bluetooth_audio', + 'bluetooth_connected', + 'bluetooth_disabled', + 'bluetooth_drive', + 'bluetooth_searching', + 'blur_circular', + 'blur_linear', + 'blur_medium', + 'blur_off', + 'blur_on', + 'blur_short', + 'body_fat', + 'body_system', + 'bolt', + 'bomb', + 'book', + 'book_2', + 'book_3', + 'book_4', + 'book_5', + 'book_online', + 'bookmark', + 'bookmark_add', + 'bookmark_added', + 'bookmark_border', + 'bookmark_manager', + 'bookmark_remove', + 'bookmarks', + 'border_all', + 'border_bottom', + 'border_clear', + 'border_color', + 'border_horizontal', + 'border_inner', + 'border_left', + 'border_outer', + 'border_right', + 'border_style', + 'border_top', + 'border_vertical', + 'bottom_app_bar', + 'bottom_drawer', + 'bottom_navigation', + 'bottom_panel_close', + 'bottom_panel_open', + 'bottom_right_click', + 'bottom_sheets', + 'box', + 'box_add', + 'box_edit', + 'boy', + 'brand_awareness', + 'branding_watermark', + 'breakfast_dining', + 'breaking_news', + 'breaking_news_alt_1', + 'breastfeeding', + 'brightness_1', + 'brightness_2', + 'brightness_3', + 'brightness_4', + 'brightness_5', + 'brightness_6', + 'brightness_7', + 'brightness_alert', + 'brightness_auto', + 'brightness_empty', + 'brightness_high', + 'brightness_low', + 'brightness_medium', + 'bring_your_own_ip', + 'broadcast_on_home', + 'broadcast_on_personal', + 'broken_image', + 'browse', + 'browse_activity', + 'browse_gallery', + 'browser_not_supported', + 'browser_updated', + 'brunch_dining', + 'brush', + 'bubble', + 'bubble_chart', + 'bubbles', + 'bug_report', + 'build', + 'build_circle', + 'bungalow', + 'burst_mode', + 'bus_alert', + 'business', + 'business_center', + 'business_chip', + 'business_messages', + 'buttons_alt', + 'cabin', + 'cable', + 'cached', + 'cake', + 'cake_add', + 'calculate', + 'calendar_add_on', + 'calendar_apps_script', + 'calendar_clock', + 'calendar_month', + 'calendar_today', + 'calendar_view_day', + 'calendar_view_month', + 'calendar_view_week', + 'call', + 'call_end', + 'call_end_alt', + 'call_log', + 'call_made', + 'call_merge', + 'call_missed', + 'call_missed_outgoing', + 'call_quality', + 'call_received', + 'call_split', + 'call_to_action', + 'camera', + 'camera_alt', + 'camera_enhance', + 'camera_front', + 'camera_indoor', + 'camera_outdoor', + 'camera_rear', + 'camera_roll', + 'camera_video', + 'cameraswitch', + 'campaign', + 'camping', + 'cancel', + 'cancel_presentation', + 'cancel_schedule_send', + 'candle', + 'candlestick_chart', + 'captive_portal', + 'capture', + 'car_crash', + 'car_rental', + 'car_repair', + 'card_giftcard', + 'card_membership', + 'card_travel', + 'cardiology', + 'cards', + 'carpenter', + 'carry_on_bag', + 'carry_on_bag_checked', + 'carry_on_bag_inactive', + 'carry_on_bag_question', + 'cases', + 'casino', + 'cast', + 'cast_connected', + 'cast_for_education', + 'cast_pause', + 'cast_warning', + 'castle', + 'category', + 'celebration', + 'cell_merge', + 'cell_tower', + 'cell_wifi', + 'center_focus_strong', + 'center_focus_weak', + 'chair', + 'chair_alt', + 'chalet', + 'change_circle', + 'change_history', + 'charger', + 'charging_station', + 'chart_data', + 'chat', + 'chat_add_on', + 'chat_apps_script', + 'chat_bubble', + 'chat_bubble_outline', + 'chat_error', + 'chat_info', + 'chat_paste_go', + 'check', + 'check_box', + 'check_box_outline_blank', + 'check_circle', + 'check_circle_filled', + 'check_circle_outline', + 'check_in_out', + 'check_indeterminate_small', + 'check_small', + 'checkbook', + 'checked_bag', + 'checked_bag_question', + 'checklist', + 'checklist_rtl', + 'checkroom', + 'cheer', + 'chess', + 'chevron_left', + 'chevron_right', + 'child_care', + 'child_friendly', + 'chip_extraction', + 'chips', + 'chrome_reader_mode', + 'chromecast_2', + 'chromecast_device', + 'chronic', + 'church', + 'cinematic_blur', + 'circle', + 'circle_notifications', + 'circles', + 'circles_ext', + 'clarify', + 'class', + 'clean_hands', + 'cleaning', + 'cleaning_bucket', + 'cleaning_services', + 'clear', + 'clear_all', + 'clear_day', + 'clear_night', + 'climate_mini_split', + 'clinical_notes', + 'clock_loader_10', + 'clock_loader_20', + 'clock_loader_40', + 'clock_loader_60', + 'clock_loader_80', + 'clock_loader_90', + 'close', + 'close_fullscreen', + 'close_small', + 'closed_caption', + 'closed_caption_disabled', + 'closed_caption_off', + 'cloud', + 'cloud_circle', + 'cloud_done', + 'cloud_download', + 'cloud_off', + 'cloud_queue', + 'cloud_sync', + 'cloud_upload', + 'cloudy', + 'cloudy_filled', + 'cloudy_snowing', + 'co2', + 'co_present', + 'code', + 'code_blocks', + 'code_off', + 'coffee', + 'coffee_maker', + 'cognition', + 'collapse_all', + 'collapse_content', + 'collections', + 'collections_bookmark', + 'color_lens', + 'colorize', + 'colors', + 'comic_bubble', + 'comment', + 'comment_bank', + 'comments_disabled', + 'commit', + 'communication', + 'communities', + 'communities_filled', + 'commute', + 'compare', + 'compare_arrows', + 'compass_calibration', + 'component_exchange', + 'compost', + 'compress', + 'computer', + 'concierge', + 'conditions', + 'confirmation_number', + 'congenital', + 'connect_without_contact', + 'connected_tv', + 'connecting_airports', + 'construction', + 'contact_emergency', + 'contact_mail', + 'contact_page', + 'contact_phone', + 'contact_phone_filled', + 'contact_support', + 'contactless', + 'contactless_off', + 'contacts', + 'contacts_product', + 'content_copy', + 'content_cut', + 'content_paste', + 'content_paste_go', + 'content_paste_off', + 'content_paste_search', + 'contract', + 'contract_delete', + 'contract_edit', + 'contrast', + 'contrast_rtl_off', + 'control_camera', + 'control_point', + 'control_point_duplicate', + 'controller_gen', + 'conversion_path', + 'conversion_path_off', + 'conveyor_belt', + 'cookie', + 'cookie_off', + 'cooking', + 'cool_to_dry', + 'copy_all', + 'copyright', + 'coronavirus', + 'corporate_fare', + 'cottage', + 'counter_0', + 'counter_1', + 'counter_2', + 'counter_3', + 'counter_4', + 'counter_5', + 'counter_6', + 'counter_7', + 'counter_8', + 'counter_9', + 'countertops', + 'create', + 'create_new_folder', + 'credit_card', + 'credit_card_gear', + 'credit_card_heart', + 'credit_card_off', + 'credit_score', + 'crib', + 'crisis_alert', + 'crop', + 'crop_16_9', + 'crop_3_2', + 'crop_5_4', + 'crop_7_5', + 'crop_9_16', + 'crop_din', + 'crop_free', + 'crop_landscape', + 'crop_original', + 'crop_portrait', + 'crop_rotate', + 'crop_square', + 'crossword', + 'crowdsource', + 'cruelty_free', + 'css', + 'csv', + 'currency_bitcoin', + 'currency_exchange', + 'currency_franc', + 'currency_lira', + 'currency_pound', + 'currency_ruble', + 'currency_rupee', + 'currency_yen', + 'currency_yuan', + 'curtains', + 'curtains_closed', + 'custom_typography', + 'cut', + 'cycle', + 'cyclone', + 'dangerous', + 'dark_mode', + 'dashboard', + 'dashboard_customize', + 'data_alert', + 'data_array', + 'data_check', + 'data_exploration', + 'data_info_alert', + 'data_loss_prevention', + 'data_object', + 'data_saver_off', + 'data_saver_on', + 'data_table', + 'data_thresholding', + 'data_usage', + 'database', + 'dataset', + 'dataset_linked', + 'date_range', + 'deblur', + 'deceased', + 'decimal_decrease', + 'decimal_increase', + 'deck', + 'dehaze', + 'delete', + 'delete_forever', + 'delete_history', + 'delete_outline', + 'delete_sweep', + 'demography', + 'density_large', + 'density_medium', + 'density_small', + 'dentistry', + 'departure_board', + 'deployed_code', + 'deployed_code_account', + 'deployed_code_alert', + 'deployed_code_history', + 'deployed_code_update', + 'dermatology', + 'description', + 'deselect', + 'design_services', + 'desk', + 'deskphone', + 'desktop_access_disabled', + 'desktop_mac', + 'desktop_windows', + 'destruction', + 'details', + 'detection_and_zone', + 'detector', + 'detector_alarm', + 'detector_battery', + 'detector_co', + 'detector_offline', + 'detector_smoke', + 'detector_status', + 'developer_board', + 'developer_board_off', + 'developer_guide', + 'developer_mode', + 'developer_mode_tv', + 'device_hub', + 'device_reset', + 'device_thermostat', + 'device_unknown', + 'devices', + 'devices_fold', + 'devices_off', + 'devices_other', + 'devices_wearables', + 'dew_point', + 'diagnosis', + 'dialer_sip', + 'dialogs', + 'dialpad', + 'diamond', + 'dictionary', + 'difference', + 'digital_out_of_home', + 'digital_wellbeing', + 'dining', + 'dinner_dining', + 'directions', + 'directions_alt', + 'directions_alt_off', + 'directions_bike', + 'directions_boat', + 'directions_boat_filled', + 'directions_bus', + 'directions_bus_filled', + 'directions_car', + 'directions_car_filled', + 'directions_off', + 'directions_railway', + 'directions_railway_filled', + 'directions_run', + 'directions_subway', + 'directions_subway_filled', + 'directions_transit', + 'directions_transit_filled', + 'directions_walk', + 'directory_sync', + 'dirty_lens', + 'disabled_by_default', + 'disabled_visible', + 'disc_full', + 'discover_tune', + 'dishwasher', + 'dishwasher_gen', + 'display_external_input', + 'display_settings', + 'distance', + 'diversity_1', + 'diversity_2', + 'diversity_3', + 'diversity_4', + 'dns', + 'do_disturb', + 'do_disturb_alt', + 'do_disturb_off', + 'do_disturb_on', + 'do_not_disturb', + 'do_not_disturb_alt', + 'do_not_disturb_off', + 'do_not_disturb_on', + 'do_not_disturb_on_total_silence', + 'do_not_step', + 'do_not_touch', + 'dock', + 'dock_to_bottom', + 'dock_to_left', + 'dock_to_right', + 'docs_add_on', + 'docs_apps_script', + 'document_scanner', + 'domain', + 'domain_add', + 'domain_disabled', + 'domain_verification', + 'domain_verification_off', + 'domino_mask', + 'done', + 'done_all', + 'done_outline', + 'donut_large', + 'donut_small', + 'door_back', + 'door_front', + 'door_open', + 'door_sensor', + 'door_sliding', + 'doorbell', + 'doorbell_3p', + 'doorbell_chime', + 'double_arrow', + 'downhill_skiing', + 'download', + 'download_2', + 'download_done', + 'download_for_offline', + 'downloading', + 'draft', + 'draft_orders', + 'drafts', + 'drag_click', + 'drag_handle', + 'drag_indicator', + 'drag_pan', + 'draw', + 'draw_abstract', + 'draw_collage', + 'drawing_recognition', + 'dresser', + 'drive_eta', + 'drive_file_move', + 'drive_file_move_outline', + 'drive_file_move_rtl', + 'drive_file_rename_outline', + 'drive_folder_upload', + 'drive_fusiontable', + 'dropdown', + 'dry', + 'dry_cleaning', + 'dual_screen', + 'duo', + 'dvr', + 'dynamic_feed', + 'dynamic_form', + 'e911_avatar', + 'e911_emergency', + 'e_mobiledata', + 'e_mobiledata_badge', + 'earbuds', + 'earbuds_battery', + 'early_on', + 'earthquake', + 'east', + 'ecg', + 'ecg_heart', + 'eco', + 'eda', + 'edgesensor_high', + 'edgesensor_low', + 'edit', + 'edit_attributes', + 'edit_calendar', + 'edit_document', + 'edit_location', + 'edit_location_alt', + 'edit_note', + 'edit_notifications', + 'edit_off', + 'edit_road', + 'edit_square', + 'editor_choice', + 'egg', + 'egg_alt', + 'eject', + 'elderly', + 'elderly_woman', + 'electric_bike', + 'electric_bolt', + 'electric_car', + 'electric_meter', + 'electric_moped', + 'electric_rickshaw', + 'electric_scooter', + 'electrical_services', + 'elevation', + 'elevator', + 'email', + 'emergency', + 'emergency_heat', + 'emergency_home', + 'emergency_recording', + 'emergency_share', + 'emergency_share_off', + 'emoji_emotions', + 'emoji_events', + 'emoji_flags', + 'emoji_food_beverage', + 'emoji_nature', + 'emoji_objects', + 'emoji_people', + 'emoji_symbols', + 'emoji_transportation', + 'emoticon', + 'empty_dashboard', + 'enable', + 'encrypted', + 'endocrinology', + 'energy', + 'energy_program_saving', + 'energy_program_time_used', + 'energy_savings_leaf', + 'engineering', + 'enhanced_encryption', + 'ent', + 'enterprise', + 'enterprise_off', + 'equal', + 'equalizer', + 'error', + 'error_circle_rounded', + 'error_med', + 'error_outline', + 'escalator', + 'escalator_warning', + 'euro', + 'euro_symbol', + 'ev_charger', + 'ev_mobiledata_badge', + 'ev_shadow', + 'ev_shadow_add', + 'ev_shadow_minus', + 'ev_station', + 'event', + 'event_available', + 'event_busy', + 'event_list', + 'event_note', + 'event_repeat', + 'event_seat', + 'event_upcoming', + 'exclamation', + 'exercise', + 'exit_to_app', + 'expand', + 'expand_all', + 'expand_circle_down', + 'expand_circle_right', + 'expand_circle_up', + 'expand_content', + 'expand_less', + 'expand_more', + 'experiment', + 'explicit', + 'explore', + 'explore_nearby', + 'explore_off', + 'explosion', + 'export_notes', + 'exposure', + 'exposure_neg_1', + 'exposure_neg_2', + 'exposure_plus_1', + 'exposure_plus_2', + 'exposure_zero', + 'extension', + 'extension_off', + 'eyeglasses', + 'face', + 'face_2', + 'face_3', + 'face_4', + 'face_5', + 'face_6', + 'face_retouching_natural', + 'face_retouching_off', + 'face_unlock', + 'fact_check', + 'factory', + 'falling', + 'familiar_face_and_zone', + 'family_history', + 'family_home', + 'family_link', + 'family_restroom', + 'family_star', + 'farsight_digital', + 'fast_forward', + 'fast_rewind', + 'fastfood', + 'faucet', + 'favorite', + 'favorite_border', + 'fax', + 'feature_search', + 'featured_play_list', + 'featured_seasonal_and_gifts', + 'featured_video', + 'feed', + 'feedback', + 'female', + 'femur', + 'femur_alt', + 'fence', + 'fertile', + 'festival', + 'fiber_dvr', + 'fiber_manual_record', + 'fiber_new', + 'fiber_pin', + 'fiber_smart_record', + 'file_copy', + 'file_download', + 'file_download_done', + 'file_download_off', + 'file_map', + 'file_open', + 'file_present', + 'file_save', + 'file_save_off', + 'file_upload', + 'file_upload_off', + 'filter', + 'filter_1', + 'filter_2', + 'filter_3', + 'filter_4', + 'filter_5', + 'filter_6', + 'filter_7', + 'filter_8', + 'filter_9', + 'filter_9_plus', + 'filter_alt', + 'filter_alt_off', + 'filter_b_and_w', + 'filter_center_focus', + 'filter_drama', + 'filter_frames', + 'filter_hdr', + 'filter_list', + 'filter_list_alt', + 'filter_list_off', + 'filter_none', + 'filter_retrolux', + 'filter_tilt_shift', + 'filter_vintage', + 'finance', + 'finance_chip', + 'finance_mode', + 'find_in_page', + 'find_replace', + 'fingerprint', + 'fire_extinguisher', + 'fire_hydrant', + 'fire_truck', + 'fireplace', + 'first_page', + 'fit_page', + 'fit_screen', + 'fit_width', + 'fitness_center', + 'flag', + 'flag_circle', + 'flag_filled', + 'flaky', + 'flare', + 'flash_auto', + 'flash_off', + 'flash_on', + 'flashlight_off', + 'flashlight_on', + 'flatware', + 'flex_direction', + 'flex_no_wrap', + 'flex_wrap', + 'flight', + 'flight_class', + 'flight_land', + 'flight_takeoff', + 'flights_and_hotels', + 'flightsmode', + 'flip', + 'flip_camera_android', + 'flip_camera_ios', + 'flip_to_back', + 'flip_to_front', + 'flood', + 'floor', + 'floor_lamp', + 'flourescent', + 'flowsheet', + 'fluid', + 'fluid_balance', + 'fluid_med', + 'fluorescent', + 'flutter', + 'flutter_dash', + 'fmd_bad', + 'fmd_good', + 'foggy', + 'folded_hands', + 'folder', + 'folder_copy', + 'folder_data', + 'folder_delete', + 'folder_managed', + 'folder_off', + 'folder_open', + 'folder_shared', + 'folder_special', + 'folder_supervised', + 'folder_zip', + 'follow_the_signs', + 'font_download', + 'font_download_off', + 'food_bank', + 'foot_bones', + 'footprint', + 'for_you', + 'forest', + 'fork_left', + 'fork_right', + 'forklift', + 'format_align_center', + 'format_align_justify', + 'format_align_left', + 'format_align_right', + 'format_bold', + 'format_clear', + 'format_color_fill', + 'format_color_reset', + 'format_color_text', + 'format_h1', + 'format_h2', + 'format_h3', + 'format_h4', + 'format_h5', + 'format_h6', + 'format_image_left', + 'format_image_right', + 'format_indent_decrease', + 'format_indent_increase', + 'format_ink_highlighter', + 'format_italic', + 'format_letter_spacing', + 'format_letter_spacing_2', + 'format_letter_spacing_standard', + 'format_letter_spacing_wide', + 'format_letter_spacing_wider', + 'format_line_spacing', + 'format_list_bulleted', + 'format_list_bulleted_add', + 'format_list_numbered', + 'format_list_numbered_rtl', + 'format_overline', + 'format_paint', + 'format_paragraph', + 'format_quote', + 'format_shapes', + 'format_size', + 'format_strikethrough', + 'format_text_clip', + 'format_text_overflow', + 'format_text_wrap', + 'format_textdirection_l_to_r', + 'format_textdirection_r_to_l', + 'format_underlined', + 'format_underlined_squiggle', + 'forms_add_on', + 'forms_apps_script', + 'fort', + 'forum', + 'forward', + 'forward_10', + 'forward_30', + 'forward_5', + 'forward_circle', + 'forward_media', + 'forward_to_inbox', + 'foundation', + 'frame_inspect', + 'frame_person', + 'frame_person_off', + 'frame_reload', + 'frame_source', + 'free_breakfast', + 'free_cancellation', + 'front_hand', + 'front_loader', + 'full_coverage', + 'full_hd', + 'full_stacked_bar_chart', + 'fullscreen', + 'fullscreen_exit', + 'function', + 'functions', + 'g_mobiledata', + 'g_mobiledata_badge', + 'g_translate', + 'gallery_thumbnail', + 'gamepad', + 'games', + 'garage', + 'garage_door', + 'garage_home', + 'garden_cart', + 'gas_meter', + 'gastroenterology', + 'gate', + 'gavel', + 'general_device', + 'generating_tokens', + 'genetics', + 'genres', + 'gesture', + 'gesture_select', + 'get_app', + 'gif', + 'gif_box', + 'girl', + 'gite', + 'glass_cup', + 'globe', + 'globe_asia', + 'globe_uk', + 'glucose', + 'glyphs', + 'go_to_line', + 'golf_course', + 'google_home_devices', + 'google_plus_reshare', + 'google_tv_remote', + 'google_wifi', + 'gpp_bad', + 'gpp_good', + 'gpp_maybe', + 'gps_fixed', + 'gps_not_fixed', + 'gps_off', + 'grade', + 'gradient', + 'grading', + 'grain', + 'graphic_eq', + 'grass', + 'grid_3x3', + 'grid_3x3_off', + 'grid_4x4', + 'grid_goldenratio', + 'grid_guides', + 'grid_off', + 'grid_on', + 'grid_view', + 'grocery', + 'group', + 'group_add', + 'group_off', + 'group_remove', + 'group_work', + 'grouped_bar_chart', + 'groups', + 'groups_2', + 'groups_3', + 'gynecology', + 'h_mobiledata', + 'h_mobiledata_badge', + 'h_plus_mobiledata', + 'h_plus_mobiledata_badge', + 'hail', + 'hallway', + 'hand_bones', + 'hand_gesture', + 'handshake', + 'handwriting_recognition', + 'handyman', + 'hangout_video', + 'hangout_video_off', + 'hard_drive', + 'hard_drive_2', + 'hardware', + 'hd', + 'hdr_auto', + 'hdr_auto_select', + 'hdr_enhanced_select', + 'hdr_off', + 'hdr_off_select', + 'hdr_on', + 'hdr_on_select', + 'hdr_plus', + 'hdr_plus_off', + 'hdr_strong', + 'hdr_weak', + 'headphones', + 'headphones_battery', + 'headset', + 'headset_mic', + 'headset_off', + 'healing', + 'health_and_beauty', + 'health_and_safety', + 'health_metrics', + 'heap_snapshot_large', + 'heap_snapshot_multiple', + 'heap_snapshot_thumbnail', + 'hearing', + 'hearing_disabled', + 'heart_broken', + 'heart_check', + 'heart_minus', + 'heart_plus', + 'heat', + 'heat_pump', + 'heat_pump_balance', + 'height', + 'helicopter', + 'help', + 'help_center', + 'help_clinic', + 'help_outline', + 'hematology', + 'hevc', + 'hexagon', + 'hide', + 'hide_image', + 'hide_source', + 'high_density', + 'high_quality', + 'high_res', + 'highlight', + 'highlight_keyboard_focus', + 'highlight_mouse_cursor', + 'highlight_off', + 'highlight_text_cursor', + 'highlighter_size_1', + 'highlighter_size_2', + 'highlighter_size_3', + 'highlighter_size_4', + 'highlighter_size_5', + 'hiking', + 'history', + 'history_edu', + 'history_toggle_off', + 'hive', + 'hls', + 'hls_off', + 'holiday_village', + 'home', + 'home_and_garden', + 'home_app_logo', + 'home_filled', + 'home_health', + 'home_improvement_and_tools', + 'home_iot_device', + 'home_max', + 'home_max_dots', + 'home_mini', + 'home_pin', + 'home_repair_service', + 'home_speaker', + 'home_storage', + 'home_work', + 'horizontal_distribute', + 'horizontal_rule', + 'horizontal_split', + 'hot_tub', + 'hotel', + 'hotel_class', + 'hourglass', + 'hourglass_bottom', + 'hourglass_disabled', + 'hourglass_empty', + 'hourglass_full', + 'hourglass_top', + 'house', + 'house_siding', + 'house_with_shield', + 'houseboat', + 'household_supplies', + 'how_to_reg', + 'how_to_vote', + 'hr_resting', + 'html', + 'http', + 'https', + 'hub', + 'humerus', + 'humerus_alt', + 'humidity_high', + 'humidity_indoor', + 'humidity_low', + 'humidity_mid', + 'humidity_percentage', + 'hvac', + 'ice_skating', + 'icecream', + 'ifl', + 'iframe', + 'iframe_off', + 'image', + 'image_aspect_ratio', + 'image_not_supported', + 'image_search', + 'imagesearch_roller', + 'imagesmode', + 'immunology', + 'import_contacts', + 'import_export', + 'important_devices', + 'in_home_mode', + 'inactive_order', + 'inbox', + 'inbox_customize', + 'incomplete_circle', + 'indeterminate_check_box', + 'indeterminate_question_box', + 'info', + 'info_i', + 'infrared', + 'ink_eraser', + 'ink_eraser_off', + 'ink_highlighter', + 'ink_highlighter_move', + 'ink_marker', + 'ink_pen', + 'inpatient', + 'input', + 'input_circle', + 'insert_chart', + 'insert_chart_filled', + 'insert_chart_outlined', + 'insert_comment', + 'insert_drive_file', + 'insert_emoticon', + 'insert_invitation', + 'insert_link', + 'insert_page_break', + 'insert_photo', + 'insert_text', + 'insights', + 'install_desktop', + 'install_mobile', + 'instant_mix', + 'integration_instructions', + 'interactive_space', + 'interests', + 'interpreter_mode', + 'inventory', + 'inventory_2', + 'invert_colors', + 'invert_colors_off', + 'ios', + 'ios_share', + 'iron', + 'iso', + 'jamboard_kiosk', + 'javascript', + 'join', + 'join_full', + 'join_inner', + 'join_left', + 'join_right', + 'joystick', + 'jump_to_element', + 'kayaking', + 'kebab_dining', + 'kettle', + 'key', + 'key_off', + 'key_vertical', + 'key_visualizer', + 'keyboard', + 'keyboard_alt', + 'keyboard_arrow_down', + 'keyboard_arrow_left', + 'keyboard_arrow_right', + 'keyboard_arrow_up', + 'keyboard_backspace', + 'keyboard_capslock', + 'keyboard_capslock_badge', + 'keyboard_command_key', + 'keyboard_control_key', + 'keyboard_double_arrow_down', + 'keyboard_double_arrow_left', + 'keyboard_double_arrow_right', + 'keyboard_double_arrow_up', + 'keyboard_external_input', + 'keyboard_full', + 'keyboard_hide', + 'keyboard_keys', + 'keyboard_off', + 'keyboard_onscreen', + 'keyboard_option_key', + 'keyboard_previous_language', + 'keyboard_return', + 'keyboard_tab', + 'keyboard_tab_rtl', + 'keyboard_voice', + 'kid_star', + 'king_bed', + 'kitchen', + 'kitesurfing', + 'lab_panel', + 'lab_profile', + 'lab_research', + 'label', + 'label_important', + 'label_important_outline', + 'label_off', + 'label_outline', + 'labs', + 'lan', + 'landscape', + 'landslide', + 'language', + 'language_chinese_array', + 'language_chinese_cangjie', + 'language_chinese_dayi', + 'language_chinese_pinyin', + 'language_chinese_quick', + 'language_chinese_wubi', + 'language_french', + 'language_gb_english', + 'language_international', + 'language_japanese_kana', + 'language_korean_latin', + 'language_pinyin', + 'language_spanish', + 'language_us', + 'language_us_colemak', + 'language_us_dvorak', + 'laps', + 'laptop', + 'laptop_chromebook', + 'laptop_mac', + 'laptop_windows', + 'lasso_select', + 'last_page', + 'launch', + 'laundry', + 'layers', + 'layers_clear', + 'lda', + 'leaderboard', + 'leak_add', + 'leak_remove', + 'left_click', + 'left_panel_close', + 'left_panel_open', + 'legend_toggle', + 'lens', + 'lens_blur', + 'letter_switch', + 'library_add', + 'library_add_check', + 'library_books', + 'library_music', + 'license', + 'lift_to_talk', + 'light', + 'light_group', + 'light_mode', + 'light_off', + 'lightbulb', + 'lightbulb_circle', + 'lightbulb_outline', + 'lightning_stand', + 'line_axis', + 'line_curve', + 'line_end', + 'line_end_arrow', + 'line_end_arrow_notch', + 'line_end_circle', + 'line_end_diamond', + 'line_end_square', + 'line_start', + 'line_start_arrow', + 'line_start_arrow_notch', + 'line_start_circle', + 'line_start_diamond', + 'line_start_square', + 'line_style', + 'line_weight', + 'linear_scale', + 'link', + 'link_off', + 'linked_camera', + 'linked_services', + 'liquor', + 'list', + 'list_alt', + 'list_alt_add', + 'lists', + 'live_help', + 'live_tv', + 'living', + 'local_activity', + 'local_airport', + 'local_atm', + 'local_bar', + 'local_cafe', + 'local_car_wash', + 'local_convenience_store', + 'local_dining', + 'local_drink', + 'local_fire_department', + 'local_florist', + 'local_gas_station', + 'local_grocery_store', + 'local_hospital', + 'local_hotel', + 'local_laundry_service', + 'local_library', + 'local_mall', + 'local_movies', + 'local_offer', + 'local_parking', + 'local_pharmacy', + 'local_phone', + 'local_pizza', + 'local_play', + 'local_police', + 'local_post_office', + 'local_printshop', + 'local_see', + 'local_shipping', + 'local_taxi', + 'location_automation', + 'location_away', + 'location_chip', + 'location_city', + 'location_disabled', + 'location_home', + 'location_off', + 'location_on', + 'location_pin', + 'location_searching', + 'locator_tag', + 'lock', + 'lock_clock', + 'lock_open', + 'lock_open_right', + 'lock_outline', + 'lock_person', + 'lock_reset', + 'login', + 'logo_dev', + 'logout', + 'looks', + 'looks_3', + 'looks_4', + 'looks_5', + 'looks_6', + 'looks_one', + 'looks_two', + 'loop', + 'loupe', + 'low_density', + 'low_priority', + 'loyalty', + 'lte_mobiledata', + 'lte_mobiledata_badge', + 'lte_plus_mobiledata', + 'lte_plus_mobiledata_badge', + 'luggage', + 'lunch_dining', + 'lyrics', + 'macro_auto', + 'macro_off', + 'magic_button', + 'magic_exchange', + 'magic_tether', + 'magnification_large', + 'magnification_small', + 'magnify_docked', + 'magnify_fullscreen', + 'mail', + 'mail_lock', + 'mail_outline', + 'male', + 'man', + 'man_2', + 'man_3', + 'man_4', + 'manage_accounts', + 'manage_history', + 'manage_search', + 'manga', + 'manufacturing', + 'map', + 'maps_home_work', + 'maps_ugc', + 'margin', + 'mark_as_unread', + 'mark_chat_read', + 'mark_chat_unread', + 'mark_email_read', + 'mark_email_unread', + 'mark_unread_chat_alt', + 'markdown', + 'markdown_copy', + 'markdown_paste', + 'markunread', + 'markunread_mailbox', + 'masked_transitions', + 'masks', + 'match_case', + 'match_word', + 'matter', + 'maximize', + 'measuring_tape', + 'media_bluetooth_off', + 'media_bluetooth_on', + 'media_link', + 'mediation', + 'medical_information', + 'medical_mask', + 'medical_services', + 'medication', + 'medication_liquid', + 'meeting_room', + 'memory', + 'memory_alt', + 'menstrual_health', + 'menu', + 'menu_book', + 'menu_open', + 'merge', + 'merge_type', + 'message', + 'metabolism', + 'mfg_nest_yale_lock', + 'mic', + 'mic_double', + 'mic_external_off', + 'mic_external_on', + 'mic_none', + 'mic_off', + 'microbiology', + 'microwave', + 'microwave_gen', + 'military_tech', + 'mimo', + 'mimo_disconnect', + 'mindfulness', + 'minimize', + 'minor_crash', + 'mintmark', + 'missed_video_call', + 'missed_video_call_filled', + 'missing_controller', + 'mist', + 'mitre', + 'mixture_med', + 'mms', + 'mobile_friendly', + 'mobile_off', + 'mobile_screen_share', + 'mobiledata_off', + 'mode', + 'mode_comment', + 'mode_cool', + 'mode_cool_off', + 'mode_dual', + 'mode_edit', + 'mode_edit_outline', + 'mode_fan', + 'mode_fan_off', + 'mode_heat', + 'mode_heat_cool', + 'mode_heat_off', + 'mode_night', + 'mode_of_travel', + 'mode_off_on', + 'mode_standby', + 'model_training', + 'monetization_on', + 'money', + 'money_off', + 'money_off_csred', + 'monitor', + 'monitor_heart', + 'monitor_weight', + 'monitor_weight_gain', + 'monitor_weight_loss', + 'monitoring', + 'monochrome_photos', + 'mood', + 'mood_bad', + 'mop', + 'more', + 'more_down', + 'more_horiz', + 'more_time', + 'more_up', + 'more_vert', + 'mosque', + 'motion_blur', + 'motion_mode', + 'motion_photos_auto', + 'motion_photos_off', + 'motion_photos_on', + 'motion_photos_pause', + 'motion_photos_paused', + 'motion_sensor_active', + 'motion_sensor_alert', + 'motion_sensor_idle', + 'motion_sensor_urgent', + 'motorcycle', + 'mountain_flag', + 'mouse', + 'move', + 'move_down', + 'move_group', + 'move_item', + 'move_location', + 'move_selection_down', + 'move_selection_left', + 'move_selection_right', + 'move_selection_up', + 'move_to_inbox', + 'move_up', + 'moved_location', + 'movie', + 'movie_creation', + 'movie_edit', + 'movie_filter', + 'movie_info', + 'moving', + 'moving_beds', + 'moving_ministry', + 'mp', + 'multicooker', + 'multiline_chart', + 'multiple_stop', + 'museum', + 'music_cast', + 'music_note', + 'music_off', + 'music_video', + 'my_location', + 'mystery', + 'nat', + 'nature', + 'nature_people', + 'navigate_before', + 'navigate_next', + 'navigation', + 'near_me', + 'near_me_disabled', + 'nearby', + 'nearby_error', + 'nearby_off', + 'nephrology', + 'nest_audio', + 'nest_cam_floodlight', + 'nest_cam_indoor', + 'nest_cam_iq', + 'nest_cam_iq_outdoor', + 'nest_cam_magnet_mount', + 'nest_cam_outdoor', + 'nest_cam_stand', + 'nest_cam_wall_mount', + 'nest_cam_wired_stand', + 'nest_clock_farsight_analog', + 'nest_clock_farsight_digital', + 'nest_connect', + 'nest_detect', + 'nest_display', + 'nest_display_max', + 'nest_doorbell_visitor', + 'nest_eco_leaf', + 'nest_farsight_weather', + 'nest_found_savings', + 'nest_gale_wifi', + 'nest_heat_link_e', + 'nest_heat_link_gen_3', + 'nest_hello_doorbell', + 'nest_locator_tag', + 'nest_mini', + 'nest_multi_room', + 'nest_protect', + 'nest_remote', + 'nest_remote_comfort_sensor', + 'nest_secure_alarm', + 'nest_sunblock', + 'nest_tag', + 'nest_thermostat', + 'nest_thermostat_e_eu', + 'nest_thermostat_gen_3', + 'nest_thermostat_sensor', + 'nest_thermostat_sensor_eu', + 'nest_thermostat_zirconium_eu', + 'nest_true_radiant', + 'nest_wake_on_approach', + 'nest_wake_on_press', + 'nest_wifi_gale', + 'nest_wifi_mistral', + 'nest_wifi_point', + 'nest_wifi_point_vento', + 'nest_wifi_pro', + 'nest_wifi_pro_2', + 'nest_wifi_router', + 'network_cell', + 'network_check', + 'network_intelligence_history', + 'network_intelligence_update', + 'network_locked', + 'network_manage', + 'network_node', + 'network_ping', + 'network_wifi', + 'network_wifi_1_bar', + 'network_wifi_1_bar_locked', + 'network_wifi_2_bar', + 'network_wifi_2_bar_locked', + 'network_wifi_3_bar', + 'network_wifi_3_bar_locked', + 'network_wifi_locked', + 'neurology', + 'new_label', + 'new_releases', + 'new_window', + 'news', + 'newsmode', + 'newspaper', + 'newsstand', + 'next_plan', + 'next_week', + 'nfc', + 'night_shelter', + 'night_sight_auto', + 'night_sight_auto_off', + 'night_sight_max', + 'nightlife', + 'nightlight', + 'nightlight_round', + 'nights_stay', + 'no_accounts', + 'no_adult_content', + 'no_backpack', + 'no_crash', + 'no_drinks', + 'no_encryption', + 'no_encryption_gmailerrorred', + 'no_flash', + 'no_food', + 'no_luggage', + 'no_meals', + 'no_meeting_room', + 'no_photography', + 'no_sim', + 'no_sound', + 'no_stroller', + 'no_transfer', + 'noise_aware', + 'noise_control_off', + 'noise_control_on', + 'nordic_walking', + 'north', + 'north_east', + 'north_west', + 'not_accessible', + 'not_accessible_forward', + 'not_interested', + 'not_listed_location', + 'not_started', + 'note', + 'note_add', + 'note_alt', + 'note_stack', + 'note_stack_add', + 'notes', + 'notification_add', + 'notification_important', + 'notification_multiple', + 'notifications', + 'notifications_active', + 'notifications_none', + 'notifications_off', + 'notifications_paused', + 'notifications_unread', + 'numbers', + 'nutrition', + 'ods', + 'odt', + 'offline_bolt', + 'offline_pin', + 'offline_share', + 'oil_barrel', + 'on_device_training', + 'on_hub_device', + 'oncology', + 'ondemand_video', + 'online_prediction', + 'onsen', + 'opacity', + 'open_in_browser', + 'open_in_full', + 'open_in_new', + 'open_in_new_down', + 'open_in_new_off', + 'open_in_phone', + 'open_jam', + 'open_with', + 'ophthalmology', + 'oral_disease', + 'order_approve', + 'order_play', + 'orders', + 'orthopedics', + 'other_admission', + 'other_houses', + 'outbound', + 'outbox', + 'outbox_alt', + 'outdoor_garden', + 'outdoor_grill', + 'outgoing_mail', + 'outlet', + 'outlined_flag', + 'outpatient', + 'outpatient_med', + 'output', + 'output_circle', + 'oven', + 'oven_gen', + 'overview', + 'overview_key', + 'oxygen_saturation', + 'p2p', + 'pace', + 'pacemaker', + 'package', + 'package_2', + 'padding', + 'page_control', + 'page_info', + 'pageless', + 'pages', + 'pageview', + 'paid', + 'palette', + 'pallet', + 'pan_tool', + 'pan_tool_alt', + 'pan_zoom', + 'panorama', + 'panorama_fish_eye', + 'panorama_horizontal', + 'panorama_photosphere', + 'panorama_vertical', + 'panorama_wide_angle', + 'paragliding', + 'park', + 'partly_cloudy_day', + 'partly_cloudy_night', + 'partner_exchange', + 'partner_reports', + 'party_mode', + 'passkey', + 'password', + 'patient_list', + 'pattern', + 'pause', + 'pause_circle', + 'pause_circle_filled', + 'pause_circle_outline', + 'pause_presentation', + 'payment', + 'payments', + 'pedal_bike', + 'pediatrics', + 'pen_size_1', + 'pen_size_2', + 'pen_size_3', + 'pen_size_4', + 'pen_size_5', + 'pending', + 'pending_actions', + 'pentagon', + 'people', + 'people_alt', + 'people_outline', + 'percent', + 'performance_max', + 'pergola', + 'perm_camera_mic', + 'perm_contact_calendar', + 'perm_data_setting', + 'perm_device_information', + 'perm_identity', + 'perm_media', + 'perm_phone_msg', + 'perm_scan_wifi', + 'person', + 'person_2', + 'person_3', + 'person_4', + 'person_add', + 'person_add_alt', + 'person_add_disabled', + 'person_alert', + 'person_apron', + 'person_book', + 'person_cancel', + 'person_celebrate', + 'person_check', + 'person_filled', + 'person_off', + 'person_outline', + 'person_pin', + 'person_pin_circle', + 'person_play', + 'person_raised_hand', + 'person_remove', + 'person_search', + 'personal_bag', + 'personal_bag_off', + 'personal_bag_question', + 'personal_injury', + 'personal_places', + 'personal_video', + 'pest_control', + 'pest_control_rodent', + 'pet_supplies', + 'pets', + 'phishing', + 'phone', + 'phone_alt', + 'phone_android', + 'phone_bluetooth_speaker', + 'phone_callback', + 'phone_disabled', + 'phone_enabled', + 'phone_forwarded', + 'phone_in_talk', + 'phone_iphone', + 'phone_locked', + 'phone_missed', + 'phone_paused', + 'phonelink', + 'phonelink_erase', + 'phonelink_lock', + 'phonelink_off', + 'phonelink_ring', + 'phonelink_ring_off', + 'phonelink_setup', + 'photo', + 'photo_album', + 'photo_auto_merge', + 'photo_camera', + 'photo_camera_back', + 'photo_camera_front', + 'photo_filter', + 'photo_frame', + 'photo_library', + 'photo_prints', + 'photo_size_select_actual', + 'photo_size_select_large', + 'photo_size_select_small', + 'php', + 'physical_therapy', + 'piano', + 'piano_off', + 'picture_as_pdf', + 'picture_in_picture', + 'picture_in_picture_alt', + 'picture_in_picture_center', + 'picture_in_picture_large', + 'picture_in_picture_medium', + 'picture_in_picture_mobile', + 'picture_in_picture_off', + 'picture_in_picture_small', + 'pie_chart', + 'pie_chart_filled', + 'pie_chart_outline', + 'pie_chart_outlined', + 'pill', + 'pill_off', + 'pin', + 'pin_drop', + 'pin_end', + 'pin_invoke', + 'pinch', + 'pinch_zoom_in', + 'pinch_zoom_out', + 'pip', + 'pip_exit', + 'pivot_table_chart', + 'place', + 'place_item', + 'plagiarism', + 'planner_banner_ad_pt', + 'planner_review', + 'play_arrow', + 'play_circle', + 'play_disabled', + 'play_for_work', + 'play_lesson', + 'play_music', + 'play_pause', + 'play_shapes', + 'playing_cards', + 'playlist_add', + 'playlist_add_check', + 'playlist_add_check_circle', + 'playlist_add_circle', + 'playlist_play', + 'playlist_remove', + 'plumbing', + 'plus_one', + 'podcasts', + 'podiatry', + 'podium', + 'point_of_sale', + 'point_scan', + 'policy', + 'poll', + 'polyline', + 'polymer', + 'pool', + 'portable_wifi_off', + 'portrait', + 'position_bottom_left', + 'position_bottom_right', + 'position_top_right', + 'post', + 'post_add', + 'potted_plant', + 'power', + 'power_input', + 'power_off', + 'power_rounded', + 'power_settings_new', + 'prayer_times', + 'precision_manufacturing', + 'pregnancy', + 'pregnant_woman', + 'preliminary', + 'prescriptions', + 'present_to_all', + 'preview', + 'preview_off', + 'price_change', + 'price_check', + 'print', + 'print_add', + 'print_connect', + 'print_disabled', + 'print_error', + 'print_lock', + 'priority', + 'priority_high', + 'privacy', + 'privacy_tip', + 'private_connectivity', + 'problem', + 'procedure', + 'process_chart', + 'production_quantity_limits', + 'productivity', + 'progress_activity', + 'propane', + 'propane_tank', + 'psychiatry', + 'psychology', + 'psychology_alt', + 'public', + 'public_off', + 'publish', + 'published_with_changes', + 'pulmonology', + 'pulse_alert', + 'punch_clock', + 'push_pin', + 'qr_code', + 'qr_code_2', + 'qr_code_2_add', + 'qr_code_scanner', + 'query_builder', + 'query_stats', + 'question_answer', + 'question_exchange', + 'question_mark', + 'queue', + 'queue_music', + 'queue_play_next', + 'quick_phrases', + 'quick_reference', + 'quick_reference_all', + 'quick_reorder', + 'quickreply', + 'quiet_time', + 'quiet_time_active', + 'quiz', + 'r_mobiledata', + 'radar', + 'radio', + 'radio_button_checked', + 'radio_button_partial', + 'radio_button_unchecked', + 'radiology', + 'railway_alert', + 'rainy', + 'rainy_heavy', + 'rainy_light', + 'rainy_snow', + 'ramen_dining', + 'ramp_left', + 'ramp_right', + 'range_hood', + 'rate_review', + 'raven', + 'raw_off', + 'raw_on', + 'read_more', + 'readiness_score', + 'real_estate_agent', + 'rear_camera', + 'rebase', + 'rebase_edit', + 'receipt', + 'receipt_long', + 'recent_actors', + 'recent_patient', + 'recommend', + 'record_voice_over', + 'rectangle', + 'recycling', + 'redeem', + 'redo', + 'reduce_capacity', + 'refresh', + 'regular_expression', + 'relax', + 'release_alert', + 'remember_me', + 'reminder', + 'reminders_alt', + 'remote_gen', + 'remove', + 'remove_circle', + 'remove_circle_outline', + 'remove_done', + 'remove_from_queue', + 'remove_moderator', + 'remove_red_eye', + 'remove_road', + 'remove_selection', + 'remove_shopping_cart', + 'reopen_window', + 'reorder', + 'repartition', + 'repeat', + 'repeat_on', + 'repeat_one', + 'repeat_one_on', + 'replay', + 'replay_10', + 'replay_30', + 'replay_5', + 'replay_circle_filled', + 'reply', + 'reply_all', + 'report', + 'report_gmailerrorred', + 'report_off', + 'report_problem', + 'request_page', + 'request_quote', + 'reset_image', + 'reset_tv', + 'reset_wrench', + 'resize', + 'respiratory_rate', + 'responsive_layout', + 'restart_alt', + 'restaurant', + 'restaurant_menu', + 'restore', + 'restore_from_trash', + 'restore_page', + 'resume', + 'reviews', + 'rewarded_ads', + 'rheumatology', + 'rib_cage', + 'rice_bowl', + 'right_click', + 'right_panel_close', + 'right_panel_open', + 'ring_volume', + 'ring_volume_filled', + 'ripples', + 'robot', + 'robot_2', + 'rocket', + 'rocket_launch', + 'roller_shades', + 'roller_shades_closed', + 'roller_skating', + 'roofing', + 'room', + 'room_preferences', + 'room_service', + 'rotate_90_degrees_ccw', + 'rotate_90_degrees_cw', + 'rotate_left', + 'rotate_right', + 'roundabout_left', + 'roundabout_right', + 'rounded_corner', + 'route', + 'router', + 'routine', + 'rowing', + 'rss_feed', + 'rsvp', + 'rtt', + 'rubric', + 'rule', + 'rule_folder', + 'rule_settings', + 'run_circle', + 'running_with_errors', + 'rv_hookup', + 'safety_check', + 'safety_check_off', + 'safety_divider', + 'sailing', + 'salinity', + 'sanitizer', + 'satellite', + 'satellite_alt', + 'sauna', + 'save', + 'save_alt', + 'save_as', + 'saved_search', + 'savings', + 'scale', + 'scan', + 'scan_delete', + 'scanner', + 'scatter_plot', + 'scene', + 'schedule', + 'schedule_send', + 'schema', + 'school', + 'science', + 'science_off', + 'score', + 'scoreboard', + 'screen_lock_landscape', + 'screen_lock_portrait', + 'screen_lock_rotation', + 'screen_record', + 'screen_rotation', + 'screen_rotation_alt', + 'screen_rotation_up', + 'screen_search_desktop', + 'screen_share', + 'screenshot', + 'screenshot_frame', + 'screenshot_keyboard', + 'screenshot_monitor', + 'screenshot_region', + 'screenshot_tablet', + 'scrollable_header', + 'scuba_diving', + 'sd', + 'sd_card', + 'sd_card_alert', + 'sd_storage', + 'sdk', + 'search', + 'search_check', + 'search_hands_free', + 'search_off', + 'security', + 'security_key', + 'security_update', + 'security_update_good', + 'security_update_warning', + 'segment', + 'select', + 'select_all', + 'select_check_box', + 'select_to_speak', + 'select_window', + 'select_window_off', + 'self_care', + 'self_improvement', + 'sell', + 'send', + 'send_and_archive', + 'send_money', + 'send_time_extension', + 'send_to_mobile', + 'sensor_door', + 'sensor_occupied', + 'sensor_window', + 'sensors', + 'sensors_krx', + 'sensors_krx_off', + 'sensors_off', + 'sentiment_calm', + 'sentiment_content', + 'sentiment_dissatisfied', + 'sentiment_excited', + 'sentiment_extremely_dissatisfied', + 'sentiment_frustrated', + 'sentiment_neutral', + 'sentiment_sad', + 'sentiment_satisfied', + 'sentiment_satisfied_alt', + 'sentiment_stressed', + 'sentiment_very_dissatisfied', + 'sentiment_very_satisfied', + 'sentiment_worried', + 'service_toolbox', + 'set_meal', + 'settings', + 'settings_accessibility', + 'settings_account_box', + 'settings_alert', + 'settings_applications', + 'settings_b_roll', + 'settings_backup_restore', + 'settings_bluetooth', + 'settings_brightness', + 'settings_cell', + 'settings_cinematic_blur', + 'settings_ethernet', + 'settings_heart', + 'settings_input_antenna', + 'settings_input_component', + 'settings_input_composite', + 'settings_input_hdmi', + 'settings_input_svideo', + 'settings_motion_mode', + 'settings_night_sight', + 'settings_overscan', + 'settings_panorama', + 'settings_phone', + 'settings_photo_camera', + 'settings_power', + 'settings_remote', + 'settings_slow_motion', + 'settings_suggest', + 'settings_system_daydream', + 'settings_timelapse', + 'settings_video_camera', + 'settings_voice', + 'settop_component', + 'severe_cold', + 'shadow', + 'shadow_add', + 'shadow_minus', + 'shape_line', + 'shape_recognition', + 'shapes', + 'share', + 'share_location', + 'share_off', + 'share_reviews', + 'share_windows', + 'sheets_rtl', + 'shelf_auto_hide', + 'shelf_position', + 'shelves', + 'shield', + 'shield_lock', + 'shield_locked', + 'shield_moon', + 'shield_person', + 'shield_question', + 'shield_with_heart', + 'shield_with_house', + 'shift', + 'shift_lock', + 'shop', + 'shop_2', + 'shop_two', + 'shopping_bag', + 'shopping_basket', + 'shopping_cart', + 'shopping_cart_checkout', + 'shoppingmode', + 'short_stay', + 'short_text', + 'shortcut', + 'show_chart', + 'shower', + 'shuffle', + 'shuffle_on', + 'shutter_speed', + 'shutter_speed_add', + 'shutter_speed_minus', + 'sick', + 'side_navigation', + 'sign_language', + 'signal_cellular_0_bar', + 'signal_cellular_1_bar', + 'signal_cellular_2_bar', + 'signal_cellular_3_bar', + 'signal_cellular_4_bar', + 'signal_cellular_add', + 'signal_cellular_alt', + 'signal_cellular_alt_1_bar', + 'signal_cellular_alt_2_bar', + 'signal_cellular_connected_no_internet_0_bar', + 'signal_cellular_connected_no_internet_4_bar', + 'signal_cellular_no_sim', + 'signal_cellular_nodata', + 'signal_cellular_null', + 'signal_cellular_off', + 'signal_cellular_pause', + 'signal_disconnected', + 'signal_wifi_0_bar', + 'signal_wifi_4_bar', + 'signal_wifi_4_bar_lock', + 'signal_wifi_bad', + 'signal_wifi_connected_no_internet_4', + 'signal_wifi_off', + 'signal_wifi_statusbar_4_bar', + 'signal_wifi_statusbar_not_connected', + 'signal_wifi_statusbar_null', + 'signature', + 'signpost', + 'sim_card', + 'sim_card_alert', + 'sim_card_download', + 'single_bed', + 'sip', + 'skateboarding', + 'skeleton', + 'skillet', + 'skillet_cooktop', + 'skip_next', + 'skip_previous', + 'skull', + 'sledding', + 'sleep', + 'sleep_score', + 'slide_library', + 'sliders', + 'slideshow', + 'slow_motion_video', + 'smart_button', + 'smart_display', + 'smart_outlet', + 'smart_screen', + 'smart_toy', + 'smartphone', + 'smb_share', + 'smoke_free', + 'smoking_rooms', + 'sms', + 'sms_failed', + 'snippet_folder', + 'snooze', + 'snowboarding', + 'snowing', + 'snowing_heavy', + 'snowmobile', + 'snowshoeing', + 'soap', + 'social_distance', + 'social_leaderboard', + 'solar_power', + 'sort', + 'sort_by_alpha', + 'sos', + 'sound_detection_dog_barking', + 'sound_detection_glass_break', + 'sound_detection_loud_sound', + 'sound_sampler', + 'soup_kitchen', + 'source', + 'source_environment', + 'source_notes', + 'south', + 'south_america', + 'south_east', + 'south_west', + 'spa', + 'space_bar', + 'space_dashboard', + 'spatial_audio', + 'spatial_audio_off', + 'spatial_tracking', + 'speaker', + 'speaker_group', + 'speaker_notes', + 'speaker_notes_off', + 'speaker_phone', + 'special_character', + 'specific_gravity', + 'speech_to_text', + 'speed', + 'spellcheck', + 'splitscreen', + 'splitscreen_bottom', + 'splitscreen_left', + 'splitscreen_right', + 'splitscreen_top', + 'spo2', + 'spoke', + 'sports', + 'sports_and_outdoors', + 'sports_bar', + 'sports_baseball', + 'sports_basketball', + 'sports_cricket', + 'sports_esports', + 'sports_football', + 'sports_golf', + 'sports_gymnastics', + 'sports_handball', + 'sports_hockey', + 'sports_kabaddi', + 'sports_martial_arts', + 'sports_mma', + 'sports_motorsports', + 'sports_rugby', + 'sports_score', + 'sports_soccer', + 'sports_tennis', + 'sports_volleyball', + 'sprinkler', + 'sprint', + 'square', + 'square_foot', + 'ssid_chart', + 'stack', + 'stack_off', + 'stack_star', + 'stacked_bar_chart', + 'stacked_email', + 'stacked_inbox', + 'stacked_line_chart', + 'stacks', + 'stadia_controller', + 'stadium', + 'stairs', + 'star', + 'star_border', + 'star_border_purple500', + 'star_half', + 'star_outline', + 'star_purple500', + 'star_rate', + 'star_rate_half', + 'stars', + 'start', + 'stat_0', + 'stat_1', + 'stat_2', + 'stat_3', + 'stat_minus_1', + 'stat_minus_2', + 'stat_minus_3', + 'stay_current_landscape', + 'stay_current_portrait', + 'stay_primary_landscape', + 'stay_primary_portrait', + 'step', + 'step_into', + 'step_out', + 'step_over', + 'steppers', + 'steps', + 'stethoscope', + 'stethoscope_arrow', + 'stethoscope_check', + 'sticky_note', + 'sticky_note_2', + 'stock_media', + 'stockpot', + 'stop', + 'stop_circle', + 'stop_screen_share', + 'storage', + 'store', + 'store_mall_directory', + 'storefront', + 'storm', + 'straight', + 'straighten', + 'strategy', + 'stream', + 'stream_apps', + 'streetview', + 'stress_management', + 'strikethrough_s', + 'stroke_full', + 'stroke_partial', + 'stroller', + 'style', + 'styler', + 'stylus', + 'stylus_laser_pointer', + 'stylus_note', + 'subdirectory_arrow_left', + 'subdirectory_arrow_right', + 'subheader', + 'subject', + 'subscript', + 'subscriptions', + 'subtitles', + 'subtitles_off', + 'subway', + 'summarize', + 'sunny', + 'sunny_snowing', + 'superscript', + 'supervised_user_circle', + 'supervised_user_circle_off', + 'supervisor_account', + 'support', + 'support_agent', + 'surfing', + 'surgical', + 'surround_sound', + 'swap_calls', + 'swap_driving_apps', + 'swap_driving_apps_wheel', + 'swap_horiz', + 'swap_horizontal_circle', + 'swap_vert', + 'swap_vertical_circle', + 'sweep', + 'swipe', + 'swipe_down', + 'swipe_down_alt', + 'swipe_left', + 'swipe_left_alt', + 'swipe_right', + 'swipe_right_alt', + 'swipe_up', + 'swipe_up_alt', + 'swipe_vertical', + 'switch', + 'switch_access', + 'switch_access_2', + 'switch_access_shortcut', + 'switch_access_shortcut_add', + 'switch_account', + 'switch_camera', + 'switch_left', + 'switch_right', + 'switch_video', + 'switches', + 'sword_rose', + 'swords', + 'symptoms', + 'synagogue', + 'sync', + 'sync_alt', + 'sync_disabled', + 'sync_lock', + 'sync_problem', + 'sync_saved_locally', + 'syringe', + 'system_security_update', + 'system_security_update_good', + 'system_security_update_warning', + 'system_update', + 'system_update_alt', + 'tab', + 'tab_close', + 'tab_close_right', + 'tab_duplicate', + 'tab_group', + 'tab_move', + 'tab_new_right', + 'tab_recent', + 'tab_unselected', + 'table', + 'table_bar', + 'table_chart', + 'table_chart_view', + 'table_lamp', + 'table_restaurant', + 'table_rows', + 'table_rows_narrow', + 'table_view', + 'tablet', + 'tablet_android', + 'tablet_mac', + 'tabs', + 'tactic', + 'tag', + 'tag_faces', + 'takeout_dining', + 'tamper_detection_off', + 'tamper_detection_on', + 'tap_and_play', + 'tapas', + 'target', + 'task', + 'task_alt', + 'taunt', + 'taxi_alert', + 'team_dashboard', + 'temp_preferences_custom', + 'temp_preferences_eco', + 'temple_buddhist', + 'temple_hindu', + 'tenancy', + 'terminal', + 'terrain', + 'text_ad', + 'text_decrease', + 'text_fields', + 'text_fields_alt', + 'text_format', + 'text_increase', + 'text_rotate_up', + 'text_rotate_vertical', + 'text_rotation_angledown', + 'text_rotation_angleup', + 'text_rotation_down', + 'text_rotation_none', + 'text_select_end', + 'text_select_jump_to_beginning', + 'text_select_jump_to_end', + 'text_select_move_back_character', + 'text_select_move_back_word', + 'text_select_move_down', + 'text_select_move_forward_character', + 'text_select_move_forward_word', + 'text_select_move_up', + 'text_select_start', + 'text_snippet', + 'text_to_speech', + 'textsms', + 'texture', + 'texture_add', + 'texture_minus', + 'theater_comedy', + 'theaters', + 'thermometer', + 'thermometer_add', + 'thermometer_gain', + 'thermometer_loss', + 'thermometer_minus', + 'thermostat', + 'thermostat_auto', + 'thermostat_carbon', + 'things_to_do', + 'thumb_down', + 'thumb_down_alt', + 'thumb_down_filled', + 'thumb_down_off', + 'thumb_down_off_alt', + 'thumb_up', + 'thumb_up_alt', + 'thumb_up_filled', + 'thumb_up_off', + 'thumb_up_off_alt', + 'thumbnail_bar', + 'thumbs_up_down', + 'thunderstorm', + 'tibia', + 'tibia_alt', + 'time_auto', + 'time_to_leave', + 'timelapse', + 'timeline', + 'timer', + 'timer_10', + 'timer_10_alt_1', + 'timer_10_select', + 'timer_3', + 'timer_3_alt_1', + 'timer_3_select', + 'timer_off', + 'tips_and_updates', + 'tire_repair', + 'title', + 'toast', + 'toc', + 'today', + 'toggle_off', + 'toggle_on', + 'token', + 'toll', + 'tonality', + 'toolbar', + 'tools_flat_head', + 'tools_installation_kit', + 'tools_ladder', + 'tools_level', + 'tools_phillips', + 'tools_pliers_wire_stripper', + 'tools_power_drill', + 'tools_wrench', + 'tooltip', + 'top_panel_close', + 'top_panel_open', + 'topic', + 'tornado', + 'total_dissolved_solids', + 'touch_app', + 'touchpad_mouse', + 'tour', + 'toys', + 'toys_and_games', + 'toys_fan', + 'track_changes', + 'traffic', + 'trail_length', + 'trail_length_medium', + 'trail_length_short', + 'train', + 'tram', + 'transcribe', + 'transfer_within_a_station', + 'transform', + 'transgender', + 'transit_enterexit', + 'transition_chop', + 'transition_dissolve', + 'transition_fade', + 'transition_push', + 'transition_slide', + 'translate', + 'transportation', + 'travel', + 'travel_explore', + 'travel_luggage_and_bags', + 'trending_down', + 'trending_flat', + 'trending_up', + 'trip', + 'trip_origin', + 'trolley', + 'trophy', + 'troubleshoot', + 'try', + 'tsunami', + 'tsv', + 'tty', + 'tune', + 'tungsten', + 'turn_left', + 'turn_right', + 'turn_sharp_left', + 'turn_sharp_right', + 'turn_slight_left', + 'turn_slight_right', + 'turned_in', + 'turned_in_not', + 'tv', + 'tv_gen', + 'tv_guide', + 'tv_off', + 'tv_options_edit_channels', + 'tv_options_input_settings', + 'tv_remote', + 'tv_signin', + 'tv_with_assistant', + 'two_pager', + 'two_wheeler', + 'type_specimen', + 'u_turn_left', + 'u_turn_right', + 'ulna_radius', + 'ulna_radius_alt', + 'umbrella', + 'unarchive', + 'undo', + 'unfold_less', + 'unfold_less_double', + 'unfold_more', + 'unfold_more_double', + 'ungroup', + 'universal_currency', + 'universal_currency_alt', + 'universal_local', + 'unknown_2', + 'unknown_5', + 'unknown_document', + 'unknown_med', + 'unlicense', + 'unpublished', + 'unsubscribe', + 'upcoming', + 'update', + 'update_disabled', + 'upgrade', + 'upload', + 'upload_2', + 'upload_file', + 'urology', + 'usb', + 'usb_off', + 'user_attributes', + 'vaccines', + 'vacuum', + 'valve', + 'vape_free', + 'vaping_rooms', + 'variable_add', + 'variable_insert', + 'variable_remove', + 'variables', + 'ventilator', + 'verified', + 'verified_user', + 'vertical_align_bottom', + 'vertical_align_center', + 'vertical_align_top', + 'vertical_distribute', + 'vertical_shades', + 'vertical_shades_closed', + 'vertical_split', + 'vibration', + 'video_call', + 'video_camera_back', + 'video_camera_front', + 'video_camera_front_off', + 'video_chat', + 'video_file', + 'video_label', + 'video_library', + 'video_search', + 'video_settings', + 'video_stable', + 'videocam', + 'videocam_off', + 'videogame_asset', + 'videogame_asset_off', + 'view_agenda', + 'view_array', + 'view_carousel', + 'view_column', + 'view_column_2', + 'view_comfy', + 'view_comfy_alt', + 'view_compact', + 'view_compact_alt', + 'view_cozy', + 'view_day', + 'view_headline', + 'view_in_ar', + 'view_in_ar_new', + 'view_in_ar_off', + 'view_kanban', + 'view_list', + 'view_module', + 'view_quilt', + 'view_sidebar', + 'view_stream', + 'view_timeline', + 'view_week', + 'vignette', + 'villa', + 'visibility', + 'visibility_lock', + 'visibility_off', + 'vital_signs', + 'vitals', + 'voice_chat', + 'voice_over_off', + 'voice_selection', + 'voicemail', + 'volcano', + 'volume_down', + 'volume_down_alt', + 'volume_mute', + 'volume_off', + 'volume_up', + 'volunteer_activism', + 'voting_chip', + 'vpn_key', + 'vpn_key_alert', + 'vpn_key_off', + 'vpn_lock', + 'vr180_create2d', + 'vr180_create2d_off', + 'vrpano', + 'wall_art', + 'wall_lamp', + 'wallet', + 'wallpaper', + 'wallpaper_slideshow', + 'ward', + 'warehouse', + 'warning', + 'warning_amber', + 'warning_off', + 'wash', + 'watch', + 'watch_button_press', + 'watch_later', + 'watch_off', + 'watch_screentime', + 'watch_wake', + 'water', + 'water_bottle', + 'water_bottle_large', + 'water_damage', + 'water_do', + 'water_drop', + 'water_ec', + 'water_full', + 'water_heater', + 'water_lock', + 'water_loss', + 'water_lux', + 'water_medium', + 'water_orp', + 'water_ph', + 'water_pump', + 'water_voc', + 'waterfall_chart', + 'waves', + 'waving_hand', + 'wb_auto', + 'wb_cloudy', + 'wb_incandescent', + 'wb_iridescent', + 'wb_shade', + 'wb_sunny', + 'wb_twilight', + 'wc', + 'weather_hail', + 'weather_mix', + 'weather_snowy', + 'web', + 'web_asset', + 'web_asset_off', + 'web_stories', + 'web_traffic', + 'webhook', + 'weekend', + 'weight', + 'west', + 'whatshot', + 'wheelchair_pickup', + 'where_to_vote', + 'widgets', + 'width', + 'width_full', + 'width_normal', + 'width_wide', + 'wifi', + 'wifi_1_bar', + 'wifi_2_bar', + 'wifi_add', + 'wifi_calling', + 'wifi_calling_1', + 'wifi_calling_2', + 'wifi_calling_3', + 'wifi_channel', + 'wifi_find', + 'wifi_home', + 'wifi_lock', + 'wifi_notification', + 'wifi_off', + 'wifi_password', + 'wifi_protected_setup', + 'wifi_proxy', + 'wifi_tethering', + 'wifi_tethering_error', + 'wifi_tethering_off', + 'wind_power', + 'window', + 'window_closed', + 'window_open', + 'window_sensor', + 'wine_bar', + 'woman', + 'woman_2', + 'work', + 'work_alert', + 'work_history', + 'work_off', + 'work_outline', + 'work_update', + 'workflow', + 'workspace_premium', + 'workspaces', + 'workspaces_outline', + 'wounds_injuries', + 'wrap_text', + 'wrist', + 'wrong_location', + 'wysiwyg', + 'yard', + 'your_trips', + 'youtube_activity', + 'youtube_searched_for', + 'zone_person_alert', + 'zone_person_idle', + 'zone_person_urgent', + 'zoom_in', + 'zoom_in_map', + 'zoom_out', + 'zoom_out_map', +] as const diff --git a/packages/design-system/lib/components/Icons/MaterialIcon/MaterialSymbol/index.tsx b/packages/design-system/lib/components/Icons/MaterialIcon/MaterialSymbol/index.tsx new file mode 100644 index 000000000..599781d45 --- /dev/null +++ b/packages/design-system/lib/components/Icons/MaterialIcon/MaterialSymbol/index.tsx @@ -0,0 +1 @@ +export { MaterialSymbol, type MaterialSymbolProps } from './MaterialSymbol' diff --git a/packages/design-system/lib/components/Icons/MaterialIcon/MaterialSymbol/types.ts b/packages/design-system/lib/components/Icons/MaterialIcon/MaterialSymbol/types.ts new file mode 100644 index 000000000..540037651 --- /dev/null +++ b/packages/design-system/lib/components/Icons/MaterialIcon/MaterialSymbol/types.ts @@ -0,0 +1,55 @@ +import type { + JSXElementConstructor, + ComponentPropsWithoutRef, + JSX, +} from 'react' +import type { MaterialSymbolWeightArray, SymbolCodepointsArray } from './consts' + +export type SymbolCodepoints = (typeof SymbolCodepointsArray)[number] + +export type MaterialSymbolWeight = (typeof MaterialSymbolWeightArray)[number] + +export interface AsProperty { + /** + * An override of the default HTML tag. + * Can also be another React component. + */ + as?: C +} + +/** + * A more sophisticated version of `InheritableElementProps` where + * the passed in `as` prop will determine which props can be included + */ +export type PolymorphicComponentProps< + C extends React.ElementType, + Properties = Record, +> = InheritableElementProps> + +/** + * Source: https://github.com/emotion-js/emotion/blob/master/packages/styled-base/types/helper.d.ts + * A more precise version of just React.ComponentPropsWithoutRef on its own + */ +export type PropsOf< + C extends keyof JSX.IntrinsicElements | JSXElementConstructor, +> = JSX.LibraryManagedAttributes> + +/** + * Allows for extending a set of props (`ExtendedProps`) by an overriding set of props + * (`OverrideProps`), ensuring that any duplicates are overridden by the overriding + * set of props. + */ +export type ExtendableProps< + ExtendedProperties = Record, + OverrideProperties = Record, +> = OverrideProperties & Omit + +/** + * Allows for inheriting the props from the specified element type so that + * props like children, className & style work, as well as element-specific + * attributes like aria roles. The component (`C`) must be passed in. + */ +export type InheritableElementProps< + C extends React.ElementType, + Properties = Record, +> = ExtendableProps, Properties> diff --git a/packages/design-system/lib/components/Loading/Loading.stories.tsx b/packages/design-system/lib/components/Loading/Loading.stories.tsx index 31b63ee78..a342ccdc2 100644 --- a/packages/design-system/lib/components/Loading/Loading.stories.tsx +++ b/packages/design-system/lib/components/Loading/Loading.stories.tsx @@ -1,5 +1,3 @@ -import 'react-material-symbols/rounded' - import type { Meta, StoryObj } from '@storybook/react' import { Loading } from './Loading' diff --git a/packages/design-system/lib/components/RateCard/Modal/modal.ts b/packages/design-system/lib/components/RateCard/Modal/modal.ts index 5fdb306d4..44e2321ab 100644 --- a/packages/design-system/lib/components/RateCard/Modal/modal.ts +++ b/packages/design-system/lib/components/RateCard/Modal/modal.ts @@ -1,4 +1,4 @@ -import type { Dispatch, SetStateAction } from 'react' +import type { Dispatch, JSX, SetStateAction } from 'react' export enum AnimationStateEnum { unmounted = 'unmounted', diff --git a/packages/design-system/lib/components/Select/Select.stories.tsx b/packages/design-system/lib/components/Select/Select.stories.tsx index 6ac4240e9..e552f6fe3 100644 --- a/packages/design-system/lib/components/Select/Select.stories.tsx +++ b/packages/design-system/lib/components/Select/Select.stories.tsx @@ -1,5 +1,3 @@ -import 'react-material-symbols/rounded' - import type { Meta, StoryObj } from '@storybook/react' import { Select } from './Select' diff --git a/packages/design-system/lib/components/Select/SelectFilter.tsx b/packages/design-system/lib/components/Select/SelectFilter.tsx index 6bf693855..c301d755c 100644 --- a/packages/design-system/lib/components/Select/SelectFilter.tsx +++ b/packages/design-system/lib/components/Select/SelectFilter.tsx @@ -99,7 +99,7 @@ export function SelectFilter({ const [value, setValue] = useState(defaultSelectedKey ?? null) const iconColor = isDisabled ? 'Icon/Interactive/Disabled' : 'Icon/Default' - const inputRef = useRef(null) + const inputRef = useRef(null!) return ( =3.3.1" peerDependenciesMeta: typescript: optional: true - checksum: 10c0/2f948d3ff43bc1a31613bca3e0d03808a085e21d210f2766a7e9ead6e79d4e5f0fda202a6d2fffe379d30a07ea2825f48349773879eab9f3232ce90f984e644d + checksum: 10c0/91cd6ba638d46c494f5cddc592c5705e342d5c459bc754b50bbf6d2047dc50e57fb7c907f3865fa92312d2df682900c102105b82a90d04cbd2519eb67d9ed172 languageName: node linkType: hard @@ -12792,7 +12949,7 @@ __metadata: languageName: node linkType: hard -"eslint-plugin-import@npm:^2.28.1, eslint-plugin-import@npm:^2.31.0": +"eslint-plugin-import@npm:^2.31.0": version: 2.31.0 resolution: "eslint-plugin-import@npm:2.31.0" dependencies: @@ -12821,7 +12978,7 @@ __metadata: languageName: node linkType: hard -"eslint-plugin-jsx-a11y@npm:^6.7.1": +"eslint-plugin-jsx-a11y@npm:^6.10.0": version: 6.10.2 resolution: "eslint-plugin-jsx-a11y@npm:6.10.2" dependencies: @@ -12846,16 +13003,7 @@ __metadata: languageName: node linkType: hard -"eslint-plugin-react-hooks@npm:^4.5.0 || 5.0.0-canary-7118f5dd7-20230705": - version: 5.0.0-canary-7118f5dd7-20230705 - resolution: "eslint-plugin-react-hooks@npm:5.0.0-canary-7118f5dd7-20230705" - peerDependencies: - eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 - checksum: 10c0/554c4e426bfeb126155510dcba8345391426af147ee629f1c56c9ef6af08340d11008213e4e15b0138830af2c4439d7158da2091987f7efb01aeab662c44b274 - languageName: node - linkType: hard - -"eslint-plugin-react-hooks@npm:^5.2.0": +"eslint-plugin-react-hooks@npm:^5.0.0, eslint-plugin-react-hooks@npm:^5.2.0": version: 5.2.0 resolution: "eslint-plugin-react-hooks@npm:5.2.0" peerDependencies: @@ -12864,18 +13012,18 @@ __metadata: languageName: node linkType: hard -"eslint-plugin-react-refresh@npm:^0.4.18": - version: 0.4.19 - resolution: "eslint-plugin-react-refresh@npm:0.4.19" +"eslint-plugin-react-refresh@npm:^0.4.20": + version: 0.4.20 + resolution: "eslint-plugin-react-refresh@npm:0.4.20" peerDependencies: eslint: ">=8.40" - checksum: 10c0/7c19c864c5fb1292dd1c9df2ce73cb1f86457937975d108e8619d6f354855d838d3f56f0262ce5cd541a7087de103ad802a32906e13724ea1b93c6e3b6477708 + checksum: 10c0/2ccf4ba28f1dcbcb9e773e46eae1e61e568bba69281a700eb26fd762152e4e90a78c991f9c8173342a7cd2a82f3f52fedb40a1e81360cef9c40ea5b814fa3613 languageName: node linkType: hard -"eslint-plugin-react@npm:^7.33.2": - version: 7.37.4 - resolution: "eslint-plugin-react@npm:7.37.4" +"eslint-plugin-react@npm:^7.37.0": + version: 7.37.5 + resolution: "eslint-plugin-react@npm:7.37.5" dependencies: array-includes: "npm:^3.1.8" array.prototype.findlast: "npm:^1.2.5" @@ -12887,7 +13035,7 @@ __metadata: hasown: "npm:^2.0.2" jsx-ast-utils: "npm:^2.4.1 || ^3.0.0" minimatch: "npm:^3.1.2" - object.entries: "npm:^1.1.8" + object.entries: "npm:^1.1.9" object.fromentries: "npm:^2.0.8" object.values: "npm:^1.2.1" prop-types: "npm:^15.8.1" @@ -12897,7 +13045,7 @@ __metadata: string.prototype.repeat: "npm:^1.0.0" peerDependencies: eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7 - checksum: 10c0/4acbbdb19669dfa9a162ed8847c3ad1918f6aea1ceb675ee320b5d903b4e463fdef25e15233295b6d0a726fef2ea8b015c527da769c7690932ddc52d5b82ba12 + checksum: 10c0/c850bfd556291d4d9234f5ca38db1436924a1013627c8ab1853f77cac73ec19b020e861e6c7b783436a48b6ffcdfba4547598235a37ad4611b6739f65fd8ad57 languageName: node linkType: hard @@ -12910,17 +13058,16 @@ __metadata: languageName: node linkType: hard -"eslint-plugin-storybook@npm:^0.11.2": - version: 0.11.3 - resolution: "eslint-plugin-storybook@npm:0.11.3" +"eslint-plugin-storybook@npm:^0.12.0": + version: 0.12.0 + resolution: "eslint-plugin-storybook@npm:0.12.0" dependencies: "@storybook/csf": "npm:^0.1.11" "@typescript-eslint/utils": "npm:^8.8.1" ts-dedent: "npm:^2.2.0" peerDependencies: eslint: ">=8" - typescript: ">=4.8.4 <5.8.0" - checksum: 10c0/118d66f03b9657b0a4eae50bb31ca91c892722ac2946f3206cbbe6778b977e5c9310595b216fe1d05d89b6b572f97c25f64347e3c5bd7b20113e18147a975bf3 + checksum: 10c0/ce491ca9d817d231584c5016597158ae889780e428eccc93686d13e396ffdfd500318e5f997531c100cc3a7feff89fa2656ee125a116cf2d4d7e2baefbb0ade6 languageName: node linkType: hard @@ -13266,6 +13413,19 @@ __metadata: languageName: node linkType: hard +"fast-glob@npm:3.3.1": + version: 3.3.1 + resolution: "fast-glob@npm:3.3.1" + dependencies: + "@nodelib/fs.stat": "npm:^2.0.2" + "@nodelib/fs.walk": "npm:^1.2.3" + glob-parent: "npm:^5.1.2" + merge2: "npm:^1.3.0" + micromatch: "npm:^4.0.4" + checksum: 10c0/b68431128fb6ce4b804c5f9622628426d990b66c75b21c0d16e3d80e2d1398bf33f7e1724e66a2e3f299285dcf5b8d745b122d0304e7dd66f5231081f33ec67c + languageName: node + linkType: hard + "fast-glob@npm:^3.3.2, fast-glob@npm:^3.3.3": version: 3.3.3 resolution: "fast-glob@npm:3.3.3" @@ -13839,21 +13999,6 @@ __metadata: languageName: node linkType: hard -"glob@npm:10.3.10": - version: 10.3.10 - resolution: "glob@npm:10.3.10" - dependencies: - foreground-child: "npm:^3.1.0" - jackspeak: "npm:^2.3.5" - minimatch: "npm:^9.0.1" - minipass: "npm:^5.0.0 || ^6.0.2 || ^7.0.0" - path-scurry: "npm:^1.10.1" - bin: - glob: dist/esm/bin.mjs - checksum: 10c0/13d8a1feb7eac7945f8c8480e11cd4a44b24d26503d99a8d8ac8d5aefbf3e9802a2b6087318a829fad04cb4e829f25c5f4f1110c68966c498720dd261c7e344d - languageName: node - linkType: hard - "glob@npm:^10.0.0, glob@npm:^10.2.2, glob@npm:^10.3.10, glob@npm:^10.3.7": version: 10.4.5 resolution: "glob@npm:10.4.5" @@ -15206,19 +15351,6 @@ __metadata: languageName: node linkType: hard -"jackspeak@npm:^2.3.5": - version: 2.3.6 - resolution: "jackspeak@npm:2.3.6" - dependencies: - "@isaacs/cliui": "npm:^8.0.2" - "@pkgjs/parseargs": "npm:^0.11.0" - dependenciesMeta: - "@pkgjs/parseargs": - optional: true - checksum: 10c0/f01d8f972d894cd7638bc338e9ef5ddb86f7b208ce177a36d718eac96ec86638a6efa17d0221b10073e64b45edc2ce15340db9380b1f5d5c5d000cbc517dc111 - languageName: node - linkType: hard - "jackspeak@npm:^3.1.2": version: 3.4.3 resolution: "jackspeak@npm:3.4.3" @@ -15744,10 +15876,10 @@ __metadata: languageName: node linkType: hard -"jose@npm:^5.1.3": - version: 5.10.0 - resolution: "jose@npm:5.10.0" - checksum: 10c0/e20d9fc58d7e402f2e5f04e824b8897d5579aae60e64cb88ebdea1395311c24537bf4892f7de413fab1acf11e922797fb1b42269bc8fc65089a3749265ccb7b0 +"jose@npm:^6.0.6": + version: 6.0.11 + resolution: "jose@npm:6.0.11" + checksum: 10c0/d290be4532174e7a53730b7fb84c74327531172bd403b196c592b312b73eedb7489949837bfe831fdbd280799bfc5ba778bc807495a73eda08ae6c49414f405a languageName: node linkType: hard @@ -16688,7 +16820,7 @@ __metadata: languageName: node linkType: hard -"loose-envify@npm:^1.1.0, loose-envify@npm:^1.4.0": +"loose-envify@npm:^1.4.0": version: 1.4.0 resolution: "loose-envify@npm:1.4.0" dependencies: @@ -17221,7 +17353,7 @@ __metadata: languageName: node linkType: hard -"minimatch@npm:^9.0.1, minimatch@npm:^9.0.3, minimatch@npm:^9.0.4": +"minimatch@npm:^9.0.3, minimatch@npm:^9.0.4": version: 9.0.5 resolution: "minimatch@npm:9.0.5" dependencies: @@ -17528,15 +17660,15 @@ __metadata: languageName: node linkType: hard -"next-auth@npm:5.0.0-beta.19": - version: 5.0.0-beta.19 - resolution: "next-auth@npm:5.0.0-beta.19" +"next-auth@npm:5.0.0-beta.27": + version: 5.0.0-beta.27 + resolution: "next-auth@npm:5.0.0-beta.27" dependencies: - "@auth/core": "npm:0.32.0" + "@auth/core": "npm:0.39.0" peerDependencies: "@simplewebauthn/browser": ^9.0.1 "@simplewebauthn/server": ^9.0.2 - next: ^14 || ^15.0.0-0 + next: ^14.0.0-0 || ^15.0.0-0 nodemailer: ^6.6.5 react: ^18.2.0 || ^19.0.0-0 peerDependenciesMeta: @@ -17546,7 +17678,7 @@ __metadata: optional: true nodemailer: optional: true - checksum: 10c0/30804eae158b9e57cdeeeef81d4aee10aabff8c415403b34cab673eb5eeadfe2232d77d782a7b1ad862bb3dc60faacf51794a23e52679243d156531609b7875f + checksum: 10c0/6f13e4d7d44bf0327cea017d7adb8cf9e9bca32bf030dd147ed5dd8301bcd1cf521b577615454b969643a08389b260347cc83c3e3c421dfa593f3ab7b126295a languageName: node linkType: hard @@ -17611,31 +17743,32 @@ __metadata: languageName: node linkType: hard -"next@npm:^14.2.25": - version: 14.2.25 - resolution: "next@npm:14.2.25" +"next@npm:15.3.2": + version: 15.3.2 + resolution: "next@npm:15.3.2" dependencies: - "@next/env": "npm:14.2.25" - "@next/swc-darwin-arm64": "npm:14.2.25" - "@next/swc-darwin-x64": "npm:14.2.25" - "@next/swc-linux-arm64-gnu": "npm:14.2.25" - "@next/swc-linux-arm64-musl": "npm:14.2.25" - "@next/swc-linux-x64-gnu": "npm:14.2.25" - "@next/swc-linux-x64-musl": "npm:14.2.25" - "@next/swc-win32-arm64-msvc": "npm:14.2.25" - "@next/swc-win32-ia32-msvc": "npm:14.2.25" - "@next/swc-win32-x64-msvc": "npm:14.2.25" - "@swc/helpers": "npm:0.5.5" + "@next/env": "npm:15.3.2" + "@next/swc-darwin-arm64": "npm:15.3.2" + "@next/swc-darwin-x64": "npm:15.3.2" + "@next/swc-linux-arm64-gnu": "npm:15.3.2" + "@next/swc-linux-arm64-musl": "npm:15.3.2" + "@next/swc-linux-x64-gnu": "npm:15.3.2" + "@next/swc-linux-x64-musl": "npm:15.3.2" + "@next/swc-win32-arm64-msvc": "npm:15.3.2" + "@next/swc-win32-x64-msvc": "npm:15.3.2" + "@swc/counter": "npm:0.1.3" + "@swc/helpers": "npm:0.5.15" busboy: "npm:1.6.0" caniuse-lite: "npm:^1.0.30001579" - graceful-fs: "npm:^4.2.11" postcss: "npm:8.4.31" - styled-jsx: "npm:5.1.1" + sharp: "npm:^0.34.1" + styled-jsx: "npm:5.1.6" peerDependencies: "@opentelemetry/api": ^1.1.0 "@playwright/test": ^1.41.2 - react: ^18.2.0 - react-dom: ^18.2.0 + babel-plugin-react-compiler: "*" + react: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 + react-dom: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 sass: ^1.3.0 dependenciesMeta: "@next/swc-darwin-arm64": @@ -17652,20 +17785,22 @@ __metadata: optional: true "@next/swc-win32-arm64-msvc": optional: true - "@next/swc-win32-ia32-msvc": - optional: true "@next/swc-win32-x64-msvc": optional: true + sharp: + optional: true peerDependenciesMeta: "@opentelemetry/api": optional: true "@playwright/test": optional: true + babel-plugin-react-compiler: + optional: true sass: optional: true bin: next: dist/bin/next - checksum: 10c0/2ee3859b957208e93dd10925d1059bc8580fedb612348d67a34523c586f19dc4666b28bc4b7107f268fc501a6ad7ea50de65a4f076b41101e633cbac68dfa142 + checksum: 10c0/81bc21e7853cd19ba0dbfedda8a0221819a12286146f43752cb6ecaeed7a8e5f1f3027bdd89e70ee1fd793d2be0f7e181f1944d2ffe8ee0aefef4c312aed4e27 languageName: node linkType: hard @@ -17818,10 +17953,10 @@ __metadata: languageName: node linkType: hard -"oauth4webapi@npm:^2.9.0": - version: 2.17.0 - resolution: "oauth4webapi@npm:2.17.0" - checksum: 10c0/a3be4f07f3050c982c9f47a899cb34eb4ce1b2072818eab37f241c7db932cf0dac31ed90b0913eaaaebfd7b23e8bf397ecef249a11aea699efb62c7657884ba5 +"oauth4webapi@npm:^3.3.0": + version: 3.5.1 + resolution: "oauth4webapi@npm:3.5.1" + checksum: 10c0/5d57ba4299d61173b28ff0612fdfcc550b02c2ce4afcd1641103960c02af18268b55a70f26d47bbfc956680967c307546284b4a0b1f13845589e247f798ff395 languageName: node linkType: hard @@ -17860,14 +17995,15 @@ __metadata: languageName: node linkType: hard -"object.entries@npm:^1.1.8": - version: 1.1.8 - resolution: "object.entries@npm:1.1.8" +"object.entries@npm:^1.1.9": + version: 1.1.9 + resolution: "object.entries@npm:1.1.9" dependencies: - call-bind: "npm:^1.0.7" + call-bind: "npm:^1.0.8" + call-bound: "npm:^1.0.4" define-properties: "npm:^1.2.1" - es-object-atoms: "npm:^1.0.0" - checksum: 10c0/db9ea979d2956a3bc26c262da4a4d212d36f374652cc4c13efdd069c1a519c16571c137e2893d1c46e1cb0e15c88fd6419eaf410c945f329f09835487d7e65d3 + es-object-atoms: "npm:^1.1.1" + checksum: 10c0/d4b8c1e586650407da03370845f029aa14076caca4e4d4afadbc69cfb5b78035fd3ee7be417141abdb0258fa142e59b11923b4c44d8b1255b28f5ffcc50da7db languageName: node linkType: hard @@ -18260,7 +18396,7 @@ __metadata: languageName: node linkType: hard -"path-scurry@npm:^1.10.1, path-scurry@npm:^1.11.1, path-scurry@npm:^1.6.1": +"path-scurry@npm:^1.11.1, path-scurry@npm:^1.6.1": version: 1.11.1 resolution: "path-scurry@npm:1.11.1" dependencies: @@ -18723,21 +18859,12 @@ __metadata: languageName: node linkType: hard -"preact-render-to-string@npm:5.2.3": - version: 5.2.3 - resolution: "preact-render-to-string@npm:5.2.3" - dependencies: - pretty-format: "npm:^3.8.0" +"preact-render-to-string@npm:6.5.11": + version: 6.5.11 + resolution: "preact-render-to-string@npm:6.5.11" peerDependencies: preact: ">=10" - checksum: 10c0/c7695dd034a2dc50e3fd44621fd55e2d41854ab0abbcbc833a81feb3593a22a011596049de5a2486f71483323467a827adc7d6077cbbb1d154c0089fd8ab4cd7 - languageName: node - linkType: hard - -"preact@npm:10.11.3": - version: 10.11.3 - resolution: "preact@npm:10.11.3" - checksum: 10c0/44f342de226a89b53a7156fad0d4192bfc8233a5cc3eb46162f53d3c0c1c2956222d997927c7dff20f52c3592f112cefec5adac64f0477cbd8370fb39126ef7b + checksum: 10c0/a68b704c1343756022fb41322154b45e39f6021b940cbc97e86c292627d017d019700339a17d67b42c308b14fc5323fc120c798f785d6a3e993c8f273610bfe2 languageName: node linkType: hard @@ -18748,6 +18875,13 @@ __metadata: languageName: node linkType: hard +"preact@npm:10.24.3": + version: 10.24.3 + resolution: "preact@npm:10.24.3" + checksum: 10c0/c863df6d7be6a660480189762d8a8f2d4148733fc2bb9efbd9d2fd27315d2c7ede850a16077d716c91666c915c0349bd3c9699733e4f08457226a0519f408761 + languageName: node + linkType: hard + "prelude-ls@npm:^1.2.1": version: 1.2.1 resolution: "prelude-ls@npm:1.2.1" @@ -18793,13 +18927,6 @@ __metadata: languageName: node linkType: hard -"pretty-format@npm:^3.8.0": - version: 3.8.0 - resolution: "pretty-format@npm:3.8.0" - checksum: 10c0/69f12937bfb7b2a537a7463b9f875a16322401f1e44d7702d643faa0d21991126c24c093217ef6da403b54c15942a834174fa1c016b72e2cb9edaae6bb3729b6 - languageName: node - linkType: hard - "proc-log@npm:^5.0.0": version: 5.0.0 resolution: "proc-log@npm:5.0.0" @@ -19195,6 +19322,17 @@ __metadata: languageName: node linkType: hard +"react-dom@npm:19.1.0, react-dom@npm:^19.1.0": + version: 19.1.0 + resolution: "react-dom@npm:19.1.0" + dependencies: + scheduler: "npm:^0.26.0" + peerDependencies: + react: ^19.1.0 + checksum: 10c0/3e26e89bb6c67c9a6aa86cb888c7a7f8258f2e347a6d2a15299c17eb16e04c19194e3452bc3255bd34000a61e45e2cb51e46292392340432f133e5a5d2dfb5fc + languageName: node + linkType: hard + "react-dom@npm:^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0": version: 19.0.0 resolution: "react-dom@npm:19.0.0" @@ -19206,18 +19344,6 @@ __metadata: languageName: node linkType: hard -"react-dom@npm:^18, react-dom@npm:^18.2.0": - version: 18.3.1 - resolution: "react-dom@npm:18.3.1" - dependencies: - loose-envify: "npm:^1.1.0" - scheduler: "npm:^0.23.2" - peerDependencies: - react: ^18.3.1 - checksum: 10c0/a752496c1941f958f2e8ac56239172296fcddce1365ce45222d04a1947e0cc5547df3e8447f855a81d6d39f008d7c32eab43db3712077f09e3f67c4874973e85 - languageName: node - linkType: hard - "react-feather@npm:^2.0.10": version: 2.0.10 resolution: "react-feather@npm:2.0.10" @@ -19317,16 +19443,6 @@ __metadata: languageName: node linkType: hard -"react-material-symbols@npm:^4.4.0": - version: 4.4.0 - resolution: "react-material-symbols@npm:4.4.0" - peerDependencies: - react: ^18.2.0 - react-dom: ^18.2.0 - checksum: 10c0/fe1755c549477967a6b7ec8d2f7e9f8631b3850577256ea8cb47be1851f53bfd916ac4a5c55b80b3710ac7be3a885b5853989fd5c50cd7a7f9d8add9035a78e6 - languageName: node - linkType: hard - "react-property@npm:2.0.2": version: 2.0.2 resolution: "react-property@npm:2.0.2" @@ -19386,6 +19502,13 @@ __metadata: languageName: node linkType: hard +"react@npm:19.1.0, react@npm:^19.1.0": + version: 19.1.0 + resolution: "react@npm:19.1.0" + checksum: 10c0/530fb9a62237d54137a13d2cfb67a7db6a2156faed43eecc423f4713d9b20c6f2728b026b45e28fcd72e8eadb9e9ed4b089e99f5e295d2f0ad3134251bdd3698 + languageName: node + linkType: hard + "react@npm:^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0": version: 19.0.0 resolution: "react@npm:19.0.0" @@ -19393,15 +19516,6 @@ __metadata: languageName: node linkType: hard -"react@npm:^18, react@npm:^18.2.0": - version: 18.3.1 - resolution: "react@npm:18.3.1" - dependencies: - loose-envify: "npm:^1.1.0" - checksum: 10c0/283e8c5efcf37802c9d1ce767f302dd569dd97a70d9bb8c7be79a789b9902451e0d16334b05d73299b20f048cbc3c7d288bbbde10b701fa194e2089c237dbea3 - languageName: node - linkType: hard - "readable-stream@npm:2": version: 2.3.8 resolution: "readable-stream@npm:2.3.8" @@ -20190,8 +20304,8 @@ __metadata: version: 0.0.0-use.local resolution: "scandic@workspace:." dependencies: - "@types/react": "npm:^18.2.0" - "@types/react-dom": "npm:^18.2.0" + "@types/react": "npm:19.1.0" + "@types/react-dom": "npm:19.1.0" husky: "npm:^9.1.7" lint-staged: "npm:^15.2.2" ts-node: "npm:^10.9.2" @@ -20199,15 +20313,6 @@ __metadata: languageName: unknown linkType: soft -"scheduler@npm:^0.23.2": - version: 0.23.2 - resolution: "scheduler@npm:0.23.2" - dependencies: - loose-envify: "npm:^1.1.0" - checksum: 10c0/26383305e249651d4c58e6705d5f8425f153211aef95f15161c151f7b8de885f24751b377e4a0b3dd42cce09aad3f87a61dab7636859c0d89b7daf1a1e2a5c78 - languageName: node - linkType: hard - "scheduler@npm:^0.25.0": version: 0.25.0 resolution: "scheduler@npm:0.25.0" @@ -20215,6 +20320,13 @@ __metadata: languageName: node linkType: hard +"scheduler@npm:^0.26.0": + version: 0.26.0 + resolution: "scheduler@npm:0.26.0" + checksum: 10c0/5b8d5bfddaae3513410eda54f2268e98a376a429931921a81b5c3a2873aab7ca4d775a8caac5498f8cbc7d0daeab947cf923dbd8e215d61671f9f4e392d34356 + languageName: node + linkType: hard + "schema-dts@npm:^1.1.5": version: 1.1.5 resolution: "schema-dts@npm:1.1.5" @@ -20409,6 +20521,78 @@ __metadata: languageName: node linkType: hard +"sharp@npm:^0.34.1": + version: 0.34.1 + resolution: "sharp@npm:0.34.1" + dependencies: + "@img/sharp-darwin-arm64": "npm:0.34.1" + "@img/sharp-darwin-x64": "npm:0.34.1" + "@img/sharp-libvips-darwin-arm64": "npm:1.1.0" + "@img/sharp-libvips-darwin-x64": "npm:1.1.0" + "@img/sharp-libvips-linux-arm": "npm:1.1.0" + "@img/sharp-libvips-linux-arm64": "npm:1.1.0" + "@img/sharp-libvips-linux-ppc64": "npm:1.1.0" + "@img/sharp-libvips-linux-s390x": "npm:1.1.0" + "@img/sharp-libvips-linux-x64": "npm:1.1.0" + "@img/sharp-libvips-linuxmusl-arm64": "npm:1.1.0" + "@img/sharp-libvips-linuxmusl-x64": "npm:1.1.0" + "@img/sharp-linux-arm": "npm:0.34.1" + "@img/sharp-linux-arm64": "npm:0.34.1" + "@img/sharp-linux-s390x": "npm:0.34.1" + "@img/sharp-linux-x64": "npm:0.34.1" + "@img/sharp-linuxmusl-arm64": "npm:0.34.1" + "@img/sharp-linuxmusl-x64": "npm:0.34.1" + "@img/sharp-wasm32": "npm:0.34.1" + "@img/sharp-win32-ia32": "npm:0.34.1" + "@img/sharp-win32-x64": "npm:0.34.1" + color: "npm:^4.2.3" + detect-libc: "npm:^2.0.3" + semver: "npm:^7.7.1" + dependenciesMeta: + "@img/sharp-darwin-arm64": + optional: true + "@img/sharp-darwin-x64": + optional: true + "@img/sharp-libvips-darwin-arm64": + optional: true + "@img/sharp-libvips-darwin-x64": + optional: true + "@img/sharp-libvips-linux-arm": + optional: true + "@img/sharp-libvips-linux-arm64": + optional: true + "@img/sharp-libvips-linux-ppc64": + optional: true + "@img/sharp-libvips-linux-s390x": + optional: true + "@img/sharp-libvips-linux-x64": + optional: true + "@img/sharp-libvips-linuxmusl-arm64": + optional: true + "@img/sharp-libvips-linuxmusl-x64": + optional: true + "@img/sharp-linux-arm": + optional: true + "@img/sharp-linux-arm64": + optional: true + "@img/sharp-linux-s390x": + optional: true + "@img/sharp-linux-x64": + optional: true + "@img/sharp-linuxmusl-arm64": + optional: true + "@img/sharp-linuxmusl-x64": + optional: true + "@img/sharp-wasm32": + optional: true + "@img/sharp-win32-ia32": + optional: true + "@img/sharp-win32-x64": + optional: true + checksum: 10c0/50f5ffb18a775ec9f0d4d39bdc4356fdfa1fc97e69d8800d68e960b93b1c0cce7ee5242225d3b86ffae5801890fd7f93acfee00018f247e7df70fee2b4de7945 + languageName: node + linkType: hard + "shebang-command@npm:^2.0.0": version: 2.0.0 resolution: "shebang-command@npm:2.0.0" @@ -21159,22 +21343,6 @@ __metadata: languageName: node linkType: hard -"styled-jsx@npm:5.1.1": - version: 5.1.1 - resolution: "styled-jsx@npm:5.1.1" - dependencies: - client-only: "npm:0.0.1" - peerDependencies: - react: ">= 16.8.0 || 17.x.x || ^18.0.0-0" - peerDependenciesMeta: - "@babel/core": - optional: true - babel-plugin-macros: - optional: true - checksum: 10c0/42655cdadfa5388f8a48bb282d6b450df7d7b8cf066ac37038bd0499d3c9f084815ebd9ff9dfa12a218fd4441338851db79603498d7557207009c1cf4d609835 - languageName: node - linkType: hard - "styled-jsx@npm:5.1.6": version: 5.1.6 resolution: "styled-jsx@npm:5.1.6"