From e4907d4b477805bfb99e03d699286ea70abc688b Mon Sep 17 00:00:00 2001 From: Linus Flood Date: Wed, 2 Apr 2025 11:37:22 +0000 Subject: [PATCH] Merged in fix/destinations-speed-test (pull request #1704) Feat(destination pages): Performance improvements * fix/destinations: try cache full response * Added more caching * Removed unsed env car * wip * merge master * wip * wip * wip * Renaming Approved-by: Michael Zetterberg --- apps/scandic-web/app/api/hoteldata/route.ts | 3 +- .../CityMap/HotelList/index.tsx | 8 +- .../CityMap/HotelList/utils.ts | 4 +- .../CityMap/HotelListItem/index.tsx | 30 +-- .../OverviewMapContainer/index.tsx | 4 +- .../HotelCardCarousel/index.tsx | 22 +- .../HotelListing/HotelListingItem/index.tsx | 25 +- .../DestinationPage/HotelListing/index.tsx | 2 +- .../ContentType/DestinationPage/Map/index.tsx | 8 +- .../ContentType/DestinationPage/Map/utils.ts | 27 +- .../ActionButtons/index.tsx | 2 +- .../PriceDetails/index.tsx | 20 +- .../NoAvailabilityAlert/alert.module.css | 2 +- .../RoomListItem/Details/details.module.css | 2 +- .../RoomListItem/Rates/getRateDefinition.ts | 9 +- .../RoomListItem/Rates/isSelected.ts | 33 ++- .../RoomListItem/Rates/totalPricePerNight.ts | 13 +- .../RoomNotAvailable/notAvailable.module.css | 2 +- .../Rooms/RoomsList/ScrollToList.tsx | 5 +- .../Rooms/RoomsList/rooms.module.css | 4 +- .../Divider/divider.module.css | 2 +- apps/scandic-web/env/server.ts | 8 - .../hooks/booking/useRateTitles.ts | 2 +- apps/scandic-web/i18n/dictionaries/en.json | 2 +- .../lib/trpc/memoizedRequests/index.ts | 8 +- .../server/routers/hotels/input.ts | 3 +- .../server/routers/hotels/output.ts | 41 +++ .../server/routers/hotels/query.ts | 252 ++++++++++-------- .../server/routers/hotels/utils.ts | 72 +++-- .../stores/destination-data/helper.ts | 22 +- .../selectRate/roomListItem.ts | 15 +- apps/scandic-web/types/hotel.ts | 9 +- .../types/providers/destination-data.ts | 4 +- .../types/stores/destination-data.ts | 6 +- 34 files changed, 381 insertions(+), 290 deletions(-) diff --git a/apps/scandic-web/app/api/hoteldata/route.ts b/apps/scandic-web/app/api/hoteldata/route.ts index b55e13a59..cc07fbe74 100644 --- a/apps/scandic-web/app/api/hoteldata/route.ts +++ b/apps/scandic-web/app/api/hoteldata/route.ts @@ -25,8 +25,9 @@ export async function GET(request: NextRequest) { throw new Error("[WARMUP] Invalid language provided") } - const hotels = await serverClient().hotel.hotels.getAllHotels.get({ + const hotels = await serverClient().hotel.hotels.getDestinationsMapData({ lang: parsedLang.data, + warmup: true, }) return NextResponse.json(hotels) } catch (error) { diff --git a/apps/scandic-web/components/ContentType/DestinationPage/DestinationCityPage/CityMap/HotelList/index.tsx b/apps/scandic-web/components/ContentType/DestinationPage/DestinationCityPage/CityMap/HotelList/index.tsx index 313500ad2..e583a9f7c 100644 --- a/apps/scandic-web/components/ContentType/DestinationPage/DestinationCityPage/CityMap/HotelList/index.tsx +++ b/apps/scandic-web/components/ContentType/DestinationPage/DestinationCityPage/CityMap/HotelList/index.tsx @@ -19,13 +19,15 @@ import { getVisibleHotels } from "./utils" import styles from "./hotelList.module.css" import { AlertTypeEnum } from "@/types/enums/alert" -import type { HotelDataWithUrl } from "@/types/hotel" +import type { DestinationPagesHotelData } from "@/types/hotel" export default function HotelList() { const intl = useIntl() const map = useMap() const coreLib = useMapsLibrary("core") - const [visibleHotels, setVisibleHotels] = useState([]) + const [visibleHotels, setVisibleHotels] = useState< + DestinationPagesHotelData[] + >([]) const { activeHotels, isLoading } = useDestinationDataStore((state) => ({ activeHotels: state.activeHotels, isLoading: state.isLoading, @@ -80,7 +82,7 @@ export default function HotelList() {
    {visibleHotels.map(({ hotel, url }) => ( -
  • +
  • ))} diff --git a/apps/scandic-web/components/ContentType/DestinationPage/DestinationCityPage/CityMap/HotelList/utils.ts b/apps/scandic-web/components/ContentType/DestinationPage/DestinationCityPage/CityMap/HotelList/utils.ts index 88d7841b9..f03282c5f 100644 --- a/apps/scandic-web/components/ContentType/DestinationPage/DestinationCityPage/CityMap/HotelList/utils.ts +++ b/apps/scandic-web/components/ContentType/DestinationPage/DestinationCityPage/CityMap/HotelList/utils.ts @@ -1,7 +1,7 @@ -import type { HotelDataWithUrl } from "@/types/hotel" +import type { DestinationPagesHotelData } from "@/types/hotel" export function getVisibleHotels( - hotels: HotelDataWithUrl[], + hotels: DestinationPagesHotelData[], map: google.maps.Map | null ) { const bounds = map?.getBounds() diff --git a/apps/scandic-web/components/ContentType/DestinationPage/DestinationCityPage/CityMap/HotelListItem/index.tsx b/apps/scandic-web/components/ContentType/DestinationPage/DestinationCityPage/CityMap/HotelListItem/index.tsx index f3670eb20..c77c3ec75 100644 --- a/apps/scandic-web/components/ContentType/DestinationPage/DestinationCityPage/CityMap/HotelListItem/index.tsx +++ b/apps/scandic-web/components/ContentType/DestinationPage/DestinationCityPage/CityMap/HotelListItem/index.tsx @@ -19,15 +19,11 @@ import { getSingleDecimal } from "@/utils/numberFormatting" import styles from "./hotelListItem.module.css" -import type { Hotel } from "@/types/hotel" +import type { DestinationPagesHotelData } from "@/types/hotel" -interface HotelListItemProps { - hotel: Hotel - url: string | null -} - -export default function HotelListItem({ hotel, url }: HotelListItemProps) { +export default function HotelListItem(data: DestinationPagesHotelData) { const intl = useIntl() + const { hotel, url } = data const galleryImages = mapApiImagesToGalleryImages(hotel.galleryImages || []) const amenities = hotel.detailedFacilities.slice(0, 5) @@ -35,7 +31,7 @@ export default function HotelListItem({ hotel, url }: HotelListItemProps) { const { setHoveredMarker, activeMarker } = useDestinationPageHotelsMapStore() useEffect(() => { - if (activeMarker === hotel.operaId) { + if (activeMarker === hotel.id) { const element = itemRef.current if (element) { element.scrollIntoView({ @@ -45,13 +41,13 @@ export default function HotelListItem({ hotel, url }: HotelListItemProps) { }) } } - }, [activeMarker, hotel.operaId]) + }, [activeMarker, hotel.id]) const handleMouseEnter = useCallback(() => { - if (hotel.operaId) { - setHoveredMarker(hotel.operaId) + if (hotel.id) { + setHoveredMarker(hotel.id) } - }, [setHoveredMarker, hotel.operaId]) + }, [setHoveredMarker, hotel.id]) const handleMouseLeave = useCallback(() => { setHoveredMarker(null) @@ -62,7 +58,7 @@ export default function HotelListItem({ hotel, url }: HotelListItemProps) { ref={itemRef} onMouseEnter={handleMouseEnter} onMouseLeave={handleMouseLeave} - className={`${styles.hotelListItem} ${activeMarker === hotel.operaId ? styles.activeCard : ""}`} + className={`${styles.hotelListItem} ${activeMarker === hotel.id ? styles.activeCard : ""}`} >
    - {hotel.ratings?.tripAdvisor.rating && ( + {hotel.tripadvisor && (
    - - {hotel.ratings.tripAdvisor.rating} - + {hotel.tripadvisor}
    )}
    - +

    {hotel.name}

    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 82815dfc5..b132b8e2e 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 { getAllHotels } from "@/lib/trpc/memoizedRequests" +import { getDestinationsMapData } 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 getAllHotels() + const hotelData = await getDestinationsMapData() if (!hotelData) { return null diff --git a/apps/scandic-web/components/ContentType/DestinationPage/HotelCardCarousel/index.tsx b/apps/scandic-web/components/ContentType/DestinationPage/HotelCardCarousel/index.tsx index e6420058d..b94ff3480 100644 --- a/apps/scandic-web/components/ContentType/DestinationPage/HotelCardCarousel/index.tsx +++ b/apps/scandic-web/components/ContentType/DestinationPage/HotelCardCarousel/index.tsx @@ -11,10 +11,10 @@ import HotelMapCard from "../HotelMapCard" import styles from "./hotelCardCarousel.module.css" -import type { Hotel, HotelDataWithUrl } from "@/types/hotel" +import type { DestinationPagesHotelData } from "@/types/hotel" interface MapCardCarouselProps { - visibleHotels: HotelDataWithUrl[] | [] + visibleHotels: DestinationPagesHotelData[] } export default function HotelCardCarousel({ visibleHotels, @@ -22,13 +22,13 @@ export default function HotelCardCarousel({ const { activeMarker, setActiveMarker } = useDestinationPageHotelsMapStore() const selectedHotelIdx = visibleHotels.findIndex( - ({ hotel }) => hotel.operaId === activeMarker + ({ hotel }) => hotel.id === activeMarker ) const handleScrollSelect = useCallback( (idx: number) => { if (selectedHotelIdx !== -1) { - setActiveMarker(visibleHotels[idx]?.hotel.operaId) + setActiveMarker(visibleHotels[idx]?.hotel.id) } }, [setActiveMarker, visibleHotels, selectedHotelIdx] @@ -44,15 +44,15 @@ export default function HotelCardCarousel({ > {visibleHotels.map(({ hotel, url }) => ( - + @@ -62,11 +62,11 @@ export default function HotelCardCarousel({ ) } -function getImage(hotel: Hotel) { +function getImage(hotel: DestinationPagesHotelData) { return { - src: hotel.galleryImages[0].imageSizes.medium, + src: hotel.hotel.galleryImages?.[0]?.imageSizes.medium, alt: - hotel.galleryImages[0].metaData.altText || - hotel.galleryImages[0].metaData.altText_En, + hotel.hotel.galleryImages?.[0]?.metaData.altText || + hotel.hotel.galleryImages?.[0]?.metaData.altText_En, } } diff --git a/apps/scandic-web/components/ContentType/DestinationPage/HotelListing/HotelListingItem/index.tsx b/apps/scandic-web/components/ContentType/DestinationPage/HotelListing/HotelListingItem/index.tsx index 0df2189d1..05e0447b1 100644 --- a/apps/scandic-web/components/ContentType/DestinationPage/HotelListing/HotelListingItem/index.tsx +++ b/apps/scandic-web/components/ContentType/DestinationPage/HotelListing/HotelListingItem/index.tsx @@ -25,19 +25,12 @@ import { getSingleDecimal } from "@/utils/numberFormatting" import styles from "./hotelListingItem.module.css" -import type { Hotel } from "@/types/hotel" +import type { DestinationPagesHotelData } from "@/types/hotel" -interface HotelListingItemProps { - hotel: Hotel - url: string | null -} - -export default function HotelListingItem({ - hotel, - url, -}: HotelListingItemProps) { +export default function HotelListingItem(data: DestinationPagesHotelData) { const intl = useIntl() const params = useParams() + const { hotel, url } = data const { setActiveMarker } = useDestinationPageHotelsMapStore() const galleryImages = mapApiImagesToGalleryImages(hotel.galleryImages || []) const amenities = hotel.detailedFacilities.slice(0, 5) @@ -61,18 +54,16 @@ export default function HotelListingItem({ { title: hotel.name } )} /> - {hotel.ratings?.tripAdvisor.rating && ( + {hotel.tripadvisor && (
    - - {hotel.ratings.tripAdvisor.rating} - + {hotel.tripadvisor}
    )}
    - +

    {hotel.name}

    @@ -93,7 +84,7 @@ export default function HotelListingItem({
    - {hotel.hotelContent.texts.descriptions?.short} + {hotel.hotelContent?.texts.descriptions?.short}
      {amenities.map((amenity) => { const Icon = ( @@ -112,7 +103,7 @@ export default function HotelListingItem({ setActiveMarker(hotel.operaId)} + onClick={() => setActiveMarker(hotel.id)} > {intl.formatMessage({ id: "See on map" })}
        {activeHotels.map(({ hotel, url }) => ( -
      • +
      • ))} diff --git a/apps/scandic-web/components/ContentType/DestinationPage/Map/index.tsx b/apps/scandic-web/components/ContentType/DestinationPage/Map/index.tsx index d4bef58bb..37bb98f3a 100644 --- a/apps/scandic-web/components/ContentType/DestinationPage/Map/index.tsx +++ b/apps/scandic-web/components/ContentType/DestinationPage/Map/index.tsx @@ -29,10 +29,10 @@ import { getHotelMapMarkers, mapMarkerDataToGeoJson } from "./utils" import styles from "./map.module.css" import type { MapLocation } from "@/types/components/mapLocation" -import type { HotelDataWithUrl } from "@/types/hotel" +import type { DestinationPagesHotelData } from "@/types/hotel" interface MapProps { - hotels: HotelDataWithUrl[] + hotels: DestinationPagesHotelData[] mapId: string apiKey: string pageType: "city" | "country" @@ -55,9 +55,7 @@ export default function Map({ () => searchParams.get("view") === "map", [searchParams] ) - const activeHotel = hotels.find( - ({ hotel }) => hotel.operaId === activeHotelId - ) + const activeHotel = hotels.find(({ hotel }) => hotel.id === activeHotelId) const rootDiv = useRef(null) const [mapHeight, setMapHeight] = useState("0px") const [scrollHeightWhenOpened, setScrollHeightWhenOpened] = useState(0) diff --git a/apps/scandic-web/components/ContentType/DestinationPage/Map/utils.ts b/apps/scandic-web/components/ContentType/DestinationPage/Map/utils.ts index b5ddb6e6c..dcdd1ecb7 100644 --- a/apps/scandic-web/components/ContentType/DestinationPage/Map/utils.ts +++ b/apps/scandic-web/components/ContentType/DestinationPage/Map/utils.ts @@ -3,7 +3,7 @@ import type { MarkerFeature, MarkerGeojson, } from "@/types/components/maps/destinationMarkers" -import type { HotelDataWithUrl } from "@/types/hotel" +import type { DestinationPagesHotelData } from "@/types/hotel" export function mapMarkerDataToGeoJson(markers: DestinationMarker[]) { const features = markers.map( @@ -28,7 +28,7 @@ export function mapMarkerDataToGeoJson(markers: DestinationMarker[]) { return geoJson } -export function getHotelMapMarkers(hotels: HotelDataWithUrl[]) { +export function getHotelMapMarkers(hotels: DestinationPagesHotelData[]) { const markers = hotels .map(({ hotel, url }) => ({ id: hotel.id, @@ -41,20 +41,21 @@ export function getHotelMapMarkers(hotels: HotelDataWithUrl[]) { } : null, url: url, - tripadvisor: hotel.ratings?.tripAdvisor.rating, - amenities: hotel.detailedFacilities.slice(0, 3), - image: - hotel.galleryImages && hotel.galleryImages[0] - ? { - src: hotel.galleryImages[0].imageSizes.medium, - alt: - hotel.galleryImages[0].metaData.altText || - hotel.galleryImages[0].metaData.altText_En, - } - : null, + tripadvisor: hotel.tripadvisor, + amenities: hotel.detailedFacilities, + image: getImage({ hotel, url }), })) .filter((item): item is DestinationMarker => !!item.coordinates) return markers } + +function getImage(hotel: DestinationPagesHotelData) { + return { + src: hotel.hotel.galleryImages?.[0]?.imageSizes.medium, + alt: + hotel.hotel.galleryImages?.[0]?.metaData.altText || + hotel.hotel.galleryImages?.[0]?.metaData.altText_En, + } +} diff --git a/apps/scandic-web/components/HotelReservation/MyStay/Ancillaries/AddAncillaryFlow/AddAncillaryFlowModal/ActionButtons/index.tsx b/apps/scandic-web/components/HotelReservation/MyStay/Ancillaries/AddAncillaryFlow/AddAncillaryFlowModal/ActionButtons/index.tsx index ba534548a..471862295 100644 --- a/apps/scandic-web/components/HotelReservation/MyStay/Ancillaries/AddAncillaryFlow/AddAncillaryFlowModal/ActionButtons/index.tsx +++ b/apps/scandic-web/components/HotelReservation/MyStay/Ancillaries/AddAncillaryFlow/AddAncillaryFlowModal/ActionButtons/index.tsx @@ -12,7 +12,7 @@ import { import { trackAddAncillary } from "@/utils/tracking/myStay" -import { type AncillaryQuantityFormData,quantitySchema } from "../../schema" +import { type AncillaryQuantityFormData, quantitySchema } from "../../schema" import styles from "./actionButtons.module.css" diff --git a/apps/scandic-web/components/HotelReservation/MyStay/Ancillaries/AddAncillaryFlow/AddAncillaryFlowModal/PriceDetails/index.tsx b/apps/scandic-web/components/HotelReservation/MyStay/Ancillaries/AddAncillaryFlow/AddAncillaryFlowModal/PriceDetails/index.tsx index bc7d00251..a618f6ce9 100644 --- a/apps/scandic-web/components/HotelReservation/MyStay/Ancillaries/AddAncillaryFlow/AddAncillaryFlowModal/PriceDetails/index.tsx +++ b/apps/scandic-web/components/HotelReservation/MyStay/Ancillaries/AddAncillaryFlow/AddAncillaryFlowModal/PriceDetails/index.tsx @@ -47,7 +47,7 @@ export default function PriceDetails({ const totalPrice = isBreakfast ? breakfastData!.priceAdult * breakfastData!.nrOfAdults + - breakfastData!.priceChild * breakfastData!.nrOfPayingChildren + breakfastData!.priceChild * breakfastData!.nrOfPayingChildren : quantityWithCard && selectedAncillary ? selectedAncillary.price.total * quantityWithCard : null @@ -101,15 +101,15 @@ export default function PriceDetails({ const items = isBreakfast ? getBreakfastItems(selectedAncillary, breakfastData) : [ - { - title: selectedAncillary.title, - totalPrice: selectedAncillary.price.total, - currency: selectedAncillary.price.currency, - points: selectedAncillary.points, - quantityWithCard, - quantityWithPoints, - }, - ] + { + title: selectedAncillary.title, + totalPrice: selectedAncillary.price.total, + currency: selectedAncillary.price.currency, + points: selectedAncillary.points, + quantityWithCard, + quantityWithPoints, + }, + ] return ( <> diff --git a/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/NoAvailabilityAlert/alert.module.css b/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/NoAvailabilityAlert/alert.module.css index beb3b8485..67ae964a1 100644 --- a/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/NoAvailabilityAlert/alert.module.css +++ b/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/NoAvailabilityAlert/alert.module.css @@ -2,4 +2,4 @@ margin: 0 auto; padding: var(--Spacing-x-one-and-half); width: 100%; -} \ No newline at end of file +} diff --git a/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/RoomsList/RoomListItem/Details/details.module.css b/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/RoomsList/RoomListItem/Details/details.module.css index 7f707f833..b6d0d0080 100644 --- a/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/RoomsList/RoomListItem/Details/details.module.css +++ b/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/RoomsList/RoomListItem/Details/details.module.css @@ -24,4 +24,4 @@ .name { display: inline-block; -} \ No newline at end of file +} diff --git a/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/RoomsList/RoomListItem/Rates/getRateDefinition.ts b/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/RoomsList/RoomListItem/Rates/getRateDefinition.ts index 6920a3caa..e89b65a84 100644 --- a/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/RoomsList/RoomListItem/Rates/getRateDefinition.ts +++ b/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/RoomsList/RoomListItem/Rates/getRateDefinition.ts @@ -1,4 +1,7 @@ -import type { Product, RateDefinition } from "@/types/trpc/routers/hotel/roomAvailability" +import type { + Product, + RateDefinition, +} from "@/types/trpc/routers/hotel/roomAvailability" /** * Get terms and rate title from the rate definitions when booking code rate @@ -12,7 +15,7 @@ export function getRateDefinition( product: Product, rateDefinitions: RateDefinition[], isUserLoggedIn: boolean, - isMainRoom: boolean, + isMainRoom: boolean ) { return rateDefinitions.find((rateDefinition) => { if ("member" in product && product.member && isUserLoggedIn && isMainRoom) { @@ -28,4 +31,4 @@ export function getRateDefinition( return rateDefinition.rateCode === product.public.rateCode } }) -} \ No newline at end of file +} diff --git a/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/RoomsList/RoomListItem/Rates/isSelected.ts b/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/RoomsList/RoomListItem/Rates/isSelected.ts index 7b9d4af9f..f4f3b01ef 100644 --- a/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/RoomsList/RoomListItem/Rates/isSelected.ts +++ b/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/RoomsList/RoomListItem/Rates/isSelected.ts @@ -8,7 +8,7 @@ import type { export function isSelectedPriceProduct( product: PriceProduct, selectedRate: SelectedRate | null, - roomTypeCode: string, + roomTypeCode: string ) { if (!selectedRate) { return false @@ -25,15 +25,15 @@ export function isSelectedPriceProduct( selectedRatePublic = selectedRate.product.public } - const selectedRateIsMember = ( - member && selectedRateMember && - (member.rateCode === selectedRateMember.rateCode) - ) + const selectedRateIsMember = + member && + selectedRateMember && + member.rateCode === selectedRateMember.rateCode - const selectedRateIsPublic = ( - standard && selectedRatePublic && - (standard.rateCode === selectedRatePublic.rateCode) - ) + const selectedRateIsPublic = + standard && + selectedRatePublic && + standard.rateCode === selectedRatePublic.rateCode return !!( (selectedRateIsMember || selectedRateIsPublic) && selectedRate.roomTypeCode === roomTypeCode @@ -43,15 +43,15 @@ export function isSelectedPriceProduct( export function isSelectedCorporateCheque( product: CorporateChequeProduct, selectedRate: SelectedRate | null, - roomTypeCode: string, + roomTypeCode: string ) { if (!selectedRate || !("corporateCheque" in selectedRate.product)) { return false } - const isSameRateCode = ( - product.corporateCheque.rateCode === selectedRate.product.corporateCheque.rateCode - ) + const isSameRateCode = + product.corporateCheque.rateCode === + selectedRate.product.corporateCheque.rateCode const isSameRoomTypeCode = selectedRate.roomTypeCode === roomTypeCode return isSameRateCode && isSameRoomTypeCode } @@ -59,15 +59,14 @@ export function isSelectedCorporateCheque( export function isSelectedVoucher( product: VoucherProduct, selectedRate: SelectedRate | null, - roomTypeCode: string, + roomTypeCode: string ) { if (!selectedRate || !("voucher" in selectedRate.product)) { return false } - const isSameRateCode = ( + const isSameRateCode = product.voucher.rateCode === selectedRate.product.voucher.rateCode - ) const isSameRoomTypeCode = selectedRate.roomTypeCode === roomTypeCode return isSameRateCode && isSameRoomTypeCode -} \ No newline at end of file +} diff --git a/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/RoomsList/RoomListItem/Rates/totalPricePerNight.ts b/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/RoomsList/RoomListItem/Rates/totalPricePerNight.ts index f33256acd..df9de9c05 100644 --- a/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/RoomsList/RoomListItem/Rates/totalPricePerNight.ts +++ b/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/RoomsList/RoomListItem/Rates/totalPricePerNight.ts @@ -1,25 +1,20 @@ -import type { - RoomPackage, -} from "@/types/components/hotelReservation/selectRate/roomFilter" +import type { RoomPackage } from "@/types/components/hotelReservation/selectRate/roomFilter" export function calculatePricePerNightPriceProduct( pricePerNight: number, requestedPricePerNight: number | undefined, nights: number, - petRoomPackage?: RoomPackage, + petRoomPackage?: RoomPackage ) { const totalPrice = petRoomPackage?.localPrice - ? Math.floor( - pricePerNight + (petRoomPackage.localPrice.price / nights) - ) + ? Math.floor(pricePerNight + petRoomPackage.localPrice.price / nights) : Math.floor(pricePerNight) let totalRequestedPrice = undefined if (requestedPricePerNight) { if (petRoomPackage?.requestedPrice) { totalRequestedPrice = Math.floor( - requestedPricePerNight + - (petRoomPackage.requestedPrice.price / nights) + requestedPricePerNight + petRoomPackage.requestedPrice.price / nights ) } else { totalRequestedPrice = Math.floor(requestedPricePerNight) diff --git a/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/RoomsList/RoomListItem/RoomNotAvailable/notAvailable.module.css b/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/RoomsList/RoomListItem/RoomNotAvailable/notAvailable.module.css index 0687e9a8b..674afbbe2 100644 --- a/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/RoomsList/RoomListItem/RoomNotAvailable/notAvailable.module.css +++ b/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/RoomsList/RoomListItem/RoomNotAvailable/notAvailable.module.css @@ -5,4 +5,4 @@ gap: var(--Spacing-x1); margin: 0; padding: var(--Spacing-x2); -} \ No newline at end of file +} diff --git a/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/RoomsList/ScrollToList.tsx b/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/RoomsList/ScrollToList.tsx index 36c482269..221d6dfd3 100644 --- a/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/RoomsList/ScrollToList.tsx +++ b/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/RoomsList/ScrollToList.tsx @@ -6,8 +6,9 @@ import { useRatesStore } from "@/stores/select-rate" import styles from "./rooms.module.css" export default function ScrollToList() { - const { isSingleRoomAndHasSelection } = useRatesStore(state => ({ - isSingleRoomAndHasSelection: state.booking.rooms.length === 1 && !!state.rateSummary.length, + const { isSingleRoomAndHasSelection } = useRatesStore((state) => ({ + isSingleRoomAndHasSelection: + state.booking.rooms.length === 1 && !!state.rateSummary.length, })) useEffect(() => { diff --git a/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/RoomsList/rooms.module.css b/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/RoomsList/rooms.module.css index c773ca61b..be8911d82 100644 --- a/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/RoomsList/rooms.module.css +++ b/apps/scandic-web/components/HotelReservation/SelectRate/RoomsContainer/Rooms/RoomsList/rooms.module.css @@ -5,6 +5,6 @@ grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); } -.roomList>li { +.roomList > li { width: 100%; -} \ No newline at end of file +} diff --git a/apps/scandic-web/components/TempDesignSystem/Divider/divider.module.css b/apps/scandic-web/components/TempDesignSystem/Divider/divider.module.css index ef2a50ca3..55c541a2d 100644 --- a/apps/scandic-web/components/TempDesignSystem/Divider/divider.module.css +++ b/apps/scandic-web/components/TempDesignSystem/Divider/divider.module.css @@ -62,4 +62,4 @@ .Border-Divider-Default { background-color: var(--Border-Divider-Default); -} \ No newline at end of file +} diff --git a/apps/scandic-web/env/server.ts b/apps/scandic-web/env/server.ts index 130a3c467..b18323cf5 100644 --- a/apps/scandic-web/env/server.ts +++ b/apps/scandic-web/env/server.ts @@ -168,13 +168,6 @@ export const env = createEnv({ // transform to boolean .transform((s) => s === "true") .default("false"), - - CACHE_TIME_HOTELDATA: z - .number() - .default(30 * 60) - .transform((val) => - process.env.CMS_ENVIRONMENT === "test" ? 5 * 60 : val - ), CACHE_TIME_HOTELS: z .number() .default(TWENTYFOUR_HOURS) @@ -284,7 +277,6 @@ export const env = createEnv({ SAS_ENABLED: process.env.SAS, SAS_POINT_TRANSFER_ENABLED: process.env.SAS_POINT_TRANSFER_ENABLED, - CACHE_TIME_HOTELDATA: process.env.CACHE_TIME_HOTELDATA, CACHE_TIME_HOTELS: process.env.CACHE_TIME_HOTELS, CACHE_TIME_CITY_SEARCH: process.env.CACHE_TIME_CITY_SEARCH, diff --git a/apps/scandic-web/hooks/booking/useRateTitles.ts b/apps/scandic-web/hooks/booking/useRateTitles.ts index ae4d8878e..05ea1c1e0 100644 --- a/apps/scandic-web/hooks/booking/useRateTitles.ts +++ b/apps/scandic-web/hooks/booking/useRateTitles.ts @@ -21,4 +21,4 @@ export default function useRateTitles() { }, noPriceAvailable: intl.formatMessage({ id: "No prices available" }), } -} \ No newline at end of file +} diff --git a/apps/scandic-web/i18n/dictionaries/en.json b/apps/scandic-web/i18n/dictionaries/en.json index a7e3911dd..764b3b860 100644 --- a/apps/scandic-web/i18n/dictionaries/en.json +++ b/apps/scandic-web/i18n/dictionaries/en.json @@ -131,9 +131,9 @@ "Breakfast ({totalChildren, plural, one {# child} other {# children}}) x {totalBreakfasts}": "Breakfast ({totalChildren, plural, one {# child} other {# children}}) x {totalBreakfasts}", "Breakfast Restaurant": "Breakfast Restaurant", "Breakfast buffet": "Breakfast buffet", - "Breakfast can only be added for the entire duration of the stay and for all guests.": "Breakfast can only be added for the entire duration of the stay and for all guests.", "Breakfast can be added after booking for an additional fee.": "Breakfast can be added after booking for an additional fee.", "Breakfast can be added after booking for an extra cost for adults and kids ages 4 and up.": "Breakfast can be added after booking for an extra cost for adults and kids ages 4 and up.", + "Breakfast can only be added for the entire duration of the stay and for all guests.": "Breakfast can only be added for the entire duration of the stay and for all guests.", "Breakfast can only be added for the entire duration of the stay
and for all guests.": "Breakfast can only be added for the entire duration of the stay
and for all guests.", "Breakfast charge": "Breakfast charge", "Breakfast deal can be purchased at the hotel.": "Breakfast deal can be purchased at the hotel.", diff --git a/apps/scandic-web/lib/trpc/memoizedRequests/index.ts b/apps/scandic-web/lib/trpc/memoizedRequests/index.ts index 2dfcc3529..b0e05275f 100644 --- a/apps/scandic-web/lib/trpc/memoizedRequests/index.ts +++ b/apps/scandic-web/lib/trpc/memoizedRequests/index.ts @@ -209,9 +209,11 @@ export const getHotelsByCityIdentifier = cache( }) } ) -export const getAllHotels = cache(async function getMemoizedAllHotels() { - return serverClient().hotel.hotels.getAllHotels.get() -}) +export const getDestinationsMapData = cache( + async function getMemoizedDestinationsMapData() { + return serverClient().hotel.hotels.getDestinationsMapData() + } +) export const getDestinationCityPage = cache( async function getMemoizedDestinationCityPage() { return serverClient().contentstack.destinationCityPage.get() diff --git a/apps/scandic-web/server/routers/hotels/input.ts b/apps/scandic-web/server/routers/hotels/input.ts index 3582367ef..2522750b7 100644 --- a/apps/scandic-web/server/routers/hotels/input.ts +++ b/apps/scandic-web/server/routers/hotels/input.ts @@ -96,9 +96,10 @@ export const nearbyHotelIdsInput = z.object({ hotelId: z.string(), }) -export const getAllHotelsInput = z +export const getDestinationsMapDataInput = z .object({ lang: z.nativeEnum(Lang), + warmup: z.boolean().optional(), }) .optional() diff --git a/apps/scandic-web/server/routers/hotels/output.ts b/apps/scandic-web/server/routers/hotels/output.ts index c922e302f..4b82013a5 100644 --- a/apps/scandic-web/server/routers/hotels/output.ts +++ b/apps/scandic-web/server/routers/hotels/output.ts @@ -12,6 +12,10 @@ import { includedSchema, relationshipsSchema as hotelRelationshipsSchema, } from "./schemas/hotel" +import { addressSchema } from "./schemas/hotel/address" +import { detailedFacilitiesSchema } from "./schemas/hotel/detailedFacility" +import { locationSchema } from "./schemas/hotel/location" +import { imageSchema } from "./schemas/image" import { locationCitySchema } from "./schemas/location/city" import { locationHotelSchema } from "./schemas/location/hotel" import { @@ -657,3 +661,40 @@ export const roomFeaturesSchema = z .transform((data) => { return data.data.attributes.roomFeatures }) + +export const destinationPagesHotelDataSchema = z + .object({ + data: z.object({ + id: z.string(), + name: z.string(), + location: locationSchema, + cityIdentifier: z.string().optional(), + tripadvisor: z.number().optional(), + detailedFacilities: detailedFacilitiesSchema, + galleryImages: z + .array(imageSchema) + .nullish() + .transform((arr) => (arr ? arr.filter(Boolean) : [])), + address: addressSchema, + hotelType: z.string(), + type: z.literal("hotels"), // No enum here but the standard return appears to be "hotels". + url: z.string().optional(), + hotelContent: z + .object({ + texts: z.object({ + descriptions: z.object({ + short: z.string().optional(), + }), + }), + }) + .optional(), + }), + }) + .transform(({ data: { ...data } }) => { + return { + hotel: { + ...data, + }, + url: data.url ?? "", + } + }) diff --git a/apps/scandic-web/server/routers/hotels/query.ts b/apps/scandic-web/server/routers/hotels/query.ts index 6b709fcad..504412a2d 100644 --- a/apps/scandic-web/server/routers/hotels/query.ts +++ b/apps/scandic-web/server/routers/hotels/query.ts @@ -26,7 +26,7 @@ import { breakfastPackageInputSchema, cityCoordinatesInputSchema, getAdditionalDataInputSchema, - getAllHotelsInput, + getDestinationsMapDataInput, getHotelsByCityIdentifierInput, getHotelsByCountryInput, getHotelsByCSFilterInput, @@ -70,7 +70,7 @@ import type { BedTypeSelection } from "@/types/components/hotelReservation/enter import { BreakfastPackageEnum } from "@/types/enums/breakfast" import { HotelTypeEnum } from "@/types/enums/hotelType" import { RateTypeEnum } from "@/types/enums/rateType" -import type { HotelDataWithUrl } from "@/types/hotel" +import type { DestinationPagesHotelData, HotelDataWithUrl } from "@/types/hotel" import type { HotelsAvailabilityInputSchema, HotelsByHotelIdsAvailabilityInputSchema, @@ -1292,45 +1292,59 @@ export const hotelQueryRouter = router({ return hotels.filter((hotel): hotel is HotelDataWithUrl => !!hotel) }), }), - getAllHotels: router({ - get: serviceProcedure.input(getAllHotelsInput).query(async function ({ - input, - ctx, - }) { + getDestinationsMapData: serviceProcedure + .input(getDestinationsMapDataInput) + .query(async function ({ input, ctx }) { const lang = input?.lang ?? ctx.lang - const countries = await getCountries({ - // Countries need to be in English regardless of incoming lang because - // we use the names as input for API endpoints. - lang: Lang.en, - serviceToken: ctx.serviceToken, - }) + const warmup = input?.warmup ?? false - if (!countries) { - throw new Error("Unable to fetch countries") + const fetchHotels = async () => { + const countries = await getCountries({ + // Countries need to be in English regardless of incoming lang because + // we use the names as input for API endpoints. + lang: Lang.en, + serviceToken: ctx.serviceToken, + }) + + if (!countries) { + throw new Error("Unable to fetch countries") + } + + const countryNames = countries.data.map((country) => country.name) + const hotelData: DestinationPagesHotelData[] = ( + await Promise.all( + countryNames.map(async (country) => { + const hotelIds = await getHotelIdsByCountry({ + country, + serviceToken: ctx.serviceToken, + }) + + const hotels = await getHotelsByHotelIds({ + hotelIds, + lang: lang, + serviceToken: ctx.serviceToken, + }) + return hotels + }) + ) + ).flat() + + return hotelData } - const countryNames = countries.data.map((country) => country.name) - const hotelData: HotelDataWithUrl[] = ( - await Promise.all( - countryNames.map(async (country) => { - const hotelIds = await getHotelIdsByCountry({ - country, - serviceToken: ctx.serviceToken, - }) + if (warmup) { + return await fetchHotels() + } - const hotels = await getHotelsByHotelIds({ - hotelIds, - lang: lang, - serviceToken: ctx.serviceToken, - }) - return hotels - }) - ) - ).flat() - return hotelData + const cacheClient = await getCacheClient() + return await cacheClient.cacheOrGet( + `${lang}:getDestinationsMapData`, + fetchHotels, + "max" + ) }), - }), }), + nearbyHotelIds: serviceProcedure .input(nearbyHotelIdsInput) .query(async function ({ ctx, input }) { @@ -1341,74 +1355,81 @@ export const hotelQueryRouter = router({ const params: Record = { language: apiLang, } - metrics.nearbyHotelIds.counter.add(1, { - hotelId, - }) - console.info( - "api.hotels.nearbyHotelIds start", - JSON.stringify({ query: { hotelId, params } }) - ) - const apiResponse = await api.get( - api.endpoints.v1.Hotel.Hotels.nearbyHotels(hotelId), - { - headers: { - Authorization: `Bearer ${ctx.serviceToken}`, - }, - }, - params - ) - if (!apiResponse.ok) { - const text = await apiResponse.text() - metrics.nearbyHotelIds.fail.add(1, { - hotelId, - error_type: "http_error", - error: JSON.stringify({ - status: apiResponse.status, - statusText: apiResponse.statusText, - text, - }), - }) - console.error( - "api.hotels.nearbyHotelIds error", - JSON.stringify({ - query: { hotelId, params }, - error: { - status: apiResponse.status, - statusText: apiResponse.statusText, - text, + const cacheClient = await getCacheClient() + return cacheClient.cacheOrGet( + `${apiLang}:nearbyHotels:${hotelId}`, + async () => { + metrics.nearbyHotelIds.counter.add(1, { + hotelId, + }) + console.info( + "api.hotels.nearbyHotelIds start", + JSON.stringify({ query: { hotelId, params } }) + ) + const apiResponse = await api.get( + api.endpoints.v1.Hotel.Hotels.nearbyHotels(hotelId), + { + headers: { + Authorization: `Bearer ${ctx.serviceToken}`, + }, }, + params + ) + if (!apiResponse.ok) { + const text = await apiResponse.text() + metrics.nearbyHotelIds.fail.add(1, { + hotelId, + error_type: "http_error", + error: JSON.stringify({ + status: apiResponse.status, + statusText: apiResponse.statusText, + text, + }), + }) + console.error( + "api.hotels.nearbyHotelIds error", + JSON.stringify({ + query: { hotelId, params }, + error: { + status: apiResponse.status, + statusText: apiResponse.statusText, + text, + }, + }) + ) + return null + } + const apiJson = await apiResponse.json() + const validateHotelData = getNearbyHotelIdsSchema.safeParse(apiJson) + if (!validateHotelData.success) { + metrics.nearbyHotelIds.fail.add(1, { + hotelId, + error_type: "validation_error", + error: JSON.stringify(validateHotelData.error), + }) + console.error( + "api.hotels.nearbyHotelIds validation error", + JSON.stringify({ + query: { hotelId, params }, + error: validateHotelData.error, + }) + ) + throw badRequestError() + } + metrics.nearbyHotelIds.success.add(1, { + hotelId, }) - ) - return null - } - const apiJson = await apiResponse.json() - const validateHotelData = getNearbyHotelIdsSchema.safeParse(apiJson) - if (!validateHotelData.success) { - metrics.nearbyHotelIds.fail.add(1, { - hotelId, - error_type: "validation_error", - error: JSON.stringify(validateHotelData.error), - }) - console.error( - "api.hotels.nearbyHotelIds validation error", - JSON.stringify({ - query: { hotelId, params }, - error: validateHotelData.error, - }) - ) - throw badRequestError() - } - metrics.nearbyHotelIds.success.add(1, { - hotelId, - }) - console.info( - "api.hotels.nearbyHotelIds success", - JSON.stringify({ - query: { hotelId, params }, - }) - ) + console.info( + "api.hotels.nearbyHotelIds success", + JSON.stringify({ + query: { hotelId, params }, + }) + ) - return validateHotelData.data.map((id: string) => parseInt(id, 10)) + return validateHotelData.data.map((id: string) => parseInt(id, 10)) + }, + env.CACHE_TIME_HOTELS + ) }), locations: router({ get: serviceProcedure.input(getLocationsInput).query(async function ({ @@ -1459,22 +1480,29 @@ export const hotelQueryRouter = router({ const { city, hotel } = input async function fetchCoordinates(address: string) { - const url = `https://maps.googleapis.com/maps/api/geocode/json?address=${encodeURIComponent(address)}&key=${apiKey}` - const response = await fetch(url) - const data = await response.json() + const cacheClient = await getCacheClient() + return await cacheClient.cacheOrGet( + `coordinates:${address}`, + async function () { + const url = `https://maps.googleapis.com/maps/api/geocode/json?address=${encodeURIComponent(address)}&key=${apiKey}` + const response = await fetch(url) + const data = await response.json() - if (data.status !== "OK") { - console.error(`Geocode error: ${data.status}`) - return null - } + if (data.status !== "OK") { + console.error(`Geocode error: ${data.status}`) + return null + } - const location = data.results[0]?.geometry?.location - if (!location) { - console.error("No location found in geocode response") - return null - } + const location = data.results[0]?.geometry?.location + if (!location) { + console.error("No location found in geocode response") + return null + } - return location + return location + }, + "1d" + ) } let location = await fetchCoordinates(city) diff --git a/apps/scandic-web/server/routers/hotels/utils.ts b/apps/scandic-web/server/routers/hotels/utils.ts index 261853348..91208f79e 100644 --- a/apps/scandic-web/server/routers/hotels/utils.ts +++ b/apps/scandic-web/server/routers/hotels/utils.ts @@ -24,7 +24,7 @@ import { getHotel } from "./query" import type { z } from "zod" import { PointOfInterestGroupEnum } from "@/types/enums/pointOfInterest" -import type { HotelDataWithUrl } from "@/types/hotel" +import type { DestinationPagesHotelData } from "@/types/hotel" import type { CitiesGroupedByCountry, CityLocation, @@ -529,19 +529,54 @@ export async function getHotelsByHotelIds({ lang: Lang serviceToken: string }) { - const hotelPages = await getHotelPageUrls(lang) - const hotels = await Promise.all( - hotelIds.map(async (hotelId) => { - const hotelData = await getHotel( - { hotelId, language: lang, isCardOnlyPayment: false }, - serviceToken - ) - const hotelPage = hotelPages.find((page) => page.hotelId === hotelId) - return hotelData ? { ...hotelData, url: hotelPage?.url ?? null } : null - }) - ) + const cacheClient = await getCacheClient() + const cacheKey = `${lang}:getHotelsByHotelIds:hotels:${hotelIds.sort().join(",")}` - return hotels.filter((hotel): hotel is HotelDataWithUrl => !!hotel) + return await cacheClient.cacheOrGet( + cacheKey, + async () => { + const hotelPages = await getHotelPageUrls(lang) + const hotels = await Promise.all( + hotelIds.map(async (hotelId) => { + const hotelResponse = await getHotel( + { hotelId, language: lang, isCardOnlyPayment: false }, + serviceToken + ) + + if (!hotelResponse) { + throw new Error(`Hotel not found: ${hotelId}`) + } + + const hotelPage = hotelPages.find((page) => page.hotelId === hotelId) + const { hotel, cities } = hotelResponse + const data: DestinationPagesHotelData = { + hotel: { + id: hotel.id, + galleryImages: hotel.galleryImages?.length + ? [hotel.galleryImages[0]] + : [], + name: hotel.name, + tripadvisor: hotel.ratings?.tripAdvisor?.rating, + detailedFacilities: hotel.detailedFacilities?.slice(0, 3) || [], + location: hotel.location, + hotelType: hotel.hotelType, + type: hotel.type, + address: hotel.address, + cityIdentifier: cities?.[0]?.cityIdentifier, + }, + url: hotelPage?.url ?? "", + } satisfies DestinationPagesHotelData + + return { ...data, url: hotelPage?.url ?? null } + }) + ) + + return hotels.filter( + (hotel): hotel is DestinationPagesHotelData => !!hotel + ) + }, + "1d" + ) } function findProduct(product: Products, rateDefinition: RateDefinition) { @@ -697,10 +732,13 @@ export async function getSelectedRoomAvailability( } if (Array.isArray(product)) { - const redemptionProduct = userPoints ? product.find( - (r) => r.redemption.rateCode === rateDefinition.rateCode && - r.redemption.localPrice.pointsPerStay <= userPoints - ) : undefined + const redemptionProduct = userPoints + ? product.find( + (r) => + r.redemption.rateCode === rateDefinition.rateCode && + r.redemption.localPrice.pointsPerStay <= userPoints + ) + : undefined if (!redemptionProduct) { return null } diff --git a/apps/scandic-web/stores/destination-data/helper.ts b/apps/scandic-web/stores/destination-data/helper.ts index 2daeb1bf0..d15e42e6b 100644 --- a/apps/scandic-web/stores/destination-data/helper.ts +++ b/apps/scandic-web/stores/destination-data/helper.ts @@ -4,20 +4,20 @@ import type { SortItem, } from "@/types/components/destinationFilterAndSort" import { SortOption } from "@/types/enums/destinationFilterAndSort" -import type { HotelDataWithUrl } from "@/types/hotel" +import type { DestinationPagesHotelData } from "@/types/hotel" import type { DestinationCityListItem } from "@/types/trpc/routers/contentstack/destinationCityPage" const HOTEL_SORTING_STRATEGIES: Partial< - Record number> + Record< + SortOption, + (a: DestinationPagesHotelData, b: DestinationPagesHotelData) => number + > > = { [SortOption.Name]: function (a, b) { return a.hotel.name.localeCompare(b.hotel.name) }, [SortOption.TripAdvisorRating]: function (a, b) { - return ( - (b.hotel.ratings?.tripAdvisor.rating ?? 0) - - (a.hotel.ratings?.tripAdvisor.rating ?? 0) - ) + return (b.hotel.tripadvisor ?? 0) - (a.hotel.tripadvisor ?? 0) }, [SortOption.Distance]: function (a, b) { return a.hotel.location.distanceToCentre - b.hotel.location.distanceToCentre @@ -48,7 +48,7 @@ const CITY_SORTING_STRATEGIES: Partial< } export function getFilteredHotels( - hotels: HotelDataWithUrl[], + hotels: DestinationPagesHotelData[], filters: string[] ) { if (filters.length) { @@ -62,11 +62,11 @@ export function getFilteredHotels( } export function getFilteredCities( - filteredHotels: HotelDataWithUrl[], + filteredHotels: DestinationPagesHotelData[], cities: DestinationCityListItem[] ) { const filteredCityIdentifiers = filteredHotels.map( - (hotel) => hotel.cities[0].cityIdentifier + (hotel) => hotel.hotel.cityIdentifier ) return cities.filter((city) => @@ -83,7 +83,7 @@ export function getSortedCities( } export function getSortedHotels( - hotels: HotelDataWithUrl[], + hotels: DestinationPagesHotelData[], sortOption: SortOption ) { const sortFn = HOTEL_SORTING_STRATEGIES[sortOption] @@ -116,7 +116,7 @@ const HOTEL_FACILITIES_FILTER_TYPE_NAMES = [ ] export function getFiltersFromHotels( - hotels: HotelDataWithUrl[] + hotels: DestinationPagesHotelData[] ): CategorizedFilters { if (hotels.length === 0) { return { facilityFilters: [], surroundingsFilters: [] } diff --git a/apps/scandic-web/types/components/hotelReservation/selectRate/roomListItem.ts b/apps/scandic-web/types/components/hotelReservation/selectRate/roomListItem.ts index 338408d72..5ec8ff612 100644 --- a/apps/scandic-web/types/components/hotelReservation/selectRate/roomListItem.ts +++ b/apps/scandic-web/types/components/hotelReservation/selectRate/roomListItem.ts @@ -10,10 +10,7 @@ export type RoomListItemProps = { export type RoomListItemImageProps = Pick< RoomConfiguration, - | "features" - | "roomType" - | "roomTypeCode" - | "roomsLeft" + "features" | "roomType" | "roomTypeCode" | "roomsLeft" > type RoomPackagePriceSchema = z.output @@ -30,9 +27,9 @@ export type CalculatePricesPerNightProps = { export interface RoomSizeProps { roomSize: - | { - max: number - min: number - } - | undefined + | { + max: number + min: number + } + | undefined } diff --git a/apps/scandic-web/types/hotel.ts b/apps/scandic-web/types/hotel.ts index 46c2b2d57..87e2f5f30 100644 --- a/apps/scandic-web/types/hotel.ts +++ b/apps/scandic-web/types/hotel.ts @@ -1,6 +1,9 @@ import type { z } from "zod" -import type { hotelSchema } from "@/server/routers/hotels/output" +import type { + destinationPagesHotelDataSchema, + hotelSchema, +} from "@/server/routers/hotels/output" import type { citySchema } from "@/server/routers/hotels/schemas/city" import type { attributesSchema } from "@/server/routers/hotels/schemas/hotel" import type { addressSchema } from "@/server/routers/hotels/schemas/hotel/address" @@ -75,3 +78,7 @@ export type AdditionalData = ReturnType export type ExtraPageSchema = z.output export type HotelDataWithUrl = HotelData & { url: string } + +export type DestinationPagesHotelData = z.output< + typeof destinationPagesHotelDataSchema +> & { url: string } diff --git a/apps/scandic-web/types/providers/destination-data.ts b/apps/scandic-web/types/providers/destination-data.ts index 4f9d8988b..308c0531d 100644 --- a/apps/scandic-web/types/providers/destination-data.ts +++ b/apps/scandic-web/types/providers/destination-data.ts @@ -1,9 +1,9 @@ -import type { HotelDataWithUrl } from "@/types/hotel" +import type { DestinationPagesHotelData } from "@/types/hotel" import type { SortItem } from "../components/destinationFilterAndSort" import type { DestinationCityListItem } from "../trpc/routers/contentstack/destinationCityPage" export interface DestinationDataProviderProps extends React.PropsWithChildren { - allHotels: HotelDataWithUrl[] + allHotels: DestinationPagesHotelData[] allCities?: DestinationCityListItem[] sortItems: SortItem[] } diff --git a/apps/scandic-web/types/stores/destination-data.ts b/apps/scandic-web/types/stores/destination-data.ts index 04419fa72..45d885f37 100644 --- a/apps/scandic-web/types/stores/destination-data.ts +++ b/apps/scandic-web/types/stores/destination-data.ts @@ -3,7 +3,7 @@ import type { SortItem, } from "../components/destinationFilterAndSort" import type { SortOption } from "../enums/destinationFilterAndSort" -import type { HotelDataWithUrl } from "../hotel" +import type { DestinationPagesHotelData } from "../hotel" import type { DestinationCityListItem } from "../trpc/routers/contentstack/destinationCityPage" interface Actions { @@ -25,8 +25,8 @@ export interface DestinationDataState { actions: Actions allCities: DestinationCityListItem[] activeCities: DestinationCityListItem[] - allHotels: HotelDataWithUrl[] - activeHotels: HotelDataWithUrl[] + allHotels: DestinationPagesHotelData[] + activeHotels: DestinationPagesHotelData[] pendingSort: SortOption activeSort: SortOption defaultSort: SortOption