feat(SW-2278): Added hotel listing to campaign page
Approved-by: Matilda Landström
This commit is contained in:
@@ -0,0 +1,28 @@
|
|||||||
|
"use client"
|
||||||
|
|
||||||
|
import { Typography } from "@scandic-hotels/design-system/Typography"
|
||||||
|
|
||||||
|
import SkeletonShimmer from "@/components/SkeletonShimmer"
|
||||||
|
|
||||||
|
import HotelListingItemSkeleton from "./HotelListingItem/HotelListingItemSkeleton"
|
||||||
|
|
||||||
|
import styles from "./campaignHotelListing.module.css"
|
||||||
|
|
||||||
|
export default function CampaignHotelListingSkeleton() {
|
||||||
|
return (
|
||||||
|
<section className={styles.hotelListingSection}>
|
||||||
|
<header className={styles.header}>
|
||||||
|
<Typography variant="Title/md">
|
||||||
|
<SkeletonShimmer width="40ch" />
|
||||||
|
</Typography>
|
||||||
|
</header>
|
||||||
|
<ul className={styles.list}>
|
||||||
|
{Array.from({ length: 3 }).map((_, index) => (
|
||||||
|
<li key={index} className={styles.listItem}>
|
||||||
|
<HotelListingItemSkeleton />
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,120 @@
|
|||||||
|
"use client"
|
||||||
|
|
||||||
|
import { cx } from "class-variance-authority"
|
||||||
|
import { useRef, useState } from "react"
|
||||||
|
import { useIntl } from "react-intl"
|
||||||
|
import { useMediaQuery } from "usehooks-ts"
|
||||||
|
|
||||||
|
import { Button } from "@scandic-hotels/design-system/Button"
|
||||||
|
import {
|
||||||
|
MaterialIcon,
|
||||||
|
type MaterialIconProps,
|
||||||
|
} from "@scandic-hotels/design-system/Icons/MaterialIcon"
|
||||||
|
import { Typography } from "@scandic-hotels/design-system/Typography"
|
||||||
|
|
||||||
|
import HotelListingItem from "./HotelListingItem"
|
||||||
|
|
||||||
|
import styles from "./campaignHotelListing.module.css"
|
||||||
|
|
||||||
|
import type { HotelDataWithUrl } from "@/types/hotel"
|
||||||
|
|
||||||
|
interface CampaignHotelListingClientProps {
|
||||||
|
heading: string
|
||||||
|
hotels: HotelDataWithUrl[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function CampaignHotelListingClient({
|
||||||
|
heading,
|
||||||
|
hotels,
|
||||||
|
}: CampaignHotelListingClientProps) {
|
||||||
|
const intl = useIntl()
|
||||||
|
const isMobile = useMediaQuery("(max-width: 767px)")
|
||||||
|
const scrollRef = useRef<HTMLElement>(null)
|
||||||
|
|
||||||
|
const initialCount = isMobile ? 3 : 6 // Initial number of hotels to show
|
||||||
|
const thresholdCount = isMobile ? 6 : 9 // This is the threshold at which we start showing the "Show More" button
|
||||||
|
const showAllThreshold = isMobile ? 9 : 18 // This is the threshold at which we show the "Show All" button
|
||||||
|
const incrementCount = isMobile ? 3 : 6 // Number of hotels to increment when the button is clicked
|
||||||
|
|
||||||
|
const [visibleCount, setVisibleCount] = useState(() =>
|
||||||
|
// Set initial visible count based on the number of hotels and the threshold
|
||||||
|
hotels.length <= thresholdCount ? hotels.length : initialCount
|
||||||
|
)
|
||||||
|
|
||||||
|
// Only show the show more/less button if the length of hotels exceeds the threshold count
|
||||||
|
const showButton = hotels.length >= thresholdCount
|
||||||
|
|
||||||
|
// Determine if we are at the stage where the user can click to show all hotels
|
||||||
|
const canShowAll =
|
||||||
|
hotels.length > visibleCount &&
|
||||||
|
(visibleCount + incrementCount > showAllThreshold ||
|
||||||
|
visibleCount + incrementCount >= hotels.length)
|
||||||
|
|
||||||
|
function handleButtonClick() {
|
||||||
|
if (visibleCount < hotels.length) {
|
||||||
|
if (canShowAll) {
|
||||||
|
setVisibleCount(hotels.length)
|
||||||
|
} else {
|
||||||
|
setVisibleCount((prev) =>
|
||||||
|
Math.min(prev + incrementCount, hotels.length)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setVisibleCount(initialCount)
|
||||||
|
if (scrollRef.current) {
|
||||||
|
scrollRef.current.scrollIntoView({ behavior: "smooth" })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let buttonText = intl.formatMessage({
|
||||||
|
defaultMessage: "Show more",
|
||||||
|
})
|
||||||
|
let iconDirection: MaterialIconProps["icon"] = "keyboard_arrow_down"
|
||||||
|
|
||||||
|
if (visibleCount === hotels.length) {
|
||||||
|
buttonText = intl.formatMessage({
|
||||||
|
defaultMessage: "Show less",
|
||||||
|
})
|
||||||
|
iconDirection = "keyboard_arrow_up"
|
||||||
|
} else if (canShowAll) {
|
||||||
|
buttonText = intl.formatMessage({
|
||||||
|
defaultMessage: "Show all",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section className={styles.hotelListingSection} ref={scrollRef}>
|
||||||
|
<header className={styles.header}>
|
||||||
|
<Typography variant="Title/md">
|
||||||
|
<h2 className={styles.heading}>{heading}</h2>
|
||||||
|
</Typography>
|
||||||
|
</header>
|
||||||
|
<ul className={styles.list}>
|
||||||
|
{hotels.map(({ hotel, url }, index) => (
|
||||||
|
<li
|
||||||
|
key={hotel.id}
|
||||||
|
className={cx(styles.listItem, {
|
||||||
|
[styles.hidden]: index >= visibleCount,
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<HotelListingItem hotel={hotel} url={url} />
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
{showButton ? (
|
||||||
|
<Button
|
||||||
|
variant="Text"
|
||||||
|
color="Primary"
|
||||||
|
size="Medium"
|
||||||
|
typography="Body/Paragraph/mdBold"
|
||||||
|
onPress={handleButtonClick}
|
||||||
|
>
|
||||||
|
<MaterialIcon icon={iconDirection} color="CurrentColor" />
|
||||||
|
{buttonText}
|
||||||
|
</Button>
|
||||||
|
) : null}
|
||||||
|
</section>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
import { Divider } from "@scandic-hotels/design-system/Divider"
|
||||||
|
import { Typography } from "@scandic-hotels/design-system/Typography"
|
||||||
|
|
||||||
|
import SkeletonShimmer from "@/components/SkeletonShimmer"
|
||||||
|
|
||||||
|
import styles from "./hotelListingItem.module.css"
|
||||||
|
|
||||||
|
export default function HotelListingItemSkeleton() {
|
||||||
|
return (
|
||||||
|
<article className={styles.hotelListingItem}>
|
||||||
|
<div className={styles.imageWrapper}>
|
||||||
|
<SkeletonShimmer width="100%" height="220px" />
|
||||||
|
</div>
|
||||||
|
<div className={styles.content}>
|
||||||
|
<div className={styles.intro}>
|
||||||
|
<SkeletonShimmer width="20ch" height="30px" />
|
||||||
|
<Typography variant="Title/Subtitle/md">
|
||||||
|
<SkeletonShimmer width="25ch" />
|
||||||
|
</Typography>
|
||||||
|
<Typography variant="Body/Supporting text (caption)/smRegular">
|
||||||
|
<div className={styles.captions}>
|
||||||
|
<SkeletonShimmer width="10ch" />
|
||||||
|
<span>
|
||||||
|
<Divider
|
||||||
|
className={styles.divider}
|
||||||
|
variant="vertical"
|
||||||
|
color="Border/Divider/Default"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
<SkeletonShimmer width="20ch" />
|
||||||
|
</div>
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
<Typography variant="Body/Paragraph/mdRegular">
|
||||||
|
<p>
|
||||||
|
<SkeletonShimmer width="100%" />
|
||||||
|
<SkeletonShimmer width="70%" />
|
||||||
|
<SkeletonShimmer width="35%" />
|
||||||
|
</p>
|
||||||
|
</Typography>
|
||||||
|
<Typography variant="Body/Supporting text (caption)/smRegular">
|
||||||
|
<ul className={styles.amenityList}>
|
||||||
|
{Array.from({ length: 5 }).map((_, index) => {
|
||||||
|
return (
|
||||||
|
<li className={styles.amenityItem} key={index}>
|
||||||
|
<SkeletonShimmer width="20px" height="20px" />
|
||||||
|
<SkeletonShimmer width="15ch" />
|
||||||
|
</li>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</ul>
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
<div className={styles.ctaWrapper}>
|
||||||
|
<SkeletonShimmer width="100%" height="40px" />
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
.hotelListingItem {
|
||||||
|
border-radius: var(--Corner-radius-md);
|
||||||
|
overflow: hidden;
|
||||||
|
display: grid;
|
||||||
|
grid-template-rows: auto 1fr auto;
|
||||||
|
gap: var(--Space-x2);
|
||||||
|
height: 100%;
|
||||||
|
padding-bottom: var(--Space-x2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.imageWrapper {
|
||||||
|
height: 220px;
|
||||||
|
width: 100%;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tripAdvisor {
|
||||||
|
position: absolute;
|
||||||
|
top: var(--Space-x2);
|
||||||
|
left: var(--Space-x2);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: var(--Space-x05);
|
||||||
|
background-color: var(--Surface-Primary-Default);
|
||||||
|
padding: var(--Space-x025) var(--Space-x1);
|
||||||
|
border-radius: var(--Corner-radius-sm);
|
||||||
|
color: var(--Text-Interactive-Default);
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
padding: 0 var(--Space-x2);
|
||||||
|
display: grid;
|
||||||
|
gap: var(--Space-x15);
|
||||||
|
align-content: start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.intro {
|
||||||
|
display: grid;
|
||||||
|
gap: var(--Space-x05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.captions {
|
||||||
|
display: flex;
|
||||||
|
column-gap: var(--Space-x1);
|
||||||
|
flex-wrap: wrap;
|
||||||
|
color: var(--Text-Tertiary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.amenityList {
|
||||||
|
display: flex;
|
||||||
|
gap: var(--Space-x025) var(--Space-x1);
|
||||||
|
flex-wrap: wrap;
|
||||||
|
color: var(--Text-Secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.amenityItem {
|
||||||
|
display: flex;
|
||||||
|
gap: var(--Space-x05);
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ctaWrapper {
|
||||||
|
padding: 0 var(--Space-x2);
|
||||||
|
}
|
||||||
@@ -0,0 +1,129 @@
|
|||||||
|
import { useIntl } from "react-intl"
|
||||||
|
|
||||||
|
import { Divider } from "@scandic-hotels/design-system/Divider"
|
||||||
|
import HotelLogoIcon from "@scandic-hotels/design-system/Icons/HotelLogoIcon"
|
||||||
|
import TripadvisorIcon from "@scandic-hotels/design-system/Icons/TripadvisorIcon"
|
||||||
|
import { Typography } from "@scandic-hotels/design-system/Typography"
|
||||||
|
|
||||||
|
import ButtonLink from "@/components/ButtonLink"
|
||||||
|
import { FacilityToIcon } from "@/components/ContentType/HotelPage/data"
|
||||||
|
import ImageGallery from "@/components/ImageGallery"
|
||||||
|
import { mapApiImagesToGalleryImages } from "@/utils/imageGallery"
|
||||||
|
import { getSingleDecimal } from "@/utils/numberFormatting"
|
||||||
|
|
||||||
|
import styles from "./hotelListingItem.module.css"
|
||||||
|
|
||||||
|
import type { Hotel } from "@/types/hotel"
|
||||||
|
|
||||||
|
interface HotelListingItemProps {
|
||||||
|
hotel: Hotel
|
||||||
|
url: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function HotelListingItem({
|
||||||
|
hotel,
|
||||||
|
url,
|
||||||
|
}: HotelListingItemProps) {
|
||||||
|
const intl = useIntl()
|
||||||
|
const galleryImages = mapApiImagesToGalleryImages(hotel.galleryImages || [])
|
||||||
|
const tripadvisorRating = hotel.ratings?.tripAdvisor.rating
|
||||||
|
const address = `${hotel.address.streetAddress}, ${hotel.address.city}`
|
||||||
|
const amenities = hotel.detailedFacilities.slice(0, 5)
|
||||||
|
const hotelDescription = hotel.hotelContent.texts.descriptions?.short
|
||||||
|
|
||||||
|
return (
|
||||||
|
<article className={styles.hotelListingItem}>
|
||||||
|
<div className={styles.imageWrapper}>
|
||||||
|
<ImageGallery
|
||||||
|
images={galleryImages}
|
||||||
|
fill
|
||||||
|
sizes="(min-width: 768px) 450px, 100vw"
|
||||||
|
title={intl.formatMessage(
|
||||||
|
{
|
||||||
|
defaultMessage: "{title} - Image gallery",
|
||||||
|
},
|
||||||
|
{ title: hotel.name }
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
{tripadvisorRating ? (
|
||||||
|
<Typography variant="Title/Overline/sm">
|
||||||
|
<div className={styles.tripAdvisor}>
|
||||||
|
<TripadvisorIcon color="CurrentColor" />
|
||||||
|
<span>{tripadvisorRating}</span>
|
||||||
|
</div>
|
||||||
|
</Typography>
|
||||||
|
) : null}
|
||||||
|
</div>
|
||||||
|
<div className={styles.content}>
|
||||||
|
<div className={styles.intro}>
|
||||||
|
<HotelLogoIcon
|
||||||
|
hotelId={hotel.operaId}
|
||||||
|
hotelType={hotel.hotelType}
|
||||||
|
height={30}
|
||||||
|
/>
|
||||||
|
<Typography variant="Title/Subtitle/md">
|
||||||
|
<h3>{hotel.name}</h3>
|
||||||
|
</Typography>
|
||||||
|
<Typography variant="Body/Supporting text (caption)/smRegular">
|
||||||
|
<div className={styles.captions}>
|
||||||
|
<span>{address}</span>
|
||||||
|
<span>
|
||||||
|
<Divider
|
||||||
|
className={styles.divider}
|
||||||
|
variant="vertical"
|
||||||
|
color="Border/Divider/Default"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
<span>
|
||||||
|
{intl.formatMessage(
|
||||||
|
{
|
||||||
|
defaultMessage: "{number} km to city center",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
number: getSingleDecimal(
|
||||||
|
hotel.location.distanceToCentre / 1000
|
||||||
|
),
|
||||||
|
}
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
{hotelDescription ? (
|
||||||
|
<Typography variant="Body/Paragraph/mdRegular">
|
||||||
|
<p>{hotelDescription}</p>
|
||||||
|
</Typography>
|
||||||
|
) : null}
|
||||||
|
<Typography variant="Body/Supporting text (caption)/smRegular">
|
||||||
|
<ul className={styles.amenityList}>
|
||||||
|
{amenities.map((amenity) => {
|
||||||
|
return (
|
||||||
|
<li className={styles.amenityItem} key={amenity.id}>
|
||||||
|
<FacilityToIcon
|
||||||
|
id={amenity.id}
|
||||||
|
color="CurrentColor"
|
||||||
|
size={20}
|
||||||
|
/>
|
||||||
|
{amenity.name}
|
||||||
|
</li>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</ul>
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
<div className={styles.ctaWrapper}>
|
||||||
|
<ButtonLink
|
||||||
|
href={url}
|
||||||
|
variant="Tertiary"
|
||||||
|
color="Primary"
|
||||||
|
size="Small"
|
||||||
|
typography="Body/Supporting text (caption)/smBold"
|
||||||
|
>
|
||||||
|
{intl.formatMessage({
|
||||||
|
defaultMessage: "See hotel details",
|
||||||
|
})}
|
||||||
|
</ButtonLink>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
.hotelListingSection {
|
||||||
|
--scroll-margin-top: calc(
|
||||||
|
var(--booking-widget-mobile-height) + var(--Spacing-x2)
|
||||||
|
);
|
||||||
|
|
||||||
|
display: grid;
|
||||||
|
gap: var(--Space-x3);
|
||||||
|
scroll-margin-top: var(--scroll-margin-top);
|
||||||
|
}
|
||||||
|
|
||||||
|
.heading {
|
||||||
|
color: var(--Text-Heading);
|
||||||
|
}
|
||||||
|
|
||||||
|
.list {
|
||||||
|
list-style: none;
|
||||||
|
display: grid;
|
||||||
|
gap: var(--Space-x4);
|
||||||
|
}
|
||||||
|
|
||||||
|
.listItem.hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (min-width: 768px) {
|
||||||
|
.hotelListingSection {
|
||||||
|
--scroll-margin-top: calc(
|
||||||
|
var(--booking-widget-tablet-height) + var(--Spacing-x2)
|
||||||
|
);
|
||||||
|
gap: var(--Space-x5);
|
||||||
|
}
|
||||||
|
.list {
|
||||||
|
row-gap: var(--Space-x5);
|
||||||
|
column-gap: var(--Space-x2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (min-width: 768px) and (max-width: 949px) {
|
||||||
|
.list {
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (min-width: 950px) {
|
||||||
|
.list {
|
||||||
|
grid-template-columns: repeat(3, 1fr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (min-width: 1367px) {
|
||||||
|
.hotelListingSection {
|
||||||
|
--scroll-margin-top: calc(
|
||||||
|
var(--booking-widget-desktop-height) + var(--Spacing-x2)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
import { getHotelsByCSFilter } from "@/lib/trpc/memoizedRequests"
|
||||||
|
|
||||||
|
import CampaignHotelListingClient from "./Client"
|
||||||
|
|
||||||
|
interface CampaignHotelListingProps {
|
||||||
|
heading: string
|
||||||
|
hotelIds: string[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export default async function CampaignHotelListing({
|
||||||
|
heading,
|
||||||
|
hotelIds,
|
||||||
|
}: CampaignHotelListingProps) {
|
||||||
|
const hotels = await getHotelsByCSFilter({ hotelsToInclude: hotelIds })
|
||||||
|
|
||||||
|
if (!hotels.length) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return <CampaignHotelListingClient heading={heading} hotels={hotels} />
|
||||||
|
}
|
||||||
@@ -18,7 +18,7 @@ export default async function Essentials({ content }: EssentialsProps) {
|
|||||||
return (
|
return (
|
||||||
<section className={styles.essentialsSection}>
|
<section className={styles.essentialsSection}>
|
||||||
<header className={styles.header}>
|
<header className={styles.header}>
|
||||||
<Typography variant="Title/sm">
|
<Typography variant="Title/smRegular">
|
||||||
<h3 className={styles.heading}>{title}</h3>
|
<h3 className={styles.heading}>{title}</h3>
|
||||||
</Typography>
|
</Typography>
|
||||||
{preamble ? (
|
{preamble ? (
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ export default function Blocks({ blocks }: BlocksProps) {
|
|||||||
key={`${block.card_gallery.heading}-${idx}`}
|
key={`${block.card_gallery.heading}-${idx}`}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
case BlocksEnums.block.HotelListing:
|
case BlocksEnums.block.ContentPageHotelListing:
|
||||||
const { heading, contentType, locationFilter, hotelsToInclude } =
|
const { heading, contentType, locationFilter, hotelsToInclude } =
|
||||||
block.hotel_listing
|
block.hotel_listing
|
||||||
if (!locationFilter && !hotelsToInclude.length) {
|
if (!locationFilter && !hotelsToInclude.length) {
|
||||||
|
|||||||
@@ -1,4 +1,8 @@
|
|||||||
|
import { Suspense } from "react"
|
||||||
|
|
||||||
import AccordionSection from "@/components/Blocks/Accordion"
|
import AccordionSection from "@/components/Blocks/Accordion"
|
||||||
|
import CampaignHotelListing from "@/components/Blocks/CampaignHotelListing"
|
||||||
|
import CampaignHotelListingSkeleton from "@/components/Blocks/CampaignHotelListing/CampaignHotelListingSkeleton"
|
||||||
import CarouselCards from "@/components/Blocks/CarouselCards"
|
import CarouselCards from "@/components/Blocks/CarouselCards"
|
||||||
import Essentials from "@/components/Blocks/Essentials"
|
import Essentials from "@/components/Blocks/Essentials"
|
||||||
|
|
||||||
@@ -27,6 +31,15 @@ export default function Blocks({ blocks }: BlocksProps) {
|
|||||||
key={block.accordion.title}
|
key={block.accordion.title}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
case BlocksEnums.block.CampaignPageHotelListing:
|
||||||
|
return (
|
||||||
|
<Suspense fallback={<CampaignHotelListingSkeleton />}>
|
||||||
|
<CampaignHotelListing
|
||||||
|
heading={block.hotel_listing.heading}
|
||||||
|
hotelIds={block.hotel_listing.hotelIds}
|
||||||
|
/>
|
||||||
|
</Suspense>
|
||||||
|
)
|
||||||
default:
|
default:
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,8 +27,8 @@
|
|||||||
|
|
||||||
.tripAdvisor {
|
.tripAdvisor {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 16px;
|
top: var(--Space-x2);
|
||||||
left: 16px;
|
left: var(--Space-x2);
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: var(--Space-x05);
|
gap: var(--Space-x05);
|
||||||
|
|||||||
@@ -22,3 +22,10 @@ fragment HotelListing_ContentPage on ContentPageBlocksHotelListing {
|
|||||||
...HotelListing
|
...HotelListing
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fragment HotelListing_CampaignPage on CampaignPageBlocksHotelListing {
|
||||||
|
hotel_listing {
|
||||||
|
heading
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,45 @@
|
|||||||
|
fragment CampaignPageIncludedHotels on CampaignPageIncludedHotels {
|
||||||
|
list_1Connection {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
... on HotelPage {
|
||||||
|
hotel_page_id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
list_2Connection {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
... on HotelPage {
|
||||||
|
hotel_page_id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fragment CampaignPageIncludedHotelsRef on CampaignPageIncludedHotels {
|
||||||
|
list_1Connection {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
... on HotelPage {
|
||||||
|
system {
|
||||||
|
...System
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
list_2Connection {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
... on HotelPage {
|
||||||
|
system {
|
||||||
|
...System
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,9 +1,12 @@
|
|||||||
#import "../../Fragments/System.graphql"
|
#import "../../Fragments/System.graphql"
|
||||||
|
|
||||||
|
#import "../../Fragments/CampaignPage/IncludedHotels.graphql"
|
||||||
|
#import "../../Fragments/CampaignPage/Hero.graphql"
|
||||||
|
|
||||||
#import "../../Fragments/Blocks/Accordion.graphql"
|
#import "../../Fragments/Blocks/Accordion.graphql"
|
||||||
#import "../../Fragments/Blocks/Essentials.graphql"
|
#import "../../Fragments/Blocks/Essentials.graphql"
|
||||||
#import "../../Fragments/Blocks/CarouselCards.graphql"
|
#import "../../Fragments/Blocks/CarouselCards.graphql"
|
||||||
#import "../../Fragments/CampaignPage/Hero.graphql"
|
#import "../../Fragments/Blocks/HotelListing.graphql"
|
||||||
|
|
||||||
query GetCampaignPage($locale: String!, $uid: String!) {
|
query GetCampaignPage($locale: String!, $uid: String!) {
|
||||||
campaign_page(uid: $uid, locale: $locale) {
|
campaign_page(uid: $uid, locale: $locale) {
|
||||||
@@ -16,11 +19,15 @@ query GetCampaignPage($locale: String!, $uid: String!) {
|
|||||||
first_column
|
first_column
|
||||||
second_column
|
second_column
|
||||||
}
|
}
|
||||||
|
included_hotels {
|
||||||
|
...CampaignPageIncludedHotels
|
||||||
|
}
|
||||||
blocks {
|
blocks {
|
||||||
__typename
|
__typename
|
||||||
...Essentials_CampaignPage
|
...Essentials_CampaignPage
|
||||||
...CarouselCards_CampaignPage
|
...CarouselCards_CampaignPage
|
||||||
...Accordion_CampaignPage
|
...Accordion_CampaignPage
|
||||||
|
...HotelListing_CampaignPage
|
||||||
}
|
}
|
||||||
system {
|
system {
|
||||||
...System
|
...System
|
||||||
@@ -36,6 +43,9 @@ query GetCampaignPage($locale: String!, $uid: String!) {
|
|||||||
|
|
||||||
query GetCampaignPageRefs($locale: String!, $uid: String!) {
|
query GetCampaignPageRefs($locale: String!, $uid: String!) {
|
||||||
campaign_page(locale: $locale, uid: $uid) {
|
campaign_page(locale: $locale, uid: $uid) {
|
||||||
|
included_hotels {
|
||||||
|
...CampaignPageIncludedHotelsRef
|
||||||
|
}
|
||||||
blocks {
|
blocks {
|
||||||
__typename
|
__typename
|
||||||
...CarouselCards_CampaignPageRefs
|
...CarouselCards_CampaignPageRefs
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import {
|
|||||||
carouselCardsSchema,
|
carouselCardsSchema,
|
||||||
} from "../schemas/blocks/carouselCards"
|
} from "../schemas/blocks/carouselCards"
|
||||||
import { essentialsBlockSchema } from "../schemas/blocks/essentials"
|
import { essentialsBlockSchema } from "../schemas/blocks/essentials"
|
||||||
|
import { campaignPageHotelListingSchema } from "../schemas/blocks/hotelListing"
|
||||||
import { tempImageVaultAssetSchema } from "../schemas/imageVault"
|
import { tempImageVaultAssetSchema } from "../schemas/imageVault"
|
||||||
import {
|
import {
|
||||||
linkConnectionRefs,
|
linkConnectionRefs,
|
||||||
@@ -38,10 +39,17 @@ export const campaignPageAccordion = z
|
|||||||
})
|
})
|
||||||
.merge(accordionSchema)
|
.merge(accordionSchema)
|
||||||
|
|
||||||
|
export const campaignPageHotelListing = z
|
||||||
|
.object({
|
||||||
|
__typename: z.literal(CampaignPageEnum.ContentStack.blocks.HotelListing),
|
||||||
|
})
|
||||||
|
.merge(campaignPageHotelListingSchema)
|
||||||
|
|
||||||
export const blocksSchema = z.discriminatedUnion("__typename", [
|
export const blocksSchema = z.discriminatedUnion("__typename", [
|
||||||
campaignPageEssentials,
|
campaignPageEssentials,
|
||||||
campaignPageCarouselCards,
|
campaignPageCarouselCards,
|
||||||
campaignPageAccordion,
|
campaignPageAccordion,
|
||||||
|
campaignPageHotelListing,
|
||||||
])
|
])
|
||||||
|
|
||||||
export const heroSchema = z.object({
|
export const heroSchema = z.object({
|
||||||
@@ -58,30 +66,88 @@ export const heroSchema = z.object({
|
|||||||
button: z.intersection(z.object({ cta: z.string() }), linkConnectionSchema),
|
button: z.intersection(z.object({ cta: z.string() }), linkConnectionSchema),
|
||||||
})
|
})
|
||||||
|
|
||||||
export const campaignPageSchema = z.object({
|
const includedHotelsSchema = z
|
||||||
campaign_page: z.object({
|
.object({
|
||||||
title: z.string(),
|
list_1Connection: z.object({
|
||||||
campaign_identifier: z.string().nullish(),
|
edges: z.array(
|
||||||
hero: heroSchema,
|
z.object({
|
||||||
heading: z.string(),
|
node: z.object({
|
||||||
subheading: z.string().nullish(),
|
hotel_page_id: z.string(),
|
||||||
preamble: z.object({
|
}),
|
||||||
is_two_columns: z.boolean().default(false),
|
})
|
||||||
first_column: z.string(),
|
),
|
||||||
second_column: z.string(),
|
|
||||||
}),
|
}),
|
||||||
blocks: discriminatedUnionArray(blocksSchema.options),
|
list_2Connection: z.object({
|
||||||
system: systemSchema.merge(
|
edges: z.array(
|
||||||
z.object({
|
z.object({
|
||||||
created_at: z.string(),
|
node: z.object({
|
||||||
updated_at: z.string(),
|
hotel_page_id: z.string(),
|
||||||
})
|
}),
|
||||||
),
|
})
|
||||||
}),
|
),
|
||||||
trackingProps: z.object({
|
}),
|
||||||
url: z.string(),
|
})
|
||||||
}),
|
.transform((data) => {
|
||||||
})
|
const list1HotelIds = data.list_1Connection.edges
|
||||||
|
.map((edge) => edge.node.hotel_page_id)
|
||||||
|
.filter(Boolean)
|
||||||
|
const list2HotelIds = data.list_2Connection.edges
|
||||||
|
.map((edge) => edge.node.hotel_page_id)
|
||||||
|
.filter(Boolean)
|
||||||
|
|
||||||
|
return [...new Set([...list1HotelIds, ...list2HotelIds])]
|
||||||
|
})
|
||||||
|
|
||||||
|
export const campaignPageSchema = z
|
||||||
|
.object({
|
||||||
|
campaign_page: z.object({
|
||||||
|
title: z.string(),
|
||||||
|
campaign_identifier: z.string().nullish(),
|
||||||
|
hero: heroSchema,
|
||||||
|
heading: z.string(),
|
||||||
|
subheading: z.string().nullish(),
|
||||||
|
included_hotels: includedHotelsSchema,
|
||||||
|
preamble: z.object({
|
||||||
|
is_two_columns: z.boolean().default(false),
|
||||||
|
first_column: z.string(),
|
||||||
|
second_column: z.string(),
|
||||||
|
}),
|
||||||
|
blocks: discriminatedUnionArray(blocksSchema.options),
|
||||||
|
system: systemSchema.merge(
|
||||||
|
z.object({
|
||||||
|
created_at: z.string(),
|
||||||
|
updated_at: z.string(),
|
||||||
|
})
|
||||||
|
),
|
||||||
|
}),
|
||||||
|
trackingProps: z.object({
|
||||||
|
url: z.string(),
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
.transform((data) => {
|
||||||
|
const blocks = data.campaign_page.blocks.map((block) => {
|
||||||
|
if (
|
||||||
|
block.__typename === CampaignPageEnum.ContentStack.blocks.HotelListing
|
||||||
|
) {
|
||||||
|
return {
|
||||||
|
...block,
|
||||||
|
hotel_listing: {
|
||||||
|
...block.hotel_listing,
|
||||||
|
hotelIds: data.campaign_page.included_hotels,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return block
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
...data,
|
||||||
|
campaign_page: {
|
||||||
|
...data.campaign_page,
|
||||||
|
blocks: [...blocks],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
/** REFS */
|
/** REFS */
|
||||||
const campaignPageCarouselCardsRef = z
|
const campaignPageCarouselCardsRef = z
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import {
|
|||||||
dynamicContentRefsSchema,
|
dynamicContentRefsSchema,
|
||||||
dynamicContentSchema as blockDynamicContentSchema,
|
dynamicContentSchema as blockDynamicContentSchema,
|
||||||
} from "../schemas/blocks/dynamicContent"
|
} from "../schemas/blocks/dynamicContent"
|
||||||
import { hotelListingSchema } from "../schemas/blocks/hotelListing"
|
import { contentPageHotelListingSchema } from "../schemas/blocks/hotelListing"
|
||||||
import {
|
import {
|
||||||
shortcutsRefsSchema,
|
shortcutsRefsSchema,
|
||||||
shortcutsSchema,
|
shortcutsSchema,
|
||||||
@@ -113,7 +113,7 @@ export const contentPageHotelListing = z
|
|||||||
.object({
|
.object({
|
||||||
__typename: z.literal(ContentPageEnum.ContentStack.blocks.HotelListing),
|
__typename: z.literal(ContentPageEnum.ContentStack.blocks.HotelListing),
|
||||||
})
|
})
|
||||||
.merge(hotelListingSchema)
|
.merge(contentPageHotelListingSchema)
|
||||||
|
|
||||||
export const blocksSchema = z.discriminatedUnion("__typename", [
|
export const blocksSchema = z.discriminatedUnion("__typename", [
|
||||||
contentPageAccordion,
|
contentPageAccordion,
|
||||||
|
|||||||
@@ -36,10 +36,10 @@ export const locationFilterSchema = z
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
export const hotelListingSchema = z.object({
|
export const contentPageHotelListingSchema = z.object({
|
||||||
typename: z
|
typename: z
|
||||||
.literal(BlocksEnums.block.HotelListing)
|
.literal(BlocksEnums.block.ContentPageHotelListing)
|
||||||
.default(BlocksEnums.block.HotelListing),
|
.default(BlocksEnums.block.ContentPageHotelListing),
|
||||||
hotel_listing: z
|
hotel_listing: z
|
||||||
.object({
|
.object({
|
||||||
heading: z.string().optional(),
|
heading: z.string().optional(),
|
||||||
@@ -60,3 +60,12 @@ export const hotelListingSchema = z.object({
|
|||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
export const campaignPageHotelListingSchema = z.object({
|
||||||
|
typename: z
|
||||||
|
.literal(BlocksEnums.block.CampaignPageHotelListing)
|
||||||
|
.default(BlocksEnums.block.CampaignPageHotelListing),
|
||||||
|
hotel_listing: z.object({
|
||||||
|
heading: z.string(),
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
|||||||
@@ -237,7 +237,7 @@ export const getHotelsByCSFilterInput = z.object({
|
|||||||
country: z.nativeEnum(Country).nullable(),
|
country: z.nativeEnum(Country).nullable(),
|
||||||
excluded: z.array(z.string()),
|
excluded: z.array(z.string()),
|
||||||
})
|
})
|
||||||
.nullable(),
|
.nullish(),
|
||||||
hotelsToInclude: z.array(z.string()),
|
hotelsToInclude: z.array(z.string()),
|
||||||
})
|
})
|
||||||
export interface GetHotelsByCSFilterInput
|
export interface GetHotelsByCSFilterInput
|
||||||
|
|||||||
@@ -7,7 +7,8 @@ export namespace BlocksEnums {
|
|||||||
Content = "Content",
|
Content = "Content",
|
||||||
DynamicContent = "DynamicContent",
|
DynamicContent = "DynamicContent",
|
||||||
FullWidthCampaign = "FullWidthCampaign",
|
FullWidthCampaign = "FullWidthCampaign",
|
||||||
HotelListing = "HotelListing",
|
CampaignPageHotelListing = "CampaignPageHotelListing",
|
||||||
|
ContentPageHotelListing = "ContentPageHotelListing",
|
||||||
JoinScandicFriends = "JoinScandicFriends",
|
JoinScandicFriends = "JoinScandicFriends",
|
||||||
Shortcuts = "Shortcuts",
|
Shortcuts = "Shortcuts",
|
||||||
Table = "Table",
|
Table = "Table",
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ export namespace CampaignPageEnum {
|
|||||||
Essentials = "CampaignPageBlocksEssentials",
|
Essentials = "CampaignPageBlocksEssentials",
|
||||||
CarouselCards = "CampaignPageBlocksCarouselCards",
|
CarouselCards = "CampaignPageBlocksCarouselCards",
|
||||||
Accordion = "CampaignPageBlocksAccordion",
|
Accordion = "CampaignPageBlocksAccordion",
|
||||||
|
HotelListing = "CampaignPageBlocksHotelListing",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import type { cardsGridSchema } from "@/server/routers/contentstack/schemas/bloc
|
|||||||
import type { carouselCardsSchema } from "@/server/routers/contentstack/schemas/blocks/carouselCards"
|
import type { carouselCardsSchema } from "@/server/routers/contentstack/schemas/blocks/carouselCards"
|
||||||
import type { contentSchema } from "@/server/routers/contentstack/schemas/blocks/content"
|
import type { contentSchema } from "@/server/routers/contentstack/schemas/blocks/content"
|
||||||
import type { dynamicContentSchema } from "@/server/routers/contentstack/schemas/blocks/dynamicContent"
|
import type { dynamicContentSchema } from "@/server/routers/contentstack/schemas/blocks/dynamicContent"
|
||||||
import type { hotelListingSchema } from "@/server/routers/contentstack/schemas/blocks/hotelListing"
|
import type { contentPageHotelListingSchema } from "@/server/routers/contentstack/schemas/blocks/hotelListing"
|
||||||
import type { shortcutsSchema } from "@/server/routers/contentstack/schemas/blocks/shortcuts"
|
import type { shortcutsSchema } from "@/server/routers/contentstack/schemas/blocks/shortcuts"
|
||||||
import type { tableSchema } from "@/server/routers/contentstack/schemas/blocks/table"
|
import type { tableSchema } from "@/server/routers/contentstack/schemas/blocks/table"
|
||||||
import type { textColsSchema } from "@/server/routers/contentstack/schemas/blocks/textCols"
|
import type { textColsSchema } from "@/server/routers/contentstack/schemas/blocks/textCols"
|
||||||
@@ -22,7 +22,8 @@ export interface TableBlock extends z.output<typeof tableSchema> {}
|
|||||||
export type TableData = TableBlock["table"]
|
export type TableData = TableBlock["table"]
|
||||||
export interface TextCols extends z.output<typeof textColsSchema> {}
|
export interface TextCols extends z.output<typeof textColsSchema> {}
|
||||||
export interface UspGrid extends z.output<typeof uspGridSchema> {}
|
export interface UspGrid extends z.output<typeof uspGridSchema> {}
|
||||||
interface GetHotelListing extends z.output<typeof hotelListingSchema> {}
|
interface GetHotelListing
|
||||||
|
extends z.output<typeof contentPageHotelListingSchema> {}
|
||||||
export type HotelListing = GetHotelListing["hotel_listing"]
|
export type HotelListing = GetHotelListing["hotel_listing"]
|
||||||
export interface CarouselCards extends z.output<typeof carouselCardsSchema> {}
|
export interface CarouselCards extends z.output<typeof carouselCardsSchema> {}
|
||||||
export interface CardGallery extends z.output<typeof cardGallerySchema> {}
|
export interface CardGallery extends z.output<typeof cardGallerySchema> {}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import type { z } from "zod"
|
import type { z } from "zod"
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
blocksSchema,
|
|
||||||
campaignPageRefsSchema,
|
campaignPageRefsSchema,
|
||||||
campaignPageSchema,
|
campaignPageSchema,
|
||||||
heroSchema,
|
heroSchema,
|
||||||
@@ -19,7 +18,7 @@ export interface GetCampaignPageRefsData
|
|||||||
export interface CampaignPageRefs
|
export interface CampaignPageRefs
|
||||||
extends z.output<typeof campaignPageRefsSchema> {}
|
extends z.output<typeof campaignPageRefsSchema> {}
|
||||||
|
|
||||||
export type Block = z.output<typeof blocksSchema>
|
export type Block = CampaignPageData["blocks"][number]
|
||||||
|
|
||||||
export type EssentialsBlock = z.output<typeof essentialsSchema>["essentials"]
|
export type EssentialsBlock = z.output<typeof essentialsSchema>["essentials"]
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { iconVariants } from '../variants'
|
|||||||
export default function DowntownCamperIcon({
|
export default function DowntownCamperIcon({
|
||||||
className,
|
className,
|
||||||
color,
|
color,
|
||||||
|
height = 30,
|
||||||
...props
|
...props
|
||||||
}: LogoProps) {
|
}: LogoProps) {
|
||||||
const classNames = iconVariants({ className, color })
|
const classNames = iconVariants({ className, color })
|
||||||
@@ -11,7 +12,7 @@ export default function DowntownCamperIcon({
|
|||||||
<svg
|
<svg
|
||||||
className={classNames}
|
className={classNames}
|
||||||
width="123"
|
width="123"
|
||||||
height="30"
|
height={height}
|
||||||
viewBox="0 0 123 30"
|
viewBox="0 0 123 30"
|
||||||
fill="none"
|
fill="none"
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import type { LogoProps } from '../icon'
|
|||||||
export default function GrandHotelOsloLogoIcon({
|
export default function GrandHotelOsloLogoIcon({
|
||||||
className,
|
className,
|
||||||
color,
|
color,
|
||||||
|
height = 30,
|
||||||
...props
|
...props
|
||||||
}: LogoProps) {
|
}: LogoProps) {
|
||||||
const classNames = iconVariants({ className, color })
|
const classNames = iconVariants({ className, color })
|
||||||
@@ -12,7 +13,7 @@ export default function GrandHotelOsloLogoIcon({
|
|||||||
<svg
|
<svg
|
||||||
className={classNames}
|
className={classNames}
|
||||||
width="69"
|
width="69"
|
||||||
height="30"
|
height={height}
|
||||||
viewBox="0 0 69 30"
|
viewBox="0 0 69 30"
|
||||||
fill="none"
|
fill="none"
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import type { LogoProps } from '../icon'
|
|||||||
export default function HaymarketIcon({
|
export default function HaymarketIcon({
|
||||||
className,
|
className,
|
||||||
color,
|
color,
|
||||||
|
height = 26,
|
||||||
...props
|
...props
|
||||||
}: LogoProps) {
|
}: LogoProps) {
|
||||||
const classNames = iconVariants({ className, color })
|
const classNames = iconVariants({ className, color })
|
||||||
@@ -12,7 +13,7 @@ export default function HaymarketIcon({
|
|||||||
<svg
|
<svg
|
||||||
className={classNames}
|
className={classNames}
|
||||||
width="100"
|
width="100"
|
||||||
height="26"
|
height={height}
|
||||||
viewBox="0 0 100 26"
|
viewBox="0 0 100 26"
|
||||||
fill="none"
|
fill="none"
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import type { LogoProps } from '../icon'
|
|||||||
export default function HotelNorgeIcon({
|
export default function HotelNorgeIcon({
|
||||||
className,
|
className,
|
||||||
color,
|
color,
|
||||||
|
height = 24,
|
||||||
...props
|
...props
|
||||||
}: LogoProps) {
|
}: LogoProps) {
|
||||||
const classNames = iconVariants({ className, color })
|
const classNames = iconVariants({ className, color })
|
||||||
@@ -12,7 +13,7 @@ export default function HotelNorgeIcon({
|
|||||||
<svg
|
<svg
|
||||||
className={classNames}
|
className={classNames}
|
||||||
width="117"
|
width="117"
|
||||||
height="24"
|
height={height}
|
||||||
viewBox="0 0 117 24"
|
viewBox="0 0 117 24"
|
||||||
fill="none"
|
fill="none"
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import type { LogoProps } from '../icon'
|
|||||||
export default function MarskiLogoIcon({
|
export default function MarskiLogoIcon({
|
||||||
className,
|
className,
|
||||||
color,
|
color,
|
||||||
|
height = 30,
|
||||||
...props
|
...props
|
||||||
}: LogoProps) {
|
}: LogoProps) {
|
||||||
const classNames = iconVariants({ className, color })
|
const classNames = iconVariants({ className, color })
|
||||||
@@ -12,7 +13,7 @@ export default function MarskiLogoIcon({
|
|||||||
<svg
|
<svg
|
||||||
className={classNames}
|
className={classNames}
|
||||||
width="92"
|
width="92"
|
||||||
height="30"
|
height={height}
|
||||||
viewBox="0 0 92 30"
|
viewBox="0 0 92 30"
|
||||||
fill="none"
|
fill="none"
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import type { LogoProps } from '../icon'
|
|||||||
export default function ScandicGoLogoIcon({
|
export default function ScandicGoLogoIcon({
|
||||||
className,
|
className,
|
||||||
color,
|
color,
|
||||||
|
height = 18,
|
||||||
...props
|
...props
|
||||||
}: LogoProps) {
|
}: LogoProps) {
|
||||||
const classNames = iconVariants({ className, color })
|
const classNames = iconVariants({ className, color })
|
||||||
@@ -12,7 +13,7 @@ export default function ScandicGoLogoIcon({
|
|||||||
<svg
|
<svg
|
||||||
className={classNames}
|
className={classNames}
|
||||||
width="90"
|
width="90"
|
||||||
height="18"
|
height={height}
|
||||||
viewBox="0 0 90 18"
|
viewBox="0 0 90 18"
|
||||||
fill="none"
|
fill="none"
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import type { LogoProps } from '../icon'
|
|||||||
export default function ScandicLogoIcon({
|
export default function ScandicLogoIcon({
|
||||||
className,
|
className,
|
||||||
color,
|
color,
|
||||||
|
height = 14,
|
||||||
...props
|
...props
|
||||||
}: LogoProps) {
|
}: LogoProps) {
|
||||||
const classNames = iconVariants({ className, color })
|
const classNames = iconVariants({ className, color })
|
||||||
@@ -12,7 +13,7 @@ export default function ScandicLogoIcon({
|
|||||||
<svg
|
<svg
|
||||||
className={classNames}
|
className={classNames}
|
||||||
width="58"
|
width="58"
|
||||||
height="14"
|
height={height}
|
||||||
viewBox="0 0 58 14"
|
viewBox="0 0 58 14"
|
||||||
fill="none"
|
fill="none"
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
|||||||
@@ -1,14 +1,19 @@
|
|||||||
import type { LogoProps } from '../icon'
|
import type { LogoProps } from '../icon'
|
||||||
import { iconVariants } from '../variants'
|
import { iconVariants } from '../variants'
|
||||||
|
|
||||||
export default function TheDockIcon({ className, color, ...props }: LogoProps) {
|
export default function TheDockIcon({
|
||||||
|
className,
|
||||||
|
color,
|
||||||
|
height = 30,
|
||||||
|
...props
|
||||||
|
}: LogoProps) {
|
||||||
const classNames = iconVariants({ className, color })
|
const classNames = iconVariants({ className, color })
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<svg
|
<svg
|
||||||
className={classNames}
|
className={classNames}
|
||||||
width="128"
|
width="128"
|
||||||
height="30"
|
height={height}
|
||||||
viewBox="0 0 128 30"
|
viewBox="0 0 128 30"
|
||||||
fill="none"
|
fill="none"
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import TheDockIcon from './TheDock'
|
|||||||
type HotelLogoProps = {
|
type HotelLogoProps = {
|
||||||
hotelId: string
|
hotelId: string
|
||||||
hotelType: string
|
hotelType: string
|
||||||
|
height?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
enum HotelTypeEnum {
|
enum HotelTypeEnum {
|
||||||
@@ -27,25 +28,29 @@ enum SignatureHotelEnum {
|
|||||||
TheDock = '796',
|
TheDock = '796',
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function HotelLogoIcon({ hotelId, hotelType }: HotelLogoProps) {
|
export default function HotelLogoIcon({
|
||||||
|
hotelId,
|
||||||
|
hotelType,
|
||||||
|
height,
|
||||||
|
}: HotelLogoProps) {
|
||||||
if (hotelType === HotelTypeEnum.ScandicGo) {
|
if (hotelType === HotelTypeEnum.ScandicGo) {
|
||||||
return <ScandicGoLogoIcon />
|
return <ScandicGoLogoIcon height={height} />
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (hotelId) {
|
switch (hotelId) {
|
||||||
case SignatureHotelEnum.Haymarket:
|
case SignatureHotelEnum.Haymarket:
|
||||||
return <HaymarketIcon />
|
return <HaymarketIcon height={height} />
|
||||||
case SignatureHotelEnum.HotelNorge:
|
case SignatureHotelEnum.HotelNorge:
|
||||||
return <HotelNorgeIcon />
|
return <HotelNorgeIcon height={height} />
|
||||||
case SignatureHotelEnum.DowntownCamper:
|
case SignatureHotelEnum.DowntownCamper:
|
||||||
return <DowntownCamperIcon />
|
return <DowntownCamperIcon height={height} />
|
||||||
case SignatureHotelEnum.GrandHotelOslo:
|
case SignatureHotelEnum.GrandHotelOslo:
|
||||||
return <GrandHotelOsloLogoIcon />
|
return <GrandHotelOsloLogoIcon height={height} />
|
||||||
case SignatureHotelEnum.Marski:
|
case SignatureHotelEnum.Marski:
|
||||||
return <MarskiLogoIcon />
|
return <MarskiLogoIcon height={height} />
|
||||||
case SignatureHotelEnum.TheDock:
|
case SignatureHotelEnum.TheDock:
|
||||||
return <TheDockIcon />
|
return <TheDockIcon height={height} />
|
||||||
default:
|
default:
|
||||||
return <ScandicLogoIcon color="Icon/Interactive/Accent" />
|
return <ScandicLogoIcon height={height} color="Icon/Interactive/Accent" />
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user