feat: add card grid component
This commit is contained in:
@@ -1,10 +1,7 @@
|
|||||||
.layout {
|
.layout {
|
||||||
--max-width: 101.4rem;
|
--max-width: 101.4rem;
|
||||||
--header-height: 4.5rem;
|
|
||||||
|
|
||||||
display: grid;
|
display: grid;
|
||||||
font-family: var(--ff-fira-sans);
|
font-family: var(--ff-fira-sans);
|
||||||
grid-template-rows: var(--header-height) auto 1fr;
|
|
||||||
min-height: 100dvh;
|
|
||||||
background-color: var(--Brand-Coffee-Subtle);
|
background-color: var(--Brand-Coffee-Subtle);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,20 +1,16 @@
|
|||||||
import { firaMono, firaSans } from "@/app/[lang]/(live)/fonts"
|
import { firaMono, firaSans } from "@/app/[lang]/(live)/fonts"
|
||||||
|
|
||||||
import Header from "@/components/MyPages/Header"
|
|
||||||
|
|
||||||
import styles from "./layout.module.css"
|
import styles from "./layout.module.css"
|
||||||
|
|
||||||
import type { MyPagesLayoutProps } from "@/types/components/myPages/layout"
|
import type { MyPagesLayoutProps } from "@/types/components/myPages/layout"
|
||||||
|
|
||||||
export default async function LoyaltyPagesLayout({
|
export default async function LoyaltyPagesLayout({
|
||||||
children,
|
children,
|
||||||
params,
|
|
||||||
}: React.PropsWithChildren<MyPagesLayoutProps>) {
|
}: React.PropsWithChildren<MyPagesLayoutProps>) {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={`${firaMono.variable} ${firaSans.variable} ${styles.layout}`}
|
className={`${firaMono.variable} ${firaSans.variable} ${styles.layout}`}
|
||||||
>
|
>
|
||||||
<Header lang={params.lang} />
|
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -9,8 +9,7 @@
|
|||||||
.blocks {
|
.blocks {
|
||||||
display: grid;
|
display: grid;
|
||||||
gap: 4.2rem;
|
gap: 4.2rem;
|
||||||
padding-left: 2rem;
|
padding: 1.6rem;
|
||||||
padding-right: 2rem;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (min-width: 950px) {
|
@media screen and (min-width: 950px) {
|
||||||
|
|||||||
@@ -1,14 +1,15 @@
|
|||||||
import { notFound } from "next/navigation"
|
import { notFound } from "next/navigation"
|
||||||
|
|
||||||
import { serverClient } from "@/lib/trpc/server"
|
import { serverClient } from "@/lib/trpc/server"
|
||||||
|
|
||||||
import MaxWidth from "@/components/MaxWidth"
|
|
||||||
import Sidebar from "@/components/Loyalty/Sidebar"
|
|
||||||
import { Blocks } from "@/components/Loyalty/Blocks"
|
import { Blocks } from "@/components/Loyalty/Blocks"
|
||||||
|
import Sidebar from "@/components/Loyalty/Sidebar"
|
||||||
import type { LangParams, PageArgs, UriParams } from "@/types/params"
|
import MaxWidth from "@/components/MaxWidth"
|
||||||
|
|
||||||
import styles from "./page.module.css"
|
import styles from "./page.module.css"
|
||||||
|
|
||||||
|
import type { LangParams, PageArgs, UriParams } from "@/types/params"
|
||||||
|
|
||||||
export default async function LoyaltyPage({
|
export default async function LoyaltyPage({
|
||||||
params,
|
params,
|
||||||
searchParams,
|
searchParams,
|
||||||
@@ -19,12 +20,12 @@ export default async function LoyaltyPage({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const loyaltyPage = await serverClient().contentstack.loyaltyPage.get({
|
const loyaltyPage = await serverClient().contentstack.loyaltyPage.get({
|
||||||
uri: searchParams.uri,
|
href: searchParams.uri,
|
||||||
lang: params.lang,
|
locale: params.lang,
|
||||||
})
|
})
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MaxWidth className={styles.content} tag="main">
|
<section className={styles.content}>
|
||||||
<aside>
|
<aside>
|
||||||
{loyaltyPage.sidebar
|
{loyaltyPage.sidebar
|
||||||
? loyaltyPage.sidebar.map((block, i) => (
|
? loyaltyPage.sidebar.map((block, i) => (
|
||||||
@@ -32,10 +33,10 @@ export default async function LoyaltyPage({
|
|||||||
))
|
))
|
||||||
: null}
|
: null}
|
||||||
</aside>
|
</aside>
|
||||||
<section className={styles.blocks}>
|
<MaxWidth className={styles.blocks} tag="main">
|
||||||
<Blocks blocks={loyaltyPage.blocks} />
|
<Blocks blocks={loyaltyPage.blocks} />
|
||||||
</section>
|
</MaxWidth>
|
||||||
</MaxWidth>
|
</section>
|
||||||
)
|
)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
return notFound()
|
return notFound()
|
||||||
|
|||||||
28
components/Loyalty/Blocks/CardGrid/cardGrid.module.css
Normal file
28
components/Loyalty/Blocks/CardGrid/cardGrid.module.css
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
.container {
|
||||||
|
display: grid;
|
||||||
|
gap: 2.4rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subtitle {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.titleContainer {
|
||||||
|
display: grid;
|
||||||
|
gap: 0.8rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cardContainer {
|
||||||
|
display: grid;
|
||||||
|
gap: 1.6rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (min-width: 950px) {
|
||||||
|
.cardContainer {
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cardWrapper:last-child {
|
||||||
|
grid-column: span 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
50
components/Loyalty/Blocks/CardGrid/index.tsx
Normal file
50
components/Loyalty/Blocks/CardGrid/index.tsx
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
import { _ } from "@/lib/translation"
|
||||||
|
|
||||||
|
import Card from "@/components/TempDesignSystem/Card"
|
||||||
|
import Title from "@/components/Title"
|
||||||
|
|
||||||
|
import styles from "./cardGrid.module.css"
|
||||||
|
|
||||||
|
import { CardGridProps, CardProps } from "@/types/components/loyalty/blocks"
|
||||||
|
|
||||||
|
export default function CardGrid({ card_grid }: CardGridProps) {
|
||||||
|
return (
|
||||||
|
<section className={styles.container}>
|
||||||
|
<header className={styles.titleContainer}>
|
||||||
|
<Title as="h3" level="h2" weight="semiBold" uppercase>
|
||||||
|
{card_grid.title}
|
||||||
|
</Title>
|
||||||
|
{card_grid.subtitle ? (
|
||||||
|
<Title
|
||||||
|
as="h5"
|
||||||
|
level="h3"
|
||||||
|
weight="regular"
|
||||||
|
className={styles.subtitle}
|
||||||
|
>
|
||||||
|
{card_grid.subtitle}
|
||||||
|
</Title>
|
||||||
|
) : null}
|
||||||
|
</header>
|
||||||
|
<div className={styles.cardContainer}>
|
||||||
|
{card_grid.cards.map((card, i) => (
|
||||||
|
<CardWrapper key={`${card.title}+${i}`} card={card} />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function CardWrapper({ card }: CardProps) {
|
||||||
|
const link = card.referenceConnection.edges.length
|
||||||
|
? {
|
||||||
|
href: card.referenceConnection.edges[0].node.url,
|
||||||
|
title: _("Read more"),
|
||||||
|
}
|
||||||
|
: undefined
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={styles.cardWrapper}>
|
||||||
|
<Card subtitle={card.subtitle} title={card.title} link={link} />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
.container {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
height: 37rem;
|
||||||
|
border-radius: 1.6rem;
|
||||||
|
background-color: var(--Base-Fill-Normal);
|
||||||
|
text-align: center;
|
||||||
|
margin-right: 1.6rem;
|
||||||
|
}
|
||||||
@@ -1,3 +1,13 @@
|
|||||||
|
import Title from "@/components/Title"
|
||||||
|
|
||||||
|
import styles from "./howItWorks.module.css"
|
||||||
|
|
||||||
export default function HowItWorks() {
|
export default function HowItWorks() {
|
||||||
return <div></div>
|
return (
|
||||||
|
<div className={styles.container}>
|
||||||
|
<Title level="h3" uppercase>
|
||||||
|
How it works Placeholder
|
||||||
|
</Title>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,26 +1,50 @@
|
|||||||
|
import { Check } from "react-feather"
|
||||||
|
|
||||||
|
import { _ } from "@/lib/translation"
|
||||||
import { serverClient } from "@/lib/trpc/server"
|
import { serverClient } from "@/lib/trpc/server"
|
||||||
|
|
||||||
|
import Image from "@/components/Image"
|
||||||
|
import Button from "@/components/TempDesignSystem/Button"
|
||||||
|
import Link from "@/components/TempDesignSystem/Link"
|
||||||
|
import Title from "@/components/Title"
|
||||||
|
|
||||||
|
import styles from "./loyaltyLevels.module.css"
|
||||||
|
|
||||||
|
import { LevelCardProps } from "@/types/components/loyalty/blocks"
|
||||||
|
|
||||||
export default async function LoyaltyLevels() {
|
export default async function LoyaltyLevels() {
|
||||||
const data = await serverClient().loyalty.levels.all()
|
const data = await serverClient().loyalty.levels.all()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<section className={styles.container}>
|
||||||
{data.map((level) => (
|
<div className={styles.cardContainer}>
|
||||||
<LevelCard key={level.tier} level={level} />
|
{data.map((level) => (
|
||||||
|
<LevelCard key={level.tier} level={level} />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<div className={styles.buttonContainer}>
|
||||||
|
<Button intent="primary" asChild>
|
||||||
|
<Link href={"/compare-all-levels"}>{_("Compare all levels")}</Link>
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function LevelCard({ level }: LevelCardProps) {
|
||||||
|
return (
|
||||||
|
<div className={styles.card}>
|
||||||
|
<Title level="h4">{level.tier}</Title>
|
||||||
|
<Image src={level.logo} alt={level.name} width={140} height={54} />
|
||||||
|
<p className={styles.qualifications}>
|
||||||
|
{level.requiredPoints} {_("or")} {level.requiredNights} {_("nights")}
|
||||||
|
</p>
|
||||||
|
{level.topBenefits.map((benefit) => (
|
||||||
|
<p key={benefit} className={styles.benefits}>
|
||||||
|
<Check className={styles.icon} />
|
||||||
|
{benefit}
|
||||||
|
</p>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
type LevelCardProps = {
|
|
||||||
level: {
|
|
||||||
tier: number
|
|
||||||
name: string
|
|
||||||
requiredPoints: number
|
|
||||||
requiredNights: string
|
|
||||||
topBenefits: string[]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function LevelCard({ level }: LevelCardProps) {
|
|
||||||
return <div></div>
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -0,0 +1,83 @@
|
|||||||
|
.container {
|
||||||
|
display: grid;
|
||||||
|
gap: 2.4rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.buttonContainer {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cardContainer {
|
||||||
|
display: flex;
|
||||||
|
gap: 0.8rem;
|
||||||
|
overflow-x: auto;
|
||||||
|
padding-right: 1.6rem;
|
||||||
|
margin-right: -1.6rem;
|
||||||
|
/* Hide scrollbar IE and Edge */
|
||||||
|
-ms-overflow-style: none;
|
||||||
|
/* Hide Scrollbar Firefox */
|
||||||
|
scrollbar-width: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
height: 37rem;
|
||||||
|
min-width: 32rem;
|
||||||
|
padding: 4rem 1rem;
|
||||||
|
background-color: var(--Base-Fill-Normal);
|
||||||
|
border-radius: 1.6rem;
|
||||||
|
gap: 1.8rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.qualifications {
|
||||||
|
margin: 0;
|
||||||
|
font-size: var(--typography-Body-Bold-fontSize);
|
||||||
|
line-height: var(--typography-Body-Bold-lineHeight);
|
||||||
|
/* font-weight: var(--typography-Body-Bold-fontWeight); -- Tokens not parsable*/
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.benefits {
|
||||||
|
font-family: var(--fira-sans);
|
||||||
|
font-size: var(--typography-Body-Regular-fontSize);
|
||||||
|
line-height: var(--typography-Body-Regular-lineHeight);
|
||||||
|
margin: 0;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
font-family: var(--fira-sans);
|
||||||
|
position: relative;
|
||||||
|
top: 0.3rem;
|
||||||
|
height: 1.4rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (min-width: 950px) {
|
||||||
|
.container {
|
||||||
|
gap: 3.2rem;
|
||||||
|
}
|
||||||
|
.cardContainer {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(
|
||||||
|
12,
|
||||||
|
auto
|
||||||
|
); /* Three columns in the first row */
|
||||||
|
padding-right: 0;
|
||||||
|
margin-right: 0rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
min-width: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card:nth-child(-n + 3) {
|
||||||
|
grid-column: span 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card:nth-last-child(-n + 4) {
|
||||||
|
grid-column: span 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
.container {
|
||||||
|
display: grid;
|
||||||
|
gap: 2.4rem;
|
||||||
|
overflow: hidden;
|
||||||
|
margin-right: -1.6rem;
|
||||||
|
padding-right: 1.6rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.titleContainer {
|
||||||
|
display: grid;
|
||||||
|
grid-template-areas: "title link";
|
||||||
|
grid-template-columns: 1fr max-content;
|
||||||
|
padding-bottom: 0.8rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
grid-area: title;
|
||||||
|
}
|
||||||
|
|
||||||
|
.link {
|
||||||
|
grid-area: link;
|
||||||
|
font-size: var(--typography-Body-Underlined-fontSize);
|
||||||
|
color: var(--some-black-color, #000);
|
||||||
|
}
|
||||||
|
|
||||||
|
.subtitle {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,18 +1,27 @@
|
|||||||
|
import Link from "@/components/TempDesignSystem/Link"
|
||||||
import Title from "@/components/Title"
|
import Title from "@/components/Title"
|
||||||
|
|
||||||
|
import HowItWorks from "./HowItWorks"
|
||||||
|
import LoyaltyLevels from "./LoyaltyLevels"
|
||||||
|
import OverviewTable from "./OverviewTable"
|
||||||
|
|
||||||
|
import styles from "./dynamicContent.module.css"
|
||||||
|
|
||||||
|
import { DynamicContentProps } from "@/types/components/loyalty/blocks"
|
||||||
import {
|
import {
|
||||||
DynamicContentProps,
|
|
||||||
LoyaltyComponent,
|
LoyaltyComponent,
|
||||||
LoyaltyComponentEnum,
|
LoyaltyComponentEnum,
|
||||||
} from "@/types/components/loyalty/blocks"
|
} from "@/types/requests/loyaltyPage"
|
||||||
|
|
||||||
function DynamicComponentBlock({ component }: { component: LoyaltyComponent }) {
|
function DynamicComponentBlock({ component }: { component: LoyaltyComponent }) {
|
||||||
switch (component) {
|
switch (component) {
|
||||||
case LoyaltyComponentEnum.how_it_works:
|
case LoyaltyComponentEnum.how_it_works:
|
||||||
return <p>How it works</p>
|
return <HowItWorks />
|
||||||
case LoyaltyComponentEnum.loyalty_levels:
|
case LoyaltyComponentEnum.loyalty_levels:
|
||||||
return <p>loyalty_levels</p>
|
return <LoyaltyLevels />
|
||||||
case LoyaltyComponentEnum.overview_table:
|
case LoyaltyComponentEnum.overview_table:
|
||||||
return <p>overview_table</p>
|
// TODO: IMPLEMENT OVERVIEW TABLE!
|
||||||
|
return <OverviewTable />
|
||||||
default:
|
default:
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
@@ -21,14 +30,44 @@ function DynamicComponentBlock({ component }: { component: LoyaltyComponent }) {
|
|||||||
export default function DynamicContent({
|
export default function DynamicContent({
|
||||||
dynamicContent,
|
dynamicContent,
|
||||||
}: DynamicContentProps) {
|
}: DynamicContentProps) {
|
||||||
|
const link = dynamicContent.link.pageConnection.edges.length
|
||||||
|
? dynamicContent.link.pageConnection.edges[0].node.url
|
||||||
|
: null
|
||||||
return (
|
return (
|
||||||
<section>
|
<section className={styles.container}>
|
||||||
<header>
|
<header>
|
||||||
<Title level="h3">{dynamicContent.title}</Title>
|
<div className={styles.titleContainer}>
|
||||||
{dynamicContent.preamble ? <p>{dynamicContent.preamble}</p> : null}
|
{dynamicContent.title && (
|
||||||
{dynamicContent.link ? <></> : null}
|
<Title
|
||||||
|
as="h3"
|
||||||
|
level="h2"
|
||||||
|
className={styles.title}
|
||||||
|
weight="semiBold"
|
||||||
|
uppercase
|
||||||
|
>
|
||||||
|
{dynamicContent.title}
|
||||||
|
</Title>
|
||||||
|
)}
|
||||||
|
{link && (
|
||||||
|
<Link className={styles.link} href={link}>
|
||||||
|
{dynamicContent.link.text}
|
||||||
|
</Link>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
{dynamicContent.subtitle && (
|
||||||
|
<Title
|
||||||
|
as="h5"
|
||||||
|
level="h3"
|
||||||
|
weight="regular"
|
||||||
|
className={styles.subtitle}
|
||||||
|
>
|
||||||
|
{dynamicContent.subtitle}
|
||||||
|
</Title>
|
||||||
|
)}
|
||||||
</header>
|
</header>
|
||||||
<DynamicComponentBlock component={dynamicContent.component} />
|
<div>
|
||||||
|
<DynamicComponentBlock component={dynamicContent.component} />
|
||||||
|
</div>
|
||||||
</section>
|
</section>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
import JsonToHtml from "@/components/JsonToHtml"
|
import JsonToHtml from "@/components/JsonToHtml"
|
||||||
import DynamicContentBlock from "@/components/Loyalty/Blocks/DynamicContent"
|
import DynamicContentBlock from "@/components/Loyalty/Blocks/DynamicContent"
|
||||||
|
|
||||||
|
import CardGrid from "./CardGrid"
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Blocks as BlocksType,
|
Blocks as BlocksType,
|
||||||
LoyaltyBlocksTypenameEnum,
|
LoyaltyBlocksTypenameEnum,
|
||||||
@@ -10,7 +12,7 @@ export function Blocks({ blocks }: { blocks: BlocksType[] }) {
|
|||||||
return blocks.map((block) => {
|
return blocks.map((block) => {
|
||||||
switch (block.__typename) {
|
switch (block.__typename) {
|
||||||
case LoyaltyBlocksTypenameEnum.LoyaltyPageBlocksCardGrid:
|
case LoyaltyBlocksTypenameEnum.LoyaltyPageBlocksCardGrid:
|
||||||
return <p>Cards</p>
|
return <CardGrid card_grid={block.card_grid} />
|
||||||
case LoyaltyBlocksTypenameEnum.LoyaltyPageBlocksContent:
|
case LoyaltyBlocksTypenameEnum.LoyaltyPageBlocksContent:
|
||||||
return (
|
return (
|
||||||
<JsonToHtml
|
<JsonToHtml
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
import Title from "@/components/Title"
|
import { _ } from "@/lib/translation"
|
||||||
import Contact from "./Contact"
|
|
||||||
|
import Image from "@/components/Image"
|
||||||
import Button from "@/components/TempDesignSystem/Button"
|
import Button from "@/components/TempDesignSystem/Button"
|
||||||
import Link from "@/components/TempDesignSystem/Link"
|
import Link from "@/components/TempDesignSystem/Link"
|
||||||
import Image from "@/components/Image"
|
import Title from "@/components/Title"
|
||||||
|
|
||||||
|
import Contact from "./Contact"
|
||||||
|
|
||||||
import styles from "./joinLoyalty.module.css"
|
import styles from "./joinLoyalty.module.css"
|
||||||
|
|
||||||
@@ -26,12 +29,12 @@ export default function JoinLoyaltyContact({
|
|||||||
/>
|
/>
|
||||||
{block.preamble && <p className={styles.preamble}>{block.preamble}</p>}
|
{block.preamble && <p className={styles.preamble}>{block.preamble}</p>}
|
||||||
<Button intent="primary">
|
<Button intent="primary">
|
||||||
<span>{block.login_button_text}</span>
|
<span>{_("Join Scandic Friends")}</span>
|
||||||
</Button>
|
</Button>
|
||||||
<div className={styles.linkContainer}>
|
<div className={styles.linkContainer}>
|
||||||
<Link href="/login" className={styles.logoutLink}>
|
<Link href="/login" className={styles.logoutLink}>
|
||||||
Already a friend? <br />
|
{_("Already a friend?")} <br />
|
||||||
Click here to log in
|
{_("Click here to log in")}
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
display: grid;
|
display: grid;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
background-color: var(--Base-Background-Elevated);
|
background-color: var(--Base-Background-Elevated);
|
||||||
border-radius: 32px 4px 4px 32px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.wrapper {
|
.wrapper {
|
||||||
@@ -10,7 +9,7 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 2rem;
|
gap: 2rem;
|
||||||
padding: 4rem 2rem;
|
padding: 6rem 2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.preamble {
|
.preamble {
|
||||||
@@ -37,6 +36,10 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (min-width: 950px) {
|
@media screen and (min-width: 950px) {
|
||||||
|
.container {
|
||||||
|
border-radius: 32px 4px 4px 32px;
|
||||||
|
}
|
||||||
|
|
||||||
.wrapper {
|
.wrapper {
|
||||||
gap: 3rem;
|
gap: 3rem;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import JsonToHtml from "@/components/JsonToHtml"
|
import JsonToHtml from "@/components/JsonToHtml"
|
||||||
|
|
||||||
import JoinLoyaltyContact from "./JoinLoyalty"
|
import JoinLoyaltyContact from "./JoinLoyalty"
|
||||||
|
|
||||||
import { Sidebar, SidebarTypenameEnum } from "@/types/requests/loyaltyPage"
|
import { Sidebar, SidebarTypenameEnum } from "@/types/requests/loyaltyPage"
|
||||||
|
|||||||
15
components/TempDesignSystem/Card/card.module.css
Normal file
15
components/TempDesignSystem/Card/card.module.css
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
.linkCard {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
height: 37rem;
|
||||||
|
width: 100%;
|
||||||
|
margin-right: 1.6rem;
|
||||||
|
border-radius: 1.6rem;
|
||||||
|
gap: 1rem;
|
||||||
|
padding: 1.6rem;
|
||||||
|
|
||||||
|
background-color: var(--Base-Fill-Normal);
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
9
components/TempDesignSystem/Card/card.ts
Normal file
9
components/TempDesignSystem/Card/card.ts
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
export type CardProps = {
|
||||||
|
link?: {
|
||||||
|
href: string
|
||||||
|
title: string
|
||||||
|
}
|
||||||
|
title?: string
|
||||||
|
subtitle?: string
|
||||||
|
openInNewTab?: boolean
|
||||||
|
}
|
||||||
38
components/TempDesignSystem/Card/index.tsx
Normal file
38
components/TempDesignSystem/Card/index.tsx
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
import { _ } from "@/lib/translation"
|
||||||
|
|
||||||
|
import Title from "@/components/Title"
|
||||||
|
|
||||||
|
import Button from "../Button"
|
||||||
|
import Link from "../Link"
|
||||||
|
import { CardProps } from "./card"
|
||||||
|
|
||||||
|
import styles from "./card.module.css"
|
||||||
|
|
||||||
|
export default function Card({
|
||||||
|
link,
|
||||||
|
subtitle,
|
||||||
|
title,
|
||||||
|
openInNewTab = false,
|
||||||
|
}: CardProps) {
|
||||||
|
return (
|
||||||
|
<div className={styles.linkCard}>
|
||||||
|
{title ? (
|
||||||
|
<Title level="h3" weight="semiBold">
|
||||||
|
{title}
|
||||||
|
</Title>
|
||||||
|
) : null}
|
||||||
|
{subtitle ? (
|
||||||
|
<Title level="h5" weight="light">
|
||||||
|
{subtitle}
|
||||||
|
</Title>
|
||||||
|
) : null}
|
||||||
|
{link ? (
|
||||||
|
<Button asChild intent="primary">
|
||||||
|
<Link href={link.href} target={openInNewTab ? "_blank" : undefined}>
|
||||||
|
{link.title}
|
||||||
|
</Link>
|
||||||
|
</Button>
|
||||||
|
) : null}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
17
lib/graphql/Query/ContentTypeUid.graphql
Normal file
17
lib/graphql/Query/ContentTypeUid.graphql
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
query GetContentTypeUid($locale: String!, $url: String!) {
|
||||||
|
all_content_page(where: { url: $url, locale: $locale }) {
|
||||||
|
items {
|
||||||
|
__typename
|
||||||
|
}
|
||||||
|
}
|
||||||
|
all_current_blocks_page(where: { url: $url, locale: $locale }) {
|
||||||
|
items {
|
||||||
|
__typename
|
||||||
|
}
|
||||||
|
}
|
||||||
|
all_loyalty_page(where: { url: $url, locale: $locale }) {
|
||||||
|
items {
|
||||||
|
__typename
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,7 +11,7 @@ query GetLoyaltyPage($locale: String!, $url: String!) {
|
|||||||
__typename
|
__typename
|
||||||
dynamic_content {
|
dynamic_content {
|
||||||
title
|
title
|
||||||
preamble
|
subtitle
|
||||||
component
|
component
|
||||||
link {
|
link {
|
||||||
text
|
text
|
||||||
@@ -29,8 +29,8 @@ query GetLoyaltyPage($locale: String!, $url: String!) {
|
|||||||
... on LoyaltyPageBlocksCardGrid {
|
... on LoyaltyPageBlocksCardGrid {
|
||||||
__typename
|
__typename
|
||||||
card_grid {
|
card_grid {
|
||||||
heading
|
title
|
||||||
preamble
|
subtitle
|
||||||
cards {
|
cards {
|
||||||
referenceConnection {
|
referenceConnection {
|
||||||
edges {
|
edges {
|
||||||
@@ -42,8 +42,8 @@ query GetLoyaltyPage($locale: String!, $url: String!) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
heading
|
title
|
||||||
preamble
|
subtitle
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,19 +1,70 @@
|
|||||||
|
import { DocumentNode } from "graphql"
|
||||||
import { NextResponse } from "next/server"
|
import { NextResponse } from "next/server"
|
||||||
|
|
||||||
import { findLang } from "@/constants/languages"
|
import { findLang } from "@/constants/languages"
|
||||||
|
import { env } from "@/env/server"
|
||||||
|
import GetContentTypeUid from "@/lib/graphql/Query/ContentTypeUid.graphql"
|
||||||
|
|
||||||
import type { NextMiddleware } from "next/server"
|
import type { NextMiddleware } from "next/server"
|
||||||
|
|
||||||
import { MiddlewareMatcher } from "@/types/middleware"
|
import { MiddlewareMatcher } from "@/types/middleware"
|
||||||
|
|
||||||
|
enum PageTypeEnum {
|
||||||
|
CurrentBlocksPage = "CurrentBlocksPage",
|
||||||
|
LoyaltyPage = "LoyaltyPage",
|
||||||
|
ContentPage = "contentPage",
|
||||||
|
}
|
||||||
|
|
||||||
|
type GetContentTypeUidType = {
|
||||||
|
all_content_page: {
|
||||||
|
items: {
|
||||||
|
__typename: PageTypeEnum.ContentPage
|
||||||
|
}[]
|
||||||
|
}
|
||||||
|
all_loyalty_page: {
|
||||||
|
items: {
|
||||||
|
__typename: PageTypeEnum.LoyaltyPage
|
||||||
|
}[]
|
||||||
|
}
|
||||||
|
all_current_blocks_page: {
|
||||||
|
items: {
|
||||||
|
__typename?: PageTypeEnum.CurrentBlocksPage
|
||||||
|
}[]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type PageType = keyof typeof PageTypeEnum
|
||||||
|
|
||||||
export const middleware: NextMiddleware = async (request) => {
|
export const middleware: NextMiddleware = async (request) => {
|
||||||
const { nextUrl } = request
|
const { nextUrl } = request
|
||||||
const lang = findLang(nextUrl.pathname)
|
const lang = findLang(nextUrl.pathname)
|
||||||
|
|
||||||
const contentType = "loyaltyPage"
|
|
||||||
const pathNameWithoutLang = nextUrl.pathname.replace(`/${lang}`, "")
|
const pathNameWithoutLang = nextUrl.pathname.replace(`/${lang}`, "")
|
||||||
const searchParams = new URLSearchParams(request.nextUrl.searchParams)
|
const searchParams = new URLSearchParams(request.nextUrl.searchParams)
|
||||||
|
|
||||||
|
const print = (await import("graphql/language/printer")).print
|
||||||
|
const result = await fetch(env.CMS_URL, {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
access_token: env.CMS_ACCESS_TOKEN,
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
query: print(GetContentTypeUid as DocumentNode),
|
||||||
|
variables: {
|
||||||
|
locale: lang,
|
||||||
|
url: pathNameWithoutLang,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
|
||||||
|
const pageTypeData = await result.json()
|
||||||
|
const pageType = pageTypeData.data as GetContentTypeUidType
|
||||||
|
|
||||||
|
const contentType = Object.values(pageType)
|
||||||
|
.map((val) => val.items[0])
|
||||||
|
.find((item) => item?.__typename)?.__typename
|
||||||
|
|
||||||
if (request.nextUrl.pathname.includes("preview")) {
|
if (request.nextUrl.pathname.includes("preview")) {
|
||||||
searchParams.set("uri", pathNameWithoutLang.replace("/preview", ""))
|
searchParams.set("uri", pathNameWithoutLang.replace("/preview", ""))
|
||||||
return NextResponse.rewrite(
|
return NextResponse.rewrite(
|
||||||
@@ -23,14 +74,14 @@ export const middleware: NextMiddleware = async (request) => {
|
|||||||
|
|
||||||
searchParams.set("uri", pathNameWithoutLang)
|
searchParams.set("uri", pathNameWithoutLang)
|
||||||
switch (contentType) {
|
switch (contentType) {
|
||||||
// case "currentContentPage":
|
case PageTypeEnum.CurrentBlocksPage:
|
||||||
// return NextResponse.rewrite(
|
return NextResponse.rewrite(
|
||||||
// new URL(
|
new URL(
|
||||||
// `/${lang}/current-content-page?${searchParams.toString()}`,
|
`/${lang}/current-content-page?${searchParams.toString()}`,
|
||||||
// nextUrl
|
nextUrl
|
||||||
// )
|
)
|
||||||
// )
|
)
|
||||||
case "loyaltyPage":
|
case PageTypeEnum.LoyaltyPage:
|
||||||
return NextResponse.rewrite(
|
return NextResponse.rewrite(
|
||||||
new URL(`/${lang}/loyalty-page?${searchParams.toString()}`, nextUrl)
|
new URL(`/${lang}/loyalty-page?${searchParams.toString()}`, nextUrl)
|
||||||
)
|
)
|
||||||
|
|||||||
BIN
public/_static/icons/new-friend.png
Normal file
BIN
public/_static/icons/new-friend.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.5 KiB |
@@ -1,10 +1,11 @@
|
|||||||
|
import { GetMyPagesBreadcrumbs } from "@/lib/graphql/Query/BreadcrumbsMyPages.graphql"
|
||||||
|
import { request } from "@/lib/graphql/request"
|
||||||
import { badRequestError, internalServerError } from "@/server/errors/trpc"
|
import { badRequestError, internalServerError } from "@/server/errors/trpc"
|
||||||
import { validateBreadcrumbsConstenstackSchema } from "./output"
|
|
||||||
import { publicProcedure, router } from "@/server/trpc"
|
import { publicProcedure, router } from "@/server/trpc"
|
||||||
|
|
||||||
import { request } from "@/lib/graphql/request"
|
|
||||||
import { GetMyPagesBreadcrumbs } from "@/lib/graphql/Query/BreadcrumbsMyPages.graphql"
|
|
||||||
import { getBreadcrumbsInput } from "./input"
|
import { getBreadcrumbsInput } from "./input"
|
||||||
|
import { validateBreadcrumbsConstenstackSchema } from "./output"
|
||||||
|
|
||||||
import { GetMyPagesBreadcrumbsData } from "@/types/requests/myPages/breadcrumbs"
|
import { GetMyPagesBreadcrumbsData } from "@/types/requests/myPages/breadcrumbs"
|
||||||
|
|
||||||
export const breadcrumbsQueryRouter = router({
|
export const breadcrumbsQueryRouter = router({
|
||||||
|
|||||||
10
server/routers/contentstack/loyaltyPage/input.ts
Normal file
10
server/routers/contentstack/loyaltyPage/input.ts
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
import { z } from "zod"
|
||||||
|
|
||||||
|
import { Lang } from "@/constants/languages"
|
||||||
|
|
||||||
|
const langs = Object.keys(Lang) as [keyof typeof Lang]
|
||||||
|
|
||||||
|
export const getLoyaltyPageInput = z.object({
|
||||||
|
href: z.string().min(1, { message: "href is required" }),
|
||||||
|
locale: z.enum(langs),
|
||||||
|
})
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
import { allLevels } from "./temp"
|
|
||||||
import { protectedProcedure, publicProcedure, router } from "@/server/trpc"
|
import { protectedProcedure, publicProcedure, router } from "@/server/trpc"
|
||||||
|
|
||||||
|
import { allLevels } from "./temp"
|
||||||
|
|
||||||
function fakingRequest<T>(payload: T): Promise<T> {
|
function fakingRequest<T>(payload: T): Promise<T> {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ export const allLevels = [
|
|||||||
"Always best price",
|
"Always best price",
|
||||||
"Book reward nights with points",
|
"Book reward nights with points",
|
||||||
],
|
],
|
||||||
|
logo: "/_static/icons/new-friend.png",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
tier: 2,
|
tier: 2,
|
||||||
@@ -20,6 +21,7 @@ export const allLevels = [
|
|||||||
"Always best price",
|
"Always best price",
|
||||||
"Book reward nights with points",
|
"Book reward nights with points",
|
||||||
],
|
],
|
||||||
|
logo: "/_static/icons/new-friend.png",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
tier: 3,
|
tier: 3,
|
||||||
@@ -31,6 +33,7 @@ export const allLevels = [
|
|||||||
"Always best price",
|
"Always best price",
|
||||||
"Book reward nights with points",
|
"Book reward nights with points",
|
||||||
],
|
],
|
||||||
|
logo: "/_static/icons/new-friend.png",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
tier: 4,
|
tier: 4,
|
||||||
@@ -42,6 +45,7 @@ export const allLevels = [
|
|||||||
"Always best price",
|
"Always best price",
|
||||||
"Book reward nights with points",
|
"Book reward nights with points",
|
||||||
],
|
],
|
||||||
|
logo: "/_static/icons/new-friend.png",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
tier: 5,
|
tier: 5,
|
||||||
@@ -53,6 +57,7 @@ export const allLevels = [
|
|||||||
"Always best price",
|
"Always best price",
|
||||||
"Book reward nights with points",
|
"Book reward nights with points",
|
||||||
],
|
],
|
||||||
|
logo: "/_static/icons/new-friend.png",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
tier: 6,
|
tier: 6,
|
||||||
@@ -64,5 +69,18 @@ export const allLevels = [
|
|||||||
"Always best price",
|
"Always best price",
|
||||||
"Book reward nights with points",
|
"Book reward nights with points",
|
||||||
],
|
],
|
||||||
|
logo: "/_static/icons/new-friend.png",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
tier: 7,
|
||||||
|
name: "New Friend",
|
||||||
|
requiredPoints: 50000,
|
||||||
|
requiredNights: "X",
|
||||||
|
topBenefits: [
|
||||||
|
"15% on food on weekends",
|
||||||
|
"Always best price",
|
||||||
|
"Book reward nights with points",
|
||||||
|
],
|
||||||
|
logo: "/_static/icons/new-friend.png",
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,47 +1,46 @@
|
|||||||
import { Embeds } from "@/types/requests/embeds"
|
import { Embeds } from "@/types/requests/embeds"
|
||||||
|
import { DynamicContentBlock } from "@/types/requests/loyaltyPage"
|
||||||
import { PageLink } from "@/types/requests/myPages/navigation"
|
import { PageLink } from "@/types/requests/myPages/navigation"
|
||||||
import { Edges } from "@/types/requests/utils/edges"
|
import { Edges } from "@/types/requests/utils/edges"
|
||||||
import { RTEDocument } from "@/types/rte/node"
|
import { RTEDocument } from "@/types/rte/node"
|
||||||
|
|
||||||
export enum LoyaltyComponentEnum {
|
|
||||||
loyalty_levels = "loyalty_levels",
|
|
||||||
how_it_works = "how_it_works",
|
|
||||||
overview_table = "overview_table",
|
|
||||||
}
|
|
||||||
|
|
||||||
export type LoyaltyComponent = keyof typeof LoyaltyComponentEnum
|
|
||||||
|
|
||||||
export type DynamicContentBlock = {
|
|
||||||
dynamic_content: {
|
|
||||||
title: string
|
|
||||||
preamble?: string
|
|
||||||
component: LoyaltyComponent
|
|
||||||
link: {
|
|
||||||
text?: string
|
|
||||||
page: Edges<PageLink>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export type DynamicContentProps = {
|
export type DynamicContentProps = {
|
||||||
dynamicContent: DynamicContentBlock["dynamic_content"]
|
dynamicContent: DynamicContentBlock["dynamic_content"]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Card = {
|
||||||
|
referenceConnection: Edges<PageLink>
|
||||||
|
title?: string
|
||||||
|
subtitle?: string
|
||||||
|
open_in_new_tab: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CardProps = { card: Card }
|
||||||
|
|
||||||
export type CardGrid = {
|
export type CardGrid = {
|
||||||
card_grid: {
|
card_grid: {
|
||||||
heading: string
|
title?: string
|
||||||
preamble: string
|
subtitle?: string
|
||||||
cards: {
|
cards: Card[]
|
||||||
referenceConnection: Edges<PageLink>
|
|
||||||
heading: string
|
|
||||||
preamble: string
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type CardGridProps = CardGrid
|
||||||
|
|
||||||
export type Content = {
|
export type Content = {
|
||||||
content: {
|
content: {
|
||||||
embedded_itemsConnection: Edges<Embeds>
|
embedded_itemsConnection: Edges<Embeds>
|
||||||
json: RTEDocument
|
json: RTEDocument
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type LevelCardProps = {
|
||||||
|
level: {
|
||||||
|
tier: number
|
||||||
|
name: string
|
||||||
|
requiredPoints: number
|
||||||
|
requiredNights: string
|
||||||
|
topBenefits: string[]
|
||||||
|
logo: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { ContactFields } from "@/types/requests/contactConfig"
|
import { ContactFields } from "@/types/requests/contactConfig"
|
||||||
import { Embeds } from "@/types/requests/embeds"
|
import { Embeds } from "@/types/requests/embeds"
|
||||||
import { JoinLoyaltyContactEnum } from "@/types/requests/loyaltyPage"
|
import { JoinLoyaltyContactContact } from "@/types/requests/loyaltyPage"
|
||||||
import { Edges } from "@/types/requests/utils/edges"
|
import { Edges } from "@/types/requests/utils/edges"
|
||||||
import { RTEDocument } from "@/types/rte/node"
|
import { RTEDocument } from "@/types/rte/node"
|
||||||
|
|
||||||
@@ -16,5 +16,5 @@ export type Contact = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export type ContactProps = {
|
export type ContactProps = {
|
||||||
contactBlock: JoinLoyaltyContactEnum[]
|
contactBlock: JoinLoyaltyContactContact[]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ export type GetContactConfigData = {
|
|||||||
|
|
||||||
// Utility types that extract the possible strings of ContactConfigField,
|
// Utility types that extract the possible strings of ContactConfigField,
|
||||||
// Which is all the dot notated values of ContactConfig (for example: 'email.name')
|
// Which is all the dot notated values of ContactConfig (for example: 'email.name')
|
||||||
|
// From: https://stackoverflow.com/questions/47057649/typescript-string-dot-notation-of-nested-object#47058976
|
||||||
type PathsToStringProps<T> = T extends string
|
type PathsToStringProps<T> = T extends string
|
||||||
? []
|
? []
|
||||||
: {
|
: {
|
||||||
@@ -65,7 +66,7 @@ type Join<T extends string[], D extends string> = T extends []
|
|||||||
: never
|
: never
|
||||||
: string
|
: string
|
||||||
|
|
||||||
type ContactConfigField = Join<PathsToStringProps<ContactConfig>, ".">
|
export type ContactConfigField = Join<PathsToStringProps<ContactConfig>, ".">
|
||||||
|
|
||||||
export type ContactFields = {
|
export type ContactFields = {
|
||||||
display_text?: string
|
display_text?: string
|
||||||
|
|||||||
@@ -1,24 +1,16 @@
|
|||||||
|
import { CardGrid, Content } from "../components/loyalty/blocks"
|
||||||
|
import { Contact, SidebarContent } from "../components/loyalty/sidebar"
|
||||||
|
import { PageLink } from "./myPages/navigation"
|
||||||
|
import { Edges } from "./utils/edges"
|
||||||
|
|
||||||
import type { AllRequestResponse } from "./utils/all"
|
import type { AllRequestResponse } from "./utils/all"
|
||||||
import type { Typename } from "./utils/typename"
|
import type { Typename } from "./utils/typename"
|
||||||
import { Contact, SidebarContent } from "../components/loyalty/sidebar"
|
|
||||||
import {
|
|
||||||
CardGrid,
|
|
||||||
Content,
|
|
||||||
DynamicContentBlock,
|
|
||||||
} from "../components/loyalty/blocks"
|
|
||||||
|
|
||||||
export enum SidebarTypenameEnum {
|
|
||||||
LoyaltyPageSidebarJoinLoyaltyContact = "LoyaltyPageSidebarJoinLoyaltyContact",
|
|
||||||
LoyaltyPageSidebarContent = "LoyaltyPageSidebarContent",
|
|
||||||
}
|
|
||||||
|
|
||||||
export type SidebarTypename = keyof typeof SidebarTypenameEnum
|
|
||||||
|
|
||||||
export enum JoinLoyaltyContactTypenameEnum {
|
export enum JoinLoyaltyContactTypenameEnum {
|
||||||
LoyaltyPageSidebarJoinLoyaltyContactBlockContactContact = "LoyaltyPageSidebarJoinLoyaltyContactBlockContactContact",
|
LoyaltyPageSidebarJoinLoyaltyContactBlockContactContact = "LoyaltyPageSidebarJoinLoyaltyContactBlockContactContact",
|
||||||
}
|
}
|
||||||
|
|
||||||
export type JoinLoyaltyContactEnum = Typename<
|
export type JoinLoyaltyContactContact = Typename<
|
||||||
Contact,
|
Contact,
|
||||||
JoinLoyaltyContactTypenameEnum.LoyaltyPageSidebarJoinLoyaltyContactBlockContactContact
|
JoinLoyaltyContactTypenameEnum.LoyaltyPageSidebarJoinLoyaltyContactBlockContactContact
|
||||||
>
|
>
|
||||||
@@ -27,11 +19,17 @@ export type JoinLoyaltyContact = {
|
|||||||
join_loyalty_contact: {
|
join_loyalty_contact: {
|
||||||
title?: string
|
title?: string
|
||||||
preamble?: string
|
preamble?: string
|
||||||
contact: JoinLoyaltyContactEnum[]
|
contact: JoinLoyaltyContactContact[]
|
||||||
login_button_text: string
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum SidebarTypenameEnum {
|
||||||
|
LoyaltyPageSidebarJoinLoyaltyContact = "LoyaltyPageSidebarJoinLoyaltyContact",
|
||||||
|
LoyaltyPageSidebarContent = "LoyaltyPageSidebarContent",
|
||||||
|
}
|
||||||
|
|
||||||
|
export type SidebarTypename = keyof typeof SidebarTypenameEnum
|
||||||
|
|
||||||
export type Sidebar =
|
export type Sidebar =
|
||||||
| Typename<SidebarContent, SidebarTypenameEnum.LoyaltyPageSidebarContent>
|
| Typename<SidebarContent, SidebarTypenameEnum.LoyaltyPageSidebarContent>
|
||||||
| Typename<
|
| Typename<
|
||||||
@@ -39,6 +37,26 @@ export type Sidebar =
|
|||||||
SidebarTypenameEnum.LoyaltyPageSidebarJoinLoyaltyContact
|
SidebarTypenameEnum.LoyaltyPageSidebarJoinLoyaltyContact
|
||||||
>
|
>
|
||||||
|
|
||||||
|
export enum LoyaltyComponentEnum {
|
||||||
|
loyalty_levels = "loyalty_levels",
|
||||||
|
how_it_works = "how_it_works",
|
||||||
|
overview_table = "overview_table",
|
||||||
|
}
|
||||||
|
|
||||||
|
export type LoyaltyComponent = keyof typeof LoyaltyComponentEnum
|
||||||
|
|
||||||
|
export type DynamicContentBlock = {
|
||||||
|
dynamic_content: {
|
||||||
|
title?: string
|
||||||
|
subtitle?: string
|
||||||
|
component: LoyaltyComponent
|
||||||
|
link: {
|
||||||
|
text?: string
|
||||||
|
pageConnection: Edges<PageLink>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export enum LoyaltyBlocksTypenameEnum {
|
export enum LoyaltyBlocksTypenameEnum {
|
||||||
LoyaltyPageBlocksDynamicContent = "LoyaltyPageBlocksDynamicContent",
|
LoyaltyPageBlocksDynamicContent = "LoyaltyPageBlocksDynamicContent",
|
||||||
LoyaltyPageBlocksCardGrid = "LoyaltyPageBlocksCardGrid",
|
LoyaltyPageBlocksCardGrid = "LoyaltyPageBlocksCardGrid",
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import type { EmbedEnum } from "./embeds"
|
|
||||||
import type { Image } from "@/types/image"
|
import type { Image } from "@/types/image"
|
||||||
|
import type { EmbedEnum } from "./embeds"
|
||||||
import type { Typename } from "./typename"
|
import type { Typename } from "./typename"
|
||||||
|
|
||||||
export type SysAsset = Typename<Image, EmbedEnum.SysAsset>
|
export type SysAsset = Typename<Image, EmbedEnum.SysAsset>
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
import {
|
import {
|
||||||
ContactConfig,
|
ContactConfig,
|
||||||
|
ContactConfigField,
|
||||||
ContactFieldGroups,
|
ContactFieldGroups,
|
||||||
} from "@/types/requests/contactConfig"
|
} from "@/types/requests/contactConfig"
|
||||||
|
|
||||||
export function getValueFromContactConfig(
|
export function getValueFromContactConfig(
|
||||||
keyStrings: string,
|
keyStrings: ContactConfigField,
|
||||||
data: ContactConfig
|
data: ContactConfig
|
||||||
): string | undefined {
|
): string | undefined {
|
||||||
const [groupName, key] = keyStrings.split(".") as [
|
const [groupName, key] = keyStrings.split(".") as [
|
||||||
|
|||||||
Reference in New Issue
Block a user