Merge branch 'master' into feature/tracking

This commit is contained in:
Linus Flood
2024-11-18 12:20:13 +01:00
240 changed files with 5429 additions and 2717 deletions

View File

@@ -23,7 +23,12 @@ import { BreakfastPackageEnum } from "@/types/enums/breakfast"
const SESSION_STORAGE_KEY = "enterDetails"
interface EnterDetailsState {
type TotalPrice = {
local: { price: number; currency: string }
euro: { price: number; currency: string }
}
export interface EnterDetailsState {
userData: {
bedType: BedTypeSchema | undefined
breakfast: BreakfastPackage | BreakfastPackageEnum.NO_BREAKFAST | undefined
@@ -32,6 +37,9 @@ interface EnterDetailsState {
steps: StepEnum[]
selectRateUrl: string
currentStep: StepEnum
totalPrice: TotalPrice
isSubmittingDisabled: boolean
isSummaryOpen: boolean
isValid: Record<StepEnum, boolean>
completeStep: (updatedData: Partial<EnterDetailsState["userData"]>) => void
navigate: (
@@ -42,6 +50,9 @@ interface EnterDetailsState {
>
) => void
setCurrentStep: (step: StepEnum) => void
toggleSummaryOpen: () => void
setTotalPrice: (totalPrice: TotalPrice) => void
setIsSubmittingDisabled: (isSubmittingDisabled: boolean) => void
}
export function initEditDetailsState(
@@ -129,6 +140,12 @@ export function initEditDetailsState(
roomData,
selectRateUrl,
steps: Object.values(StepEnum),
totalPrice: {
local: { price: 0, currency: "" },
euro: { price: 0, currency: "" },
},
isSummaryOpen: false,
isSubmittingDisabled: false,
setCurrentStep: (step) => set({ currentStep: step }),
navigate: (step, updatedData) =>
set(
@@ -166,6 +183,10 @@ export function initEditDetailsState(
get().navigate(nextStep, updatedData)
})
),
toggleSummaryOpen: () => set({ isSummaryOpen: !get().isSummaryOpen }),
setTotalPrice: (totalPrice) => set({ totalPrice: totalPrice }),
setIsSubmittingDisabled: (isSubmittingDisabled) =>
set({ isSubmittingDisabled }),
}))
}

View File

@@ -1,227 +0,0 @@
"use client"
import { produce } from "immer"
import { createContext, useContext } from "react"
import { create, useStore } from "zustand"
import { ChildBedMapEnum } from "@/types/components/bookingWidget/enums"
import {
Child,
GuestsRoom,
} from "@/types/components/bookingWidget/guestsRoomsPicker"
const SESSION_STORAGE_KEY = "guests_rooms"
interface extendedGuestsRoom extends GuestsRoom {
childrenInAdultsBed: number
}
interface GuestsRoomsState {
rooms: extendedGuestsRoom[]
adultCount: number
childCount: number
isValidated: boolean
}
interface GuestsRoomsStoreState extends GuestsRoomsState {
increaseAdults: (roomIndex: number) => void
decreaseAdults: (roomIndex: number) => void
increaseChildren: (roomIndex: number) => void
decreaseChildren: (roomIndex: number) => Child[]
updateChildAge: (age: number, roomIndex: number, childIndex: number) => void
updateChildBed: (bed: number, roomIndex: number, childIndex: number) => void
increaseChildInAdultsBed: (roomIndex: number) => void
decreaseChildInAdultsBed: (roomIndex: number) => void
increaseRoom: () => void
decreaseRoom: (roomIndex: number) => void
setIsValidated: (isValidated: boolean) => void
}
export function validateBedTypes(data: extendedGuestsRoom[]) {
data.forEach((room) => {
room.child.forEach((child) => {
const allowedBedTypes: number[] = []
if (child.age <= 5 && room.adults >= room.childrenInAdultsBed) {
allowedBedTypes.push(ChildBedMapEnum.IN_ADULTS_BED)
} else if (child.age <= 5) {
room.childrenInAdultsBed = room.childrenInAdultsBed - 1
}
if (child.age < 3) {
allowedBedTypes.push(ChildBedMapEnum.IN_CRIB)
}
if (child.age > 2) {
allowedBedTypes.push(ChildBedMapEnum.IN_EXTRA_BED)
}
if (!allowedBedTypes.includes(child.bed)) {
child.bed = allowedBedTypes[0]
}
})
})
}
export function initGuestsRoomsState(initData?: GuestsRoom[]) {
const isBrowser = typeof window !== "undefined"
const sessionData = isBrowser
? sessionStorage.getItem(SESSION_STORAGE_KEY)
: null
const defaultGuestsData: extendedGuestsRoom = {
adults: 1,
child: [],
childrenInAdultsBed: 0,
}
const defaultData: GuestsRoomsState = {
rooms: [defaultGuestsData],
adultCount: 1,
childCount: 0,
isValidated: false,
}
let inputData: GuestsRoomsState = defaultData
if (sessionData) {
inputData = JSON.parse(sessionData)
}
if (initData) {
inputData.rooms = initData.map((room) => {
const childrenInAdultsBed = room.child
? room.child.reduce((acc, child) => {
acc = acc + (child.bed == ChildBedMapEnum.IN_ADULTS_BED ? 1 : 0)
return acc
}, 0)
: 0
return { ...defaultGuestsData, ...room, childrenInAdultsBed }
}) as extendedGuestsRoom[]
inputData.adultCount = initData.reduce((acc, room) => {
acc = acc + room.adults
return acc
}, 0)
inputData.childCount = initData.reduce((acc, room) => {
acc = acc + room.child?.length
return acc
}, 0)
validateBedTypes(inputData.rooms)
}
return create<GuestsRoomsStoreState>()((set, get) => ({
...inputData,
increaseAdults: (roomIndex) =>
set(
produce((state: GuestsRoomsState) => {
state.rooms[roomIndex].adults = state.rooms[roomIndex].adults + 1
state.adultCount = state.adultCount + 1
})
),
decreaseAdults: (roomIndex) =>
set(
produce((state: GuestsRoomsState) => {
state.rooms[roomIndex].adults = state.rooms[roomIndex].adults - 1
state.adultCount = state.adultCount - 1
if (
state.rooms[roomIndex].childrenInAdultsBed >
state.rooms[roomIndex].adults
) {
const toUpdateIndex = state.rooms[roomIndex].child.findIndex(
(child) => child.bed == ChildBedMapEnum.IN_ADULTS_BED
)
if (toUpdateIndex != -1) {
state.rooms[roomIndex].child[toUpdateIndex].bed =
state.rooms[roomIndex].child[toUpdateIndex].age < 3
? ChildBedMapEnum.IN_CRIB
: ChildBedMapEnum.IN_EXTRA_BED
state.rooms[roomIndex].childrenInAdultsBed =
state.rooms[roomIndex].adults
}
}
})
),
increaseChildren: (roomIndex) =>
set(
produce((state: GuestsRoomsState) => {
state.rooms[roomIndex].child.push({
age: -1,
bed: -1,
})
state.childCount = state.childCount + 1
})
),
decreaseChildren: (roomIndex) => {
set(
produce((state: GuestsRoomsState) => {
const roomChildren = state.rooms[roomIndex].child
if (
roomChildren.length &&
roomChildren[roomChildren.length - 1].bed ==
ChildBedMapEnum.IN_ADULTS_BED
) {
state.rooms[roomIndex].childrenInAdultsBed =
state.rooms[roomIndex].childrenInAdultsBed - 1
}
state.rooms[roomIndex].child.pop()
state.childCount = state.childCount - 1
})
)
return get().rooms[roomIndex].child
},
updateChildAge: (age, roomIndex, childIndex) =>
set(
produce((state: GuestsRoomsState) => {
state.rooms[roomIndex].child[childIndex].age = age
})
),
updateChildBed: (bed, roomIndex, childIndex) =>
set(
produce((state: GuestsRoomsState) => {
state.rooms[roomIndex].child[childIndex].bed = bed
})
),
increaseChildInAdultsBed: (roomIndex) =>
set(
produce((state: GuestsRoomsState) => {
state.rooms[roomIndex].childrenInAdultsBed =
state.rooms[roomIndex].childrenInAdultsBed + 1
})
),
decreaseChildInAdultsBed: (roomIndex) =>
set(
produce((state: GuestsRoomsState) => {
state.rooms[roomIndex].childrenInAdultsBed =
state.rooms[roomIndex].childrenInAdultsBed - 1
})
),
increaseRoom: () =>
set(
produce((state: GuestsRoomsState) => {
state.rooms.push({
adults: 1,
child: [],
childrenInAdultsBed: 0,
})
})
),
decreaseRoom: (roomIndex) =>
set(
produce((state: GuestsRoomsState) => {
state.rooms.splice(roomIndex, 1)
})
),
setIsValidated: (isValidated) => set(() => ({ isValidated })),
}))
}
export type GuestsRoomsStore = ReturnType<typeof initGuestsRoomsState>
export const GuestsRoomsContext = createContext<GuestsRoomsStore | null>(null)
export const useGuestsRoomsStore = <T>(
selector: (store: GuestsRoomsStoreState) => T
): T => {
const guestsRoomsContextStore = useContext(GuestsRoomsContext)
if (!guestsRoomsContextStore) {
throw new Error(
`guestsRoomsContextStore must be used within GuestsRoomsContextProvider`
)
}
return useStore(guestsRoomsContextStore, selector)
}

View File

@@ -0,0 +1,17 @@
"use client"
import { create } from "zustand"
interface RoomAvailabilityState {
noRoomsAvailable: boolean
setNoRoomsAvailable: () => void
setRoomsAvailable: () => void
}
const useRoomAvailableStore = create<RoomAvailabilityState>((set) => ({
noRoomsAvailable: false,
setNoRoomsAvailable: () => set(() => ({ noRoomsAvailable: true })),
setRoomsAvailable: () => set(() => ({ noRoomsAvailable: false })),
}))
export default useRoomAvailableStore

View File

@@ -6,14 +6,17 @@ interface SidePeekState {
activeSidePeek: SidePeekEnum | null
hotelId: string | null
roomTypeCode: string | null
showCTA: boolean
openSidePeek: ({
key,
hotelId,
roomTypeCode,
showCTA,
}: {
key: SidePeekEnum | null
hotelId: string
roomTypeCode?: string
showCTA?: boolean
}) => void
closeSidePeek: () => void
}
@@ -22,8 +25,9 @@ const useSidePeekStore = create<SidePeekState>((set) => ({
activeSidePeek: null,
hotelId: null,
roomTypeCode: null,
openSidePeek: ({ key, hotelId, roomTypeCode }) =>
set({ activeSidePeek: key, hotelId, roomTypeCode }),
showCTA: true,
openSidePeek: ({ key, hotelId, roomTypeCode, showCTA }) =>
set({ activeSidePeek: key, hotelId, roomTypeCode, showCTA }),
closeSidePeek: () =>
set({ activeSidePeek: null, hotelId: null, roomTypeCode: null }),
}))

View File

@@ -3,7 +3,6 @@ import { create } from "zustand"
export enum StickyElementNameEnum {
SITEWIDE_ALERT = "SITEWIDE_ALERT",
BOOKING_WIDGET = "BOOKING_WIDGET",
BOOKING_WIDGET_MOBILE = "BOOKING_WIDGET_MOBILE",
HOTEL_TAB_NAVIGATION = "HOTEL_TAB_NAVIGATION",
HOTEL_STATIC_MAP = "HOTEL_STATIC_MAP",
}
@@ -32,7 +31,6 @@ interface StickyStore {
const priorityMap: Record<StickyElementNameEnum, number> = {
[StickyElementNameEnum.SITEWIDE_ALERT]: 1,
[StickyElementNameEnum.BOOKING_WIDGET]: 2,
[StickyElementNameEnum.BOOKING_WIDGET_MOBILE]: 2,
[StickyElementNameEnum.HOTEL_TAB_NAVIGATION]: 3,
[StickyElementNameEnum.HOTEL_STATIC_MAP]: 3,