feat(SW-914): add accessibility component

This commit is contained in:
Fredrik Thorsson
2024-11-27 15:35:58 +01:00
parent 384f044dac
commit 0cd9c33512
26 changed files with 117 additions and 86 deletions

View File

@@ -10,7 +10,7 @@ import { getLang } from "@/i18n/serverContext"
import styles from "./contactInformation.module.css" import styles from "./contactInformation.module.css"
import type { ContactInformationProps } from "@/types/components/hotelPage/sidepeek/contactInformation" import type { ContactInformationProps } from "@/types/components/hotelPage/sidepeek/aboutTheHotel"
export default async function ContactInformation({ export default async function ContactInformation({
hotelAddress, hotelAddress,
@@ -21,7 +21,6 @@ export default async function ContactInformation({
}: ContactInformationProps) { }: ContactInformationProps) {
const intl = await getIntl() const intl = await getIntl()
const lang = getLang() const lang = getLang()
const { latitude, longitude } = coordinates const { latitude, longitude } = coordinates
const directionsUrl = `https://www.google.com/maps/dir/?api=1&destination=${latitude},${longitude}` const directionsUrl = `https://www.google.com/maps/dir/?api=1&destination=${latitude},${longitude}`

View File

@@ -0,0 +1,5 @@
.wrapper {
display: flex;
flex-direction: column;
gap: var(--Spacing-x3);
}

View File

@@ -1,16 +1,39 @@
import { ArrowRightIcon } from "@/components/Icons"
import AccordionItem from "@/components/TempDesignSystem/Accordion/AccordionItem" import AccordionItem from "@/components/TempDesignSystem/Accordion/AccordionItem"
import Link from "@/components/TempDesignSystem/Link"
import Body from "@/components/TempDesignSystem/Text/Body"
import { getIntl } from "@/i18n" import { getIntl } from "@/i18n"
import styles from "./accessibilityAmenity.module.css"
import type { AccessibilityAmenityProps } from "@/types/components/hotelPage/sidepeek/accessibility"
import { IconName } from "@/types/components/icon" import { IconName } from "@/types/components/icon"
export default async function AccessibilityAmenity() { export default async function AccessibilityAmenity({
accessibility,
}: AccessibilityAmenityProps) {
const intl = await getIntl() const intl = await getIntl()
return ( return (
<AccordionItem <AccordionItem
title={intl.formatMessage({ id: "Accessibility" })} title={intl.formatMessage({ id: "Accessibility" })}
icon={IconName.Accessibility} icon={IconName.Accessibility}
> >
Accessibility <div className={styles.wrapper}>
{accessibility?.description && (
<Body color="uiTextHighContrast">{accessibility.description}</Body>
)}
{accessibility?.link && (
<Link
href={accessibility.link}
color="burgundy"
textDecoration="underline"
variant="icon"
>
{intl.formatMessage({ id: "About accessibility" })}
<ArrowRightIcon color="burgundy" />
</Link>
)}
</div>
</AccordionItem> </AccordionItem>
) )
} }

View File

@@ -10,7 +10,7 @@ export default async function BreakfastAmenity() {
title={intl.formatMessage({ id: "Breakfast" })} title={intl.formatMessage({ id: "Breakfast" })}
icon={IconName.CoffeeAlt} icon={IconName.CoffeeAlt}
> >
Breakfast {/* TODO: breakfast to be implemented */}
</AccordionItem> </AccordionItem>
) )
} }

View File

@@ -1,31 +1,6 @@
import { getIntl } from "@/i18n"
import { ParkingPricesProps } from "@/types/components/hotelPage/sidepeek/parking" import { ParkingPricesProps } from "@/types/components/hotelPage/sidepeek/parking"
export default async function ParkingPrices({ data }: ParkingPricesProps) { export default async function ParkingPrices({ data }: ParkingPricesProps) {
const intl = await getIntl() // TODO: Parking prices to be implemented.
const hour = intl.formatMessage({ id: "per hour during" }) return <div></div>
const day = intl.formatMessage({ id: "per day during" })
const night = intl.formatMessage({ id: "per night during" })
const allDay = intl.formatMessage({ id: "per whole day" })
function translatePeriods(period: string) {
switch (period) {
case "Hour":
return hour
case "Day":
return day
case "Night":
return night
case "AllDay":
return allDay
}
}
return (
<>
{data?.map((price) => {
return price.amount && <div>hello</div>
})}
</>
)
} }

View File

@@ -4,7 +4,7 @@ import { getIntl } from "@/i18n"
import ParkingPrices from "./ParkingPrices" import ParkingPrices from "./ParkingPrices"
import styles from "./parking.module.css" import styles from "./parkingAmenity.module.css"
import { ParkingAmenityProps } from "@/types/components/hotelPage/sidepeek/parking" import { ParkingAmenityProps } from "@/types/components/hotelPage/sidepeek/parking"
import { IconName } from "@/types/components/icon" import { IconName } from "@/types/components/icon"
@@ -19,45 +19,51 @@ export default async function ParkingAmenity({ parking }: ParkingAmenityProps) {
> >
<div className={styles.wrapper}> <div className={styles.wrapper}>
{parking.map((data) => ( {parking.map((data) => (
<> <div key={data.type} className={styles.information}>
<div key={data.type} className={styles.information}> <div className={styles.list}>
<Body textTransform="bold">{`${data.type} (${data.name})`}</Body> <Body textTransform="bold">{`${data.type} ${data.name}`}</Body>
<Body color="uiTextHighContrast" asChild> <Body color="uiTextHighContrast" asChild>
<ul> <ul>
<li>{`Number of charging points for electric cars: ${data.numberOfChargingSpaces}`}</li> {data.numberOfChargingSpaces ? (
<li>{`Number of charging points for electric cars: ${data.numberOfChargingSpaces}`}</li>
) : null}
<li>{`${intl.formatMessage({ id: "Parking can be reserved in advance" })}: ${data.canMakeReservation ? intl.formatMessage({ id: "Yes" }) : intl.formatMessage({ id: "No" })}`}</li> <li>{`${intl.formatMessage({ id: "Parking can be reserved in advance" })}: ${data.canMakeReservation ? intl.formatMessage({ id: "Yes" }) : intl.formatMessage({ id: "No" })}`}</li>
<li>{`${intl.formatMessage({ id: "Number of parking spots" })}: ${data.numberOfParkingSpots}`}</li> {data.numberOfParkingSpots ? (
<li>{`${intl.formatMessage({ id: "Distance to hotel" })}: ${data.distanceToHotel}`}</li> <li>{`${intl.formatMessage({ id: "Number of parking spots" })}: ${data.numberOfParkingSpots}`}</li>
<li>{`${intl.formatMessage({ id: "Address" })}: ${data.address}`}</li> ) : null}
{data.distanceToHotel ? (
<li>{`${intl.formatMessage({ id: "Distance to hotel" })}: ${data.distanceToHotel}m`}</li>
) : null}
{data.address ? (
<li>{`${intl.formatMessage({ id: "Address" })}: ${data.address}`}</li>
) : null}
</ul> </ul>
</Body> </Body>
</div> </div>
<div> <div className={styles.prices}>
<Body textTransform="bold"> <Body textTransform="bold">
{intl.formatMessage({ id: "Prices" })} {intl.formatMessage({ id: "Prices" })}
</Body> </Body>
<div className={styles.prices}> <div>
<div> <Body color="uiTextMediumContrast">
<Body color="uiTextMediumContrast"> {intl.formatMessage({ id: "Ordinary" })}
{intl.formatMessage({ id: "Ordinary" })} </Body>
</Body> <ParkingPrices
<ParkingPrices data={data.pricing.localCurrency.ordinary}
data={data.pricing.localCurrency.ordinary} currency={data.pricing.localCurrency.currency}
currency={data.pricing.localCurrency.currency} />
/> </div>
</div> <Body color="uiTextMediumContrast">
<div> {intl.formatMessage({ id: "Weekday" })}
<Body color="uiTextMediumContrast"> </Body>
{intl.formatMessage({ id: "Weekday" })} <div>
</Body> <ParkingPrices
<ParkingPrices data={data.pricing.localCurrency.weekend}
data={data.pricing.localCurrency.weekend} currency={data.pricing.localCurrency.currency}
currency={data.pricing.localCurrency.currency} />
/>
</div>
</div> </div>
</div> </div>
</> </div>
))} ))}
</div> </div>
</AccordionItem> </AccordionItem>

View File

@@ -11,8 +11,9 @@
gap: var(--Spacing-x-one-and-half); gap: var(--Spacing-x-one-and-half);
} }
.list,
.prices { .prices {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: var(--Spacing-x1); gap: var(--Spacing-x-half);
} }

