diff --git a/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-rate/page.tsx b/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-rate/page.tsx index d43330adb..603bbbf4a 100644 --- a/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-rate/page.tsx +++ b/app/[lang]/(live)/(public)/hotelreservation/(standard)/select-rate/page.tsx @@ -1,12 +1,12 @@ import { getProfileSafely } from "@/lib/trpc/memoizedRequests" import { serverClient } from "@/lib/trpc/server" -import { RoomPackageCode } from "@/server/routers/hotels/schemas/packages" import HotelInfoCard from "@/components/HotelReservation/SelectRate/HotelInfoCard" import Rooms from "@/components/HotelReservation/SelectRate/Rooms" import getHotelReservationQueryParams from "@/components/HotelReservation/SelectRate/RoomSelection/utils" import { setLang } from "@/i18n/serverContext" +import { RoomPackageCodeEnum } from "@/types/components/hotelReservation/selectRate/roomFilter" import { SelectRateSearchParams } from "@/types/components/hotelReservation/selectRate/selectRate" import { LangParams, PageArgs } from "@/types/params" @@ -42,9 +42,9 @@ export default async function SelectRatePage({ adults: adults, children: children, packageCodes: [ - RoomPackageCode.ACCE, - RoomPackageCode.PETR, - RoomPackageCode.ALLG, + RoomPackageCodeEnum.ACCE, + RoomPackageCodeEnum.PETR, + RoomPackageCodeEnum.ALLG, ], }), getProfileSafely(), diff --git a/components/HotelReservation/SelectRate/RoomFilter/index.tsx b/components/HotelReservation/SelectRate/RoomFilter/index.tsx index 3c3586994..836dd5b49 100644 --- a/components/HotelReservation/SelectRate/RoomFilter/index.tsx +++ b/components/HotelReservation/SelectRate/RoomFilter/index.tsx @@ -6,16 +6,19 @@ import { FormProvider, useForm } from "react-hook-form" import { useIntl } from "react-intl" import { z } from "zod" -import { RoomPackageCode } from "@/server/routers/hotels/schemas/packages" - -import Chip from "@/components/TempDesignSystem/Chip" -import Checkbox from "@/components/TempDesignSystem/Form/Checkbox" +import { InfoCircleIcon } from "@/components/Icons" +import CheckboxChip from "@/components/TempDesignSystem/Form/FilterChip/Checkbox" import Body from "@/components/TempDesignSystem/Text/Body" -import Caption from "@/components/TempDesignSystem/Text/Caption" +import { Tooltip } from "@/components/TempDesignSystem/Tooltip" + +import { getIconForFeatureCode } from "../utils" import styles from "./roomFilter.module.css" -import { RoomFilterProps } from "@/types/components/hotelReservation/selectRate/roomFilter" +import { + RoomFilterProps, + RoomPackageCodeEnum, +} from "@/types/components/hotelReservation/selectRate/roomFilter" export default function RoomFilter({ numberOfRooms, @@ -43,8 +46,8 @@ export default function RoomFilter({ }) const { watch, getValues, handleSubmit } = methods - const petFriendly = watch(RoomPackageCode.PETR) - const allergyFriendly = watch(RoomPackageCode.ALLG) + const petFriendly = watch(RoomPackageCodeEnum.PETR) + const allergyFriendly = watch(RoomPackageCodeEnum.ALLG) const submitFilter = useCallback(() => { const data = getValues() @@ -65,21 +68,27 @@ export default function RoomFilter({
{filterOptions.map((option) => ( - - - {intl.formatMessage({ id: option.description })} - - + label={intl.formatMessage({ id: option.description })} + disabled={ + (option.code === RoomPackageCodeEnum.ALLG && petFriendly) || + (option.code === RoomPackageCodeEnum.PETR && allergyFriendly) + } + selected={getValues(option.code)} + Icon={getIconForFeatureCode(option.code)} + /> ))} + + +
diff --git a/components/HotelReservation/SelectRate/RoomFilter/roomFilter.module.css b/components/HotelReservation/SelectRate/RoomFilter/roomFilter.module.css index 3c715f5c3..c0eff095a 100644 --- a/components/HotelReservation/SelectRate/RoomFilter/roomFilter.module.css +++ b/components/HotelReservation/SelectRate/RoomFilter/roomFilter.module.css @@ -2,10 +2,18 @@ display: flex; flex-direction: row; justify-content: space-between; + align-items: center; } .roomsFilter { display: flex; flex-direction: row; - gap: var(--Spacing-x3); + gap: var(--Spacing-x1); + align-items: center; +} + +.roomsFilter .infoIcon, +.roomsFilter .infoIcon path { + stroke: var(--UI-Text-Medium-contrast); + fill: transparent; } diff --git a/components/HotelReservation/SelectRate/RoomSelection/FlexibilityOption/index.tsx b/components/HotelReservation/SelectRate/RoomSelection/FlexibilityOption/index.tsx index a523305ae..a0a92bb66 100644 --- a/components/HotelReservation/SelectRate/RoomSelection/FlexibilityOption/index.tsx +++ b/components/HotelReservation/SelectRate/RoomSelection/FlexibilityOption/index.tsx @@ -19,6 +19,7 @@ export default function FlexibilityOption({ priceInformation, roomType, roomTypeCode, + features, handleSelectRate, }: FlexibilityOptionProps) { const [rootDiv, setRootDiv] = useState(undefined) @@ -52,6 +53,7 @@ export default function FlexibilityOption({ priceName: name, public: publicPrice, member: memberPrice, + features, } handleSelectRate(rate) } diff --git a/components/HotelReservation/SelectRate/RoomSelection/RateSummary/index.tsx b/components/HotelReservation/SelectRate/RoomSelection/RateSummary/index.tsx index b929bfe76..98915efa6 100644 --- a/components/HotelReservation/SelectRate/RoomSelection/RateSummary/index.tsx +++ b/components/HotelReservation/SelectRate/RoomSelection/RateSummary/index.tsx @@ -7,15 +7,28 @@ import Subtitle from "@/components/TempDesignSystem/Text/Subtitle" import styles from "./rateSummary.module.css" import { RateSummaryProps } from "@/types/components/hotelReservation/selectRate/rateSummary" +import { RoomPackageCodeEnum } from "@/types/components/hotelReservation/selectRate/roomFilter" export default function RateSummary({ rateSummary, isUserLoggedIn, + packages, }: RateSummaryProps) { const intl = useIntl() const priceToShow = isUserLoggedIn ? rateSummary.member : rateSummary.public + const isPetRoomSelect = rateSummary.features.some( + (feature) => feature.code === RoomPackageCodeEnum.PETR + ) + + const petRoomPackage = packages.find( + (pkg) => pkg.code === RoomPackageCodeEnum.PETR + ) + + const petRoomPrice = petRoomPackage ? petRoomPackage.calculatedPrice : null + const petRoomCurrency = petRoomPackage ? petRoomPackage.currency : null + return (
@@ -34,6 +47,16 @@ export default function RateSummary({ {priceToShow?.requestedPrice?.currency}
+ {isPetRoomSelect && ( +
+ + + {petRoomPrice} {petRoomCurrency} + + + {intl.formatMessage({ id: "Pet charge" })} + +
+ )} diff --git a/components/HotelReservation/SelectRate/RoomSelection/RateSummary/rateSummary.module.css b/components/HotelReservation/SelectRate/RoomSelection/RateSummary/rateSummary.module.css index c8352efb1..07e9841b4 100644 --- a/components/HotelReservation/SelectRate/RoomSelection/RateSummary/rateSummary.module.css +++ b/components/HotelReservation/SelectRate/RoomSelection/RateSummary/rateSummary.module.css @@ -15,3 +15,8 @@ display: flex; gap: var(--Spacing-x4); } + +.petInfo { + border-left: 1px solid var(--Primary-Light-On-Surface-Divider-subtle); + padding-left: var(--Spacing-x2); +} diff --git a/components/HotelReservation/SelectRate/RoomSelection/RoomCard/index.tsx b/components/HotelReservation/SelectRate/RoomSelection/RoomCard/index.tsx index 1afec6119..3b161d8c7 100644 --- a/components/HotelReservation/SelectRate/RoomSelection/RoomCard/index.tsx +++ b/components/HotelReservation/SelectRate/RoomSelection/RoomCard/index.tsx @@ -1,5 +1,6 @@ "use client" +import { createElement } from "react" import { useIntl } from "react-intl" import { RateDefinition } from "@/server/routers/hotels/output" @@ -12,6 +13,7 @@ import Subtitle from "@/components/TempDesignSystem/Text/Subtitle" import ImageGallery from "../../ImageGallery" import RoomSidePeek from "../RoomSidePeek" +import { getIconForFeatureCode } from "../../utils" import styles from "./roomCard.module.css" @@ -47,16 +49,16 @@ export default function RoomCard({ : undefined } - function getPriceForRate( + function getPriceInformationForRate( rate: typeof saveRate | typeof changeRate | typeof flexRate ) { return rateDefinitions.find((def) => def.rateCode === rate?.rateCode) ?.generalTerms } + const selectedRoom = roomCategories.find( (room) => room.name === roomConfiguration.roomType ) - const roomSize = selectedRoom?.roomSize const occupancy = selectedRoom?.occupancy.total const roomDescription = selectedRoom?.descriptions.short @@ -68,7 +70,6 @@ export default function RoomCard({
- {/*TODO: Handle pluralisation*/} {intl.formatMessage( { id: "booking.guests", @@ -105,44 +106,58 @@ export default function RoomCard({ value="non-refundable" paymentTerm={intl.formatMessage({ id: "Pay now" })} product={findProductForRate(saveRate)} - priceInformation={getPriceForRate(saveRate)} + priceInformation={getPriceInformationForRate(saveRate)} handleSelectRate={handleSelectRate} roomType={roomConfiguration.roomType} roomTypeCode={roomConfiguration.roomTypeCode} + features={roomConfiguration.features} />
{mainImage && (
- {roomConfiguration.roomsLeft < 5 && ( - - {`${roomConfiguration.roomsLeft} ${intl.formatMessage({ id: "Left" })}`} - - )} +
+ {roomConfiguration.roomsLeft < 5 && ( + + {`${roomConfiguration.roomsLeft} ${intl.formatMessage({ id: "Left" })}`} + + )} + {roomConfiguration.features.map((feature) => ( + + {createElement(getIconForFeatureCode(feature.code), { + width: 16, + height: 16, + color: "burgundy", + })} + + ))} +
{/*NOTE: images from the test API are hosted on test3.scandichotels.com, which can't be accessed unless on Scandic's Wifi or using Citrix. */} {images && ( diff --git a/components/HotelReservation/SelectRate/RoomSelection/RoomCard/roomCard.module.css b/components/HotelReservation/SelectRate/RoomSelection/RoomCard/roomCard.module.css index ef5d9b8fc..537c1b30a 100644 --- a/components/HotelReservation/SelectRate/RoomSelection/RoomCard/roomCard.module.css +++ b/components/HotelReservation/SelectRate/RoomSelection/RoomCard/roomCard.module.css @@ -64,10 +64,17 @@ gap: var(--Spacing-x2); } -.roomsLeft { +.chipContainer { position: absolute; + z-index: 1; top: 12px; left: 12px; + display: flex; + flex-direction: row; + gap: var(--Spacing-x1); +} + +.chip { background-color: var(--Main-Grey-White); padding: var(--Spacing-x-half) var(--Spacing-x1); border-radius: var(--Corner-radius-Small); diff --git a/components/HotelReservation/SelectRate/RoomSelection/index.tsx b/components/HotelReservation/SelectRate/RoomSelection/index.tsx index 8592e64ea..351efd5b3 100644 --- a/components/HotelReservation/SelectRate/RoomSelection/index.tsx +++ b/components/HotelReservation/SelectRate/RoomSelection/index.tsx @@ -15,6 +15,7 @@ export default function RoomSelection({ roomsAvailability, roomCategories, user, + packages, }: RoomSelectionProps) { const [rateSummary, setRateSummary] = useState(null) @@ -69,6 +70,7 @@ export default function RoomSelection({ )} diff --git a/components/HotelReservation/SelectRate/RoomSelection/roomSelection.module.css b/components/HotelReservation/SelectRate/RoomSelection/roomSelection.module.css index 66a27302e..1dab63afb 100644 --- a/components/HotelReservation/SelectRate/RoomSelection/roomSelection.module.css +++ b/components/HotelReservation/SelectRate/RoomSelection/roomSelection.module.css @@ -3,7 +3,6 @@ } .roomList { - margin-top: var(--Spacing-x4); list-style: none; display: grid; grid-template-columns: 1fr; diff --git a/components/HotelReservation/SelectRate/Rooms/index.tsx b/components/HotelReservation/SelectRate/Rooms/index.tsx index 963f266d4..0cd98156e 100644 --- a/components/HotelReservation/SelectRate/Rooms/index.tsx +++ b/components/HotelReservation/SelectRate/Rooms/index.tsx @@ -9,15 +9,15 @@ 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" +import { RoomSelectionProps } from "@/types/components/hotelReservation/selectRate/roomSelection" export default function Rooms({ roomsAvailability, roomCategories = [], user, packages, -}: RoomProps) { +}: RoomSelectionProps) { const [rooms, setRooms] = useState(roomsAvailability) function handleFilter(filter: Record) { @@ -47,6 +47,7 @@ export default function Rooms({ roomsAvailability={rooms} roomCategories={roomCategories} user={user} + packages={packages} />
) diff --git a/components/HotelReservation/SelectRate/Rooms/rooms.module.css b/components/HotelReservation/SelectRate/Rooms/rooms.module.css index a8e573530..5e2bca00b 100644 --- a/components/HotelReservation/SelectRate/Rooms/rooms.module.css +++ b/components/HotelReservation/SelectRate/Rooms/rooms.module.css @@ -3,6 +3,6 @@ margin: 0 auto; display: flex; flex-direction: column; - gap: var(--Spacing-x7); + gap: var(--Spacing-x2); padding: var(--Spacing-x2); } diff --git a/components/HotelReservation/SelectRate/utils.ts b/components/HotelReservation/SelectRate/utils.ts new file mode 100644 index 000000000..6002b0705 --- /dev/null +++ b/components/HotelReservation/SelectRate/utils.ts @@ -0,0 +1,19 @@ +import { AllergyIcon,PetsIcon, WheelchairIcon } from "@/components/Icons" + +import { + RoomPackageCodeEnum, + RoomPackageCodes, +} from "@/types/components/hotelReservation/selectRate/roomFilter" + +export function getIconForFeatureCode(featureCode: RoomPackageCodes) { + switch (featureCode) { + case RoomPackageCodeEnum.ACCE: + return WheelchairIcon + case RoomPackageCodeEnum.ALLG: + return AllergyIcon + case RoomPackageCodeEnum.PETR: + return PetsIcon + default: + return PetsIcon + } +} diff --git a/components/Icons/Allergy.tsx b/components/Icons/Allergy.tsx new file mode 100644 index 000000000..0fe399445 --- /dev/null +++ b/components/Icons/Allergy.tsx @@ -0,0 +1,36 @@ +import { iconVariants } from "./variants" + +import type { IconProps } from "@/types/components/icon" + +export default function AllergyIcon({ className, color, ...props }: IconProps) { + const classNames = iconVariants({ className, color }) + return ( + + + + + + + + + ) +} diff --git a/components/Icons/Pets.tsx b/components/Icons/Pets.tsx index 679a3afee..e5e475b2e 100644 --- a/components/Icons/Pets.tsx +++ b/components/Icons/Pets.tsx @@ -16,7 +16,7 @@ export default function PetsIcon({ className, color, ...props }: IconProps) { > ) diff --git a/components/Icons/Wheelchair.tsx b/components/Icons/Wheelchair.tsx new file mode 100644 index 000000000..991951761 --- /dev/null +++ b/components/Icons/Wheelchair.tsx @@ -0,0 +1,40 @@ +import { iconVariants } from "./variants" + +import type { IconProps } from "@/types/components/icon" + +export default function WheelchairIcon({ + className, + color, + ...props +}: IconProps) { + const classNames = iconVariants({ className, color }) + return ( + + + + + + + + + ) +} diff --git a/components/Icons/icon.module.css b/components/Icons/icon.module.css index ec5a15fd4..68ace50b3 100644 --- a/components/Icons/icon.module.css +++ b/components/Icons/icon.module.css @@ -76,3 +76,8 @@ .baseButtonTextOnFillNormal * { fill: var(--Base-Button-Text-On-Fill-Normal); } + +.disabled, +.disabled * { + fill: var(--Base-Text-Disabled); +} diff --git a/components/Icons/index.tsx b/components/Icons/index.tsx index fc7407ce8..ce23296fe 100644 --- a/components/Icons/index.tsx +++ b/components/Icons/index.tsx @@ -4,6 +4,7 @@ export { default as AccessibilityIcon } from "./Accessibility" export { default as AccountCircleIcon } from "./AccountCircle" export { default as AirIcon } from "./Air" export { default as AirplaneIcon } from "./Airplane" +export { default as AllergyIcon } from "./Allergy" export { default as ArrowRightIcon } from "./ArrowRight" export { default as BarIcon } from "./Bar" export { default as BathtubIcon } from "./Bathtub" @@ -111,6 +112,7 @@ export { default as TshirtIcon } from "./Tshirt" export { default as TshirtWashIcon } from "./TshirtWash" export { default as TvCastingIcon } from "./TvCasting" export { default as WarningTriangle } from "./WarningTriangle" +export { default as WheelchairIcon } from "./Wheelchair" export { default as WifiIcon } from "./Wifi" export { default as WindowCurtainsAltIcon } from "./WindowCurtainsAlt" export { default as WindowNotAvailableIcon } from "./WindowNotAvailable" diff --git a/components/Icons/variants.ts b/components/Icons/variants.ts index d319c466e..09d69364f 100644 --- a/components/Icons/variants.ts +++ b/components/Icons/variants.ts @@ -20,6 +20,7 @@ const config = { white: styles.white, uiTextHighContrast: styles.uiTextHighContrast, uiTextMediumContrast: styles.uiTextMediumContrast, + disabled: styles.disabled, }, }, defaultVariants: { diff --git a/components/TempDesignSystem/Form/FilterChip/Checkbox.tsx b/components/TempDesignSystem/Form/FilterChip/Checkbox.tsx new file mode 100644 index 000000000..c2697d560 --- /dev/null +++ b/components/TempDesignSystem/Form/FilterChip/Checkbox.tsx @@ -0,0 +1,7 @@ +import Chip from "./_Chip" + +import type { FilterChipCheckboxProps } from "@/types/components/form/filterChip" + +export default function CheckboxChip(props: FilterChipCheckboxProps) { + return +} diff --git a/components/TempDesignSystem/Form/FilterChip/_Chip/chip.module.css b/components/TempDesignSystem/Form/FilterChip/_Chip/chip.module.css new file mode 100644 index 000000000..19e1db812 --- /dev/null +++ b/components/TempDesignSystem/Form/FilterChip/_Chip/chip.module.css @@ -0,0 +1,27 @@ +.label { + display: flex; + align-items: center; + gap: var(--Spacing-x-half); + padding: var(--Spacing-x1) var(--Spacing-x-one-and-half); + border: 1px solid var(--Base-Border-Subtle); + border-radius: var(--Corner-radius-Small); + background-color: var(--Base-Surface-Secondary-light-Normal); + cursor: pointer; +} + +.label[data-selected="true"], +.label[data-selected="true"]:hover { + background-color: var(--Primary-Light-Surface-Normal); + border-color: var(--Base-Border-Hover); +} + +.label:hover { + background-color: var(--Base-Surface-Primary-light-Hover-alt); + border-color: var(--Base-Border-Subtle); +} + +.label[data-disabled="true"] { + background-color: var(--Base-Button-Primary-Fill-Disabled); + border-color: var(--Base-Button-Primary-Fill-Disabled); + cursor: not-allowed; +} diff --git a/components/TempDesignSystem/Form/FilterChip/_Chip/index.tsx b/components/TempDesignSystem/Form/FilterChip/_Chip/index.tsx new file mode 100644 index 000000000..c88f17d29 --- /dev/null +++ b/components/TempDesignSystem/Form/FilterChip/_Chip/index.tsx @@ -0,0 +1,57 @@ +import { useMemo } from "react" +import { useFormContext } from "react-hook-form" + +import { HeartIcon } from "@/components/Icons" +import Caption from "@/components/TempDesignSystem/Text/Caption" + +import styles from "./chip.module.css" + +import { FilterChipProps } from "@/types/components/form/filterChip" + +export default function FilterChip({ + Icon = HeartIcon, + iconHeight = 20, + iconWidth = 20, + id, + name, + label, + type, + value, + selected, + disabled, +}: FilterChipProps) { + const { register } = useFormContext() + + const color = useMemo(() => { + if (selected) return "burgundy" + if (disabled) return "disabled" + return "uiTextPlaceholder" + }, [selected, disabled]) + + return ( + + ) +} diff --git a/components/TempDesignSystem/Tooltip/tooltip.module.css b/components/TempDesignSystem/Tooltip/tooltip.module.css index 2a6b00b43..da8e50cbd 100644 --- a/components/TempDesignSystem/Tooltip/tooltip.module.css +++ b/components/TempDesignSystem/Tooltip/tooltip.module.css @@ -15,6 +15,7 @@ opacity: 0; transition: opacity 0.3s; max-width: 200px; + min-width: 150px; } .tooltipContainer:hover .tooltip { @@ -31,11 +32,15 @@ } .top { - bottom: 100%; + bottom: calc(100% + 8px); } .bottom { - top: 100%; + top: calc(100% + 8px); +} + +.bottom.arrowRight { + right: 0; } .tooltip::before { diff --git a/i18n/dictionaries/da.json b/i18n/dictionaries/da.json index af4c667b8..74d3e165b 100644 --- a/i18n/dictionaries/da.json +++ b/i18n/dictionaries/da.json @@ -218,6 +218,7 @@ "Pay now": "Betal nu", "Payment info": "Betalingsoplysninger", "Pet Room": "Kæledyrsrum", + "Pet-friendly rooms have an additional fee of 20 EUR per stay": "Kæledyrsrum har en ekstra gebyr på 20 EUR per ophold", "Phone": "Telefon", "Phone is required": "Telefonnummer er påkrævet", "Phone number": "Telefonnummer", diff --git a/i18n/dictionaries/de.json b/i18n/dictionaries/de.json index c9483e349..adb01b099 100644 --- a/i18n/dictionaries/de.json +++ b/i18n/dictionaries/de.json @@ -218,6 +218,7 @@ "Pay now": "Jetzt bezahlen", "Payment info": "Zahlungsinformationen", "Pet Room": "Haustierzimmer", + "Pet-friendly rooms have an additional fee of 20 EUR per stay": "Haustierzimmer haben einen zusätzlichen Preis von 20 EUR pro Aufenthalt", "Phone": "Telefon", "Phone is required": "Telefon ist erforderlich", "Phone number": "Telefonnummer", diff --git a/i18n/dictionaries/en.json b/i18n/dictionaries/en.json index 0511cf5a9..2e92e936a 100644 --- a/i18n/dictionaries/en.json +++ b/i18n/dictionaries/en.json @@ -228,6 +228,7 @@ "Payment info": "Payment info", "Payment received": "Payment received", "Pet Room": "Pet room", + "Pet-friendly rooms have an additional fee of 20 EUR per stay": "Pet-friendly rooms have an additional fee of 20 EUR per stay", "Phone": "Phone", "Phone is required": "Phone is required", "Phone number": "Phone number", diff --git a/i18n/dictionaries/fi.json b/i18n/dictionaries/fi.json index c8427a306..5f464d30f 100644 --- a/i18n/dictionaries/fi.json +++ b/i18n/dictionaries/fi.json @@ -218,6 +218,7 @@ "Pay now": "Maksa nyt", "Payment info": "Maksutiedot", "Pet Room": "Lemmikkihuone", + "Pet-friendly rooms have an additional fee of 20 EUR per stay": "Lemmikkihuoneen lisäkustannus on 20 EUR per majoitus", "Phone": "Puhelin", "Phone is required": "Puhelin vaaditaan", "Phone number": "Puhelinnumero", diff --git a/i18n/dictionaries/no.json b/i18n/dictionaries/no.json index 69a1fbec4..8ef615923 100644 --- a/i18n/dictionaries/no.json +++ b/i18n/dictionaries/no.json @@ -216,6 +216,7 @@ "Pay now": "Betal nå", "Payment info": "Betalingsinformasjon", "Pet Room": "Kjæledyrsrom", + "Pet-friendly rooms have an additional fee of 20 EUR per stay": "Kjæledyrsrom har en tilleggsavgift på 20 EUR per opphold", "Phone": "Telefon", "Phone is required": "Telefon kreves", "Phone number": "Telefonnummer", diff --git a/i18n/dictionaries/sv.json b/i18n/dictionaries/sv.json index c2f90d520..df8d576c8 100644 --- a/i18n/dictionaries/sv.json +++ b/i18n/dictionaries/sv.json @@ -216,6 +216,7 @@ "Pay now": "Betala nu", "Payment info": "Betalningsinformation", "Pet Room": "Husdjursrum", + "Pet-friendly rooms have an additional fee of 20 EUR per stay": "Husdjursrum har en extra avgift på 20 EUR per vistelse", "Phone": "Telefon", "Phone is required": "Telefonnummer är obligatorisk", "Phone number": "Telefonnummer", diff --git a/server/routers/hotels/output.ts b/server/routers/hotels/output.ts index 0f545d673..91032ffdc 100644 --- a/server/routers/hotels/output.ts +++ b/server/routers/hotels/output.ts @@ -7,6 +7,7 @@ import { imageMetaDataSchema, imageSizesSchema } from "./schemas/image" import { roomSchema } from "./schemas/room" import { getPoiGroupByCategoryName } from "./utils" +import { RoomPackageCodeEnum } from "@/types/components/hotelReservation/selectRate/roomFilter" import { AlertTypeEnum } from "@/types/enums/alert" import { FacilityEnum } from "@/types/enums/facilities" import { PointOfInterestCategoryNameEnum } from "@/types/hotel" @@ -545,7 +546,16 @@ const roomConfigurationSchema = z.object({ roomTypeCode: z.string().optional(), roomType: z.string(), roomsLeft: z.number(), - features: z.array(z.object({ inventory: z.number(), code: z.string() })), + features: z.array( + z.object({ + inventory: z.number(), + code: z.enum([ + RoomPackageCodeEnum.PETR, + RoomPackageCodeEnum.ALLG, + RoomPackageCodeEnum.ACCE, + ]), + }) + ), products: z.array(productSchema), }) diff --git a/server/routers/hotels/schemas/packages.ts b/server/routers/hotels/schemas/packages.ts index d7ff6a4e1..a239c6b50 100644 --- a/server/routers/hotels/schemas/packages.ts +++ b/server/routers/hotels/schemas/packages.ts @@ -1,10 +1,6 @@ import { z } from "zod" -export enum RoomPackageCode { - PETR = "PETR", - ALLG = "ALLG", - ACCE = "ACCE", -} +import { RoomPackageCodeEnum } from "@/types/components/hotelReservation/selectRate/roomFilter" export const getRoomPackagesInputSchema = z.object({ hotelId: z.string(), @@ -18,9 +14,9 @@ export const getRoomPackagesInputSchema = z.object({ const packagesSchema = z.array( z.object({ code: z.enum([ - RoomPackageCode.PETR, - RoomPackageCode.ALLG, - RoomPackageCode.ACCE, + RoomPackageCodeEnum.PETR, + RoomPackageCodeEnum.ALLG, + RoomPackageCodeEnum.ACCE, ]), itemCode: z.string(), description: z.string(), diff --git a/types/components/form/filterChip.ts b/types/components/form/filterChip.ts new file mode 100644 index 000000000..3ff40673d --- /dev/null +++ b/types/components/form/filterChip.ts @@ -0,0 +1,16 @@ +type FilterChipType = "checkbox" | "radio" + +export interface FilterChipProps { + Icon?: React.ElementType + iconHeight?: number + iconWidth?: number + id?: string + label: string + name: string + type: FilterChipType + value?: string + selected?: boolean + disabled?: boolean +} + +export type FilterChipCheckboxProps = Omit diff --git a/types/components/hotelReservation/selectRate/flexibilityOption.ts b/types/components/hotelReservation/selectRate/flexibilityOption.ts index 1835c3b65..1a432dc32 100644 --- a/types/components/hotelReservation/selectRate/flexibilityOption.ts +++ b/types/components/hotelReservation/selectRate/flexibilityOption.ts @@ -18,6 +18,7 @@ export type FlexibilityOptionProps = { priceInformation?: Array roomType: RoomConfiguration["roomType"] roomTypeCode: RoomConfiguration["roomTypeCode"] + features: RoomConfiguration["features"] handleSelectRate: (rate: Rate) => void } diff --git a/types/components/hotelReservation/selectRate/rateSummary.ts b/types/components/hotelReservation/selectRate/rateSummary.ts index 672df21dd..c9685f180 100644 --- a/types/components/hotelReservation/selectRate/rateSummary.ts +++ b/types/components/hotelReservation/selectRate/rateSummary.ts @@ -1,6 +1,8 @@ +import { RoomPackageData } from "./roomFilter" import { Rate } from "./selectRate" export interface RateSummaryProps { rateSummary: Rate isUserLoggedIn: boolean + packages: RoomPackageData } diff --git a/types/components/hotelReservation/selectRate/room.ts b/types/components/hotelReservation/selectRate/room.ts deleted file mode 100644 index b84e5c667..000000000 --- a/types/components/hotelReservation/selectRate/room.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { RoomPackageData } from "./roomFilter" -import { RoomSelectionProps } from "./roomSelection" - -export interface RoomProps extends RoomSelectionProps { - packages: RoomPackageData -} diff --git a/types/components/hotelReservation/selectRate/roomCard.ts b/types/components/hotelReservation/selectRate/roomCard.ts index a6ed91ac1..99552916d 100644 --- a/types/components/hotelReservation/selectRate/roomCard.ts +++ b/types/components/hotelReservation/selectRate/roomCard.ts @@ -3,6 +3,7 @@ import { RoomConfiguration, } from "@/server/routers/hotels/output" +import { RoomPackageCodes } from "./roomFilter" import { Rate } from "./selectRate" import { RoomData } from "@/types/hotel" diff --git a/types/components/hotelReservation/selectRate/roomFilter.ts b/types/components/hotelReservation/selectRate/roomFilter.ts index c70f8f1d0..aaf807508 100644 --- a/types/components/hotelReservation/selectRate/roomFilter.ts +++ b/types/components/hotelReservation/selectRate/roomFilter.ts @@ -2,6 +2,11 @@ import { z } from "zod" import { getRoomPackagesSchema } from "@/server/routers/hotels/schemas/packages" +export enum RoomPackageCodeEnum { + PETR = "PETR", + ALLG = "ALLG", + ACCE = "ACCE", +} export interface RoomFilterProps { numberOfRooms: number onFilter: (filter: Record) => void diff --git a/types/components/hotelReservation/selectRate/roomSelection.ts b/types/components/hotelReservation/selectRate/roomSelection.ts index fd633fa50..03e84245e 100644 --- a/types/components/hotelReservation/selectRate/roomSelection.ts +++ b/types/components/hotelReservation/selectRate/roomSelection.ts @@ -1,5 +1,7 @@ import { RoomsAvailability } from "@/server/routers/hotels/output" +import { RoomPackageData } from "./roomFilter" + import { RoomData } from "@/types/hotel" import { SafeUser } from "@/types/user" @@ -7,4 +9,5 @@ export interface RoomSelectionProps { roomsAvailability: RoomsAvailability roomCategories: RoomData[] user: SafeUser + packages: RoomPackageData } diff --git a/types/components/hotelReservation/selectRate/selectRate.ts b/types/components/hotelReservation/selectRate/selectRate.ts index da8792133..b22c010c0 100644 --- a/types/components/hotelReservation/selectRate/selectRate.ts +++ b/types/components/hotelReservation/selectRate/selectRate.ts @@ -26,4 +26,5 @@ export interface Rate { priceName: string public: Product["productType"]["public"] member: Product["productType"]["member"] + features: RoomConfiguration["features"] }