feat(sw-453): implemented filter from packages

This commit is contained in:
Pontus Dreij
2024-10-25 12:55:13 +02:00
parent 260c9096f6
commit 7b36139684
20 changed files with 330 additions and 133 deletions

View File

@@ -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"

View File

@@ -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

View 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>
)
}

View File

@@ -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);
}