feat(SW-219): add support for content card in cards grid in content pages
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import SectionContainer from "@/components/Section/Container"
|
||||
import SectionHeader from "@/components/Section/Header"
|
||||
import Card from "@/components/TempDesignSystem/Card"
|
||||
import ContentCard from "@/components/TempDesignSystem/ContentCard"
|
||||
import Grids from "@/components/TempDesignSystem/Grids"
|
||||
import LoyaltyCard from "@/components/TempDesignSystem/LoyaltyCard"
|
||||
|
||||
@@ -22,17 +23,32 @@ export default function CardsGrid({
|
||||
{cards_grid.cards.map((card) => {
|
||||
switch (card.__typename) {
|
||||
case CardsGridEnum.Card: {
|
||||
return (
|
||||
<Card
|
||||
theme={cards_grid.theme || "one"}
|
||||
key={card.system.uid}
|
||||
scriptedTopTitle={card.scripted_top_title}
|
||||
heading={card.heading}
|
||||
bodyText={card.body_text}
|
||||
secondaryButton={card.secondaryButton}
|
||||
primaryButton={card.primaryButton}
|
||||
/>
|
||||
)
|
||||
if (card.isContentCard) {
|
||||
return (
|
||||
<ContentCard
|
||||
key={card.system.uid}
|
||||
title={card.heading || ""}
|
||||
description={card.body_text || ""}
|
||||
primaryButton={card.primaryButton}
|
||||
secondaryButton={card.secondaryButton}
|
||||
sidePeekButton={card.sidePeekButton}
|
||||
backgroundImage={card.background_image}
|
||||
style="default"
|
||||
/>
|
||||
)
|
||||
} else {
|
||||
return (
|
||||
<Card
|
||||
theme={cards_grid.theme || "one"}
|
||||
key={card.system.uid}
|
||||
scriptedTopTitle={card.scripted_top_title}
|
||||
heading={card.heading}
|
||||
bodyText={card.body_text}
|
||||
secondaryButton={card.secondaryButton}
|
||||
primaryButton={card.primaryButton}
|
||||
/>
|
||||
)
|
||||
}
|
||||
}
|
||||
case CardsGridEnum.LoyaltyCard:
|
||||
return (
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
import { env } from "@/env/server"
|
||||
import { serverClient } from "@/lib/trpc/server"
|
||||
|
||||
import ContentCard from "@/components/TempDesignSystem/ContentCard"
|
||||
|
||||
import { MOCK_FACILITIES } from "./Facilities/mockData"
|
||||
import { setActivityCard } from "./Facilities/utils"
|
||||
import DynamicMap from "./Map/DynamicMap"
|
||||
@@ -67,35 +65,6 @@ export default async function HotelPage() {
|
||||
</div>
|
||||
<Rooms rooms={roomCategories} />
|
||||
<Facilities facilities={facilities} />
|
||||
{/* NOTE: These are added here for testing. Remove before PR */}
|
||||
{/* Example of ContentCard with Button CTA's */}
|
||||
<ContentCard
|
||||
title="Special Offer"
|
||||
description="Mattis sit duis pulvinar ultricies auctor euismod. Augue mattis mauris at est iaculis pulvinar pulvinar."
|
||||
alwaysStack={true}
|
||||
primaryCTA={{
|
||||
label: "Book Now",
|
||||
href: "/booking",
|
||||
}}
|
||||
secondaryCTA={{
|
||||
label: "Learn More",
|
||||
href: "/offers",
|
||||
openInNewTab: true,
|
||||
}}
|
||||
backgroundImage="https://www.scandichotels.com/imageVault/publishedmedia/sixadhu91jy67aal2pla/Scandic_Downtown_Camper_cocktail_lounge_bar_the_ne.jpg"
|
||||
/>
|
||||
|
||||
{/* Example of ContentCard with SidePeek */}
|
||||
<ContentCard
|
||||
title="Explore Facilities"
|
||||
description="Mattis sit duis pulvinar ultricies auctor euismod. Augue mattis mauris at est iaculis pulvinar pulvinar."
|
||||
sidePeekCTA={{
|
||||
label: "View Facilities",
|
||||
onClick: true,
|
||||
}}
|
||||
style="default"
|
||||
backgroundImage="https://www.scandichotels.com/imageVault/publishedmedia/sixadhu91jy67aal2pla/Scandic_Downtown_Camper_cocktail_lounge_bar_the_ne.jpg"
|
||||
/>
|
||||
</main>
|
||||
{googleMapsApiKey ? (
|
||||
<>
|
||||
|
||||
@@ -16,9 +16,9 @@ import type { ContentCardProps } from "@/types/components/contentCard"
|
||||
export default function ContentCard({
|
||||
title,
|
||||
description,
|
||||
primaryCTA,
|
||||
secondaryCTA,
|
||||
sidePeekCTA,
|
||||
primaryButton,
|
||||
secondaryButton,
|
||||
sidePeekButton,
|
||||
backgroundImage,
|
||||
style = "default",
|
||||
alwaysStack = false,
|
||||
@@ -31,8 +31,8 @@ export default function ContentCard({
|
||||
{backgroundImage && (
|
||||
<div className={styles.imageContainer}>
|
||||
<Image
|
||||
src={backgroundImage}
|
||||
alt=""
|
||||
src={backgroundImage.url}
|
||||
alt={backgroundImage.meta?.alt || ""}
|
||||
className={styles.backgroundImage}
|
||||
width={399}
|
||||
height={201}
|
||||
@@ -44,21 +44,23 @@ export default function ContentCard({
|
||||
{title}
|
||||
</Subtitle>
|
||||
<Body color="black">{description}</Body>
|
||||
{sidePeekCTA ? (
|
||||
{!!sidePeekButton ? (
|
||||
<Button
|
||||
// onClick={sidePeekCTA.onClick}
|
||||
// onClick={() => {
|
||||
// // TODO: Implement sidePeek functionality once SW-341 is merged.
|
||||
// }}
|
||||
theme="base"
|
||||
variant="icon"
|
||||
intent="text"
|
||||
size="small"
|
||||
className={styles.sidePeekCTA}
|
||||
>
|
||||
{sidePeekCTA.label}
|
||||
{sidePeekButton.title}
|
||||
<ChevronRightIcon />
|
||||
</Button>
|
||||
) : (
|
||||
<div className={styles.ctaContainer}>
|
||||
{primaryCTA && (
|
||||
{primaryButton && (
|
||||
<Button
|
||||
asChild
|
||||
intent="primary"
|
||||
@@ -66,14 +68,14 @@ export default function ContentCard({
|
||||
className={styles.ctaButton}
|
||||
>
|
||||
<Link
|
||||
href={primaryCTA.href}
|
||||
target={primaryCTA.openInNewTab ? "_blank" : undefined}
|
||||
href={primaryButton.href}
|
||||
target={primaryButton.openInNewTab ? "_blank" : undefined}
|
||||
>
|
||||
{primaryCTA.label}
|
||||
{primaryButton.title}
|
||||
</Link>
|
||||
</Button>
|
||||
)}
|
||||
{secondaryCTA && (
|
||||
{secondaryButton && (
|
||||
<Button
|
||||
asChild
|
||||
intent="secondary"
|
||||
@@ -81,10 +83,10 @@ export default function ContentCard({
|
||||
className={styles.ctaButton}
|
||||
>
|
||||
<Link
|
||||
href={secondaryCTA.href}
|
||||
target={secondaryCTA.openInNewTab ? "_blank" : undefined}
|
||||
href={secondaryButton.href}
|
||||
target={secondaryButton.openInNewTab ? "_blank" : undefined}
|
||||
>
|
||||
{secondaryCTA.label}
|
||||
{secondaryButton.title}
|
||||
</Link>
|
||||
</Button>
|
||||
)}
|
||||
|
||||
@@ -1,30 +1,13 @@
|
||||
fragment CardBlock on Card {
|
||||
is_content_card
|
||||
heading
|
||||
body_text
|
||||
background_image
|
||||
scripted_top_title
|
||||
title
|
||||
has_secondary_button
|
||||
secondary_button {
|
||||
is_contentstack_link
|
||||
cta_text
|
||||
open_in_new_tab
|
||||
external_link {
|
||||
title
|
||||
href
|
||||
}
|
||||
linkConnection {
|
||||
edges {
|
||||
node {
|
||||
__typename
|
||||
...LoyaltyPageLink
|
||||
...ContentPageLink
|
||||
...AccountPageLink
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
has_primary_button
|
||||
has_secondary_button
|
||||
has_sidepeek_button
|
||||
primary_button {
|
||||
is_contentstack_link
|
||||
cta_text
|
||||
@@ -44,6 +27,28 @@ fragment CardBlock on Card {
|
||||
}
|
||||
}
|
||||
}
|
||||
secondary_button {
|
||||
is_contentstack_link
|
||||
cta_text
|
||||
open_in_new_tab
|
||||
external_link {
|
||||
title
|
||||
href
|
||||
}
|
||||
linkConnection {
|
||||
edges {
|
||||
node {
|
||||
__typename
|
||||
...LoyaltyPageLink
|
||||
...ContentPageLink
|
||||
...AccountPageLink
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
sidepeek_button {
|
||||
call_to_action_text
|
||||
}
|
||||
system {
|
||||
locale
|
||||
uid
|
||||
|
||||
@@ -68,6 +68,7 @@ export const contentPageDynamicContent = z.object({
|
||||
|
||||
export const cardBlock = z.object({
|
||||
__typename: z.literal(CardsGridEnum.Card),
|
||||
isContentCard: z.boolean(),
|
||||
heading: z.string().nullable(),
|
||||
body_text: z.string().nullable(),
|
||||
background_image: z.any(),
|
||||
@@ -88,6 +89,11 @@ export const cardBlock = z.object({
|
||||
isExternal: z.boolean(),
|
||||
})
|
||||
.optional(),
|
||||
sidePeekButton: z
|
||||
.object({
|
||||
title: z.string(),
|
||||
})
|
||||
.optional(),
|
||||
system: z.object({
|
||||
locale: z.nativeEnum(Lang),
|
||||
uid: z.string(),
|
||||
|
||||
@@ -102,6 +102,7 @@ export const contentPageQueryRouter = router({
|
||||
case CardsGridEnum.Card:
|
||||
return {
|
||||
...card,
|
||||
isContentCard: !!card.is_content_card,
|
||||
backgroundImage: makeImageVaultImage(
|
||||
card.background_image
|
||||
),
|
||||
@@ -111,6 +112,14 @@ export const contentPageQueryRouter = router({
|
||||
secondaryButton: card.has_secondary_button
|
||||
? makeButtonObject(card.secondary_button)
|
||||
: undefined,
|
||||
sidePeekButton:
|
||||
card.has_sidepeek_button ||
|
||||
!!card.sidepeek_button?.call_to_action_text
|
||||
? {
|
||||
title:
|
||||
card.sidepeek_button.call_to_action_text,
|
||||
}
|
||||
: undefined,
|
||||
}
|
||||
case CardsGridEnum.LoyaltyCard:
|
||||
return {
|
||||
|
||||
@@ -1,27 +1,21 @@
|
||||
import { VariantProps } from "class-variance-authority"
|
||||
|
||||
import { CardProps } from "@/components/TempDesignSystem/Card/card"
|
||||
import { contentCardVariants } from "@/components/TempDesignSystem/ContentCard/variants"
|
||||
|
||||
export interface CTA {
|
||||
label: string
|
||||
href: string
|
||||
openInNewTab?: boolean
|
||||
}
|
||||
import { ImageVaultAsset } from "@/types/components/imageVault"
|
||||
|
||||
export interface SidePeekCTA {
|
||||
label: string
|
||||
// onClick: () => void
|
||||
// TODO: change back to function.
|
||||
onClick: boolean
|
||||
export interface SidePeekButton {
|
||||
title: string
|
||||
}
|
||||
|
||||
export interface ContentCardProps
|
||||
extends VariantProps<typeof contentCardVariants> {
|
||||
title: string
|
||||
description: string
|
||||
primaryCTA?: CTA
|
||||
secondaryCTA?: CTA
|
||||
sidePeekCTA?: SidePeekCTA
|
||||
backgroundImage?: string
|
||||
primaryButton?: CardProps["primaryButton"]
|
||||
secondaryButton?: CardProps["secondaryButton"]
|
||||
sidePeekButton?: SidePeekButton
|
||||
backgroundImage?: ImageVaultAsset
|
||||
className?: string
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user