diff --git a/components/HotelReservation/EnterDetails/BedType/bedOptions.module.css b/components/HotelReservation/EnterDetails/BedType/bedOptions.module.css index 9bde9175b..b52fefa3e 100644 --- a/components/HotelReservation/EnterDetails/BedType/bedOptions.module.css +++ b/components/HotelReservation/EnterDetails/BedType/bedOptions.module.css @@ -10,3 +10,8 @@ grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); width: min(600px, 100%); } + +.iconContainer { + display: flex; + gap: var(--Spacing-x-one-and-half); +} diff --git a/components/HotelReservation/EnterDetails/BedType/index.tsx b/components/HotelReservation/EnterDetails/BedType/index.tsx index 9002f344e..064eb47a3 100644 --- a/components/HotelReservation/EnterDetails/BedType/index.tsx +++ b/components/HotelReservation/EnterDetails/BedType/index.tsx @@ -4,9 +4,13 @@ import { zodResolver } from "@hookform/resolvers/zod" import { useCallback, useEffect } from "react" import { FormProvider, useForm } from "react-hook-form" +import { + BED_TYPE_ICONS, + type BedTypeEnum, + type ExtraBedTypeEnum, +} from "@/constants/booking" import { useEnterDetailsStore } from "@/stores/enter-details" -import { KingBedIcon } from "@/components/Icons" import RadioCard from "@/components/TempDesignSystem/Form/ChoiceCard/Radio" import BedTypeInfo from "./BedTypeInfo" @@ -18,6 +22,7 @@ import type { BedTypeFormSchema, BedTypeProps, } from "@/types/components/hotelReservation/enterDetails/bedType" +import type { IconProps } from "@/types/components/icon" export default function BedType({ bedTypes }: BedTypeProps) { const initialBedType = useEnterDetailsStore( @@ -74,8 +79,13 @@ export default function BedType({ bedTypes }: BedTypeProps) { return ( ( + + )} id={roomType.value} name="bedType" subtitle={width} @@ -89,3 +99,25 @@ export default function BedType({ bedTypes }: BedTypeProps) { ) } + +function BedIconRenderer({ + mainBedType, + extraBedType, + props, +}: { + mainBedType: BedTypeEnum + extraBedType: ExtraBedTypeEnum | undefined + props: IconProps +}) { + const MainBedIcon = BED_TYPE_ICONS[mainBedType] + const ExtraBedIcon = extraBedType ? BED_TYPE_ICONS[extraBedType] : null + + return ( +
+ + {ExtraBedIcon && ( + + )} +
+ ) +} diff --git a/components/Icons/Bed.tsx b/components/Icons/Beds/Bed.tsx similarity index 100% rename from components/Icons/Bed.tsx rename to components/Icons/Beds/Bed.tsx diff --git a/components/Icons/BedDouble.tsx b/components/Icons/Beds/BedDouble.tsx similarity index 97% rename from components/Icons/BedDouble.tsx rename to components/Icons/Beds/BedDouble.tsx index be6e87ac8..1ede5a587 100644 --- a/components/Icons/BedDouble.tsx +++ b/components/Icons/Beds/BedDouble.tsx @@ -1,4 +1,4 @@ -import { iconVariants } from "./variants" +import { iconVariants } from "../variants" import type { IconProps } from "@/types/components/icon" diff --git a/components/Icons/BedSingle.tsx b/components/Icons/Beds/BedSingle.tsx similarity index 97% rename from components/Icons/BedSingle.tsx rename to components/Icons/Beds/BedSingle.tsx index 9ff42333a..8c6ceeb76 100644 --- a/components/Icons/BedSingle.tsx +++ b/components/Icons/Beds/BedSingle.tsx @@ -1,4 +1,4 @@ -import { iconVariants } from "./variants" +import { iconVariants } from "../variants" import type { IconProps } from "@/types/components/icon" diff --git a/components/Icons/Beds/ExtraBunkBed.tsx b/components/Icons/Beds/ExtraBunkBed.tsx new file mode 100644 index 000000000..597643bfa --- /dev/null +++ b/components/Icons/Beds/ExtraBunkBed.tsx @@ -0,0 +1,101 @@ +import { iconVariants } from "../variants" + +import type { IconProps } from "@/types/components/icon" + +export default function ExtraBunkBedIcon({ + className, + color, + ...props +}: IconProps) { + const classNames = iconVariants({ className, color }) + return ( + + + + + + + + + + + + + + + + ) +} diff --git a/components/Icons/Beds/ExtraPullOutBed.tsx b/components/Icons/Beds/ExtraPullOutBed.tsx new file mode 100644 index 000000000..649fb7f53 --- /dev/null +++ b/components/Icons/Beds/ExtraPullOutBed.tsx @@ -0,0 +1,29 @@ +import { iconVariants } from "../variants" + +import type { IconProps } from "@/types/components/icon" + +export default function ExtraPullOutBedIcon({ + className, + color, + ...props +}: IconProps) { + const classNames = iconVariants({ className, color }) + return ( + + + + ) +} diff --git a/components/Icons/Beds/ExtraSofaBed.tsx b/components/Icons/Beds/ExtraSofaBed.tsx new file mode 100644 index 000000000..3bd95eb96 --- /dev/null +++ b/components/Icons/Beds/ExtraSofaBed.tsx @@ -0,0 +1,27 @@ +import { iconVariants } from "../variants" + +import type { IconProps } from "@/types/components/icon" + +export default function ExtraSofaBedIcon({ + className, + color, + ...props +}: IconProps) { + const classNames = iconVariants({ className, color }) + return ( + + + + ) +} diff --git a/components/Icons/Beds/ExtraWallBed.tsx b/components/Icons/Beds/ExtraWallBed.tsx new file mode 100644 index 000000000..b6f05c335 --- /dev/null +++ b/components/Icons/Beds/ExtraWallBed.tsx @@ -0,0 +1,29 @@ +import { iconVariants } from "../variants" + +import type { IconProps } from "@/types/components/icon" + +export default function ExtraWallBedIcon({ + className, + color, + ...props +}: IconProps) { + const classNames = iconVariants({ className, color }) + return ( + + + + ) +} diff --git a/components/Icons/Beds/KingBed.tsx b/components/Icons/Beds/KingBed.tsx new file mode 100644 index 000000000..6b65cbc3f --- /dev/null +++ b/components/Icons/Beds/KingBed.tsx @@ -0,0 +1,25 @@ +import { iconVariants } from "../variants" + +import type { IconProps } from "@/types/components/icon" + +export default function KingBedIcon({ className, color, ...props }: IconProps) { + const classNames = iconVariants({ className, color }) + return ( + + + + ) +} diff --git a/components/Icons/KingBedSmall.tsx b/components/Icons/Beds/KingBedSmall.tsx similarity index 97% rename from components/Icons/KingBedSmall.tsx rename to components/Icons/Beds/KingBedSmall.tsx index 6c3bc9be6..bdd230642 100644 --- a/components/Icons/KingBedSmall.tsx +++ b/components/Icons/Beds/KingBedSmall.tsx @@ -1,4 +1,4 @@ -import { iconVariants } from "./variants" +import { iconVariants } from "../variants" import type { IconProps } from "@/types/components/icon" diff --git a/components/Icons/Beds/QueenBed.tsx b/components/Icons/Beds/QueenBed.tsx new file mode 100644 index 000000000..2445148a8 --- /dev/null +++ b/components/Icons/Beds/QueenBed.tsx @@ -0,0 +1,29 @@ +import { iconVariants } from "../variants" + +import type { IconProps } from "@/types/components/icon" + +export default function QueenBedIcon({ + className, + color, + ...props +}: IconProps) { + const classNames = iconVariants({ className, color }) + return ( + + + + ) +} diff --git a/components/Icons/Beds/SingleBed.tsx b/components/Icons/Beds/SingleBed.tsx new file mode 100644 index 000000000..a6122139b --- /dev/null +++ b/components/Icons/Beds/SingleBed.tsx @@ -0,0 +1,29 @@ +import { iconVariants } from "../variants" + +import type { IconProps } from "@/types/components/icon" + +export default function SingleBedIcon({ + className, + color, + ...props +}: IconProps) { + const classNames = iconVariants({ className, color }) + return ( + + + + ) +} diff --git a/components/Icons/Beds/TwinBeds.tsx b/components/Icons/Beds/TwinBeds.tsx new file mode 100644 index 000000000..ee55d973c --- /dev/null +++ b/components/Icons/Beds/TwinBeds.tsx @@ -0,0 +1,29 @@ +import { iconVariants } from "../variants" + +import type { IconProps } from "@/types/components/icon" + +export default function TwinBedsIcon({ + className, + color, + ...props +}: IconProps) { + const classNames = iconVariants({ className, color }) + return ( + + + + ) +} diff --git a/components/Icons/KingBed.tsx b/components/Icons/KingBed.tsx deleted file mode 100644 index 5e0f0615d..000000000 --- a/components/Icons/KingBed.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import { iconVariants } from "./variants" - -import type { IconProps } from "@/types/components/icon" - -export default function KingBedIcon({ className, color, ...props }: IconProps) { - const classNames = iconVariants({ className, color }) - return ( - - - - ) -} diff --git a/components/Icons/index.tsx b/components/Icons/index.tsx index e5fe75235..1c4a1387d 100644 --- a/components/Icons/index.tsx +++ b/components/Icons/index.tsx @@ -10,11 +10,20 @@ export { default as ArrowUpIcon } from "./ArrowUp" export { default as BalconyIcon } from "./Balcony" export { default as BarIcon } from "./Bar" export { default as BathtubIcon } from "./Bathtub" -export { default as BedIcon } from "./Bed" -export { default as BedDoubleIcon } from "./BedDouble" export { default as BedHotelIcon } from "./BedHotel" export { default as BedroomParentIcon } from "./BedroomParent" -export { default as BedSingleIcon } from "./BedSingle" +export { default as BedIcon } from "./Beds/Bed" +export { default as BedDoubleIcon } from "./Beds/BedDouble" +export { default as BedSingleIcon } from "./Beds/BedSingle" +export { default as ExtraBunkBedIcon } from "./Beds/ExtraBunkBed" +export { default as ExtraPullOutBedIcon } from "./Beds/ExtraPullOutBed" +export { default as ExtraSofaBedIcon } from "./Beds/ExtraSofaBed" +export { default as ExtraWallBedIcon } from "./Beds/ExtraWallBed" +export { default as KingBedIcon } from "./Beds/KingBed" +export { default as KingBedSmallIcon } from "./Beds/KingBedSmall" +export { default as QueenBedIcon } from "./Beds/QueenBed" +export { default as SingleBedIcon } from "./Beds/SingleBed" +export { default as TwinBedsIcon } from "./Beds/TwinBeds" export { default as BikeIcon } from "./Bike" export { default as BikingIcon } from "./Biking" export { default as BreakfastIcon } from "./Breakfast" @@ -99,8 +108,6 @@ export { default as KayakingIcon } from "./Kayaking" export { default as KettleIcon } from "./Kettle" export { default as KidsIcon } from "./Kids" export { default as KidsMocktailIcon } from "./KidsMocktail" -export { default as KingBedIcon } from "./KingBed" -export { default as KingBedSmallIcon } from "./KingBedSmall" export { default as LampIcon } from "./Lamp" export { default as LaptopIcon } from "./Laptop" export { default as LaundryMachineIcon } from "./LaundryMachine" diff --git a/components/TempDesignSystem/Form/ChoiceCard/_Card/card.module.css b/components/TempDesignSystem/Form/ChoiceCard/_Card/card.module.css index d50df8a15..29c3a0ea5 100644 --- a/components/TempDesignSystem/Form/ChoiceCard/_Card/card.module.css +++ b/components/TempDesignSystem/Form/ChoiceCard/_Card/card.module.css @@ -8,6 +8,7 @@ padding: var(--Spacing-x-one-and-half) var(--Spacing-x2); transition: all 200ms ease; width: min(100%, 600px); + grid-column-gap: var(--Spacing-x2); } .label:hover { diff --git a/constants/booking.ts b/constants/booking.ts index 76e27b0e8..a7c9cf32f 100644 --- a/constants/booking.ts +++ b/constants/booking.ts @@ -1,3 +1,16 @@ +import { + ExtraBunkBedIcon, + ExtraPullOutBedIcon, + ExtraSofaBedIcon, + ExtraWallBedIcon, + KingBedIcon, + QueenBedIcon, + SingleBedIcon, + TwinBedsIcon, +} from "@/components/Icons" + +import type { IconProps } from "@/types/components/icon" + export enum BookingStatusEnum { BookingCompleted = "BookingCompleted", Cancelled = "Cancelled", @@ -101,3 +114,35 @@ export const PAYMENT_METHOD_ICONS: Record< chinaUnionPay: "/_static/icons/payment/china-union-pay.svg", discover: "/_static/icons/payment/discover.svg", } + +export enum BedTypeEnum { + King = "King", + Queen = "Queen", + Single = "Single", + Twin = "Twin", + Other = "Other", +} + +export enum ExtraBedTypeEnum { + SofaBed = "SofaBed", + WallBed = "WallBed", + PullOutBed = "PullOutBed", + BunkBed = "BunkBed", +} + +type BedTypes = keyof typeof BedTypeEnum | keyof typeof ExtraBedTypeEnum + +export const BED_TYPE_ICONS: Record< + BedTypes, + (props: IconProps) => JSX.Element +> = { + King: KingBedIcon, + Queen: QueenBedIcon, + Single: SingleBedIcon, + Twin: TwinBedsIcon, + SofaBed: ExtraSofaBedIcon, + WallBed: ExtraWallBedIcon, + BunkBed: ExtraBunkBedIcon, + PullOutBed: ExtraPullOutBedIcon, + Other: SingleBedIcon, +} diff --git a/server/routers/hotels/query.ts b/server/routers/hotels/query.ts index e17f1a51f..fc6a118ae 100644 --- a/server/routers/hotels/query.ts +++ b/server/routers/hotels/query.ts @@ -612,6 +612,13 @@ export const hotelQueryRouter = router({ description: matchingRoom.description, size: matchingRoom.mainBed.widthRange, value: matchingRoom.code, + type: matchingRoom.mainBed.type, + extraBed: matchingRoom.fixedExtraBed + ? { + type: matchingRoom.fixedExtraBed.type, + description: matchingRoom.fixedExtraBed.description, + } + : undefined, } } }) diff --git a/server/routers/hotels/schemas/room.ts b/server/routers/hotels/schemas/room.ts index 1de76227d..b12232708 100644 --- a/server/routers/hotels/schemas/room.ts +++ b/server/routers/hotels/schemas/room.ts @@ -1,5 +1,7 @@ import { z } from "zod" +import { BedTypeEnum, ExtraBedTypeEnum } from "@/constants/booking" + import { imageSchema } from "./image" const roomContentSchema = z.object({ @@ -17,22 +19,40 @@ const roomTypesSchema = z.object({ description: z.string(), code: z.string(), roomCount: z.number(), - mainBed: z.object({ - type: z.string(), - description: z.string(), - widthRange: z.object({ - min: z.number(), - max: z.number(), + mainBed: z + .object({ + type: z.string(), + description: z.string(), + widthRange: z.object({ + min: z.number(), + max: z.number(), + }), + }) + .transform((data) => ({ + type: + data.type in BedTypeEnum + ? (data.type as BedTypeEnum) + : BedTypeEnum.Other, + description: data.description, + widthRange: data.widthRange, + })), + fixedExtraBed: z + .object({ + type: z.string(), + description: z.string().optional(), + widthRange: z.object({ + min: z.number(), + max: z.number(), + }), + }) + .transform((data) => { + return data.type in ExtraBedTypeEnum + ? { + type: data.type as ExtraBedTypeEnum, + description: data.description, + } + : undefined }), - }), - fixedExtraBed: z.object({ - type: z.string(), - description: z.string().optional(), - widthRange: z.object({ - min: z.number(), - max: z.number(), - }), - }), roomSize: z.object({ min: z.number(), max: z.number(), diff --git a/stores/enter-details/useEnterDetailsStore.test.tsx b/stores/enter-details/useEnterDetailsStore.test.tsx index cfb6c9827..8b57e270f 100644 --- a/stores/enter-details/useEnterDetailsStore.test.tsx +++ b/stores/enter-details/useEnterDetailsStore.test.tsx @@ -2,6 +2,7 @@ import { describe, expect, test } from "@jest/globals" import { act, renderHook } from "@testing-library/react" import { type PropsWithChildren } from "react" +import { BedTypeEnum } from "@/constants/booking" import { Lang } from "@/constants/languages" import EnterDetailsProvider from "@/providers/EnterDetailsProvider" @@ -43,6 +44,7 @@ const booking = { const bedTypes = [ { + type: BedTypeEnum.King, description: "King-size bed", value: "SKS", size: { @@ -50,8 +52,10 @@ const bedTypes = [ max: 200, }, roomTypeCode: "SKS", + extraBed: undefined, }, { + type: BedTypeEnum.Queen, description: "Queen-size bed", value: "QZ", size: { @@ -59,6 +63,7 @@ const bedTypes = [ max: 200, }, roomTypeCode: "QZ", + extraBed: undefined, }, ] diff --git a/types/components/hotelReservation/enterDetails/bedType.ts b/types/components/hotelReservation/enterDetails/bedType.ts index 9f1fae723..0d4e0e11f 100644 --- a/types/components/hotelReservation/enterDetails/bedType.ts +++ b/types/components/hotelReservation/enterDetails/bedType.ts @@ -4,6 +4,7 @@ import type { bedTypeFormSchema, bedTypeSchema, } from "@/components/HotelReservation/EnterDetails/BedType/schema" +import type { BedTypeEnum, ExtraBedTypeEnum } from "@/constants/booking" export type BedTypeSelection = { description: string @@ -12,6 +13,13 @@ export type BedTypeSelection = { max: number } value: string + type: BedTypeEnum + extraBed: + | { + description: string + type: ExtraBedTypeEnum + } + | undefined } export type BedTypeProps = { bedTypes: BedTypeSelection[]