feat(SW-219): add support for content card in cards grid in content pages

This commit is contained in:
Chuma McPhoy
2024-09-12 18:01:32 +02:00
parent 3eb7e5f653
commit 24dc404370
7 changed files with 93 additions and 92 deletions

View File

@@ -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 (

View File

@@ -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 ? (
<>

View File

@@ -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>
)}

View File

@@ -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

View File

@@ -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(),

View File

@@ -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 {

View File

@@ -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
}