Merged in feat/415-room-card-image-gallery (pull request #679)

feat(SW-415): Added Image gallery to room card

Approved-by: Simon.Emanuelsson
This commit is contained in:
Pontus Dreij
2024-10-14 14:20:15 +00:00
9 changed files with 125 additions and 36 deletions

View File

@@ -4,7 +4,9 @@ import { useIntl } from "react-intl"
import { RateDefinition } from "@/server/routers/hotels/output"
import FlexibilityOption from "@/components/HotelReservation/SelectRate/RoomSelection/FlexibilityOption"
import { ChevronRightSmallIcon } from "@/components/Icons"
import { ChevronRightSmallIcon, GalleryIcon } from "@/components/Icons"
import Image from "@/components/Image"
import Lightbox from "@/components/Lightbox"
import Button from "@/components/TempDesignSystem/Button"
import Body from "@/components/TempDesignSystem/Text/Body"
import Caption from "@/components/TempDesignSystem/Text/Caption"
@@ -51,18 +53,15 @@ export default function RoomCard({
return rateDefinitions.find((def) => def.rateCode === rate?.rateCode)
?.generalTerms
}
const roomSize = roomCategories.find(
(category) => category.name === roomConfiguration.roomType
)?.roomSize
const occupancy = roomCategories.find(
(category) => category.name === roomConfiguration.roomType
)?.occupancy.total
const roomDescription = roomCategories.find(
const selectedRoom = roomCategories.find(
(room) => room.name === roomConfiguration.roomType
)?.descriptions.short
)
const roomSize = selectedRoom?.roomSize
const occupancy = selectedRoom?.occupancy.total
const roomDescription = selectedRoom?.descriptions.short
const images = selectedRoom?.images
const mainImage = images?.[0]
return (
<div className={styles.card}>
@@ -78,7 +77,10 @@ export default function RoomCard({
)}
</Caption>
<Caption color="uiTextMediumContrast">
{roomSize?.min}-{roomSize?.max} m²
{roomSize?.min === roomSize?.max
? roomSize?.min
: `${roomSize?.min}-${roomSize?.max}`}
m²
</Caption>
<Button
intent="text"
@@ -103,7 +105,7 @@ export default function RoomCard({
id: "Breakfast selection in next step.",
})}
</Caption>
<div>
<div className={styles.flexibilityOptions}>
<FlexibilityOption
name={intl.formatMessage({ id: "Non-refundable" })}
value="non-refundable"
@@ -128,22 +130,41 @@ export default function RoomCard({
</div>
</div>
</div>
<div className={styles.imageContainer}>
<span className={styles.roomsLeft}>
<Footnote
color="burgundy"
textTransform="uppercase"
>{`${roomConfiguration.roomsLeft} ${intl.formatMessage({ id: "Left" })}`}</Footnote>
</span>
{/* TODO: maybe use the `Image` component instead of the `img` tag. Waiting until we know how to get the image */}
{/* eslint-disable-next-line @next/next/no-img-element */}
<img
alt={intl.formatMessage({ id: "A photo of the room" })}
// TODO: Correct image URL
src="https://www.scandichotels.se/imageVault/publishedmedia/xnmqnmz6mz0uhuat0917/scandic-helsinki-hub-room-standard-KR-7.jpg"
/>
</div>
{mainImage && (
<div className={styles.imageContainer}>
{roomConfiguration.roomsLeft < 5 && (
<span className={styles.roomsLeft}>
<Footnote
color="burgundy"
textTransform="uppercase"
>{`${roomConfiguration.roomsLeft} ${intl.formatMessage({ id: "Left" })}`}</Footnote>
</span>
)}
{/*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. */}
<Image
src={mainImage.imageSizes.small}
alt={mainImage.metaData.altText}
width={330}
height={185}
/>
{images && (
<Lightbox
images={images.map((image) => ({
url: image.imageSizes.small,
alt: image.metaData.altText,
title: image.metaData.title,
}))}
dialogTitle={roomConfiguration.roomType}
>
<div className={styles.galleryIcon} id="lightboxTrigger">
<GalleryIcon color="white" />
<Footnote color="white">{images.length}</Footnote>
</div>
</Lightbox>
)}
</div>
)}
</div>
)
}

View File

@@ -44,6 +44,7 @@
display: flex;
flex-direction: column;
gap: var(--Spacing-x1);
margin-bottom: var(--Spacing-x2);
}
.name {
@@ -57,6 +58,12 @@
border-radius: var(--Corner-radius-Medium) var(--Corner-radius-Medium) 0 0;
}
.flexibilityOptions {
display: flex;
flex-direction: column;
gap: var(--Spacing-x2);
}
.roomsLeft {
position: absolute;
top: 12px;
@@ -65,3 +72,22 @@
padding: var(--Spacing-x-half) var(--Spacing-x1);
border-radius: var(--Corner-radius-Small);
}
.imageContainer {
min-height: 185px;
position: relative;
}
.galleryIcon {
position: absolute;
bottom: 16px;
right: 16px;
height: 24px;
background-color: rgba(64, 57, 55, 0.9);
padding: 0 var(--Spacing-x-half);
border-radius: var(--Corner-radius-Small);
cursor: pointer;
display: flex;
align-items: center;
gap: var(--Spacing-x-quarter);
}

View File

@@ -1,8 +1,5 @@
"use client"
import { useRouter, useSearchParams } from "next/navigation"
import { useIntl } from "react-intl"
import Button from "@/components/TempDesignSystem/Button"
import RoomCard from "./RoomCard"
@@ -16,7 +13,6 @@ export default function RoomSelection({
}: RoomSelectionProps) {
const router = useRouter()
const searchParams = useSearchParams()
const intl = useIntl()
function handleSubmit(e: React.FormEvent<HTMLFormElement>) {
e.preventDefault()
@@ -44,12 +40,12 @@ export default function RoomSelection({
</li>
))}
</ul>
<div className={styles.summary}>
{/* <div className={styles.summary}>
This is summary
<Button type="submit" size="small" theme="primaryDark">
{intl.formatMessage({ id: "Choose room" })}
</Button>
</div>
</div> */}
</form>
</div>
)

View File

@@ -0,0 +1,36 @@
import { iconVariants } from "./variants"
import type { IconProps } from "@/types/components/icon"
export default function GalleryIcon({ className, color, ...props }: IconProps) {
const classNames = iconVariants({ className, color })
return (
<svg
className={classNames}
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
{...props}
>
<mask
id="mask0_69_3274"
style={{ maskType: "alpha" }}
maskUnits="userSpaceOnUse"
x="0"
y="0"
width="24"
height="24"
>
<rect width="24" height="24" fill="#D9D9D9" />
</mask>
<g mask="url(#mask0_5887_18142)">
<path
d="M9.15 13.9H18.65L15.3725 9.625L13.1875 12.475L11.715 10.575L9.15 13.9ZM8.2 17.7C7.6775 17.7 7.23021 17.514 6.85813 17.1419C6.48604 16.7698 6.3 16.3225 6.3 15.8V4.4C6.3 3.8775 6.48604 3.43021 6.85813 3.05813C7.23021 2.68604 7.6775 2.5 8.2 2.5H19.6C20.1225 2.5 20.5698 2.68604 20.9419 3.05813C21.314 3.43021 21.5 3.8775 21.5 4.4V15.8C21.5 16.3225 21.314 16.7698 20.9419 17.1419C20.5698 17.514 20.1225 17.7 19.6 17.7H8.2ZM8.2 15.8H19.6V4.4H8.2V15.8ZM4.4 21.5C3.8775 21.5 3.43021 21.314 3.05813 20.9419C2.68604 20.5698 2.5 20.1225 2.5 19.6V6.3H4.4V19.6H17.7V21.5H4.4Z"
fill="white"
/>
</g>
</svg>
)
}

View File

@@ -32,6 +32,7 @@ import {
EyeHideIcon,
EyeShowIcon,
FitnessIcon,
GalleryIcon,
GiftIcon,
GlobeIcon,
HouseIcon,
@@ -124,6 +125,8 @@ export function getIconByIconName(icon?: IconName): FC<IconProps> | null {
return FacebookIcon
case IconName.Fitness:
return FitnessIcon
case IconName.Gallery:
return GalleryIcon
case IconName.Gift:
return GiftIcon
case IconName.Globe:

View File

@@ -31,6 +31,7 @@ export { default as ErrorCircleIcon } from "./ErrorCircle"
export { default as EyeHideIcon } from "./EyeHide"
export { default as EyeShowIcon } from "./EyeShow"
export { default as FitnessIcon } from "./Fitness"
export { default as GalleryIcon } from "./Gallery"
export { default as GiftIcon } from "./Gift"
export { default as GlobeIcon } from "./Globe"
export { default as HeartIcon } from "./Heart"

View File

@@ -66,3 +66,7 @@
.uiTextPlaceholder {
color: var(--UI-Text-Placeholder);
}
.white {
color: var(--Main-Grey-White);
}

View File

@@ -11,6 +11,7 @@ const config = {
peach50: styles.peach50,
uiTextMediumContrast: styles.uiTextMediumContrast,
uiTextPlaceholder: styles.uiTextPlaceholder,
white: styles.white,
},
textAlign: {
center: styles.center,

View File

@@ -36,6 +36,7 @@ export enum IconName {
EyeShow = "EyeShow",
Facebook = "Facebook",
Fitness = "Fitness",
Gallery = "Gallery",
Gift = "Gift",
Globe = "Globe",
House = "House",