From 24f7bc290d7ca3f549156c0eab6ab99b90619937 Mon Sep 17 00:00:00 2001 From: Hrishikesh Vaipurkar Date: Thu, 12 Sep 2024 11:30:56 +0200 Subject: [PATCH] feat: SW-276 Implemented Guests and rooms picker --- .../Forms/BookingWidget/FormContent/index.tsx | 3 +- components/Forms/BookingWidget/schema.ts | 1 - .../AdultSelector/adult-selector.module.css | 9 ++ .../GuestsRoomPicker/AdultSelector/index.tsx | 44 ++++++++ .../ChildSelector/ChildInfoSelector.tsx | 83 ++++++++++++++ .../ChildSelector/child-selector.module.css | 14 +++ .../GuestsRoomPicker/ChildSelector/index.tsx | 101 ++++++++++++++++++ .../guests-room-picker.module.css | 6 ++ .../GuestsRoomPicker/index.tsx | 47 ++++++++ .../GuestsRoomsPicker/GuestsRoomsPicker.tsx | 89 +++++++++++++++ .../guests-rooms-picker.module.css | 34 ++++++ components/GuestsRoomsPicker/index.tsx | 85 +++++++++++++++ i18n/dictionaries/da.json | 8 ++ i18n/dictionaries/de.json | 8 ++ i18n/dictionaries/en.json | 10 ++ i18n/dictionaries/fi.json | 8 ++ i18n/dictionaries/no.json | 8 ++ i18n/dictionaries/sv.json | 10 +- .../bookingWidget/guestsRoomsPicker.ts | 41 +++++++ 19 files changed, 605 insertions(+), 4 deletions(-) create mode 100644 components/GuestsRoomsPicker/GuestsRoomPicker/AdultSelector/adult-selector.module.css create mode 100644 components/GuestsRoomsPicker/GuestsRoomPicker/AdultSelector/index.tsx create mode 100644 components/GuestsRoomsPicker/GuestsRoomPicker/ChildSelector/ChildInfoSelector.tsx create mode 100644 components/GuestsRoomsPicker/GuestsRoomPicker/ChildSelector/child-selector.module.css create mode 100644 components/GuestsRoomsPicker/GuestsRoomPicker/ChildSelector/index.tsx create mode 100644 components/GuestsRoomsPicker/GuestsRoomPicker/guests-room-picker.module.css create mode 100644 components/GuestsRoomsPicker/GuestsRoomPicker/index.tsx create mode 100644 components/GuestsRoomsPicker/GuestsRoomsPicker.tsx create mode 100644 components/GuestsRoomsPicker/guests-rooms-picker.module.css create mode 100644 components/GuestsRoomsPicker/index.tsx create mode 100644 types/components/bookingWidget/guestsRoomsPicker.ts diff --git a/components/Forms/BookingWidget/FormContent/index.tsx b/components/Forms/BookingWidget/FormContent/index.tsx index c7f990c38..4c50474bd 100644 --- a/components/Forms/BookingWidget/FormContent/index.tsx +++ b/components/Forms/BookingWidget/FormContent/index.tsx @@ -7,6 +7,7 @@ import { dt } from "@/lib/dt" import DatePicker from "@/components/DatePicker" import { SearchIcon } from "@/components/Icons" import Button from "@/components/TempDesignSystem/Button" +import GuestsRoomsPickerForm from "@/components/GuestsRoomsPicker" import Caption from "@/components/TempDesignSystem/Text/Caption" import Input from "./Input" @@ -51,7 +52,7 @@ export default function FormContent({ {rooms} - +
diff --git a/components/Forms/BookingWidget/schema.ts b/components/Forms/BookingWidget/schema.ts index f474a72e1..bc0be8d9c 100644 --- a/components/Forms/BookingWidget/schema.ts +++ b/components/Forms/BookingWidget/schema.ts @@ -26,7 +26,6 @@ export const bookingWidgetSchema = z.object({ ), redemption: z.boolean().default(false), rooms: z.array( - // This will be updated when working in guests component z.object({ adults: z.number().default(1), children: z.array( diff --git a/components/GuestsRoomsPicker/GuestsRoomPicker/AdultSelector/adult-selector.module.css b/components/GuestsRoomsPicker/GuestsRoomPicker/AdultSelector/adult-selector.module.css new file mode 100644 index 000000000..dd5f45c74 --- /dev/null +++ b/components/GuestsRoomsPicker/GuestsRoomPicker/AdultSelector/adult-selector.module.css @@ -0,0 +1,9 @@ +.container { + display: grid; + grid-template-columns: auto auto auto auto; + align-items: center; +} + +.textCenter { + text-align: center; +} diff --git a/components/GuestsRoomsPicker/GuestsRoomPicker/AdultSelector/index.tsx b/components/GuestsRoomsPicker/GuestsRoomPicker/AdultSelector/index.tsx new file mode 100644 index 000000000..d3b6a1297 --- /dev/null +++ b/components/GuestsRoomsPicker/GuestsRoomPicker/AdultSelector/index.tsx @@ -0,0 +1,44 @@ +import { useIntl } from "react-intl" + +import Button from "@/components/TempDesignSystem/Button" +import Caption from "@/components/TempDesignSystem/Text/Caption" + +import styles from "./adult-selector.module.css" + +import { AdultSelectorProps } from "@/types/components/bookingWidget/guestsRoomsPicker" + +export default function AdultSelector({ + adults = 1, + updateAdults = (count: number) => {}, +}: AdultSelectorProps) { + const intl = useIntl() + const adultsLabel = intl.formatMessage({ id: "Adults" }) + + function decreaseAdults() { + if (adults <= 1) { + return + } + adults = adults - 1 + updateAdults(adults) + } + function increaseAdults() { + if (adults > 5) { + return + } + adults = adults + 1 + updateAdults(adults) + } + + return ( +
+ {adultsLabel} + + {adults} + +
+ ) +} diff --git a/components/GuestsRoomsPicker/GuestsRoomPicker/ChildSelector/ChildInfoSelector.tsx b/components/GuestsRoomsPicker/GuestsRoomPicker/ChildSelector/ChildInfoSelector.tsx new file mode 100644 index 000000000..7dbc6d303 --- /dev/null +++ b/components/GuestsRoomsPicker/GuestsRoomPicker/ChildSelector/ChildInfoSelector.tsx @@ -0,0 +1,83 @@ +import { useIntl } from "react-intl" + +import Select from "@/components/TempDesignSystem/Select" + +import { + Child, + ChildBed, +} from "@/types/components/bookingWidget/guestsRoomsPicker" + +type ChildSelectorProps = { + child: Child + index: number + availableBedTypes?: ChildBed[] + updateChild: (child: Child, index: number) => void +} + +export default function ChildInfoSelector({ + child = { age: -1, bed: -1 }, + index = 0, + availableBedTypes = [ + { label: "In adults bed", value: 0 }, + { label: "In crib", value: 1 }, + { label: "In extra bed", value: 2 }, + ], + updateChild = (child: Child, index: number) => {}, +}: ChildSelectorProps) { + const intl = useIntl() + const ageLabel = intl.formatMessage({ id: "Age" }) + const bedLabel = intl.formatMessage({ id: "Bed" }) + + const ageList = [ + { label: "0", value: 0 }, + { label: "1", value: 1 }, + { label: "2", value: 2 }, + { label: "3", value: 3 }, + { label: "4", value: 4 }, + { label: "5", value: 5 }, + { label: "6", value: 6 }, + { label: "7", value: 7 }, + { label: "8", value: 8 }, + { label: "9", value: 9 }, + { label: "10", value: 10 }, + { label: "11", value: 11 }, + { label: "12", value: 12 }, + ] + + function handleOnSelect(selectedKey: any, childInfo: string) { + if (childInfo == "age") { + child.age = selectedKey + } else if (childInfo == "bed") { + child.bed = selectedKey + } + updateChild(child, index) + } + + return ( + <> + { + handleOnSelect(key, "bed") + }} + name="bed" + /> + ) : null} + + ) +} diff --git a/components/GuestsRoomsPicker/GuestsRoomPicker/ChildSelector/child-selector.module.css b/components/GuestsRoomsPicker/GuestsRoomPicker/ChildSelector/child-selector.module.css new file mode 100644 index 000000000..7f7bd09d7 --- /dev/null +++ b/components/GuestsRoomsPicker/GuestsRoomPicker/ChildSelector/child-selector.module.css @@ -0,0 +1,14 @@ +.container { + display: grid; + grid-template-columns: auto auto auto auto; + align-items: center; +} + +.childInfoContainer { + display: flex; + gap: 20px; +} + +.textCenter { + text-align: center; +} diff --git a/components/GuestsRoomsPicker/GuestsRoomPicker/ChildSelector/index.tsx b/components/GuestsRoomsPicker/GuestsRoomPicker/ChildSelector/index.tsx new file mode 100644 index 000000000..d1ca9138b --- /dev/null +++ b/components/GuestsRoomsPicker/GuestsRoomPicker/ChildSelector/index.tsx @@ -0,0 +1,101 @@ +import { useIntl } from "react-intl" + +import Button from "@/components/TempDesignSystem/Button" +import Caption from "@/components/TempDesignSystem/Text/Caption" + +import ChildInfoSelector from "./ChildInfoSelector" + +import styles from "./child-selector.module.css" + +import { + Child, + ChildBed, + ChildSelectorProps, +} from "@/types/components/bookingWidget/guestsRoomsPicker" + +export default function ChildSelector({ + roomChildren = [], + adultCount = 1, + updateChildren = (children: Child[]) => {}, +}: ChildSelectorProps) { + const intl = useIntl() + const childrenLabel = intl.formatMessage({ id: "Children" }) + + function decreaseChildren() { + if (roomChildren.length < 1) { + return + } + roomChildren.pop() + updateChildren(roomChildren) + } + + function increaseChildren() { + if (roomChildren.length > 5) { + return + } + roomChildren.push({ age: -1, bed: -1 }) + updateChildren(roomChildren) + } + + function updateChildInfo(child: Child, index: number) { + roomChildren[index] = child + updateChildren(roomChildren) + } + + const childInAdultsBedIndices: number[] = [] + let availableInAdultsBed = adultCount + const availableBedTypes: ChildBed[] = [ + { label: intl.formatMessage({ id: "In adults bed" }), value: 0 }, + { label: intl.formatMessage({ id: "In crib" }), value: 1 }, + { label: intl.formatMessage({ id: "In extra bed" }), value: 2 }, + ] + + const childBedTypes: ChildBed[][] = [] + for (let i = 0; i < roomChildren.length; i++) { + if (roomChildren[i].bed == 0 && availableInAdultsBed > 0) { + childInAdultsBedIndices.push(i) + availableInAdultsBed = availableInAdultsBed - 1 + } + } + roomChildren.forEach((child, index) => { + let types: typeof availableBedTypes = [] + if ( + child.age <= 5 && + (availableInAdultsBed > 0 || childInAdultsBedIndices.indexOf(index) != -1) + ) { + types.push(availableBedTypes[0]) + } + if (child.age < 3) { + types.push(availableBedTypes[1]) + } + if (child.age > 2) { + types.push(availableBedTypes[2]) + } + childBedTypes[index] = types + }) + + return ( + <> +
+ {childrenLabel} + + {roomChildren.length} + +
+ {roomChildren.map((child, index) => ( +
+ +
+ ))} + + ) +} diff --git a/components/GuestsRoomsPicker/GuestsRoomPicker/guests-room-picker.module.css b/components/GuestsRoomsPicker/GuestsRoomPicker/guests-room-picker.module.css new file mode 100644 index 000000000..64c253dff --- /dev/null +++ b/components/GuestsRoomsPicker/GuestsRoomPicker/guests-room-picker.module.css @@ -0,0 +1,6 @@ +.container { + width: 280px; + display: grid; + gap: var(--Spacing-x2); + padding-bottom: var(--Spacing-x1); +} diff --git a/components/GuestsRoomsPicker/GuestsRoomPicker/index.tsx b/components/GuestsRoomsPicker/GuestsRoomPicker/index.tsx new file mode 100644 index 000000000..1dcca2cb5 --- /dev/null +++ b/components/GuestsRoomsPicker/GuestsRoomPicker/index.tsx @@ -0,0 +1,47 @@ +import { useIntl } from "react-intl" + +import Subtitle from "@/components/TempDesignSystem/Text/Subtitle" + +import AdultSelector from "./AdultSelector" +import ChildSelector from "./ChildSelector" + +import styles from "./guests-room-picker.module.css" + +import { + Child, + GuestsRoom, + GuestsRoomPickerProps, +} from "@/types/components/bookingWidget/guestsRoomsPicker" + +export default function GuestsRoomPicker({ + handleOnSelect = (selected: GuestsRoom, index: number) => {}, + room = { adults: 1, children: [] }, + index = 1, +}: GuestsRoomPickerProps) { + const intl = useIntl() + const roomLabel = intl.formatMessage({ id: "Room" }) + + function updateAdults(count: number) { + room.adults = count + handleOnSelect(room, index) + } + + function updateChildren(children: Child[]) { + room.children = children + handleOnSelect(room, index) + } + + return ( +
+ + {roomLabel} {index + 1} + + + +
+ ) +} diff --git a/components/GuestsRoomsPicker/GuestsRoomsPicker.tsx b/components/GuestsRoomsPicker/GuestsRoomsPicker.tsx new file mode 100644 index 000000000..33ac64ecb --- /dev/null +++ b/components/GuestsRoomsPicker/GuestsRoomsPicker.tsx @@ -0,0 +1,89 @@ +"use client" +import { useState } from "react" + +import useLang from "@/hooks/useLang" + +import Button from "../TempDesignSystem/Button" +import Divider from "../TempDesignSystem/Divider" +import GuestsRoomPicker from "./GuestsRoomPicker" + +import styles from "./guests-rooms-picker.module.css" + +import { + GuestsRoom, + GuestsRoomsPickerProps, +} from "@/types/components/bookingWidget/guestsRoomsPicker" + +export default function GuestsRoomsPicker({ + handleOnSelect, + initialSelected = [ + { + adults: 1, + children: [], + }, + ], + closePicker, +}: GuestsRoomsPickerProps) { + const lang = useLang() + const [selectedGuests, setSelectedGuests] = + useState(initialSelected) + + function handleSelectRoomGuests( + selectedGuestsRoom: GuestsRoom, + index: number + ) { + let updatedSelectedGuests = JSON.parse(JSON.stringify(selectedGuests)) + updatedSelectedGuests[index] = selectedGuestsRoom + handleOnSelect(updatedSelectedGuests) + setSelectedGuests(updatedSelectedGuests) + } + + function addRoom() { + if (selectedGuests.length < 4) { + let updatedSelectedGuests = JSON.parse(JSON.stringify(selectedGuests)) + updatedSelectedGuests.push({ + adults: 1, + children: [], + }) + setSelectedGuests(updatedSelectedGuests) + handleOnSelect(updatedSelectedGuests) + } + } + + function removeRoom(index: number) { + if (selectedGuests.length > 1) { + let updatedSelectedGuests = JSON.parse(JSON.stringify(selectedGuests)) + updatedSelectedGuests.splice(index, 1) + setSelectedGuests(updatedSelectedGuests) + handleOnSelect(updatedSelectedGuests) + } + } + + return ( + <> + {selectedGuests.map((room, index) => ( +
+ + + {index > 0 ? ( + + ) : null} +
+ ))} +
+ {selectedGuests.length < 4 ? ( + + ) : null} + +
+ + ) +} diff --git a/components/GuestsRoomsPicker/guests-rooms-picker.module.css b/components/GuestsRoomsPicker/guests-rooms-picker.module.css new file mode 100644 index 000000000..15c7fd05e --- /dev/null +++ b/components/GuestsRoomsPicker/guests-rooms-picker.module.css @@ -0,0 +1,34 @@ +.container { + overflow: hidden; + position: relative; + z-index: 10; + &[data-isopen="true"] { + overflow: visible; + } +} +.hideWrapper { + background-color: var(--Main-Grey-White); + border-radius: var(--Corner-radius-Medium); + box-shadow: 0px 16px 24px 0px rgba(0, 0, 0, 0.08); + padding: var(--Spacing-x-one-and-half); + position: absolute; + /** BookingWidget padding + border-width */ + top: calc(100% + var(--Spacing-x2) + 1px); +} +.btn { + background: none; + border: none; + cursor: pointer; + outline: none; + padding: 0; + width: 100%; +} +.body { + opacity: 0.8; +} +.footer { + display: grid; + gap: 20px; + grid-template-columns: auto auto; + margin: 10px 0 0; +} diff --git a/components/GuestsRoomsPicker/index.tsx b/components/GuestsRoomsPicker/index.tsx new file mode 100644 index 000000000..66f0cce70 --- /dev/null +++ b/components/GuestsRoomsPicker/index.tsx @@ -0,0 +1,85 @@ +"use client" + +import { useEffect, useRef, useState } from "react" +import { useFormContext, useWatch } from "react-hook-form" +import { useIntl } from "react-intl" + +import Body from "@/components/TempDesignSystem/Text/Body" + +import GuestsRoomsPicker from "./GuestsRoomsPicker" + +import styles from "./guests-rooms-picker.module.css" + +import { + GuestsRoom, + GuestsRoomsFormProps, +} from "@/types/components/bookingWidget/guestsRoomsPicker" + +export default function GuestsRoomsPickerForm({ + name = "rooms", +}: GuestsRoomsFormProps) { + const intl = useIntl() + const [isOpen, setIsOpen] = useState(false) + const selectedGuests = useWatch({ name }) + const { register, setValue } = useFormContext() + const ref = useRef(null) + function handleOnClick() { + setIsOpen((prevIsOpen) => !prevIsOpen) + } + function handleSelectGuest(selected: GuestsRoom[]) { + setValue(name, selected) + } + useEffect(() => { + function handleClickOutside(evt: Event) { + const target = evt.target as HTMLElement + if (ref.current && target && !ref.current.contains(target)) { + setIsOpen(false) + } + } + document.addEventListener("click", handleClickOutside) + return () => { + document.removeEventListener("click", handleClickOutside) + } + }, [setIsOpen]) + + let selectedAdultsCount = 0 + let selectedChildrenCount = 0 + selectedGuests.forEach((room: GuestsRoom) => { + selectedAdultsCount = selectedAdultsCount + room.adults + selectedChildrenCount = + selectedChildrenCount + (room.children ? room.children.length : 0) + }) + const selectedRoomsCount = selectedGuests.length + const childCountLabel = + (selectedChildrenCount > 1 + ? intl.formatMessage({ id: "Children" }) + : intl.formatMessage({ id: "Child" })) + ", " + + return ( +
+ +
+ +
+
+ ) +} diff --git a/i18n/dictionaries/da.json b/i18n/dictionaries/da.json index bbb2b33f6..ba9699d47 100644 --- a/i18n/dictionaries/da.json +++ b/i18n/dictionaries/da.json @@ -9,6 +9,8 @@ "Add new card": "Tilføj nyt kort", "Address": "Adresse", "Airport": "Lufthavn", + "Adult": "Voksen", + "Adults": "voksne", "All our breakfast buffets offer gluten free, vegan, and allergy-friendly options.": "Alle vores morgenmadsbuffeter tilbyder glutenfrie, veganske og allergivenlige muligheder.", "Already a friend?": "Allerede en ven?", "Amenities": "Faciliteter", @@ -44,6 +46,8 @@ "Check in": "Check ind", "Check out": "Check ud", "Check out the credit cards saved to your profile. Pay with a saved card when signed in for a smoother web experience.": "Tjek de kreditkort, der er gemt på din profil. Betal med et gemt kort, når du er logget ind for en mere jævn weboplevelse.", + "Child": "Barn", + "Children": "børn", "Choose room": "Vælg rum", "Cities": "Byer", "City": "By", @@ -123,6 +127,9 @@ "How it works": "Hvordan det virker", "I would like to get my booking confirmation via sms": "Jeg vil gerne få min booking bekræftelse via SMS", "Image gallery": "Billedgalleri", + "In adults bed": "i de voksnes seng", + "In crib": "i tremmeseng", + "In extra bed": "i ekstra seng", "Included": "Inkluderet", "It is not posible to manage your communication preferences right now, please try again later or contact support if the problem persists.": "Det er ikke muligt at administrere dine kommunikationspræferencer lige nu, prøv venligst igen senere eller kontakt support, hvis problemet fortsætter.", "Join Scandic Friends": "Tilmeld dig Scandic Friends", @@ -224,6 +231,7 @@ "Retype new password": "Gentag den nye adgangskode", "Room & Terms": "Værelse & Vilkår", "Room facilities": "Værelsesfaciliteter", + "Room": "Værelse", "Rooms": "Værelser", "Rooms & Guests": "Værelser & gæster", "Sauna and gym": "Sauna and gym", diff --git a/i18n/dictionaries/de.json b/i18n/dictionaries/de.json index bec9801ef..98e640c48 100644 --- a/i18n/dictionaries/de.json +++ b/i18n/dictionaries/de.json @@ -9,6 +9,8 @@ "Add new card": "Neue Karte hinzufügen", "Address": "Adresse", "Airport": "Flughafen", + "Adult": "Erwachsener", + "Adults": "Erwachsene", "All our breakfast buffets offer gluten free, vegan, and allergy-friendly options.": "Alle unsere Frühstücksbuffets bieten glutenfreie, vegane und allergikerfreundliche Speisen.", "Already a friend?": "Sind wir schon Freunde?", "Amenities": "Annehmlichkeiten", @@ -44,6 +46,8 @@ "Check in": "Einchecken", "Check out": "Auschecken", "Check out the credit cards saved to your profile. Pay with a saved card when signed in for a smoother web experience.": "Sehen Sie sich die in Ihrem Profil gespeicherten Kreditkarten an. Bezahlen Sie mit einer gespeicherten Karte, wenn Sie angemeldet sind, für ein reibungsloseres Web-Erlebnis.", + "Child": "Kind", + "Children": "Kinder", "Choose room": "Zimmer wählen", "Cities": "Städte", "City": "Stadt", @@ -123,6 +127,9 @@ "How it works": "Wie es funktioniert", "I would like to get my booking confirmation via sms": "Ich möchte meine Buchungsbestätigung per SMS erhalten", "Image gallery": "Bildergalerie", + "In adults bed": "Im Bett der Eltern", + "In crib": "im Kinderbett", + "In extra bed": "im zusätzlichen Bett", "Included": "Iinklusive", "It is not posible to manage your communication preferences right now, please try again later or contact support if the problem persists.": "Es ist derzeit nicht möglich, Ihre Kommunikationseinstellungen zu verwalten. Bitte versuchen Sie es später erneut oder wenden Sie sich an den Support, wenn das Problem weiterhin besteht.", "Join Scandic Friends": "Treten Sie Scandic Friends bei", @@ -225,6 +232,7 @@ "Room & Terms": "Zimmer & Bedingungen", "Room facilities": "Zimmerausstattung", "Rooms": "Räume", + "Room": "Zimmer", "Rooms & Guests": "Zimmer & Gäste", "Sauna and gym": "Sauna and gym", "Save": "Speichern", diff --git a/i18n/dictionaries/en.json b/i18n/dictionaries/en.json index ed2dc9439..feb80f103 100644 --- a/i18n/dictionaries/en.json +++ b/i18n/dictionaries/en.json @@ -9,6 +9,9 @@ "Add new card": "Add new card", "Address": "Address", "Airport": "Airport", + "Adult": "Adult", + "Adults": "Adults", + "Age": "Age", "All our breakfast buffets offer gluten free, vegan, and allergy-friendly options.": "All our breakfast buffets offer gluten free, vegan, and allergy-friendly options.", "Already a friend?": "Already a friend?", "Amenities": "Amenities", @@ -27,6 +30,7 @@ "Attractions": "Attractions", "Back to scandichotels.com": "Back to scandichotels.com", "Bar": "Bar", + "Bed": "Bed", "Bed type": "Bed type", "Birth date": "Birth date", "Book": "Book", @@ -44,6 +48,8 @@ "Check in": "Check in", "Check out": "Check out", "Check out the credit cards saved to your profile. Pay with a saved card when signed in for a smoother web experience.": "Check out the credit cards saved to your profile. Pay with a saved card when signed in for a smoother web experience.", + "Child": "Child", + "Children": "Children", "Choose room": "Choose room", "Cities": "Cities", "City": "City", @@ -123,6 +129,9 @@ "How it works": "How it works", "I would like to get my booking confirmation via sms": "I would like to get my booking confirmation via sms", "Image gallery": "Image gallery", + "In adults bed": "In adults bed", + "In crib": "In crib", + "In extra bed": "In extra bed", "Included": "Included", "It is not posible to manage your communication preferences right now, please try again later or contact support if the problem persists.": "It is not posible to manage your communication preferences right now, please try again later or contact support if the problem persists.", "Join Scandic Friends": "Join Scandic Friends", @@ -224,6 +233,7 @@ "Retype new password": "Retype new password", "Room & Terms": "Room & Terms", "Room facilities": "Room facilities", + "Room": "Room", "Rooms": "Rooms", "Rooms & Guests": "Rooms & Guests", "Sauna and gym": "Sauna and gym", diff --git a/i18n/dictionaries/fi.json b/i18n/dictionaries/fi.json index de38d2341..1f3dfdfa8 100644 --- a/i18n/dictionaries/fi.json +++ b/i18n/dictionaries/fi.json @@ -9,6 +9,8 @@ "Add new card": "Lisää uusi kortti", "Address": "Osoite", "Airport": "Lentokenttä", + "Adult": "Aikuinen", + "Adults": "Aikuista", "All our breakfast buffets offer gluten free, vegan, and allergy-friendly options.": "Kaikki aamiaisbuffettimme tarjoavat gluteenittomia, vegaanisia ja allergiaystävällisiä vaihtoehtoja.", "Already a friend?": "Oletko jo ystävä?", "Amenities": "Mukavuudet", @@ -44,6 +46,8 @@ "Check in": "Sisäänkirjautuminen", "Check out": "Uloskirjautuminen", "Check out the credit cards saved to your profile. Pay with a saved card when signed in for a smoother web experience.": "Tarkista profiiliisi tallennetut luottokortit. Maksa tallennetulla kortilla kirjautuneena, jotta verkkokokemus on sujuvampi.", + "Child": "Lapsi", + "Children": "Lasta", "Choose room": "Valitse huone", "Cities": "Kaupungit", "City": "Kaupunki", @@ -123,6 +127,9 @@ "How it works": "Kuinka se toimii", "I would like to get my booking confirmation via sms": "Haluan saada varauksen vahvistuksen SMS-viestillä", "Image gallery": "Kuvagalleria", + "In adults bed": "Aikuisten vuoteessa", + "In crib": "Pinnasängyssä", + "In extra bed": "Oma vuodepaikka", "Included": "Sisälly hintaan", "It is not posible to manage your communication preferences right now, please try again later or contact support if the problem persists.": "Viestintäasetuksiasi ei voi hallita juuri nyt. Yritä myöhemmin uudelleen tai ota yhteyttä tukeen, jos ongelma jatkuu.", "Join Scandic Friends": "Liity jäseneksi", @@ -224,6 +231,7 @@ "Retype new password": "Kirjoita uusi salasana uudelleen", "Room & Terms": "Huone & Ehdot", "Room facilities": "Huoneen varustelu", + "Room": "Huone", "Rooms": "Huoneet", "Rooms & Guests": "Huoneet & Vieraat", "Rooms & Guestss": "Huoneet & Vieraat", diff --git a/i18n/dictionaries/no.json b/i18n/dictionaries/no.json index 10985583c..ab2181fe9 100644 --- a/i18n/dictionaries/no.json +++ b/i18n/dictionaries/no.json @@ -9,6 +9,8 @@ "Add new card": "Legg til nytt kort", "Address": "Adresse", "Airport": "Flyplass", + "Adult": "Voksen", + "Adults": "Voksne", "All our breakfast buffets offer gluten free, vegan, and allergy-friendly options.": "Alle våre frokostbufféer tilbyr glutenfrie, veganske og allergivennlige alternativer.", "Already a friend?": "Allerede Friend?", "Amenities": "Fasiliteter", @@ -44,6 +46,8 @@ "Check in": "Sjekk inn", "Check out": "Sjekk ut", "Check out the credit cards saved to your profile. Pay with a saved card when signed in for a smoother web experience.": "Sjekk ut kredittkortene som er lagret på profilen din. Betal med et lagret kort når du er pålogget for en jevnere nettopplevelse.", + "Child": "Barn", + "Children": "Barn", "Choose room": "Velg rom", "Cities": "Byer", "City": "By", @@ -121,6 +125,9 @@ "How do you want to sleep?": "Hvordan vil du sove?", "How it works": "Hvordan det fungerer", "Image gallery": "Bildegalleri", + "In adults bed": "i voksnes seng", + "In crib": "i sprinkelseng", + "In extra bed": "i ekstraseng", "Included": "Inkludert", "It is not posible to manage your communication preferences right now, please try again later or contact support if the problem persists.": "Det er ikke mulig å administrere kommunikasjonspreferansene dine akkurat nå, prøv igjen senere eller kontakt support hvis problemet vedvarer.", "Join Scandic Friends": "Bli med i Scandic Friends", @@ -222,6 +229,7 @@ "Retype new password": "Skriv inn nytt passord på nytt", "Room & Terms": "Rom & Vilkår", "Room facilities": "Romfasiliteter", + "Room": "Rom", "Rooms": "Rom", "Rooms & Guests": "Rom og gjester", "Sauna and gym": "Sauna and gym", diff --git a/i18n/dictionaries/sv.json b/i18n/dictionaries/sv.json index 9803d5f6e..3f96e263f 100644 --- a/i18n/dictionaries/sv.json +++ b/i18n/dictionaries/sv.json @@ -9,6 +9,8 @@ "Add new card": "Lägg till nytt kort", "Address": "Adress", "Airport": "Flygplats", + "Adult": "Vuxen", + "Adults": "Vuxna", "All our breakfast buffets offer gluten free, vegan, and allergy-friendly options.": "Alla våra frukostbufféer erbjuder glutenfria, veganska och allergivänliga alternativ.", "Already a friend?": "Är du redan en vän?", "Amenities": "Bekvämligheter", @@ -44,6 +46,8 @@ "Check in": "Checka in", "Check out": "Checka ut", "Check out the credit cards saved to your profile. Pay with a saved card when signed in for a smoother web experience.": "Kolla in kreditkorten som sparats i din profil. Betala med ett sparat kort när du är inloggad för en smidigare webbupplevelse.", + "Child": "Barn", + "Children": "Barn", "Choose room": "Välj rum", "Cities": "Städer", "City": "Ort", @@ -121,6 +125,9 @@ "How do you want to sleep?": "Hur vill du sova?", "How it works": "Hur det fungerar", "Image gallery": "Bildgalleri", + "In adults bed": "I vuxens säng", + "In crib": "I spjälsäng", + "In extra bed": "Egen sängplats", "Included": "Inkluderad", "It is not posible to manage your communication preferences right now, please try again later or contact support if the problem persists.": "Det gick inte att hantera dina kommunikationsinställningar just nu, försök igen senare eller kontakta supporten om problemet kvarstår.", "Join Scandic Friends": "Gå med i Scandic Friends", @@ -222,6 +229,7 @@ "Retype new password": "Upprepa nytt lösenord", "Room & Terms": "Rum & Villkor", "Room facilities": "Rumfaciliteter", + "Room": "Rum", "Rooms": "Rum", "Rooms & Guests": "Rum och gäster", "Sauna and gym": "Sauna and gym", @@ -315,7 +323,6 @@ "Zoo": "Djurpark", "Zoom in": "Zooma in", "Zoom out": "Zooma ut", - "as of today": "från och med idag", "booking.adults": "{totalAdults, plural, one {# vuxen} other {# vuxna}}", "booking.guests": "Max {nrOfGuests, plural, one {# gäst} other {# gäster}}", "booking.nights": "{totalNights, plural, one {# natt} other {# nätter}}", @@ -340,7 +347,6 @@ "special character": "speciell karaktär", "spendable points expiring by": "{points} poäng förfaller {date}", "to": "till", - "uppercase letter": "stor bokstav", "{amount} {currency}": "{amount} {currency}", "{difference}{amount} {currency}": "{difference}{amount} {currency}", "{width} cm × {length} cm": "{width} cm × {length} cm" diff --git a/types/components/bookingWidget/guestsRoomsPicker.ts b/types/components/bookingWidget/guestsRoomsPicker.ts new file mode 100644 index 000000000..150dc0334 --- /dev/null +++ b/types/components/bookingWidget/guestsRoomsPicker.ts @@ -0,0 +1,41 @@ +export type ChildBed = { + label: string + value: number +} + +export type Child = { + age: number + bed: number +} + +export type GuestsRoom = { + adults: number + children: Child[] +} + +export type GuestsRoomsFormProps = { + name?: string +} + +export interface GuestsRoomsPickerProps { + handleOnSelect: (selected: GuestsRoom[]) => void + initialSelected?: GuestsRoom[] + closePicker: () => void +} + +export type GuestsRoomPickerProps = { + handleOnSelect: (selected: GuestsRoom, index: number) => void + room: GuestsRoom + index: number +} + +export type AdultSelectorProps = { + adults: number + updateAdults: (count: number) => void +} + +export type ChildSelectorProps = { + roomChildren: Child[] + adultCount: number + updateChildren: (children: Child[]) => void +}