fix: add next level perks block
This commit is contained in:
@@ -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" },
|
||||||
|
]
|
||||||
@@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -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;
|
||||||
@@ -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>
|
||||||
@@ -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) => (
|
||||||
|
|||||||
@@ -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: {
|
||||||
|
|||||||
@@ -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
2
package-lock.json
generated
@@ -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",
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -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
|
||||||
|
}),
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user