feat(SW-718): fix comments

This commit is contained in:
Pontus Dreij
2025-01-27 09:29:34 +01:00
parent 22fe34d5c0
commit bfdc62d263
8 changed files with 134 additions and 46 deletions

View File

@@ -2,6 +2,7 @@ import { useEffect, useState } from "react"
import { useIntl } from "react-intl" import { useIntl } from "react-intl"
import { dt } from "@/lib/dt" import { dt } from "@/lib/dt"
import { useRateSelectionStore } from "@/stores/rate-selection"
import SignupPromoDesktop from "@/components/HotelReservation/SignupPromo/Desktop" import SignupPromoDesktop from "@/components/HotelReservation/SignupPromo/Desktop"
import SignupPromoMobile from "@/components/HotelReservation/SignupPromo/Mobile" import SignupPromoMobile from "@/components/HotelReservation/SignupPromo/Mobile"
@@ -16,9 +17,9 @@ import styles from "./rateSummary.module.css"
import type { RateSummaryProps } from "@/types/components/hotelReservation/selectRate/rateSummary" import type { RateSummaryProps } from "@/types/components/hotelReservation/selectRate/rateSummary"
import { RoomPackageCodeEnum } from "@/types/components/hotelReservation/selectRate/roomFilter" import { RoomPackageCodeEnum } from "@/types/components/hotelReservation/selectRate/roomFilter"
import type { Rate } from "@/types/components/hotelReservation/selectRate/selectRate"
export default function RateSummary({ export default function RateSummary({
rateSummary,
isUserLoggedIn, isUserLoggedIn,
packages, packages,
roomsAvailability, roomsAvailability,
@@ -26,12 +27,19 @@ export default function RateSummary({
const intl = useIntl() const intl = useIntl()
const [isVisible, setIsVisible] = useState(false) const [isVisible, setIsVisible] = useState(false)
const { rateSummary } = useRateSelectionStore()
useEffect(() => { useEffect(() => {
const timer = setTimeout(() => setIsVisible(true), 0) const timer = setTimeout(() => setIsVisible(true), 0)
return () => clearTimeout(timer) return () => clearTimeout(timer)
}, []) }, [])
if (rateSummary.length === 0) return null if (rateSummary.length === 0) return null
const selectedRateSummary = rateSummary.filter(
(summary): summary is Rate => summary !== null
)
const { const {
member, member,
public: publicRate, public: publicRate,
@@ -39,7 +47,7 @@ export default function RateSummary({
roomType, roomType,
priceName, priceName,
priceTerm, priceTerm,
} = rateSummary[0] // TODO: Support multiple rooms } = selectedRateSummary[0] // TODO: Support multiple rooms
const isPetRoomSelected = features.some( const isPetRoomSelected = features.some(
(feature) => feature.code === RoomPackageCodeEnum.PET_ROOM (feature) => feature.code === RoomPackageCodeEnum.PET_ROOM

View File

@@ -75,6 +75,8 @@ export async function RoomsContainer({
const [roomsAvailability, roomsAvailabilityError] = const [roomsAvailability, roomsAvailabilityError] =
await roomsAvailabilityPromise await roomsAvailabilityPromise
console.log("roomsAvailability_", roomsAvailability)
if (packagesError) { if (packagesError) {
// TODO: Log packages error // TODO: Log packages error
console.error("[RoomsContainer] unable to fetch packages") console.error("[RoomsContainer] unable to fetch packages")

View File

@@ -7,7 +7,6 @@ import { useIntl } from "react-intl"
import { useRateSelectionStore } from "@/stores/rate-selection" import { useRateSelectionStore } from "@/stores/rate-selection"
import Subtitle from "@/components/TempDesignSystem/Text/Subtitle" import Subtitle from "@/components/TempDesignSystem/Text/Subtitle"
import { useRateSummary } from "@/hooks/selectRate/useRateSummary"
import { useRoomFiltering } from "@/hooks/selectRate/useRoomFiltering" import { useRoomFiltering } from "@/hooks/selectRate/useRoomFiltering"
import { trackLowestRoomPrice } from "@/utils/tracking" import { trackLowestRoomPrice } from "@/utils/tracking"
import { convertObjToSearchParams, convertSearchParamsToObj } from "@/utils/url" import { convertObjToSearchParams, convertSearchParamsToObj } from "@/utils/url"
@@ -24,10 +23,7 @@ import {
RoomPackageCodeEnum, RoomPackageCodeEnum,
} from "@/types/components/hotelReservation/selectRate/roomFilter" } from "@/types/components/hotelReservation/selectRate/roomFilter"
import type { SelectRateProps } from "@/types/components/hotelReservation/selectRate/roomSelection" import type { SelectRateProps } from "@/types/components/hotelReservation/selectRate/roomSelection"
import type { import type { SelectRateSearchParams } from "@/types/components/hotelReservation/selectRate/selectRate"
Rate,
SelectRateSearchParams,
} from "@/types/components/hotelReservation/selectRate/selectRate"
import type { RoomConfiguration } from "@/server/routers/hotels/output" import type { RoomConfiguration } from "@/server/routers/hotels/output"
export default function Rooms({ export default function Rooms({
@@ -45,8 +41,13 @@ export default function Rooms({
const arrivalDate = searchParams.get("fromDate") const arrivalDate = searchParams.get("fromDate")
const departureDate = searchParams.get("toDate") const departureDate = searchParams.get("toDate")
const { modifyRate, selectedRates, setSelectedRates } = const {
useRateSelectionStore() modifyRate,
selectedRates,
rateSummary,
calculateRateSummary,
initializeRates,
} = useRateSelectionStore()
const bookingWidgetSearchData = useMemo( const bookingWidgetSearchData = useMemo(
() => () =>
@@ -61,10 +62,8 @@ export default function Rooms({
const intl = useIntl() const intl = useIntl()
useEffect(() => { useEffect(() => {
setSelectedRates( initializeRates(bookingWidgetSearchData.rooms.length)
new Array(bookingWidgetSearchData.rooms.length).fill(undefined) }, [initializeRates, bookingWidgetSearchData.rooms.length])
)
}, [setSelectedRates, bookingWidgetSearchData.rooms.length])
const visibleRooms: RoomConfiguration[] = useMemo(() => { const visibleRooms: RoomConfiguration[] = useMemo(() => {
const deduped = filterDuplicateRoomTypesByLowestPrice( const deduped = filterDuplicateRoomTypesByLowestPrice(
@@ -117,14 +116,20 @@ export default function Rooms({
const { selectedPackagesByRoom, getRooms, handleFilter, getFilteredRooms } = const { selectedPackagesByRoom, getRooms, handleFilter, getFilteredRooms } =
useRoomFiltering({ roomsAvailability }) useRoomFiltering({ roomsAvailability })
const rateSummary = useRateSummary({ useEffect(() => {
searchedRoomsAndGuests: bookingWidgetSearchData.rooms, calculateRateSummary({
selectedRates, getFilteredRooms,
availablePackages,
roomCategories,
selectedPackagesByRoom,
})
}, [
getFilteredRooms, getFilteredRooms,
selectedPackagesByRoom,
availablePackages, availablePackages,
roomCategories, roomCategories,
}) selectedPackagesByRoom,
calculateRateSummary,
])
useEffect(() => { useEffect(() => {
if (!rateSummary?.some((rate) => rate === null)) return if (!rateSummary?.some((rate) => rate === null)) return
@@ -180,13 +185,6 @@ export default function Rooms({
router.push(`select-bed?${queryParams}`) router.push(`select-bed?${queryParams}`)
} }
const handleModify = useCallback(
(index: number) => () => {
modifyRate(index)
},
[modifyRate]
)
const handleFilterForRoom = useCallback( const handleFilterForRoom = useCallback(
(index: number) => (index: number) =>
(filter: Record<RoomPackageCodeEnum, boolean | undefined>) => { (filter: Record<RoomPackageCodeEnum, boolean | undefined>) => {
@@ -251,9 +249,7 @@ export default function Rooms({
<SelectedRoomPanel <SelectedRoomPanel
roomIndex={index} roomIndex={index}
room={room} room={room}
selectedRate={rateSummary[index]}
roomCategories={roomCategories} roomCategories={roomCategories}
handleModify={handleModify(index)}
/> />
</div> </div>
<div className={styles.roomSelectionPanel}> <div className={styles.roomSelectionPanel}>
@@ -291,9 +287,6 @@ export default function Rooms({
onSubmit={handleSubmit} onSubmit={handleSubmit}
> >
<RateSummary <RateSummary
rateSummary={rateSummary.filter(
(summary): summary is Rate => summary !== null
)}
isUserLoggedIn={isUserLoggedIn} isUserLoggedIn={isUserLoggedIn}
packages={availablePackages} packages={availablePackages}
roomsAvailability={roomsAvailability} roomsAvailability={roomsAvailability}

View File

@@ -1,6 +1,9 @@
"use client" "use client"
import { useCallback } from "react"
import { useIntl } from "react-intl" import { useIntl } from "react-intl"
import { useRateSelectionStore } from "@/stores/rate-selection"
import { EditIcon } from "@/components/Icons" import { EditIcon } from "@/components/Icons"
import Image from "@/components/Image" import Image from "@/components/Image"
import Button from "@/components/TempDesignSystem/Button" import Button from "@/components/TempDesignSystem/Button"
@@ -9,34 +12,33 @@ import Subtitle from "@/components/TempDesignSystem/Text/Subtitle"
import styles from "./selectedRoomPanel.module.css" import styles from "./selectedRoomPanel.module.css"
import type { import type { Room } from "@/types/components/hotelReservation/selectRate/selectRate"
Rate,
Room,
} from "@/types/components/hotelReservation/selectRate/selectRate"
import type { RoomData } from "@/types/hotel" import type { RoomData } from "@/types/hotel"
interface SelectedRoomPanelProps { interface SelectedRoomPanelProps {
roomIndex: number roomIndex: number
room: Room room: Room
selectedRate: Rate | null
roomCategories: RoomData[] roomCategories: RoomData[]
handleModify: () => void
} }
export default function SelectedRoomPanel({ export default function SelectedRoomPanel({
roomIndex, roomIndex,
room, room,
selectedRate,
roomCategories, roomCategories,
handleModify,
}: SelectedRoomPanelProps) { }: SelectedRoomPanelProps) {
const intl = useIntl() const intl = useIntl()
const { rateSummary, modifyRate } = useRateSelectionStore()
const selectedRate = rateSummary[roomIndex]
const images = roomCategories.find((roomCategory) => const images = roomCategories.find((roomCategory) =>
roomCategory.roomTypes.some( roomCategory.roomTypes.some(
(roomType) => roomType.code === selectedRate?.roomTypeCode (roomType) => roomType.code === selectedRate?.roomTypeCode
) )
)?.images )?.images
const handleModify = useCallback(() => {
modifyRate(roomIndex)
}, [modifyRate, roomIndex])
return ( return (
<div className={styles.selectedRoomPanel}> <div className={styles.selectedRoomPanel}>
<div> <div>

View File

@@ -10,7 +10,7 @@ import type {
} from "@/types/components/hotelReservation/selectRate/selectRate" } from "@/types/components/hotelReservation/selectRate/selectRate"
import type { RoomConfiguration } from "@/server/routers/hotels/output" import type { RoomConfiguration } from "@/server/routers/hotels/output"
interface UseRateSummaryProps { interface UseRateSummary {
searchedRoomsAndGuests: Array<{ adults: number; children?: any[] }> searchedRoomsAndGuests: Array<{ adults: number; children?: any[] }>
selectedRates: (RateCode | undefined)[] selectedRates: (RateCode | undefined)[]
getFilteredRooms: (roomIndex: number) => RoomConfiguration[] getFilteredRooms: (roomIndex: number) => RoomConfiguration[]
@@ -26,7 +26,7 @@ export function useRateSummary({
selectedPackagesByRoom, selectedPackagesByRoom,
availablePackages, availablePackages,
roomCategories, roomCategories,
}: UseRateSummaryProps) { }: UseRateSummary) {
return useMemo(() => { return useMemo(() => {
const summaries: (Rate | null)[] = [] const summaries: (Rate | null)[] = []

View File

@@ -1,17 +1,40 @@
import { create } from "zustand" import { create } from "zustand"
import type { RateCode } from "@/types/components/hotelReservation/selectRate/selectRate" import type {
RoomPackageCodeEnum,
RoomPackageData} from "@/types/components/hotelReservation/selectRate/roomFilter";
import type { RoomParam } from "@/types/components/hotelReservation/selectRate/section"
import type {
Rate,
RateCode,
} from "@/types/components/hotelReservation/selectRate/selectRate"
import type { RoomConfiguration } from "@/server/routers/hotels/output"
interface RateSummaryParams {
getFilteredRooms: (roomIndex: number) => RoomConfiguration[]
availablePackages: RoomPackageData
roomCategories: Array<{ name: string; roomTypes: Array<{ code: string }> }>
selectedPackagesByRoom: Record<number, RoomPackageCodeEnum[]>
}
interface RateSelectionState { interface RateSelectionState {
selectedRates: (RateCode | undefined)[] selectedRates: (RateCode | undefined)[]
setSelectedRates: (rates: (RateCode | undefined)[]) => void roomsAndGuests: RoomParam[]
rateSummary: (Rate | null)[]
modifyRate: (index: number) => void modifyRate: (index: number) => void
selectRate: (index: number, rate: RateCode | undefined) => void selectRate: (index: number, rate: RateCode | undefined) => void
setRoomsAndGuests: (rooms: RoomParam[]) => void
initializeRates: (count: number) => void
calculateRateSummary: ({
getFilteredRooms,
availablePackages,
roomCategories,
}: RateSummaryParams) => void
} }
export const useRateSelectionStore = create<RateSelectionState>((set) => ({ export const useRateSelectionStore = create<RateSelectionState>((set, get) => ({
selectedRates: [], selectedRates: [],
setSelectedRates: (rates) => set({ selectedRates: rates }), roomsAndGuests: [],
rateSummary: [],
modifyRate: (index) => modifyRate: (index) =>
set((state) => { set((state) => {
const newRates = [...state.selectedRates] const newRates = [...state.selectedRates]
@@ -24,4 +47,64 @@ export const useRateSelectionStore = create<RateSelectionState>((set) => ({
newRates[index] = rate newRates[index] = rate
return { selectedRates: newRates } return { selectedRates: newRates }
}), }),
initializeRates: (count) =>
set({ selectedRates: new Array(count).fill(undefined) }),
setRoomsAndGuests: (rooms) => set({ roomsAndGuests: rooms }),
calculateRateSummary: ({
getFilteredRooms,
availablePackages,
roomCategories,
selectedPackagesByRoom,
}) => {
const state = get()
const summaries = state.roomsAndGuests.map((_, roomIndex) => {
const selectedRate = state.selectedRates[roomIndex]
const filteredRooms = getFilteredRooms(roomIndex)
const selectedPackages = selectedPackagesByRoom[roomIndex] || []
const room = filteredRooms.find(
(room) => room.roomTypeCode === selectedRate?.roomTypeCode
)
if (!room) return null
const product = room.products.find(
(product) =>
product.productType.public.rateCode === selectedRate?.publicRateCode
)
if (!product) return null
const petRoomPackage =
(selectedPackages.includes(RoomPackageCodeEnum.PET_ROOM) &&
availablePackages.find(
(pkg) => pkg.code === RoomPackageCodeEnum.PET_ROOM
)) ||
undefined
const features = filteredRooms.find((room) =>
room.features.some(
(feature) => feature.code === RoomPackageCodeEnum.PET_ROOM
)
)?.features
const roomType = roomCategories.find((roomCategory) =>
roomCategory.roomTypes.some(
(roomType) => roomType.code === room.roomTypeCode
)
)
return {
features: petRoomPackage && features ? features : [],
priceName: selectedRate?.name,
priceTerm: selectedRate?.paymentTerm,
public: product.productType.public,
member: product.productType.member,
roomType: roomType?.name ?? room.roomType,
roomTypeCode: room.roomTypeCode,
}
})
set({ rateSummary: summaries })
},
})) }))

View File

@@ -3,7 +3,6 @@ import type { RoomPackageData } from "./roomFilter"
import type { Rate } from "./selectRate" import type { Rate } from "./selectRate"
export interface RateSummaryProps { export interface RateSummaryProps {
rateSummary: Rate[]
isUserLoggedIn: boolean isUserLoggedIn: boolean
packages: RoomPackageData | undefined packages: RoomPackageData | undefined
roomsAvailability: RoomsAvailability roomsAvailability: RoomsAvailability

View File

@@ -1,5 +1,6 @@
import type { CreditCard, SafeUser } from "@/types/user" import type { CreditCard, SafeUser } from "@/types/user"
import type { PaymentMethodEnum } from "@/constants/booking" import type { PaymentMethodEnum } from "@/constants/booking"
import type { Child } from "./selectRate"
export interface SectionProps { export interface SectionProps {
nextPath: string nextPath: string
@@ -43,7 +44,7 @@ export interface PaymentClientProps
export interface RoomParam { export interface RoomParam {
adults: number adults: number
children?: { age: number; bed: number }[] children?: Child[]
} }
export interface SectionPageProps { export interface SectionPageProps {