refactor(SW-96): use images from API & reduce data returned in getHotel
This commit is contained in:
@@ -11,11 +11,11 @@ export default async function PreviewImages({ images }: PreviewImagesProps) {
|
|||||||
const intl = await getIntl()
|
const intl = await getIntl()
|
||||||
return (
|
return (
|
||||||
<Lightbox images={images}>
|
<Lightbox images={images}>
|
||||||
{/*TODO: Replace with images from API once SW-188 is merged. */}
|
|
||||||
<div className={styles.mobileWrapper}>
|
<div className={styles.mobileWrapper}>
|
||||||
<Image
|
<Image
|
||||||
src={images[0].url}
|
src={images[0].url}
|
||||||
alt={images[0].alt}
|
alt={images[0].alt}
|
||||||
|
title={images[0].title}
|
||||||
width={752}
|
width={752}
|
||||||
height={540}
|
height={540}
|
||||||
objectFit="cover"
|
objectFit="cover"
|
||||||
@@ -37,6 +37,7 @@ export default async function PreviewImages({ images }: PreviewImagesProps) {
|
|||||||
key={index}
|
key={index}
|
||||||
src={image.url}
|
src={image.url}
|
||||||
alt={image.alt}
|
alt={image.alt}
|
||||||
|
title={image.title}
|
||||||
width={index === 0 ? 752 : 292}
|
width={index === 0 ? 752 : 292}
|
||||||
height={index === 0 ? 540 : 266}
|
height={index === 0 ? 540 : 266}
|
||||||
objectFit="cover"
|
objectFit="cover"
|
||||||
|
|||||||
@@ -22,44 +22,3 @@ export function mapFacilityToIcon(facilityName: string): FC<IconProps> | null {
|
|||||||
const iconName = facilityToIconMap[facilityName]
|
const iconName = facilityToIconMap[facilityName]
|
||||||
return getIconByIconName(iconName) || null
|
return getIconByIconName(iconName) || null
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 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.
|
|
||||||
* So I've added some placeholder images here for use when running the app locally.
|
|
||||||
*/
|
|
||||||
export const tempHotelLightboxImage: ImageItem[] = [
|
|
||||||
{
|
|
||||||
url: "https://www.scandichotels.com/imagevault/publishedmedia/kd4e35n41mrqinfrkzok/scandic-continental-entrance-vasagatan.jpg",
|
|
||||||
alt: "Hotel entrance",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
url: "https://www.scandichotels.com/imageVault/publishedmedia/ip4a2rc93qda3aq9ph73/scandic-continental-room-standard.jpg",
|
|
||||||
alt: "Standard room",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
url: "https://www.scandichotels.com/imageVault/publishedmedia/75y2b2x8uvma4s7zvy50/scandic-continental-room-juniorsuite-detail-1.jpg",
|
|
||||||
alt: "Junior suite",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
url: "https://www.scandichotels.com/imageVault/publishedmedia/pwotq99pbr68djxnym4a/scandic-continental-diningroom-themarket.jpg",
|
|
||||||
alt: "Dining room, The Market",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
url: "https://www.scandichotels.com/imageVault/publishedmedia/yc2cjoxq2j01gp0f80gt/scandic-continental-room-juniorsuite-bathroom-1.jpg",
|
|
||||||
alt: "Junior suite bathroom",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
url: "https://www.scandichotels.com/imageVault/publishedmedia/xocam1f69h7lh57u8f9v/scandic-continental-themarket-detail.jpg",
|
|
||||||
alt: "The Market detail",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
url: "https://www.scandichotels.com/imageVault/publishedmedia/0nnwt72vwzfvkkx5whf0/scandic-continental-caldo.jpg",
|
|
||||||
alt: "Caldo",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
url: "https://www.scandichotels.com/imageVault/publishedmedia/mg9bbtbumfxbfjhovk2e/Scandic_Continental_Capitol_The_View_6.jpg",
|
|
||||||
alt: "Rooftop bar",
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import { MOCK_FACILITIES } from "./Facilities/mockData"
|
|||||||
import Facilities from "./Facilities"
|
import Facilities from "./Facilities"
|
||||||
|
|
||||||
import AmenitiesList from "./AmenitiesList"
|
import AmenitiesList from "./AmenitiesList"
|
||||||
import { tempHotelLightboxImage } from "./data"
|
|
||||||
import IntroSection from "./IntroSection"
|
import IntroSection from "./IntroSection"
|
||||||
import PreviewImages from "./PreviewImages"
|
import PreviewImages from "./PreviewImages"
|
||||||
import { Rooms } from "./Rooms"
|
import { Rooms } from "./Rooms"
|
||||||
@@ -20,23 +19,32 @@ export default async function HotelPage() {
|
|||||||
if (!hotelData) {
|
if (!hotelData) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
const { hotel, roomCategories } = hotelData
|
const {
|
||||||
|
hotelName,
|
||||||
|
hotelDescription,
|
||||||
|
hotelLocation,
|
||||||
|
hotelAddress,
|
||||||
|
hotelRatings,
|
||||||
|
hotelDetailedFacilities,
|
||||||
|
hotelImages,
|
||||||
|
roomCategories,
|
||||||
|
} = hotelData
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.pageContainer}>
|
<div className={styles.pageContainer}>
|
||||||
<PreviewImages images={tempHotelLightboxImage} />
|
<PreviewImages images={hotelImages} />
|
||||||
<TabNavigation />
|
<TabNavigation />
|
||||||
<main className={styles.mainSection}>
|
<main className={styles.mainSection}>
|
||||||
<div className={styles.introContainer}>
|
<div className={styles.introContainer}>
|
||||||
<IntroSection
|
<IntroSection
|
||||||
hotelName={hotel.name}
|
hotelName={hotelName}
|
||||||
hotelDescription={hotel.hotelContent.texts.descriptions.short}
|
hotelDescription={hotelDescription}
|
||||||
location={hotel.location}
|
location={hotelLocation}
|
||||||
address={hotel.address}
|
address={hotelAddress}
|
||||||
tripAdvisor={hotel.ratings?.tripAdvisor}
|
tripAdvisor={hotelRatings?.tripAdvisor}
|
||||||
/>
|
/>
|
||||||
<SidePeeks />
|
<SidePeeks />
|
||||||
<AmenitiesList detailedFacilities={hotel.detailedFacilities} />
|
<AmenitiesList detailedFacilities={hotelDetailedFacilities} />
|
||||||
</div>
|
</div>
|
||||||
<Rooms rooms={roomCategories} />
|
<Rooms rooms={roomCategories} />
|
||||||
<Facilities facilities={MOCK_FACILITIES} />
|
<Facilities facilities={MOCK_FACILITIES} />
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ export default function FullView({
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<div className={styles.fullViewFooter}>
|
<div className={styles.fullViewFooter}>
|
||||||
<Body color="white">{image.alt}</Body>
|
<Body color="white">{image.title}</Body>
|
||||||
</div>
|
</div>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
</AnimatePresence>
|
</AnimatePresence>
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ export default function Gallery({
|
|||||||
<div className={styles.desktopGallery}>
|
<div className={styles.desktopGallery}>
|
||||||
<div className={styles.galleryHeader}>
|
<div className={styles.galleryHeader}>
|
||||||
<div className={styles.imageCaption}>
|
<div className={styles.imageCaption}>
|
||||||
<Caption color="textMediumContrast">{mainImage.alt}</Caption>
|
<Caption color="textMediumContrast">{mainImage.title}</Caption>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.mainImageWrapper}>
|
<div className={styles.mainImageWrapper}>
|
||||||
|
|||||||
@@ -5,7 +5,6 @@
|
|||||||
.mobileGallery {
|
.mobileGallery {
|
||||||
margin-top: 70.047px;
|
margin-top: 70.047px;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
overflow-y: auto;
|
|
||||||
position: relative;
|
position: relative;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@@ -51,6 +50,7 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.galleryHeader {
|
.galleryHeader {
|
||||||
@@ -60,6 +60,10 @@
|
|||||||
margin-bottom: var(--Spacing-x1);
|
margin-bottom: var(--Spacing-x1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.desktopGalleryCloseButton {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
.imageCaption {
|
.imageCaption {
|
||||||
background-color: var(--Base-Surface-Subtle-Normal);
|
background-color: var(--Base-Surface-Subtle-Normal);
|
||||||
padding: var(--Spacing-x-half) var(--Spacing-x1);
|
padding: var(--Spacing-x-half) var(--Spacing-x1);
|
||||||
@@ -187,6 +191,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.desktopGalleryCloseButton {
|
.desktopGalleryCloseButton {
|
||||||
|
display: block;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: var(--Spacing-x-one-and-half);
|
top: var(--Spacing-x-one-and-half);
|
||||||
right: var(--Spacing-x-half);
|
right: var(--Spacing-x-half);
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import {
|
|||||||
publicProcedure,
|
publicProcedure,
|
||||||
router,
|
router,
|
||||||
} from "@/server/trpc"
|
} from "@/server/trpc"
|
||||||
|
import { extractHotelImages } from "@/server/routers/utils/hotels"
|
||||||
import { toApiLang } from "@/server/utils"
|
import { toApiLang } from "@/server/utils"
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@@ -153,6 +154,10 @@ export const hotelQueryRouter = router({
|
|||||||
|
|
||||||
const included = validatedHotelData.data.included || []
|
const included = validatedHotelData.data.included || []
|
||||||
|
|
||||||
|
const hotelAttributes = validatedHotelData.data.data.attributes
|
||||||
|
|
||||||
|
const images = extractHotelImages(hotelAttributes)
|
||||||
|
|
||||||
const roomCategories = included
|
const roomCategories = included
|
||||||
? included
|
? included
|
||||||
.filter((item) => item.type === "roomcategories")
|
.filter((item) => item.type === "roomcategories")
|
||||||
@@ -193,8 +198,14 @@ export const hotelQueryRouter = router({
|
|||||||
})
|
})
|
||||||
)
|
)
|
||||||
return {
|
return {
|
||||||
hotel: validatedHotelData.data.data.attributes,
|
hotelName: hotelAttributes.name,
|
||||||
roomCategories: roomCategories,
|
hotelDescription: hotelAttributes.hotelContent.texts.descriptions.short,
|
||||||
|
hotelLocation: hotelAttributes.location,
|
||||||
|
hotelAddress: hotelAttributes.address,
|
||||||
|
hotelRatings: hotelAttributes.ratings,
|
||||||
|
hotelDetailedFacilities: hotelAttributes.detailedFacilities,
|
||||||
|
hotelImages: images,
|
||||||
|
roomCategories,
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
rates: router({
|
rates: router({
|
||||||
|
|||||||
30
server/routers/utils/hotels.ts
Normal file
30
server/routers/utils/hotels.ts
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
import { ImageItem } from "@/types/components/lightbox/lightbox"
|
||||||
|
import { Hotel } from "@/types/hotel"
|
||||||
|
|
||||||
|
export function extractHotelImages(hotelData: Hotel): ImageItem[] {
|
||||||
|
const images: ImageItem[] = []
|
||||||
|
|
||||||
|
if (hotelData.hotelContent?.images) {
|
||||||
|
images.push({
|
||||||
|
url: hotelData.hotelContent.images.imageSizes.large,
|
||||||
|
alt: hotelData.hotelContent.images.metaData.altText,
|
||||||
|
title:
|
||||||
|
hotelData.hotelContent.images.metaData.title ||
|
||||||
|
hotelData.hotelContent.images.metaData.altText,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hotelData.healthFacilities) {
|
||||||
|
hotelData.healthFacilities.forEach((facility: any) => {
|
||||||
|
facility.content.images.forEach((image: any) => {
|
||||||
|
images.push({
|
||||||
|
url: image.imageSizes.large,
|
||||||
|
alt: image.metaData.altText,
|
||||||
|
title: image.metaData.title || image.metaData.altText,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return images
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
export interface ImageItem {
|
export interface ImageItem {
|
||||||
url: string
|
url: string
|
||||||
alt: string
|
alt: string
|
||||||
|
title: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LightboxProps {
|
export interface LightboxProps {
|
||||||
|
|||||||
Reference in New Issue
Block a user