fix: add next level perks block

This commit is contained in:
Christel Westerberg
2024-04-11 16:02:30 +02:00
parent c398309cdd
commit 85b83bc58b
15 changed files with 182 additions and 103 deletions

View File

@@ -0,0 +1,5 @@
export const shortcuts = [
{ href: "#", title: "Member prices on hotel nights" },
{ href: "#", title: "Great deals from our partners" },
{ href: "#", title: "A special gift on your birthday" },
]

View File

@@ -1,6 +1,6 @@
.container { .container {
display: flex; display: flex;
gap: 20px; gap: 2rem;
flex-direction: column; flex-direction: column;
max-width: var(--max-width); max-width: var(--max-width);
padding-left: 2rem; padding-left: 2rem;
@@ -10,15 +10,22 @@
.header { .header {
display: grid; display: grid;
gap: 2rem; gap: 2rem;
margin-top: 40px; margin-top: 4rem;
} }
.title { .title {
font-weight: 600; font-weight: 600;
} }
.red {
color: var(--some-red-color, #ed2027);
}
.preamble { .preamble {
font-weight: 400; font-weight: 400;
font-family: var(--fira-sans);
font-size: 2.4rem;
margin: 0;
} }
@media screen and (min-width: 950px) { @media screen and (min-width: 950px) {
@@ -29,6 +36,6 @@
.container { .container {
padding-left: 0; padding-left: 0;
padding-right: 0; padding-right: 0;
gap: 34px; gap: 3.4rem;
} }
} }

View File

@@ -1,42 +1,38 @@
import { request } from "@/lib/graphql/request"
import { serverClient } from "@/lib/trpc/server"
import GetBenefitsPage from "@/lib/graphql/Query/BenefitPage.graphql"
import Title from "@/components/MyPages/Title" import Title from "@/components/MyPages/Title"
import BenefitsBlock from "@/components/MyPages/Blocks/Benefits" import CurrentBenefitsBlock from "@/components/MyPages/Blocks/Benefits/CurrentLevel"
import NextLevelBenefitsBlock from "@/components/MyPages/Blocks/Benefits/NextLevel"
import Shortcuts from "@/components/MyPages/Blocks/Shortcuts"
import styles from "./page.module.css" import { shortcuts } from "./_constants"
import type { LangParams, PageArgs } from "@/types/params" import type { LangParams, PageArgs } from "@/types/params"
import type { GetBenefitsPageData } from "@/types/requests/benefitPage" import styles from "./page.module.css"
export default async function BenefitsPage({ params }: PageArgs<LangParams>) {
const contentResponse = await request<GetBenefitsPageData>(GetBenefitsPage, {
locale: params.lang,
url: "/my-pages/benefits",
})
const benefitsData = await serverClient().user.get()
if (!contentResponse.data.all_my_page?.total) {
console.log("#### DATA ####")
console.log(contentResponse.data)
throw new Error("Not found")
}
const contentData = contentResponse.data.all_my_page.items[0]
export default function BenefitsPage({ params }: PageArgs<LangParams>) {
return ( return (
<main className={styles.container}> <main className={styles.container}>
<header className={styles.header}> <header className={styles.header}>
<Title level="h2" className={styles.title} uppercase> <Title as="h3" className={styles.title} uppercase>
{contentData.title} Your Perks and benefits. Tailored just for{" "}
</Title> <span className={styles.red}>you.</span>
<Title level="h3" className={styles.preamble}>
{contentData.preamble}
</Title> </Title>
<p className={styles.preamble}>
Discover the exclusive benefits and delightful surprises our
friendship unlocks.
</p>
</header> </header>
<BenefitsBlock /> <CurrentBenefitsBlock />
<Shortcuts
shortcuts={shortcuts}
title={
<span className={styles.title}>
Perks and benefits{" "}
<span className={styles.red}>for All friends.</span>
</span>
}
subtitle="Always Yours. Universal Benefits for the Scandic Friends community."
/>
<NextLevelBenefitsBlock />
</main> </main>
) )
} }

View File

@@ -27,7 +27,11 @@ export default async function MyPage({ params }: PageArgs<LangParams>) {
<main className={styles.blocks}> <main className={styles.blocks}>
<Overview user={user} /> <Overview user={user} />
<UpcomingStays lang={params.lang} stays={user.stays} /> <UpcomingStays lang={params.lang} stays={user.stays} />
<Shortcuts shortcuts={user.shortcuts} /> <Shortcuts
shortcuts={user.shortcuts}
title="Handy Shortcuts"
subtitle="The community at your fingertips"
/>
</main> </main>
) )
} }

