diff --git a/apps/scandic-web/app/api/hoteldata/route.ts b/apps/scandic-web/app/api/hoteldata/route.ts index 9173ec111..bee05be25 100644 --- a/apps/scandic-web/app/api/hoteldata/route.ts +++ b/apps/scandic-web/app/api/hoteldata/route.ts @@ -27,7 +27,7 @@ export async function GET(request: NextRequest) { } const caller = await serverClient() - const hotels = await caller.hotel.hotels.getDestinationsMapData({ + const hotels = await caller.hotel.hotels.getAllHotelData({ lang: parsedLang.data, warmup: true, }) diff --git a/apps/scandic-web/components/Blocks/DynamicContent/RewardNights/index.tsx b/apps/scandic-web/components/Blocks/DynamicContent/RewardNights/index.tsx new file mode 100644 index 000000000..b755b6d7d --- /dev/null +++ b/apps/scandic-web/components/Blocks/DynamicContent/RewardNights/index.tsx @@ -0,0 +1,122 @@ +import { cx } from "class-variance-authority" + +import Table from "@scandic-hotels/design-system/Table" +import { TextLink } from "@scandic-hotels/design-system/TextLink" +import { Typography } from "@scandic-hotels/design-system/Typography" + +import { getAllHotelData } from "@/lib/trpc/memoizedRequests" + +import { getIntl } from "@/i18n" + +import styles from "./rewardNights.module.css" + +export async function RewardNights() { + const intl = await getIntl() + const hotelData = await getAllHotelData() + + return ( + + + + + {intl.formatMessage({ + id: "rewardNights.table.hotel", + defaultMessage: "Hotel", + })} + + + {intl.formatMessage({ + id: "rewardNights.table.destination", + defaultMessage: "Destination", + })} + + + {intl.formatMessage({ + id: "common.points", + defaultMessage: "Points", + })} + + + + + {hotelData.map((data) => { + const { hotel } = data + const hasCampaign = hotel.rewardNight.campaign.points + return ( + + + {hotel.name} + + + {/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */} + {`${hotel.address.city}, ${hotel.address.country}`} + {hasCampaign ? ( + + ) : null} + + +
+ {formatPoints(hotel.rewardNight.points)} + {hasCampaign ? ( + + + {formatPoints(hotel.rewardNight.campaign.points)} + + + ) : null} +
+
+
+ ) + })} +
+
+ ) +} +interface OfferPriceProps { + points: number + start: string + end: string +} +async function OfferPrice(offer: OfferPriceProps) { + const intl = await getIntl() + + return ( +
+ +

+ {intl.formatMessage({ + id: "rewardNights.offerPrice", + defaultMessage: "Offer price", + })} +

+
+ +

+ {intl.formatMessage({ + id: "rewardNights.stayBetween:", + defaultMessage: "Stay between:", + })} +

+
+ + + +
+ ) +} + +function formatPoints(number: number) { + const format = new Intl.NumberFormat("fr-FR") + return format.format(number).replace(/\u202F/g, " ") +} + +function formatDate(date: string) { + return new Date(date).toISOString().split("T")[0] +} diff --git a/apps/scandic-web/components/Blocks/DynamicContent/RewardNights/rewardNights.module.css b/apps/scandic-web/components/Blocks/DynamicContent/RewardNights/rewardNights.module.css new file mode 100644 index 000000000..14273ea70 --- /dev/null +++ b/apps/scandic-web/components/Blocks/DynamicContent/RewardNights/rewardNights.module.css @@ -0,0 +1,13 @@ +.offerPrice { + display: grid; + gap: var(--Space-x05); +} + +.highlightedText { + color: var(--Text-Interactive-Secondary); + padding-top: var(--Space-x2); +} + +.grid { + display: grid; +} diff --git a/apps/scandic-web/components/Blocks/DynamicContent/index.tsx b/apps/scandic-web/components/Blocks/DynamicContent/index.tsx index 049ffb3a8..f49371c8f 100644 --- a/apps/scandic-web/components/Blocks/DynamicContent/index.tsx +++ b/apps/scandic-web/components/Blocks/DynamicContent/index.tsx @@ -28,6 +28,7 @@ import { SJWidget } from "@/components/SJWidget" import JobylonFeed from "./JobylonFeed" import type { DynamicContentProps } from "@/types/components/blocks/dynamicContent" +import { RewardNights } from "./RewardNights" export default function DynamicContent(props: DynamicContentProps) { return ( @@ -91,6 +92,8 @@ function DynamicContentBlocks(props: DynamicContentProps) { case DynamicContentEnum.Blocks.components.sj_widget: return + case DynamicContentEnum.Blocks.components.reward_nights: + return default: return null } diff --git a/apps/scandic-web/components/ContentType/DestinationPage/DestinationOverviewPage/OverviewMapContainer/index.tsx b/apps/scandic-web/components/ContentType/DestinationPage/DestinationOverviewPage/OverviewMapContainer/index.tsx index 4d3d3e0f0..16ab49cf1 100644 --- a/apps/scandic-web/components/ContentType/DestinationPage/DestinationOverviewPage/OverviewMapContainer/index.tsx +++ b/apps/scandic-web/components/ContentType/DestinationPage/DestinationOverviewPage/OverviewMapContainer/index.tsx @@ -1,5 +1,5 @@ import { env } from "@/env/server" -import { getDestinationsMapData } from "@/lib/trpc/memoizedRequests" +import { getAllHotelData } from "@/lib/trpc/memoizedRequests" import DynamicMap from "../../Map/DynamicMap" import MapContent from "../../Map/MapContent" @@ -8,7 +8,7 @@ import { getHotelMapMarkers, mapMarkerDataToGeoJson } from "../../Map/utils" import ActiveMapCard from "./ActiveMapCard" export default async function OverviewMapContainer() { - const hotelData = await getDestinationsMapData() + const hotelData = await getAllHotelData() if (!hotelData) { return null diff --git a/apps/scandic-web/lib/trpc/memoizedRequests/index.ts b/apps/scandic-web/lib/trpc/memoizedRequests/index.ts index d4fc6b7b1..1a77b3ec2 100644 --- a/apps/scandic-web/lib/trpc/memoizedRequests/index.ts +++ b/apps/scandic-web/lib/trpc/memoizedRequests/index.ts @@ -203,12 +203,10 @@ export const getHotelsByCityIdentifier = cache( }) } ) -export const getDestinationsMapData = cache( - async function getMemoizedDestinationsMapData() { - const caller = await serverClient() - return caller.hotel.hotels.getDestinationsMapData() - } -) +export const getAllHotelData = cache(async function getMemoizedAllHotelData() { + const caller = await serverClient() + return caller.hotel.hotels.getAllHotelData() +}) export const getDestinationCityPage = cache( async function getMemoizedDestinationCityPage() { const caller = await serverClient() diff --git a/apps/scandic-web/services/warmup/warmupHotelData.ts b/apps/scandic-web/services/warmup/warmupHotelData.ts index 1972d54f8..c625e9ff2 100644 --- a/apps/scandic-web/services/warmup/warmupHotelData.ts +++ b/apps/scandic-web/services/warmup/warmupHotelData.ts @@ -16,7 +16,7 @@ export const warmupHotelData = try { const caller = await serverClient() - await caller.hotel.hotels.getDestinationsMapData({ + await caller.hotel.hotels.getAllHotelData({ lang, warmup: true, }) diff --git a/packages/trpc/lib/routers/contentstack/schemas/blocks/table.ts b/packages/trpc/lib/routers/contentstack/schemas/blocks/table.ts index de256fed8..02c88b418 100644 --- a/packages/trpc/lib/routers/contentstack/schemas/blocks/table.ts +++ b/packages/trpc/lib/routers/contentstack/schemas/blocks/table.ts @@ -24,7 +24,7 @@ export const tableSchema = z.object({ ), data: z.array(z.object({}).catchall(z.string())), skipReset: z.boolean(), - tableActionEnabled: z.boolean(), + tableActionEnabled: z.boolean().optional().default(false), headerRowAdded: z.boolean().optional().default(false), }), }), diff --git a/packages/trpc/lib/routers/hotels/output.ts b/packages/trpc/lib/routers/hotels/output.ts index 14f025e42..71a48859e 100644 --- a/packages/trpc/lib/routers/hotels/output.ts +++ b/packages/trpc/lib/routers/hotels/output.ts @@ -26,6 +26,7 @@ import { import { addressSchema } from "./schemas/hotel/address" import { detailedFacilitiesSchema } from "./schemas/hotel/detailedFacility" import { locationSchema } from "./schemas/hotel/location" +import { rewardNightSchema } from "./schemas/hotel/rewardNight" import { imageSchema } from "./schemas/image" import { relationshipsSchema } from "./schemas/relationships" import { roomConfigurationSchema } from "./schemas/roomAvailability/configuration" @@ -600,6 +601,7 @@ export const hotelListingHotelDataSchema = z.object({ hotelType: z.string(), type: z.literal("hotels"), // No enum here but the standard return appears to be "hotels". description: z.string().nullable(), + rewardNight: rewardNightSchema, }), url: z.string().nullable(), meetingUrl: z.string().nullable(), diff --git a/packages/trpc/lib/routers/hotels/query.ts b/packages/trpc/lib/routers/hotels/query.ts index 896bc06de..f11e801c1 100644 --- a/packages/trpc/lib/routers/hotels/query.ts +++ b/packages/trpc/lib/routers/hotels/query.ts @@ -229,7 +229,7 @@ export const hotelQueryRouter = router({ return hotels }), }), - getDestinationsMapData: serviceProcedure + getAllHotelData: serviceProcedure .input(getDestinationsMapDataInput) .query(async function ({ input, ctx }) { const lang = input?.lang ?? ctx.lang diff --git a/packages/trpc/lib/routers/hotels/services/getHotelsByHotelIds.ts b/packages/trpc/lib/routers/hotels/services/getHotelsByHotelIds.ts index c684dd668..e0110064f 100644 --- a/packages/trpc/lib/routers/hotels/services/getHotelsByHotelIds.ts +++ b/packages/trpc/lib/routers/hotels/services/getHotelsByHotelIds.ts @@ -94,6 +94,7 @@ export async function getHotelsByHotelIds({ address: hotel.address, cityIdentifier: cities[0]?.cityIdentifier || null, description: content.description || null, + rewardNight: hotel.rewardNight, }, url: content.url, meetingUrl: additionalData.meetingRooms.meetingOnlineLink || null, diff --git a/packages/trpc/lib/types/dynamicContent.ts b/packages/trpc/lib/types/dynamicContent.ts index 01cb3e076..075035c1a 100644 --- a/packages/trpc/lib/types/dynamicContent.ts +++ b/packages/trpc/lib/types/dynamicContent.ts @@ -29,6 +29,7 @@ export namespace DynamicContentEnum { sas_tier_comparison: "sas_tier_comparison", manage_cookie_consent: "manage_cookie_consent", sj_widget: "sj_widget", + reward_nights: "reward_nights", unknown: "unknown", } as const