feat(WEB-131): add loyalty page

This commit is contained in:
Christel Westerberg
2024-04-17 16:20:55 +02:00
parent 4243056fe8
commit c00f7b78eb
21 changed files with 386 additions and 11 deletions

View File

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

View File

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

View File

@@ -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<MyPagesLayoutProps>) {
return (
<div
className={`${firaMono.variable} ${firaSans.variable} ${styles.layout}`}
>
<Header lang={params.lang} />
{children}
</div>
)
}

View File

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

View File

@@ -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<LangParams, UriParams>) {
try {
if (!searchParams.uri) {
throw new Error("Bad URI")
}
const loyaltyPage = await serverClient().contentstack.loyaltyPage.get({
uri: searchParams.uri,
lang: params.lang,
})
return (
<main className={styles.content}>
<aside>{loyaltyPage.sidebar ? <></> : null}</aside>
<MaxWidth>
<Title>{loyaltyPage.title}</Title>
<Content content={loyaltyPage.content} />
</MaxWidth>
</main>
)
} catch (err) {
return notFound()
}
}
function Content(content: any) {
return <></>
}

View File

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

View File

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

View File

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

View File

@@ -1,4 +1,4 @@
import Title from "@/components/MyPages/Title"
import Title from "@/components/Title"
import Friend from "./Friend"
import Stats from "./Stats"

View File

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

View File

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

View File

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

View File

@@ -82,4 +82,4 @@
font-size: var(--typography-Title5-Desktop-fontSize);
line-height: var(--typography-Title5-Desktop-lineHeight);
}
}
}

View File

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

View File

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

View File

@@ -0,0 +1,5 @@
import { mergeRouters } from "@/server/trpc"
import { loyaltyPageQueryRouter } from "./query"
export const loyaltyPageRouter = mergeRouters(loyaltyPageQueryRouter)

View File

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

View File

@@ -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<HTMLHeadingElement>, VariantProps<typeof headingVariants> {
export interface HeadingProps
extends React.HTMLAttributes<HTMLHeadingElement>,
VariantProps<typeof headingVariants> {
as?: HeadingLevel
level?: HeadingLevel
uppercase?: boolean

View File

@@ -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<SidebarContent, SidebarTypenameEnum.LoyaltyPageSidebarContent>
| 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<ContentPageLink, LinkedPageConnection.ContentPage>
| Typename<LoyaltyPageLink, ContentBlocks.LoyaltyPageContentLoyaltyLevels>
| Typename<AccountPageLink, ContentBlocks.LoyaltyPageContentLoyaltyLevels>
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<CardGrid, ContentBlocks.LoyaltyPageContentCardGrid>
| Typename<LoyaltyLevels, ContentBlocks.LoyaltyPageContentLoyaltyLevels>
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<LoyaltyPage>
}