View File

@@ -11,6 +11,7 @@ import type { Metadata } from "next"
import type { LangParams, LayoutArgs } from "@/types/params" import type { LangParams, LayoutArgs } from "@/types/params"
import "@/app/globals.css" import "@/app/globals.css"
import "@scandic-hotels/design-system/style.css"
export const metadata: Metadata = { export const metadata: Metadata = {
description: "New web", description: "New web",

View File

@@ -7,15 +7,28 @@
color: var(--some-black-color, #111); color: var(--some-black-color, #111);
/* font-family: var(--ff-brandon-text); */ /* font-family: var(--ff-brandon-text); */
font-weight: 500; font-weight: 500;
text-align: center;
} }
.value { .value {
color: var(--some-red-color, #ed2027); color: var(--some-red-color, #ed2027);
} }
.subtitle {
font-family: var(--ff-fira-sans);
font-size: 12px;
font-weight: 400;
line-height: 14.4px;
text-align: center;
color: var(--some-black-color, #111);
margin: 0;
}
.card { .card {
text-decoration: none; text-decoration: none;
display: grid; display: flex;
flex-direction: column;
gap: 10px;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
padding: 30px; padding: 30px;

View File

@@ -1,19 +1,20 @@
import { serverClient } from "@/lib/trpc/server" import { serverClient } from "@/lib/trpc/server"
import Title from "../../Title" import Title from "../../../Title"
import styles from "./benefits.module.css" import styles from "./current.module.css"
import Link from "next/link" import Link from "next/link"
export default async function BenefitsBlock() { export default async function CurrentBenefitsBlock() {
const benefits = await serverClient().user.benefits() const benefits = await serverClient().user.benefits.current()
return ( return (
<section className={styles.container}> <section className={styles.container}>
{benefits.map((benefit) => ( {benefits.map((benefit) => (
<Link href={benefit.href} key={benefit.id} className={styles.card}> <Link href={benefit.href} key={benefit.id} className={styles.card}>
<Title level="h2" className={styles.title}> <Title level="h3" as="h4" className={styles.title}>
<span className={styles.value}>{benefit.value}</span>{" "} <span className={styles.value}>{benefit.value}</span>{" "}
{benefit.explanation} {benefit.explanation}
</Title> </Title>
<p className={styles.subtitle}>{benefit.subtitle}</p>
</Link> </Link>
))} ))}
</section> </section>

View File

@@ -6,14 +6,18 @@ import styles from "./shortcuts.module.css"
import type { ShortcutsProps } from "@/types/components/myPages/shortcuts" import type { ShortcutsProps } from "@/types/components/myPages/shortcuts"
export default function Shortcuts({ shortcuts }: ShortcutsProps) { export default function Shortcuts({
shortcuts,
title,
subtitle,
}: ShortcutsProps) {
return ( return (
<section className={styles.shortcuts}> <section className={styles.shortcuts}>
<header className={styles.header}> <header className={styles.header}>
<Title level="h2" uppercase> <Title level="h2" as="h4" uppercase>
Handy Shortcuts {title}
</Title> </Title>
<p className={styles.subtitle}>The community at your fingertips</p> <p className={styles.subtitle}>{subtitle}</p>
</header> </header>
<section className={styles.links}> <section className={styles.links}>
{shortcuts.map((shortcut) => ( {shortcuts.map((shortcut) => (

View File

@@ -15,7 +15,6 @@ const config = {
h3: styles.h3, h3: styles.h3,
h4: styles.h4, h4: styles.h4,
h5: styles.h5, h5: styles.h5,
h6: styles.h6,
}, },
}, },
defaultVariants: { defaultVariants: {

View File

@@ -9,41 +9,53 @@
} }
.h1 { .h1 {
font-size: 2.4rem; font-size: var(--typography-Title1-Mobile-fontSize);
line-height: 2.8rem; line-height: var(--typography-Title1-Mobile-lineHeight) + "%";
} }
.h2 { .h2 {
font-size: 2.2rem; font-size: var(--typography-Title2-Mobile-fontSize);
line-height: 2.6rem; line-height: var(--typography-Title2-Mobile-lineHeight) + "%";
} }
.h3 { .h3 {
font-size: 1.8rem; font-size: var(--typography-Title3-Mobile-fontSize);
line-height: 2.2rem; line-height: var(--typography-Title3-Mobile-lineHeight) + "%";
} }
.h4 { .h4 {
font-size: 1.6rem; font-size: var(--typography-Title4-Mobile-fontSize);
line-height: 1.8rem; line-height: var(--typography-Title4-Mobile-lineHeight) + "%";
} }
.h5 { .h5 {
font-size: 1.3rem; font-size: var(--typography-Title5-Mobile-fontSize);
} line-height: var(--typography-Title5-Mobile-lineHeight) + "%";
.h6 {
font-size: 1rem;
} }
@media screen and (min-width: 950px) { @media screen and (min-width: 950px) {
.h1 { .h1 {
font-size: 3.8rem; font-size: var(--typography-Title1-Desktop-fontSize);
line-height: 4.5rem; line-height: var(--typography-Title1-Desktop-lineHeight) + "%";
} }
.h2 { .h2 {
font-size: 3.4rem; font-size: var(--typography-Title2-Desktop-fontSize);
line-height: 4.1rem; line-height: var(--typography-Title2-Desktop-lineHeight) + "%";
}
.h3 {
font-size: var(--typography-Title3-Desktop-fontSize);
line-height: var(--typography-Title3-Desktop-lineHeight) + "%";
}
.h4 {
font-size: var(--typography-Title4-Desktop-fontSize);
line-height: var(--typography-Title4-Desktop-lineHeight) + "%";
}
.h5 {
font-size: var(--typography-Title5-Desktop-fontSize);
line-height: var(--typography-Title5-Desktop-lineHeight) + "%";
} }
} }

2
package-lock.json generated
View File

@@ -12,7 +12,7 @@
"@contentstack/live-preview-utils": "^1.4.0", "@contentstack/live-preview-utils": "^1.4.0",
"@netlify/plugin-nextjs": "^5.0.0", "@netlify/plugin-nextjs": "^5.0.0",
"@radix-ui/react-slot": "^1.0.2", "@radix-ui/react-slot": "^1.0.2",
"@scandic-hotels/design-system": "git+https://x-token-auth:$DESIGN_SYSTEM_ACCESS_TOKEN@bitbucket.org/scandic-swap/design-system.git#v0.1.0-rc.2", "@scandic-hotels/design-system": "git+https://x-token-auth:$DESIGN_SYSTEM_ACCESS_TOKEN@bitbucket.org/scandic-swap/design-system.git#v0.1.0-rc.3",
"@t3-oss/env-nextjs": "^0.9.2", "@t3-oss/env-nextjs": "^0.9.2",
"@tanstack/react-query": "^5.28.6", "@tanstack/react-query": "^5.28.6",
"@trpc/client": "^11.0.0-next-beta.318", "@trpc/client": "^11.0.0-next-beta.318",

View File

@@ -21,7 +21,7 @@
"@contentstack/live-preview-utils": "^1.4.0", "@contentstack/live-preview-utils": "^1.4.0",
"@netlify/plugin-nextjs": "^5.0.0", "@netlify/plugin-nextjs": "^5.0.0",
"@radix-ui/react-slot": "^1.0.2", "@radix-ui/react-slot": "^1.0.2",
"@scandic-hotels/design-system": "git+https://x-token-auth:$DESIGN_SYSTEM_ACCESS_TOKEN@bitbucket.org/scandic-swap/design-system.git#v0.1.0-rc.2", "@scandic-hotels/design-system": "git+https://x-token-auth:$DESIGN_SYSTEM_ACCESS_TOKEN@bitbucket.org/scandic-swap/design-system.git#v0.1.0-rc.3",
"@t3-oss/env-nextjs": "^0.9.2", "@t3-oss/env-nextjs": "^0.9.2",
"@tanstack/react-query": "^5.28.6", "@tanstack/react-query": "^5.28.6",
"@trpc/client": "^11.0.0-next-beta.318", "@trpc/client": "^11.0.0-next-beta.318",

View File

@@ -23,46 +23,80 @@ export const userQueryRouter = router({
} }
return validJson return validJson
}), }),
benefits: protectedProcedure.query(async function (opts) { benefits: router({
// TODO: Make request to get user data from Scandic API current: protectedProcedure.query(async function (opts) {
// TODO: Make request to get user data from Scandic API
const hardCodedBenefits = [ const hardCodedBenefits = [
{ {
id: 1, id: 1,
value: "€5 voucher", value: "€5 voucher",
explanation: "to spend in bar & restaurant for each night", explanation: "to spend in bar & restaurant for each night",
subtitle: subtitle:
"Lorem ipsum dolor sit amet consectetur. Pharetra lectus sagittis turpis blandit feugiat amet enim massa.", "Lorem ipsum dolor sit amet consectetur. Pharetra lectus sagittis turpis blandit feugiat amet enim massa.",
href: "#", href: "#",
}, },
{ {
id: 2, id: 2,
value: "Breakfast to go", value: "Breakfast to go",
explanation: "for early birds, when staying", explanation: "for early birds, when staying",
subtitle: subtitle:
"Lorem ipsum dolor sit amet consectetur. Pharetra lectus sagittis turpis blandit feugiat amet enim massa.", "Lorem ipsum dolor sit amet consectetur. Pharetra lectus sagittis turpis blandit feugiat amet enim massa.",
href: "#", href: "#",
}, },
{ {
id: 3, id: 3,
value: "15% discount", value: "15% discount",
explanation: "in the restaurant & the bar", explanation: "in the restaurant & the bar",
subtitle: subtitle:
"Lorem ipsum dolor sit amet consectetur. Pharetra lectus sagittis turpis blandit feugiat amet enim massa.", "Lorem ipsum dolor sit amet consectetur. Pharetra lectus sagittis turpis blandit feugiat amet enim massa.",
href: "#", href: "#",
}, },
] ]
const response = hardCodedBenefits const response = hardCodedBenefits
return response return response
// if (!response.ok) { // if (!response.ok) {
// throw internalServerError() // throw internalServerError()
// } // }
// const json = await response.json() // const json = await response.json()
// const validJson = getUserSchema.parse(json) // const validJson = getUserSchema.parse(json)
// if (!validJson) { // if (!validJson) {
// throw badRequestError() // throw badRequestError()
// } // }
// return validJson // return validJson
}),
next: protectedProcedure.query(async function (opts) {
// TODO: Make request to get user data from Scandic API
const hardCodedBenefits = [
{
id: 1,
explanation: "Free soft drink voucher for the kids when staying",
},
{
id: 2,
explanation: "Free early check in",
},
{
id: 3,
explanation: "25% extra bonus points on each stay",
},
]
const response = { nextLevel: "Close Friend", perks: hardCodedBenefits }
return response
// if (!response.ok) {
// throw internalServerError()
// }
// const json = await response.json()
// const validJson = getUserSchema.parse(json)
// if (!validJson) {
// throw badRequestError()
// }
// return validJson
}),
}), }),
}) })

View File

@@ -1,5 +1,8 @@
import type { User } from "@/types/user" import type { User } from "@/types/user"
import { ReactNode } from "react"
export type ShortcutsProps = { export type ShortcutsProps = {
shortcuts: User["shortcuts"] shortcuts: User["shortcuts"]
title: string | ReactNode
subtitle?: string
} }

View File

@@ -1,4 +1,4 @@
type HeadingLevel = "h1" | "h2" | "h3" | "h4" | "h5" | "h6" type HeadingLevel = "h1" | "h2" | "h3" | "h4" | "h5"
export interface HeadingProps extends React.HTMLAttributes<HTMLHeadingElement> { export interface HeadingProps extends React.HTMLAttributes<HTMLHeadingElement> {
as?: HeadingLevel as?: HeadingLevel