feat(sw-453): implemented filter from packages
This commit is contained in:
@@ -22,7 +22,7 @@ import { useEnterDetailsStore } from "@/stores/enter-details"
|
||||
|
||||
import LoadingSpinner from "@/components/LoadingSpinner"
|
||||
import Button from "@/components/TempDesignSystem/Button"
|
||||
import Checkbox from "@/components/TempDesignSystem/Checkbox"
|
||||
import Checkbox from "@/components/TempDesignSystem/Form/Checkbox"
|
||||
import Link from "@/components/TempDesignSystem/Link"
|
||||
import Body from "@/components/TempDesignSystem/Text/Body"
|
||||
import Caption from "@/components/TempDesignSystem/Text/Caption"
|
||||
|
||||
@@ -1,49 +1,60 @@
|
||||
"use client"
|
||||
|
||||
import { zodResolver } from "@hookform/resolvers/zod"
|
||||
import { useRef } from "react"
|
||||
import { useCallback, useEffect, useMemo } from "react"
|
||||
import { FormProvider, useForm } from "react-hook-form"
|
||||
import { useIntl } from "react-intl"
|
||||
import { z } from "zod"
|
||||
|
||||
import { roomFilterSchema } from "@/server/routers/hotels/schemas/room"
|
||||
import { RoomPackageCode } from "@/server/routers/hotels/schemas/packages"
|
||||
|
||||
import Chip from "@/components/TempDesignSystem/Chip"
|
||||
import Checkbox from "@/components/TempDesignSystem/Form/Checkbox"
|
||||
import Body from "@/components/TempDesignSystem/Text/Body"
|
||||
import Caption from "@/components/TempDesignSystem/Text/Caption"
|
||||
|
||||
import styles from "./roomFilter.module.css"
|
||||
|
||||
import {
|
||||
RoomFilterFormData,
|
||||
RoomFilterProps,
|
||||
} from "@/types/components/hotelReservation/selectRate/roomFilter"
|
||||
import { RoomFilterProps } from "@/types/components/hotelReservation/selectRate/roomFilter"
|
||||
|
||||
export default function RoomFilter({
|
||||
numberOfRooms,
|
||||
onFilter,
|
||||
filterOptions,
|
||||
}: RoomFilterProps) {
|
||||
const initialFilterValues = useMemo(
|
||||
() =>
|
||||
filterOptions.reduce(
|
||||
(acc, option) => {
|
||||
acc[option.code] = false
|
||||
return acc
|
||||
},
|
||||
{} as Record<string, boolean | undefined>
|
||||
),
|
||||
[filterOptions]
|
||||
)
|
||||
|
||||
function RoomFilter({ numberOfRooms }: RoomFilterProps) {
|
||||
const intl = useIntl()
|
||||
const methods = useForm<RoomFilterFormData>({
|
||||
defaultValues: {
|
||||
allergyFriendly: false,
|
||||
petFriendly: false,
|
||||
accessibility: false,
|
||||
},
|
||||
const methods = useForm<Record<string, boolean | undefined>>({
|
||||
defaultValues: initialFilterValues,
|
||||
mode: "all",
|
||||
reValidateMode: "onChange",
|
||||
resolver: zodResolver(roomFilterSchema),
|
||||
resolver: zodResolver(z.object({})),
|
||||
})
|
||||
|
||||
const formRef = useRef<HTMLFormElement | null>(null)
|
||||
const { watch, setValue } = methods
|
||||
const petFriendly = watch("petFriendly")
|
||||
const allergyFriendly = watch("allergyFriendly")
|
||||
const { watch, getValues, handleSubmit } = methods
|
||||
const petFriendly = watch(RoomPackageCode.PETR)
|
||||
const allergyFriendly = watch(RoomPackageCode.ALLG)
|
||||
|
||||
const onSubmit = (data: RoomFilterFormData) => {
|
||||
if (data.petFriendly) {
|
||||
setValue("allergyFriendly", false)
|
||||
} else if (data.allergyFriendly) {
|
||||
setValue("petFriendly", false)
|
||||
}
|
||||
console.log("Form submitted with data:", data)
|
||||
}
|
||||
const submitFilter = useCallback(() => {
|
||||
const data = getValues()
|
||||
onFilter(data)
|
||||
}, [onFilter, getValues])
|
||||
|
||||
useEffect(() => {
|
||||
const subscription = watch(() => handleSubmit(submitFilter)())
|
||||
return () => subscription.unsubscribe()
|
||||
}, [handleSubmit, watch, submitFilter])
|
||||
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
@@ -51,45 +62,27 @@ function RoomFilter({ numberOfRooms }: RoomFilterProps) {
|
||||
{intl.formatMessage({ id: "Room types available" }, { numberOfRooms })}
|
||||
</Body>
|
||||
<FormProvider {...methods}>
|
||||
<form ref={formRef} onSubmit={methods.handleSubmit(onSubmit)}>
|
||||
<form onSubmit={handleSubmit(submitFilter)}>
|
||||
<div className={styles.roomsFilter}>
|
||||
<Checkbox
|
||||
name="accessibility"
|
||||
onChange={() => formRef.current?.requestSubmit()}
|
||||
>
|
||||
<Caption color="uiTextHighContrast">
|
||||
{intl.formatMessage({ id: "Accessibility room" })}
|
||||
</Caption>
|
||||
</Checkbox>
|
||||
<Checkbox
|
||||
name="petFriendly"
|
||||
onChange={() => {
|
||||
setValue("petFriendly", !petFriendly)
|
||||
formRef.current?.requestSubmit()
|
||||
}}
|
||||
registerOptions={{ disabled: allergyFriendly }}
|
||||
>
|
||||
<Caption color="uiTextHighContrast">
|
||||
{intl.formatMessage({ id: "Pet room" })}
|
||||
</Caption>
|
||||
</Checkbox>
|
||||
<Checkbox
|
||||
name="allergyFriendly"
|
||||
onChange={() => {
|
||||
setValue("allergyFriendly", !allergyFriendly)
|
||||
formRef.current?.requestSubmit()
|
||||
}}
|
||||
registerOptions={{ disabled: petFriendly }}
|
||||
>
|
||||
<Caption color="uiTextHighContrast">
|
||||
{intl.formatMessage({ id: "Allergy room" })}
|
||||
</Caption>
|
||||
</Checkbox>
|
||||
{filterOptions.map((option) => (
|
||||
<Checkbox
|
||||
name={option.code}
|
||||
key={option.code}
|
||||
registerOptions={{
|
||||
required: false,
|
||||
disabled:
|
||||
(option.code === RoomPackageCode.PETR && allergyFriendly) ||
|
||||
(option.code === RoomPackageCode.ALLG && petFriendly),
|
||||
}}
|
||||
>
|
||||
<Caption color="uiTextHighContrast">
|
||||
{intl.formatMessage({ id: option.description })}
|
||||
</Caption>
|
||||
</Checkbox>
|
||||
))}
|
||||
</div>
|
||||
</form>
|
||||
</FormProvider>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default RoomFilter
|
||||
|
||||
53
components/HotelReservation/SelectRate/Rooms/index.tsx
Normal file
53
components/HotelReservation/SelectRate/Rooms/index.tsx
Normal file
@@ -0,0 +1,53 @@
|
||||
"use client"
|
||||
|
||||
import { useState } from "react"
|
||||
|
||||
import { RoomsAvailability } from "@/server/routers/hotels/output"
|
||||
|
||||
import RoomFilter from "../RoomFilter"
|
||||
import RoomSelection from "../RoomSelection"
|
||||
|
||||
import styles from "./rooms.module.css"
|
||||
|
||||
import { RoomProps } from "@/types/components/hotelReservation/selectRate/room"
|
||||
import { RoomPackageCodes } from "@/types/components/hotelReservation/selectRate/roomFilter"
|
||||
|
||||
export default function Rooms({
|
||||
roomsAvailability,
|
||||
roomCategories = [],
|
||||
user,
|
||||
packages,
|
||||
}: RoomProps) {
|
||||
const [rooms, setRooms] = useState<RoomsAvailability>(roomsAvailability)
|
||||
|
||||
function handleFilter(filter: Record<string, boolean | undefined>) {
|
||||
const selectedCodes = Object.keys(filter).filter((key) => filter[key])
|
||||
|
||||
if (selectedCodes.length === 0) {
|
||||
setRooms(roomsAvailability)
|
||||
return
|
||||
}
|
||||
|
||||
const filteredRooms = roomsAvailability.roomConfigurations.filter((room) =>
|
||||
room.features.some((feature) =>
|
||||
selectedCodes.includes(feature.code as RoomPackageCodes)
|
||||
)
|
||||
)
|
||||
setRooms({ ...roomsAvailability, roomConfigurations: filteredRooms })
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={styles.content}>
|
||||
<RoomFilter
|
||||
numberOfRooms={rooms.roomConfigurations.length}
|
||||
onFilter={handleFilter}
|
||||
filterOptions={packages}
|
||||
/>
|
||||
<RoomSelection
|
||||
roomsAvailability={rooms}
|
||||
roomCategories={roomCategories}
|
||||
user={user}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
.content {
|
||||
max-width: var(--max-width);
|
||||
margin: 0 auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--Spacing-x7);
|
||||
padding: var(--Spacing-x2);
|
||||
}
|
||||
Reference in New Issue
Block a user