fix: remove guest picker store

This commit is contained in:
Christel Westerberg
2024-11-12 16:45:25 +01:00
parent 58678244fc
commit ca3819f7cc
17 changed files with 368 additions and 597 deletions

View File

@@ -3,8 +3,6 @@
import { useFormContext } from "react-hook-form"
import { useIntl } from "react-intl"
import { useGuestsRoomsStore } from "@/stores/guests-rooms"
import Caption from "@/components/TempDesignSystem/Text/Caption"
import Counter from "../Counter"
@@ -13,39 +11,37 @@ import styles from "./adult-selector.module.css"
import { ChildBedMapEnum } from "@/types/components/bookingWidget/enums"
import {
AdultSelectorProps,
Child,
SelectorProps,
} from "@/types/components/bookingWidget/guestsRoomsPicker"
export default function AdultSelector({ roomIndex = 0 }: AdultSelectorProps) {
export default function AdultSelector({
roomIndex = 0,
currentAdults,
currentChildren,
childrenInAdultsBed,
}: SelectorProps) {
const intl = useIntl()
const adultsLabel = intl.formatMessage({ id: "Adults" })
const { setValue } = useFormContext()
const { adults, child, childrenInAdultsBed } = useGuestsRoomsStore(
(state) => state.rooms[roomIndex]
)
const increaseAdults = useGuestsRoomsStore((state) => state.increaseAdults)
const decreaseAdults = useGuestsRoomsStore((state) => state.decreaseAdults)
function increaseAdultsCount(roomIndex: number) {
if (adults < 6) {
increaseAdults(roomIndex)
setValue(`rooms.${roomIndex}.adults`, adults + 1)
if (currentAdults < 6) {
setValue(`rooms.${roomIndex}.adults`, currentAdults + 1)
}
}
function decreaseAdultsCount(roomIndex: number) {
if (adults > 1) {
decreaseAdults(roomIndex)
setValue(`rooms.${roomIndex}.adults`, adults - 1)
if (childrenInAdultsBed > adults) {
const toUpdateIndex = child.findIndex(
if (currentAdults > 1) {
setValue(`rooms.${roomIndex}.adults`, currentAdults - 1)
if (childrenInAdultsBed > currentAdults) {
const toUpdateIndex = currentChildren.findIndex(
(child: Child) => child.bed == ChildBedMapEnum.IN_ADULTS_BED
)
if (toUpdateIndex != -1) {
setValue(
`rooms.${roomIndex}.children.${toUpdateIndex}.bed`,
child[toUpdateIndex].age < 3
currentChildren[toUpdateIndex].age < 3
? ChildBedMapEnum.IN_CRIB
: ChildBedMapEnum.IN_EXTRA_BED
)
@@ -60,15 +56,15 @@ export default function AdultSelector({ roomIndex = 0 }: AdultSelectorProps) {
{adultsLabel}
</Caption>
<Counter
count={adults}
count={currentAdults}
handleOnDecrease={() => {
decreaseAdultsCount(roomIndex)
}}
handleOnIncrease={() => {
increaseAdultsCount(roomIndex)
}}
disableDecrease={adults == 1}
disableIncrease={adults == 6}
disableDecrease={currentAdults == 1}
disableIncrease={currentAdults == 6}
/>
</section>
)

View File

@@ -3,8 +3,6 @@
import { useFormContext } from "react-hook-form"
import { useIntl } from "react-intl"
import { useGuestsRoomsStore } from "@/stores/guests-rooms"
import { ErrorCircleIcon } from "@/components/Icons"
import Select from "@/components/TempDesignSystem/Select"
import Caption from "@/components/TempDesignSystem/Text/Caption"
@@ -19,6 +17,8 @@ import {
export default function ChildInfoSelector({
child = { age: -1, bed: -1 },
childrenInAdultsBed,
adults,
index = 0,
roomIndex = 0,
}: ChildInfoSelectorProps) {
@@ -26,23 +26,7 @@ export default function ChildInfoSelector({
const ageLabel = intl.formatMessage({ id: "Age" })
const ageReqdErrMsg = intl.formatMessage({ id: "Child age is required" })
const bedLabel = intl.formatMessage({ id: "Bed" })
const { setValue } = useFormContext()
const { adults, childrenInAdultsBed } = useGuestsRoomsStore(
(state) => state.rooms[roomIndex]
)
const {
isValidated,
updateChildAge,
updateChildBed,
increaseChildInAdultsBed,
decreaseChildInAdultsBed,
} = useGuestsRoomsStore((state) => ({
isValidated: state.isValidated,
updateChildAge: state.updateChildAge,
updateChildBed: state.updateChildBed,
increaseChildInAdultsBed: state.increaseChildInAdultsBed,
decreaseChildInAdultsBed: state.decreaseChildInAdultsBed,
}))
const { setValue, formState } = useFormContext()
const ageList = Array.from(Array(13).keys()).map((age) => ({
label: `${age}`,
@@ -50,7 +34,6 @@ export default function ChildInfoSelector({
}))
function updateSelectedAge(age: number) {
updateChildAge(age, roomIndex, index)
setValue(`rooms.${roomIndex}.child.${index}.age`, age, {
shouldValidate: true,
})
@@ -59,12 +42,6 @@ export default function ChildInfoSelector({
}
function updateSelectedBed(bed: number) {
if (bed == ChildBedMapEnum.IN_ADULTS_BED) {
increaseChildInAdultsBed(roomIndex)
} else if (child.bed == ChildBedMapEnum.IN_ADULTS_BED) {
decreaseChildInAdultsBed(roomIndex)
}
updateChildBed(bed, roomIndex, index)
setValue(`rooms.${roomIndex}.child.${index}.bed`, bed)
}
@@ -97,6 +74,7 @@ export default function ChildInfoSelector({
return availableBedTypes
}
console.log("ALL TJHE ERORRORS", formState.errors)
return (
<>
<div key={index} className={styles.childInfoContainer}>
@@ -131,12 +109,13 @@ export default function ChildInfoSelector({
) : null}
</div>
</div>
{isValidated && child.age < 0 ? (
{/* {isValidated && child.age < 0 ? (
<Caption color="red" className={styles.error}>
<ErrorCircleIcon color="red" />
{ageReqdErrMsg}
</Caption>
) : null}
) : null} */}
</>
)
}

View File

@@ -3,8 +3,6 @@
import { useFormContext } from "react-hook-form"
import { useIntl } from "react-intl"
import { useGuestsRoomsStore } from "@/stores/guests-rooms"
import Caption from "@/components/TempDesignSystem/Text/Caption"
import Counter from "../Counter"
@@ -13,25 +11,22 @@ import ChildInfoSelector from "./ChildInfoSelector"
import styles from "./child-selector.module.css"
import { BookingWidgetSchema } from "@/types/components/bookingWidget"
import { ChildSelectorProps } from "@/types/components/bookingWidget/guestsRoomsPicker"
import { SelectorProps } from "@/types/components/bookingWidget/guestsRoomsPicker"
export default function ChildSelector({ roomIndex = 0 }: ChildSelectorProps) {
export default function ChildSelector({
roomIndex = 0,
currentAdults,
childrenInAdultsBed,
currentChildren,
}: SelectorProps) {
const intl = useIntl()
const childrenLabel = intl.formatMessage({ id: "Children" })
const { setValue, trigger } = useFormContext<BookingWidgetSchema>()
const children = useGuestsRoomsStore((state) => state.rooms[roomIndex].child)
const increaseChildren = useGuestsRoomsStore(
(state) => state.increaseChildren
)
const decreaseChildren = useGuestsRoomsStore(
(state) => state.decreaseChildren
)
const { setValue } = useFormContext<BookingWidgetSchema>()
function increaseChildrenCount(roomIndex: number) {
if (children.length < 5) {
increaseChildren(roomIndex)
if (currentChildren.length < 5) {
setValue(
`rooms.${roomIndex}.child.${children.length}`,
`rooms.${roomIndex}.child.${currentChildren.length}`,
{
age: -1,
bed: -1,
@@ -41,9 +36,9 @@ export default function ChildSelector({ roomIndex = 0 }: ChildSelectorProps) {
}
}
function decreaseChildrenCount(roomIndex: number) {
if (children.length > 0) {
const newChildrenList = decreaseChildren(roomIndex)
setValue(`rooms.${roomIndex}.child`, newChildrenList, {
if (currentChildren.length > 0) {
currentChildren.pop()
setValue(`rooms.${roomIndex}.child`, currentChildren, {
shouldValidate: true,
})
}
@@ -56,23 +51,25 @@ export default function ChildSelector({ roomIndex = 0 }: ChildSelectorProps) {
{childrenLabel}
</Caption>
<Counter
count={children.length}
count={currentChildren.length}
handleOnDecrease={() => {
decreaseChildrenCount(roomIndex)
}}
handleOnIncrease={() => {
increaseChildrenCount(roomIndex)
}}
disableDecrease={children.length == 0}
disableIncrease={children.length == 5}
disableDecrease={currentChildren.length == 0}
disableIncrease={currentChildren.length == 5}
/>
</section>
{children.map((child, index) => (
{currentChildren.map((child, index) => (
<ChildInfoSelector
roomIndex={roomIndex}
index={index}
child={child}
adults={currentAdults}
key={"child_" + index}
childrenInAdultsBed={childrenInAdultsBed}
/>
))}
</>

View File

@@ -1,130 +0,0 @@
"use client"
import { Dialog } from "react-aria-components"
import { useFormContext } from "react-hook-form"
import { useIntl } from "react-intl"
import { useGuestsRoomsStore } from "@/stores/guests-rooms"
import { CloseLargeIcon, PlusCircleIcon, PlusIcon } from "../Icons"
import Button from "../TempDesignSystem/Button"
import Divider from "../TempDesignSystem/Divider"
import Subtitle from "../TempDesignSystem/Text/Subtitle"
import { Tooltip } from "../TempDesignSystem/Tooltip"
import AdultSelector from "./AdultSelector"
import ChildSelector from "./ChildSelector"
import styles from "./guests-rooms-picker.module.css"
import { BookingWidgetSchema } from "@/types/components/bookingWidget"
export default function GuestsRoomsPickerDialog() {
const intl = useIntl()
const doneLabel = intl.formatMessage({ id: "Done" })
const roomLabel = intl.formatMessage({ id: "Room" })
const disabledBookingOptionsHeader = intl.formatMessage({
id: "Disabled booking options header",
})
const disabledBookingOptionsText = intl.formatMessage({
id: "Disabled adding room",
})
const addRoomLabel = intl.formatMessage({ id: "Add Room" })
const { getFieldState } = useFormContext<BookingWidgetSchema>()
const rooms = useGuestsRoomsStore((state) => state.rooms)
return (
<Dialog className={styles.pickerContainer}>
{({ close }) => {
return (
<>
<header className={styles.header}>
<button type="button" className={styles.close}>
<CloseLargeIcon />
</button>
</header>
<div className={styles.contentContainer}>
{rooms.map((room, index) => (
<div className={styles.roomContainer} key={index}>
<section className={styles.roomDetailsContainer}>
<Subtitle type="two" className={styles.roomHeading}>
{roomLabel} {index + 1}
</Subtitle>
<AdultSelector roomIndex={index} />
<ChildSelector roomIndex={index} />
</section>
<Divider color="primaryLightSubtle" />
</div>
))}
<div className={styles.addRoomMobileContainer}>
<Tooltip
heading={disabledBookingOptionsHeader}
text={disabledBookingOptionsText}
position="top"
arrow="left"
>
{rooms.length < 4 ? (
<Button
intent="text"
variant="icon"
wrapping
disabled
theme="base"
fullWidth
>
<PlusIcon />
{addRoomLabel}
</Button>
) : null}
</Tooltip>
</div>
</div>
<footer className={styles.footer}>
<div className={styles.hideOnMobile}>
<Tooltip
heading={disabledBookingOptionsHeader}
text={disabledBookingOptionsText}
position="top"
arrow="left"
>
{rooms.length < 4 ? (
<Button
intent="text"
variant="icon"
wrapping
disabled
theme="base"
>
<PlusCircleIcon />
{addRoomLabel}
</Button>
) : null}
</Tooltip>
</div>
<Button
onPress={close}
disabled={getFieldState("rooms").invalid}
className={styles.hideOnMobile}
intent="tertiary"
theme="base"
size="small"
>
{doneLabel}
</Button>
<Button
onPress={close}
disabled={getFieldState("rooms").invalid}
className={styles.hideOnDesktop}
intent="tertiary"
theme="base"
size="large"
>
{doneLabel}
</Button>
</footer>
</>
)
}}
</Dialog>
)
}

View File

@@ -0,0 +1,146 @@
"use client"
import { useFormContext } from "react-hook-form"
import { useIntl } from "react-intl"
import { CloseLargeIcon, PlusCircleIcon, PlusIcon } from "../Icons"
import Button from "../TempDesignSystem/Button"
import Divider from "../TempDesignSystem/Divider"
import Subtitle from "../TempDesignSystem/Text/Subtitle"
import { Tooltip } from "../TempDesignSystem/Tooltip"
import AdultSelector from "./AdultSelector"
import ChildSelector from "./ChildSelector"
import styles from "./guests-rooms-picker.module.css"
import { BookingWidgetSchema } from "@/types/components/bookingWidget"
import { ChildBedMapEnum } from "@/types/components/bookingWidget/enums"
import { GuestsRoom } from "@/types/components/bookingWidget/guestsRoomsPicker"
export default function GuestsRoomsPickerDialog({
rooms,
onClose,
}: {
rooms: GuestsRoom[]
onClose: () => void
}) {
const intl = useIntl()
const doneLabel = intl.formatMessage({ id: "Done" })
const roomLabel = intl.formatMessage({ id: "Room" })
const disabledBookingOptionsHeader = intl.formatMessage({
id: "Disabled booking options header",
})
const disabledBookingOptionsText = intl.formatMessage({
id: "Disabled adding room",
})
const addRoomLabel = intl.formatMessage({ id: "Add Room" })
const { getFieldState } = useFormContext<BookingWidgetSchema>()
return (
<>
<header className={styles.header}>
<button type="button" className={styles.close} onClick={onClose}>
<CloseLargeIcon />
</button>
</header>
<div className={styles.contentContainer}>
{rooms.map((room, index) => {
const currentAdults = room.adults
const currentChildren = room.child
const childrenInAdultsBed = currentChildren.filter(
(child) => child.bed === ChildBedMapEnum.IN_ADULTS_BED
).length
return (
<div className={styles.roomContainer} key={index}>
<section className={styles.roomDetailsContainer}>
<Subtitle type="two" className={styles.roomHeading}>
{roomLabel} {index + 1}
</Subtitle>
<AdultSelector
roomIndex={index}
currentAdults={currentAdults}
currentChildren={currentChildren}
childrenInAdultsBed={childrenInAdultsBed}
/>
<ChildSelector
roomIndex={index}
currentAdults={currentAdults}
currentChildren={currentChildren}
childrenInAdultsBed={childrenInAdultsBed}
/>
</section>
<Divider color="primaryLightSubtle" />
</div>
)
})}
<div className={styles.addRoomMobileContainer}>
<Tooltip
heading={disabledBookingOptionsHeader}
text={disabledBookingOptionsText}
position="top"
arrow="left"
>
{rooms.length < 4 ? (
<Button
intent="text"
variant="icon"
wrapping
disabled
theme="base"
fullWidth
>
<PlusIcon />
{addRoomLabel}
</Button>
) : null}
</Tooltip>
</div>
</div>
<footer className={styles.footer}>
<div className={styles.hideOnMobile}>
<Tooltip
heading={disabledBookingOptionsHeader}
text={disabledBookingOptionsText}
position="top"
arrow="left"
>
{rooms.length < 4 ? (
<Button
intent="text"
variant="icon"
wrapping
disabled
theme="base"
>
<PlusCircleIcon />
{addRoomLabel}
</Button>
) : null}
</Tooltip>
</div>
<Button
onPress={onClose}
disabled={getFieldState("rooms").invalid}
className={styles.hideOnMobile}
intent="tertiary"
theme="base"
size="small"
>
{doneLabel}
</Button>
<Button
onPress={onClose}
disabled={getFieldState("rooms").invalid}
className={styles.hideOnDesktop}
intent="tertiary"
theme="base"
size="large"
>
{doneLabel}
</Button>
</footer>
</>
)
}

View File

@@ -1,26 +0,0 @@
"use client"
import { PropsWithChildren, useRef } from "react"
import {
GuestsRoomsContext,
type GuestsRoomsStore,
initGuestsRoomsState,
} from "@/stores/guests-rooms"
import { GuestsRoom } from "@/types/components/bookingWidget/guestsRoomsPicker"
export default function GuestsRoomsProvider({
selectedGuests,
children,
}: PropsWithChildren<{ selectedGuests?: GuestsRoom[] }>) {
const initialStore = useRef<GuestsRoomsStore>()
if (!initialStore.current) {
initialStore.current = initGuestsRoomsState(selectedGuests)
}
return (
<GuestsRoomsContext.Provider value={initialStore.current}>
{children}
</GuestsRoomsContext.Provider>
)
}

View File

@@ -1,7 +1,23 @@
.container {
overflow: hidden;
position: relative;
.triggerDesktop {
display: none;
}
.pickerContainerMobile {
background-color: var(--Main-Grey-White);
border-radius: var(--Corner-radius-Large) var(--Corner-radius-Large) 0 0;
bottom: 0;
left: 0;
position: fixed;
right: 0;
top: 0;
transition: top 300ms ease;
z-index: 1000;
}
.pickerContainerDesktop {
display: none;
}
.roomContainer {
display: grid;
gap: var(--Spacing-x2);
@@ -23,9 +39,7 @@
width: 100%;
text-align: left;
}
.body {
opacity: 0.8;
}
.footer {
display: grid;
gap: var(--Spacing-x1);
@@ -33,25 +47,7 @@
margin-top: var(--Spacing-x2);
}
.pickerContainer {
--header-height: 72px;
--sticky-button-height: 140px;
background-color: var(--Main-Grey-White);
display: grid;
border-radius: var(--Corner-radius-Large);
box-shadow: 0px 0px 14px 6px rgba(0, 0, 0, 0.1);
max-width: calc(100vw - 20px);
padding: var(--Spacing-x2) var(--Spacing-x3);
width: 360px;
}
@media screen and (max-width: 1366px) {
.container[data-isopen="true"] .hideWrapper {
top: 20px;
}
.contentContainer {
grid-area: content;
overflow-y: scroll;
@@ -107,6 +103,32 @@
}
@media screen and (min-width: 1367px) {
.pickerContainerMobisse {
display: none;
}
.triggerMobile {
display: none;
}
.triggerDesktop {
display: block;
}
.pickerContainerDesktop {
--header-height: 72px;
--sticky-button-height: 140px;
background-color: var(--Main-Grey-White);
display: grid;
border-radius: var(--Corner-radius-Large);
box-shadow: 0px 0px 14px 6px rgba(0, 0, 0, 0.1);
max-width: calc(100vw - 20px);
padding: var(--Spacing-x2) var(--Spacing-x3);
width: 360px;
}
.header {
display: none;
}

View File

@@ -1,37 +1,64 @@
"use client"
import { useCallback, useEffect, useRef, useState } from "react"
import { Button, DialogTrigger, Popover } from "react-aria-components"
import {
Button,
Dialog,
DialogTrigger,
Modal,
Popover,
} from "react-aria-components"
import { useFormContext } from "react-hook-form"
import { useIntl } from "react-intl"
import { useGuestsRoomsStore } from "@/stores/guests-rooms"
import { guestRoomsSchema } from "@/components/Forms/BookingWidget/schema"
import Body from "@/components/TempDesignSystem/Text/Body"
import Dialog from "./Dialog"
import PickerForm from "./Form"
import styles from "./guests-rooms-picker.module.css"
export default function GuestsRoomsPickerForm({
name = "rooms",
import { GuestsRoom } from "@/types/components/bookingWidget/guestsRoomsPicker"
export default function GuestsRoomsPickerForm() {
const { watch } = useFormContext()
const rooms = watch("rooms") as GuestsRoom[]
return (
<>
<DialogTrigger>
<Trigger rooms={rooms} className={styles.triggerMobile} />
<Modal className="my-modal">
<Dialog className={styles.pickerContainerMobile}>
{({ close }) => <PickerForm rooms={rooms} onClose={close} />}
</Dialog>
</Modal>
</DialogTrigger>
<DialogTrigger>
<Trigger rooms={rooms} className={styles.triggerDesktop} />
<Popover placement="bottom start" offset={22}>
<Dialog className={styles.pickerContainerDesktop}>
{({ close }) => <PickerForm rooms={rooms} onClose={close} />}
</Dialog>
</Popover>
</DialogTrigger>
</>
)
}
function Trigger({
rooms,
className,
}: {
name: string
rooms: GuestsRoom[]
className: string
}) {
const intl = useIntl()
const { rooms, adultCount, childCount } = useGuestsRoomsStore((state) => ({
rooms: state.rooms,
adultCount: state.adultCount,
childCount: state.childCount,
}))
return (
<DialogTrigger>
<Button className={styles.btn} type="button">
<Body className={styles.body} asChild>
<span>
<Button className={`${className} ${styles.btn}`} type="button">
<Body>
{rooms.map((room, i) => (
<span key={i}>
{intl.formatMessage(
{ id: "booking.rooms" },
{ totalRooms: rooms.length }
@@ -39,21 +66,18 @@ export default function GuestsRoomsPickerForm({
{", "}
{intl.formatMessage(
{ id: "booking.adults" },
{ totalAdults: adultCount }
{ totalAdults: room.adults }
)}
{childCount > 0
{room.child.length > 0
? ", " +
intl.formatMessage(
{ id: "booking.children" },
{ totalChildren: childCount }
{ totalChildren: room.child.length }
)
: null}
</span>
</Body>
</Button>
<Popover>
<Dialog />
</Popover>
</DialogTrigger>
))}
</Body>
</Button>
)
}