View File

@@ -3,11 +3,13 @@ import Body from "@/components/TempDesignSystem/Text/Body"
import { mapFacilityToIcon } from "../../../data" import { mapFacilityToIcon } from "../../../data"
import styles from "./amenity.module.css" import styles from "./filteredAmenities.module.css"
import type { AmenityProps } from "@/types/components/hotelPage/sidepeek/amenity" import type { FilteredAmenitiesProps } from "@/types/components/hotelPage/sidepeek/amenities"
export default function Amenity({ filteredAmenities }: AmenityProps) { export default function FilteredAmenities({
filteredAmenities,
}: FilteredAmenitiesProps) {
return ( return (
<> <>
{filteredAmenities?.map((amenity) => { {filteredAmenities?.map((amenity) => {

View File

@@ -11,23 +11,30 @@ import {
CheckInAmenity, CheckInAmenity,
ParkingAmenity, ParkingAmenity,
} from "./AccordionAmenities" } from "./AccordionAmenities"
import Amenity from "./Amenity" import FilteredAmenities from "./FilteredAmenities"
import type { AmenitiesSidePeekProps } from "@/types/components/hotelPage/sidepeek/amenities" import type { AmenitiesSidePeekProps } from "@/types/components/hotelPage/sidepeek/amenities"
import { FacilityEnum } from "@/types/enums/facilities"
export default async function AmenitiesSidePeek({ export default async function AmenitiesSidePeek({
amenitiesList, amenitiesList,
parking, parking,
checkInInformation, checkInInformation,
accessibility,
}: AmenitiesSidePeekProps) { }: AmenitiesSidePeekProps) {
const lang = getLang() const lang = getLang()
const intl = await getIntl() const intl = await getIntl()
const filteredAmenities = amenitiesList.filter((filter) => { const filteredAmenities = amenitiesList.filter((filter) => {
return ( return (
!filter.name.startsWith("Parking") && filter.id !== FacilityEnum.ParkingAdditionalCost &&
filter.name !== "Meeting / conference facilities" && filter.id !== FacilityEnum.ParkingElectricCharging &&
filter.name !== "Late check-out until 14:00 guaranteed" filter.id !== FacilityEnum.ParkingFreeParking &&
filter.id !== FacilityEnum.ParkingGarage &&
filter.id !== FacilityEnum.ParkingOutdoor &&
filter.id !== FacilityEnum.MeetingArea &&
filter.id !== FacilityEnum.ServesBreakfastAlwaysIncluded &&
filter.id !== FacilityEnum.LateCheckOutUntil1400Guaranteed
) )
}) })
@@ -40,8 +47,10 @@ export default async function AmenitiesSidePeek({
{parking.length ? <ParkingAmenity parking={parking} /> : null} {parking.length ? <ParkingAmenity parking={parking} /> : null}
<BreakfastAmenity /> <BreakfastAmenity />
<CheckInAmenity checkInInformation={checkInInformation} /> <CheckInAmenity checkInInformation={checkInInformation} />
<AccessibilityAmenity /> {accessibility && (
<Amenity filteredAmenities={filteredAmenities} /> <AccessibilityAmenity accessibility={accessibility} />
)}
<FilteredAmenities filteredAmenities={filteredAmenities} />
</Accordion> </Accordion>
</SidePeek> </SidePeek>
) )

View File

@@ -281,13 +281,11 @@ const facilityToIconMap: Record<FacilityEnum, IconName> = {
[FacilityEnum.WideEntrance]: IconName.StarFilled, [FacilityEnum.WideEntrance]: IconName.StarFilled,
[FacilityEnum.WideRestaurantEntrance]: IconName.StarFilled, [FacilityEnum.WideRestaurantEntrance]: IconName.StarFilled,
[FacilityEnum.WiFiWirelessInternetAccessAllScandic]: IconName.StarFilled, [FacilityEnum.WiFiWirelessInternetAccessAllScandic]: IconName.StarFilled,
[FacilityEnum.MeetingArea]: IconName.Business,
[FacilityEnum.LateCheckOutUntil1400Guaranteed]: IconName.Business,
} }
export function mapFacilityToIcon(id: FacilityEnum): FC<IconProps> | null { export function mapFacilityToIcon(id: FacilityEnum): FC<IconProps> | null {
const iconName = facilityToIconMap[id] const iconName = facilityToIconMap[id]
return getIconByIconName(iconName) || null return getIconByIconName(iconName) || null
} }
export function mapFacilityToIconName(id: FacilityEnum): IconName {
return facilityToIconMap[id]
}

View File

@@ -183,6 +183,7 @@ export default async function HotelPage({ hotelId }: HotelPageProps) {
amenitiesList={detailedFacilities} amenitiesList={detailedFacilities}
parking={parking} parking={parking}
checkInInformation={hotelFacts.checkin} checkInInformation={hotelFacts.checkin}
accessibility={hotelFacts.hotelInformation.accessibility}
/> />
<AboutTheHotelSidePeek <AboutTheHotelSidePeek
hotelAddress={address} hotelAddress={address}

View File

@@ -6,6 +6,7 @@
"A photo of the room": "Et foto af værelset", "A photo of the room": "Et foto af værelset",
"ACCE": "Tilgængelighed", "ACCE": "Tilgængelighed",
"ALLG": "Allergi", "ALLG": "Allergi",
"About accessibility": "Om tilgængelighed",
"About meetings & conferences": "About meetings & conferences", "About meetings & conferences": "About meetings & conferences",
"About the hotel": "Om hotellet", "About the hotel": "Om hotellet",
"Accept new price": "Accepter ny pris", "Accept new price": "Accepter ny pris",

View File

@@ -6,6 +6,7 @@
"A photo of the room": "Ein Foto des Zimmers", "A photo of the room": "Ein Foto des Zimmers",
"ACCE": "Zugänglichkeit", "ACCE": "Zugänglichkeit",
"ALLG": "Allergie", "ALLG": "Allergie",
"About accessibility": "Über Barrierefreiheit",
"About meetings & conferences": "About meetings & conferences", "About meetings & conferences": "About meetings & conferences",
"About the hotel": "Über das Hotel", "About the hotel": "Über das Hotel",
"Accept new price": "Neuen Preis akzeptieren", "Accept new price": "Neuen Preis akzeptieren",

View File

@@ -6,6 +6,7 @@
"A photo of the room": "A photo of the room", "A photo of the room": "A photo of the room",
"ACCE": "Accessibility", "ACCE": "Accessibility",
"ALLG": "Allergy", "ALLG": "Allergy",
"About accessibility": "About accessibility",
"About meetings & conferences": "About meetings & conferences", "About meetings & conferences": "About meetings & conferences",
"About the hotel": "About the hotel", "About the hotel": "About the hotel",
"Accept new price": "Accept new price", "Accept new price": "Accept new price",

View File

@@ -6,6 +6,7 @@
"A photo of the room": "Kuva huoneesta", "A photo of the room": "Kuva huoneesta",
"ACCE": "Saavutettavuus", "ACCE": "Saavutettavuus",
"ALLG": "Allergia", "ALLG": "Allergia",
"About accessibility": "Tietoja saavutettavuudesta",
"About meetings & conferences": "About meetings & conferences", "About meetings & conferences": "About meetings & conferences",
"About the hotel": "Tietoja hotellista", "About the hotel": "Tietoja hotellista",
"Accept new price": "Hyväksy uusi hinta", "Accept new price": "Hyväksy uusi hinta",

View File

@@ -6,6 +6,7 @@
"A photo of the room": "Et bilde av rommet", "A photo of the room": "Et bilde av rommet",
"ACCE": "Tilgjengelighet", "ACCE": "Tilgjengelighet",
"ALLG": "Allergi", "ALLG": "Allergi",
"About accessibility": "Om tilgjengelighet",
"About meetings & conferences": "About meetings & conferences", "About meetings & conferences": "About meetings & conferences",
"About the hotel": "Om hotellet", "About the hotel": "Om hotellet",
"Accept new price": "Aksepterer ny pris", "Accept new price": "Aksepterer ny pris",

View File

@@ -6,6 +6,7 @@
"A photo of the room": "Ett foto av rummet", "A photo of the room": "Ett foto av rummet",
"ACCE": "Tillgänglighet", "ACCE": "Tillgänglighet",
"ALLG": "Allergi", "ALLG": "Allergi",
"About accessibility": "Om tillgänglighet",
"About meetings & conferences": "About meetings & conferences", "About meetings & conferences": "About meetings & conferences",
"About the hotel": "Om hotellet", "About the hotel": "Om hotellet",
"Accept new price": "Accepter ny pris", "Accept new price": "Accepter ny pris",

View File

@@ -8,3 +8,8 @@ export type AboutTheHotelSidePeekProps = {
ecoLabels: Hotel["hotelFacts"]["ecoLabels"] ecoLabels: Hotel["hotelFacts"]["ecoLabels"]
descriptions: Hotel["hotelContent"]["texts"] descriptions: Hotel["hotelContent"]["texts"]
} }
export type ContactInformationProps = Omit<
AboutTheHotelSidePeekProps,
"descriptions"
>

View File

@@ -0,0 +1,5 @@
import type { Hotel } from "@/types/hotel"
export type AccessibilityAmenityProps = {
accessibility: Hotel["hotelFacts"]["hotelInformation"]["accessibility"]
}

View File

@@ -4,4 +4,9 @@ export type AmenitiesSidePeekProps = {
amenitiesList: Hotel["detailedFacilities"] amenitiesList: Hotel["detailedFacilities"]
parking: Hotel["parking"] parking: Hotel["parking"]
checkInInformation: Hotel["hotelFacts"]["checkin"] checkInInformation: Hotel["hotelFacts"]["checkin"]
accessibility: Hotel["hotelFacts"]["hotelInformation"]["accessibility"]
}
export type FilteredAmenitiesProps = {
filteredAmenities: Hotel["detailedFacilities"]
} }

View File

@@ -1,5 +0,0 @@
import type { Hotel } from "@/types/hotel"
export type AmenityProps = {
filteredAmenities?: Hotel["detailedFacilities"]
}

View File

@@ -1,6 +0,0 @@
import type { AboutTheHotelSidePeekProps } from "./aboutTheHotel"
export type ContactInformationProps = Omit<
AboutTheHotelSidePeekProps,
"descriptions"
>

View File

@@ -259,4 +259,6 @@ export enum FacilityEnum {
WideEntrance = 2085, WideEntrance = 2085,
WideRestaurantEntrance = 2087, WideRestaurantEntrance = 2087,
WiFiWirelessInternetAccessAllScandic = 5774, WiFiWirelessInternetAccessAllScandic = 5774,
MeetingArea = 1692,
LateCheckOutUntil1400Guaranteed = 324101,
} }