diff --git a/app/[lang]/(live)/(protected)/my-pages/benefits/page.tsx b/app/[lang]/(live)/(protected)/my-pages/benefits/page.tsx index c3aba6b90..ada9f3e70 100644 --- a/app/[lang]/(live)/(protected)/my-pages/benefits/page.tsx +++ b/app/[lang]/(live)/(protected)/my-pages/benefits/page.tsx @@ -1,7 +1,7 @@ import CurrentBenefitsBlock from "@/components/MyPages/Blocks/Benefits/CurrentLevel" import NextLevelBenefitsBlock from "@/components/MyPages/Blocks/Benefits/NextLevel" import Shortcuts from "@/components/MyPages/Blocks/Shortcuts" -import Title from "@/components/MyPages/Title" +import Title from "@/components/Title" import { shortcuts } from "./_constants" diff --git a/app/[lang]/(live)/(public)/loyalty-page/layout.module.css b/app/[lang]/(live)/(public)/loyalty-page/layout.module.css new file mode 100644 index 000000000..cd47ec147 --- /dev/null +++ b/app/[lang]/(live)/(public)/loyalty-page/layout.module.css @@ -0,0 +1,9 @@ +.layout { + --max-width: 101.4rem; + --header-height: 4.5rem; + + display: grid; + font-family: var(--ff-fira-sans); + grid-template-rows: var(--header-height) auto 1fr; + min-height: 100dvh; +} diff --git a/app/[lang]/(live)/(public)/loyalty-page/layout.tsx b/app/[lang]/(live)/(public)/loyalty-page/layout.tsx new file mode 100644 index 000000000..e925346f6 --- /dev/null +++ b/app/[lang]/(live)/(public)/loyalty-page/layout.tsx @@ -0,0 +1,21 @@ +import { firaMono, firaSans } from "@/app/[lang]/(live)/fonts" + +import Header from "@/components/MyPages/Header" + +import styles from "./layout.module.css" + +import type { MyPagesLayoutProps } from "@/types/components/myPages/layout" + +export default async function LoyaltyPagesLayout({ + children, + params, +}: React.PropsWithChildren) { + return ( +
+
+ {children} +
+ ) +} diff --git a/app/[lang]/(live)/(public)/loyalty-page/page.module.css b/app/[lang]/(live)/(public)/loyalty-page/page.module.css new file mode 100644 index 000000000..ebc27135f --- /dev/null +++ b/app/[lang]/(live)/(public)/loyalty-page/page.module.css @@ -0,0 +1,18 @@ +.content { + display: grid; + padding-bottom: 7.7rem; + padding-left: 0; + padding-right: 0; + position: relative; +} + +@media screen and (min-width: 950px) { + .content { + gap: 10rem; + grid-template-columns: 25rem 1fr; + padding-bottom: 17.5rem; + padding-left: 2.4rem; + padding-right: 2.4rem; + padding-top: 5.8rem; + } +} diff --git a/app/[lang]/(live)/(public)/loyalty-page/page.tsx b/app/[lang]/(live)/(public)/loyalty-page/page.tsx new file mode 100644 index 000000000..7b03e2191 --- /dev/null +++ b/app/[lang]/(live)/(public)/loyalty-page/page.tsx @@ -0,0 +1,40 @@ +import Title from "@/components/Title" +import MaxWidth from "@/components/MaxWidth" + +import { serverClient } from "@/lib/trpc/server" +import { LangParams, PageArgs, UriParams } from "@/types/params" +import { notFound } from "next/navigation" + +import styles from "./page.module.css" + +export default async function LoyaltyPage({ + params, + searchParams, +}: PageArgs) { + try { + if (!searchParams.uri) { + throw new Error("Bad URI") + } + + const loyaltyPage = await serverClient().contentstack.loyaltyPage.get({ + uri: searchParams.uri, + lang: params.lang, + }) + + return ( +
+ + + {loyaltyPage.title} + + +
+ ) + } catch (err) { + return notFound() + } +} + +function Content(content: any) { + return <> +} diff --git a/components/MyPages/Blocks/Benefits/CurrentLevel/index.tsx b/components/MyPages/Blocks/Benefits/CurrentLevel/index.tsx index 9371fde25..e106697c4 100644 --- a/components/MyPages/Blocks/Benefits/CurrentLevel/index.tsx +++ b/components/MyPages/Blocks/Benefits/CurrentLevel/index.tsx @@ -2,7 +2,7 @@ import Link from "next/link" import { serverClient } from "@/lib/trpc/server" -import Title from "@/components/MyPages/Title" +import Title from "@/components/Title" import styles from "./current.module.css" diff --git a/components/MyPages/Blocks/Benefits/NextLevel/index.tsx b/components/MyPages/Blocks/Benefits/NextLevel/index.tsx index 1e0fe88ed..70bf4d4c8 100644 --- a/components/MyPages/Blocks/Benefits/NextLevel/index.tsx +++ b/components/MyPages/Blocks/Benefits/NextLevel/index.tsx @@ -3,7 +3,7 @@ import { Lock } from "react-feather" import { serverClient } from "@/lib/trpc/server" -import Title from "@/components/MyPages/Title" +import Title from "@/components/Title" import Button from "@/components/TempDesignSystem/Button" import styles from "./next.module.css" diff --git a/components/MyPages/Blocks/Challenges/index.tsx b/components/MyPages/Blocks/Challenges/index.tsx index faa96b342..b1c5036e7 100644 --- a/components/MyPages/Blocks/Challenges/index.tsx +++ b/components/MyPages/Blocks/Challenges/index.tsx @@ -1,5 +1,5 @@ import Image from "@/components/Image" -import Title from "@/components/MyPages/Title" +import Title from "@/components/Title" import styles from "./challenges.module.css" diff --git a/components/MyPages/Blocks/Overview/index.tsx b/components/MyPages/Blocks/Overview/index.tsx index 9725c5ca2..fb63d7415 100644 --- a/components/MyPages/Blocks/Overview/index.tsx +++ b/components/MyPages/Blocks/Overview/index.tsx @@ -1,4 +1,4 @@ -import Title from "@/components/MyPages/Title" +import Title from "@/components/Title" import Friend from "./Friend" import Stats from "./Stats" diff --git a/components/MyPages/Blocks/Shortcuts/index.tsx b/components/MyPages/Blocks/Shortcuts/index.tsx index 100ecda0b..cb80b61c0 100644 --- a/components/MyPages/Blocks/Shortcuts/index.tsx +++ b/components/MyPages/Blocks/Shortcuts/index.tsx @@ -1,7 +1,7 @@ import Link from "next/link" import Image from "@/components/Image" -import Title from "@/components/MyPages/Title" +import Title from "@/components/Title" import styles from "./shortcuts.module.css" diff --git a/components/MyPages/Blocks/Stays/StayCard/index.tsx b/components/MyPages/Blocks/Stays/StayCard/index.tsx index 459f7fb6e..c7e36641a 100644 --- a/components/MyPages/Blocks/Stays/StayCard/index.tsx +++ b/components/MyPages/Blocks/Stays/StayCard/index.tsx @@ -1,7 +1,7 @@ import { dt } from "@/lib/dt" import Image from "@/components/Image" -import Title from "@/components/MyPages/Title" +import Title from "@/components/Title" import styles from "./stay.module.css" diff --git a/components/MyPages/Sidebar/index.tsx b/components/MyPages/Sidebar/index.tsx index 9134e8cbe..9c43e0a6e 100644 --- a/components/MyPages/Sidebar/index.tsx +++ b/components/MyPages/Sidebar/index.tsx @@ -4,9 +4,10 @@ import { LogOut } from "react-feather" import { GetNavigationMyPages } from "@/lib/graphql/Query/NavigationMyPages.graphql" import { request } from "@/lib/graphql/request" +import Title from "@/components/Title" import Link from "@/components/TempDesignSystem/Link" -import Title from "../Title" + import { mapMenuItems } from "./helpers" import styles from "./sidebar.module.css" diff --git a/components/MyPages/Title/index.tsx b/components/Title/index.tsx similarity index 100% rename from components/MyPages/Title/index.tsx rename to components/Title/index.tsx diff --git a/components/MyPages/Title/title.module.css b/components/Title/title.module.css similarity index 99% rename from components/MyPages/Title/title.module.css rename to components/Title/title.module.css index b8b2490f7..a51d9629b 100644 --- a/components/MyPages/Title/title.module.css +++ b/components/Title/title.module.css @@ -82,4 +82,4 @@ font-size: var(--typography-Title5-Desktop-fontSize); line-height: var(--typography-Title5-Desktop-lineHeight); } -} \ No newline at end of file +} diff --git a/components/MyPages/Title/variants.ts b/components/Title/variants.ts similarity index 100% rename from components/MyPages/Title/variants.ts rename to components/Title/variants.ts diff --git a/lib/graphql/Query/LoyaltyPage.graphql b/lib/graphql/Query/LoyaltyPage.graphql new file mode 100644 index 000000000..5cfb1d59b --- /dev/null +++ b/lib/graphql/Query/LoyaltyPage.graphql @@ -0,0 +1,140 @@ +query GetLoyaltyPage($locale: String!, $url: String!) { + all_loyalty_page(where: { url: $url, locale: $locale }) { + items { + content { + ... on LoyaltyPageContentLoyaltyLevels { + __typename + loyalty_levels { + heading + sub_heading + level_card { + loyalty_level + } + } + } + ... on LoyaltyPageContentCardGrid { + __typename + card_grid { + heading + subheading + cards { + referenceConnection { + edges { + node { + ... on LoyaltyPage { + url + } + ... on ContentPage { + web { + url + } + } + ... on AccountPage { + url + } + } + } + } + heading + subheading + } + } + } + } + title + sidebar { + ... on LoyaltyPageSidebarLoyaltyJoinContact { + __typename + loyalty_join_contact { + title + contact { + ... on LoyaltyPageSidebarLoyaltyJoinContactBlockContactContact { + __typename + contact { + contact_fields + } + } + } + login_button_text + body { + json + embedded_itemsConnection { + edges { + node { + ... on SysAsset { + title + dimension { + width + height + } + file_size + filename + url + } + } + } + } + } + } + } + ... on LoyaltyPageSidebarContent { + __typename + content { + content { + json + embedded_itemsConnection { + edges { + node { + ... on SysAsset { + title + url + file_size + filename + dimension { + width + height + } + } + } + } + } + } + } + } + } + web { + breadcrumbs { + title + parents { + href + title + } + } + original_url + seo_metadata { + description + title + imageConnection { + edges { + node { + file_size + filename + dimension { + height + width + } + url + title + } + } + } + } + } + system { + uid + created_at + updated_at + } + } + } +} diff --git a/server/routers/contentstack/index.ts b/server/routers/contentstack/index.ts index 8098575a0..1a570fa8e 100644 --- a/server/routers/contentstack/index.ts +++ b/server/routers/contentstack/index.ts @@ -1,7 +1,9 @@ import { router } from "@/server/trpc" import { breadcrumbsRouter } from "./breadcrumbs" +import { loyaltyPageRouter } from "./loyaltyPage" export const contentstackRouter = router({ breadcrumbs: breadcrumbsRouter, + loyaltyPage: loyaltyPageRouter, }) diff --git a/server/routers/contentstack/loyaltyPage/index.tsx b/server/routers/contentstack/loyaltyPage/index.tsx new file mode 100644 index 000000000..5e47223a1 --- /dev/null +++ b/server/routers/contentstack/loyaltyPage/index.tsx @@ -0,0 +1,5 @@ +import { mergeRouters } from "@/server/trpc" + +import { loyaltyPageQueryRouter } from "./query" + +export const loyaltyPageRouter = mergeRouters(loyaltyPageQueryRouter) diff --git a/server/routers/contentstack/loyaltyPage/query.ts b/server/routers/contentstack/loyaltyPage/query.ts new file mode 100644 index 000000000..3d22cf6a3 --- /dev/null +++ b/server/routers/contentstack/loyaltyPage/query.ts @@ -0,0 +1,33 @@ +import { z } from "zod" + +import { badRequestError } from "@/server/errors/trpc" +import { publicProcedure, router } from "@/server/trpc" +import { request } from "@/lib/graphql/request" +import { Lang } from "@/constants/languages" + +import GetLoyaltyPage from "@/lib/graphql/Query/LoyaltyPage.graphql" + +import type { GetLoyaltyPageData } from "@/types/requests/loyaltyPage" + +export const loyaltyPageQueryRouter = router({ + get: publicProcedure + .input(z.object({ uri: z.string(), lang: z.nativeEnum(Lang) })) + .query(async ({ input }) => { + const loyaltyPage = await request( + GetLoyaltyPage, + { + locale: input.lang, + url: input.uri, + }, + { + tags: [`${input.uri}-${input.lang}`], + } + ) + + if (loyaltyPage.data && loyaltyPage.data.all_loyalty_page.items.length) { + return loyaltyPage.data.all_loyalty_page.items[0] + } + + throw badRequestError() + }), +}) diff --git a/types/components/myPages/title.ts b/types/components/myPages/title.ts index fa73698bf..9b93f2807 100644 --- a/types/components/myPages/title.ts +++ b/types/components/myPages/title.ts @@ -1,10 +1,12 @@ -import { headingVariants } from "@/components/MyPages/Title/variants" +import { headingVariants } from "@/components/Title/variants" import type { VariantProps } from "class-variance-authority" type HeadingLevel = "h1" | "h2" | "h3" | "h4" | "h5" | "h6" -export interface HeadingProps extends React.HTMLAttributes, VariantProps { +export interface HeadingProps + extends React.HTMLAttributes, + VariantProps { as?: HeadingLevel level?: HeadingLevel uppercase?: boolean diff --git a/types/requests/loyaltyPage.ts b/types/requests/loyaltyPage.ts new file mode 100644 index 000000000..ea71c3813 --- /dev/null +++ b/types/requests/loyaltyPage.ts @@ -0,0 +1,104 @@ +import type { AllRequestResponse } from "./utils/all" +import type { Typename } from "./utils/typename" + +enum SidebarTypenameEnum { + LoyaltyPageSidebarLoyaltyJoinContact = "LoyaltyPageSidebarLoyaltyJoinContact", + LoyaltyPageSidebarContent = "LoyaltyPageSidebarContent", +} + +type SidebarContent = {} + +type JoinContact = {} + +export type Sidebar = + | Typename + | Typename< + JoinContact, + SidebarTypenameEnum.LoyaltyPageSidebarLoyaltyJoinContact + > + +enum ContentBlocks { + LoyaltyPageContentLoyaltyLevels = "LoyaltyPageContentLoyaltyLevels", + LoyaltyPageContentCardGrid = "LoyaltyPageContentCardGrid", +} + +enum LinkedPageConnection { + LoyaltyPage = "LoyaltyPage", + ContentPage = "ContentPage", + AccountPage = "AccountPage", +} + +type ContentPageLink = { + web: { url: string } +} +type LoyaltyPageLink = { + url: string +} + +type AccountPageLink = { + url: string +} + +type LinkedPage = + | Typename + | Typename + | Typename + +type CardGrid = { + card_grid: { + heading: string + subheading: string + cards: { + referenceConnection: { + edges: { + node: LinkedPage + } + } + heading: string + subheading: string + } + } +} + +type LoyaltyLevels = { + loyalty_levels: { + heading: string + sub_heading?: string + level_card: { + loyalty_level: number + }[] + } +} + +export type Content = + | Typename + | Typename + +export type Breadcrumb = { + href: string + title: string +} + +export type Breadcrumbs = { + parents: Breadcrumb[] + title: string +} + +export type LoyaltyPage = { + sidebar: Sidebar[] + content: Content[] + web: { + breadcrumbs: Breadcrumbs + } + system: { + created_at: string + uid: string + updated_at: string + } + title: string + url: string +} + +export type GetLoyaltyPageData = { + all_loyalty_page: AllRequestResponse +}