Merged in feat/my-pages-breadcrumbs-contentstack (pull request #129)

Feat/my pages breadcrumbs contentstack

Approved-by: Michael Zetterberg
This commit is contained in:
Simon.Emanuelsson
2024-04-19 13:29:23 +00:00
committed by Michael Zetterberg
31 changed files with 291 additions and 139 deletions

View File

@@ -1,10 +1,17 @@
import { serverClient } from "@/lib/trpc/server" import { serverClient } from "@/lib/trpc/server"
import { benefits } from "@/constants/routes/myPages"
import Breadcrumbs from "@/components/MyPages/Breadcrumbs" import Breadcrumbs from "@/components/MyPages/Breadcrumbs"
export default async function BenefitsBreadcrumbs() { import type { LangParams, PageArgs } from "@/types/params"
export default async function BenefitsBreadcrumbs({
params,
}: PageArgs<LangParams>) {
const href = benefits[params.lang].replace(`/${params.lang}`, "")
const breadcrumbs = await serverClient().contentstack.breadcrumbs.get({ const breadcrumbs = await serverClient().contentstack.breadcrumbs.get({
href: "/my-pages/benefits", href,
locale: params.lang,
}) })
return <Breadcrumbs breadcrumbs={breadcrumbs} /> return <Breadcrumbs breadcrumbs={breadcrumbs} />
} }

View File

@@ -1,10 +1,17 @@
import { serverClient } from "@/lib/trpc/server" import { serverClient } from "@/lib/trpc/server"
import { overview } from "@/constants/routes/myPages"
import Breadcrumbs from "@/components/MyPages/Breadcrumbs" import Breadcrumbs from "@/components/MyPages/Breadcrumbs"
export default async function OverviewBreadcrumbs() { import type { LangParams, PageArgs } from "@/types/params"
export default async function OverviewBreadcrumbs({
params,
}: PageArgs<LangParams>) {
const href = overview[params.lang].replace(`/${params.lang}`, "")
const breadcrumbs = await serverClient().contentstack.breadcrumbs.get({ const breadcrumbs = await serverClient().contentstack.breadcrumbs.get({
href: "/my-pages/overview", href,
locale: params.lang,
}) })
return <Breadcrumbs breadcrumbs={breadcrumbs} /> return <Breadcrumbs breadcrumbs={breadcrumbs} />
} }

View File

@@ -1,10 +1,17 @@
import { serverClient } from "@/lib/trpc/server" import { serverClient } from "@/lib/trpc/server"
import { profile } from "@/constants/routes/myPages"
import Breadcrumbs from "@/components/MyPages/Breadcrumbs" import Breadcrumbs from "@/components/MyPages/Breadcrumbs"
export default async function ProfileBreadcrumbs() { import type { LangParams, PageArgs } from "@/types/params"
export default async function ProfileBreadcrumbs({
params,
}: PageArgs<LangParams>) {
const href = profile[params.lang].replace(`/${params.lang}`, "")
const breadcrumbs = await serverClient().contentstack.breadcrumbs.get({ const breadcrumbs = await serverClient().contentstack.breadcrumbs.get({
href: "/my-pages/profile", href,
locale: params.lang,
}) })
return <Breadcrumbs breadcrumbs={breadcrumbs} /> return <Breadcrumbs breadcrumbs={breadcrumbs} />
} }

View File

@@ -1,10 +1,17 @@
import { serverClient } from "@/lib/trpc/server" import { serverClient } from "@/lib/trpc/server"
import { profile } from "@/constants/routes/myPages"
import Breadcrumbs from "@/components/MyPages/Breadcrumbs" import Breadcrumbs from "@/components/MyPages/Breadcrumbs"
export default async function ProfileBreadcrumbs() { import type { LangParams, PageArgs } from "@/types/params"
export default async function ProfileBreadcrumbs({
params,
}: PageArgs<LangParams>) {
const href = profile[params.lang].replace(`/${params.lang}`, "")
const breadcrumbs = await serverClient().contentstack.breadcrumbs.get({ const breadcrumbs = await serverClient().contentstack.breadcrumbs.get({
href: "/my-pages/profile", href,
locale: params.lang,
}) })
return <Breadcrumbs breadcrumbs={breadcrumbs} /> return <Breadcrumbs breadcrumbs={breadcrumbs} />
} }

View File

@@ -1,3 +0,0 @@
export default function Default() {
return null
}

View File

@@ -1,3 +0,0 @@
export default function Default() {
return null
}

View File

@@ -0,0 +1,4 @@
import "../profileLayout.css"
export default function EditProfilePage() {
return null
}

View File

@@ -1,10 +1,9 @@
import MaxWidth from "@/components/MaxWidth" import MaxWidth from "@/components/MaxWidth"
import styles from "./layout.module.css"
import type { ProfileLayoutProps } from "@/types/components/myPages/myProfile/layout" import type { ProfileLayoutProps } from "@/types/components/myPages/myProfile/layout"
export default function ProfileLayout({ export default function ProfileLayout({
children,
communication, communication,
creditCards, creditCards,
edit, edit,
@@ -15,13 +14,14 @@ export default function ProfileLayout({
wishes, wishes,
}: React.PropsWithChildren<ProfileLayoutProps>) { }: React.PropsWithChildren<ProfileLayoutProps>) {
return ( return (
<MaxWidth className={styles.page} tag="main"> <MaxWidth className="profile-page" tag="main">
<div className={styles.btns}> <div className="profile-btns">
{edit} {edit}
{view} {view}
</div> </div>
{profile} {profile}
<section className={styles.cards}> {children}
<section className="profile-cards">
{communication} {communication}
{wishes} {wishes}
{membershipCard} {membershipCard}

View File

@@ -0,0 +1,5 @@
import "./profileLayout.css"
export default function ProfilePage() {
return null
}

View File

@@ -1,9 +1,13 @@
.page { /**
* Due to css import issues with parallell routes we are forced to
* use a regular css file and import it in the page.tsx
*/
.profile-page {
display: grid; display: grid;
gap: 3rem; gap: 3rem;
} }
.btns { .profile-btns {
align-items: center; align-items: center;
display: flex; display: flex;
gap: 1rem; gap: 1rem;
@@ -16,7 +20,7 @@
transform: translateY(-100%); transform: translateY(-100%);
} }
.cards { .profile-cards {
display: grid; display: grid;
gap: 0.4rem; gap: 0.4rem;
grid-template-columns: 1fr 1fr; grid-template-columns: 1fr 1fr;

View File

@@ -15,16 +15,15 @@ export default function Breadcrumbs({ breadcrumbs }: BreadcrumbsProps) {
{breadcrumbs.map((breadcrumb) => { {breadcrumbs.map((breadcrumb) => {
if (breadcrumb.href) { if (breadcrumb.href) {
return ( return (
<BreadcrumbsWithLink <BreadcrumbsWithLink key={breadcrumb.uid} href={breadcrumb.href}>
key={breadcrumb.title}
href={breadcrumb.href}
>
{breadcrumb.title} {breadcrumb.title}
</BreadcrumbsWithLink> </BreadcrumbsWithLink>
) )
} }
return <Breadcrumb>{breadcrumb.title}</Breadcrumb> return (
<Breadcrumb key={breadcrumb.uid}>{breadcrumb.title}</Breadcrumb>
)
})} })}
</ul> </ul>
</nav> </nav>

View File

@@ -43,11 +43,11 @@ export default function FormContent({ control }: EditFormContentProps) {
<Field.Icon> <Field.Icon>
<CalendarIcon /> <CalendarIcon />
</Field.Icon> </Field.Icon>
<Field.Label htmlFor="dob">*{_("Date of Birth")}</Field.Label> <Field.Label htmlFor="dateOfBirth">*{_("Date of Birth")}</Field.Label>
<Field.Content> <Field.Content>
<DateSelect <DateSelect
control={control} control={control}
name="dob" name="dateOfBirth"
registerOptions={{ required: true }} registerOptions={{ required: true }}
/> />
</Field.Content> </Field.Content>

View File

@@ -12,7 +12,7 @@ export const editProfileSchema = z.object({
"address.zipCode": z "address.zipCode": z
.string({ required_error: _("Zip code is required") }) .string({ required_error: _("Zip code is required") })
.min(1, { message: _("Zip code is required") }), .min(1, { message: _("Zip code is required") }),
dob: z dateOfBirth: z
.string({ required_error: _("Date of Birth is required") }) .string({ required_error: _("Date of Birth is required") })
.min(1, { message: _("Date of Birth is required") }), .min(1, { message: _("Date of Birth is required") }),
email: z.string().email(), email: z.string().email(),

View File

@@ -13,12 +13,14 @@ import Field from "../Field"
import styles from "./profile.module.css" import styles from "./profile.module.css"
import { serverClient } from "@/lib/trpc/server" import { serverClient } from "@/lib/trpc/server"
import { dt } from "@/lib/dt"
export default async function Profile() { export default async function Profile() {
const user = await serverClient().user.get() const user = await serverClient().user.get()
const countryName = countries.find( const countryName = countries.find(
(country) => country.code === user.address.country (country) => country.code === user.address.country
) )
const dob = dt(user.dateOfBirth).format("DD/MM/YYYY")
return ( return (
<Container user={user}> <Container user={user}>
<section className={styles.info}> <section className={styles.info}>
@@ -32,8 +34,7 @@ export default async function Profile() {
<CalendarIcon /> <CalendarIcon />
</Field.Icon> </Field.Icon>
<Field.TextLabel>{_("Date of Birth")}</Field.TextLabel> <Field.TextLabel>{_("Date of Birth")}</Field.TextLabel>
{/* TODO: Get this from user when API team adds it to payload */} <Field.Content>{dob}</Field.Content>
<Field.Content>27/05/1977</Field.Content>
</Field> </Field>
<Field> <Field>
<Field.Icon> <Field.Icon>
@@ -61,7 +62,6 @@ export default async function Profile() {
<HouseIcon /> <HouseIcon />
</Field.Icon> </Field.Icon>
<Field.TextLabel>{_("City/State")}</Field.TextLabel> <Field.TextLabel>{_("City/State")}</Field.TextLabel>
{/* TODO: Get this from user when API team adds it to payload */}
<Field.Content>{user.address.city || "-"}</Field.Content> <Field.Content>{user.address.city || "-"}</Field.Content>
</Field> </Field>
<Field> <Field>

View File

@@ -40,12 +40,12 @@ export const profile = {
/** @type {import('@/types/routes').LangRoute} */ /** @type {import('@/types/routes').LangRoute} */
export const profileEdit = { export const profileEdit = {
da: `${profile.da}/edit`, da: `${profile.da}/rediger`,
de: `${profile.de}/edit`, de: `${profile.de}/bearbeiten`,
en: `${profile.en}/edit`, en: `${profile.en}/edit`,
fi: `${profile.fi}/edit`, fi: `${profile.fi}/muokkaa`,
no: `${profile.no}/edit`, no: `${profile.no}/rediger`,
sv: `${profile.sv}/edit`, sv: `${profile.sv}/redigera`,
} }
/** @type {import('@/types/routes').LangRoute} */ /** @type {import('@/types/routes').LangRoute} */

View File

@@ -11,6 +11,7 @@ import type { Endpoint } from "./endpoints"
export { endpoints } from "./endpoints" export { endpoints } from "./endpoints"
const defaultOptions: RequestInit = { const defaultOptions: RequestInit = {
cache: "no-store",
headers: { headers: {
"Content-Type": "application/json", "Content-Type": "application/json",
}, },

View File

@@ -0,0 +1,20 @@
fragment Breadcrumbs on AccountPage {
breadcrumbs {
title
parents: parentsConnection {
edges {
node {
... on AccountPage {
breadcrumbs {
title
}
system {
uid
}
url
}
}
}
}
}
}

View File

@@ -0,0 +1,13 @@
#import "../Fragments/MyPages/Breadcrumbs.graphql"
query GetMyPagesBreadcrumbs($locale: String!, $url: String!) {
all_account_page(locale: $locale, where: { url: $url }) {
items {
...Breadcrumbs
system {
uid
}
}
total
}
}

106
package-lock.json generated
View File

@@ -27,7 +27,7 @@
"graphql-request": "^6.1.0", "graphql-request": "^6.1.0",
"graphql-tag": "^2.12.6", "graphql-tag": "^2.12.6",
"libphonenumber-js": "^1.10.60", "libphonenumber-js": "^1.10.60",
"next": "^14.1.0", "next": "^14.2.0",
"next-auth": "^5.0.0-beta.15", "next-auth": "^5.0.0-beta.15",
"react": "^18", "react": "^18",
"react-dom": "^18", "react-dom": "^18",
@@ -476,9 +476,9 @@
} }
}, },
"node_modules/@next/env": { "node_modules/@next/env": {
"version": "14.1.4", "version": "14.2.2",
"resolved": "https://registry.npmjs.org/@next/env/-/env-14.1.4.tgz", "resolved": "https://registry.npmjs.org/@next/env/-/env-14.2.2.tgz",
"integrity": "sha512-e7X7bbn3Z6DWnDi75UWn+REgAbLEqxI8Tq2pkFOFAMpWAWApz/YCUhtWMWn410h8Q2fYiYL7Yg5OlxMOCfFjJQ==" "integrity": "sha512-sk72qRfM1Q90XZWYRoJKu/UWlTgihrASiYw/scb15u+tyzcze3bOuJ/UV6TBOQEeUaxOkRqGeuGUdiiuxc5oqw=="
}, },
"node_modules/@next/eslint-plugin-next": { "node_modules/@next/eslint-plugin-next": {
"version": "14.1.4", "version": "14.1.4",
@@ -490,9 +490,9 @@
} }
}, },
"node_modules/@next/swc-darwin-arm64": { "node_modules/@next/swc-darwin-arm64": {
"version": "14.1.4", "version": "14.2.2",
"resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.1.4.tgz", "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.2.tgz",
"integrity": "sha512-ubmUkbmW65nIAOmoxT1IROZdmmJMmdYvXIe8211send9ZYJu+SqxSnJM4TrPj9wmL6g9Atvj0S/2cFmMSS99jg==", "integrity": "sha512-3iPgMhzbalizGwHNFUcGnDhFPSgVBHQ8aqSTAMxB5BvJG0oYrDf1WOJZlbXBgunOEj/8KMVbejEur/FpvFsgFQ==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -505,9 +505,9 @@
} }
}, },
"node_modules/@next/swc-darwin-x64": { "node_modules/@next/swc-darwin-x64": {
"version": "14.1.4", "version": "14.2.2",
"resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.1.4.tgz", "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.2.tgz",
"integrity": "sha512-b0Xo1ELj3u7IkZWAKcJPJEhBop117U78l70nfoQGo4xUSvv0PJSTaV4U9xQBLvZlnjsYkc8RwQN1HoH/oQmLlQ==", "integrity": "sha512-x7Afi/jt0ZBRUZHTi49yyej4o8znfIMHO4RvThuoc0P+uli8Jd99y5GKjxoYunPKsXL09xBXEM1+OQy2xEL0Ag==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -520,9 +520,9 @@
} }
}, },
"node_modules/@next/swc-linux-arm64-gnu": { "node_modules/@next/swc-linux-arm64-gnu": {
"version": "14.1.4", "version": "14.2.2",
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.1.4.tgz", "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.2.tgz",
"integrity": "sha512-457G0hcLrdYA/u1O2XkRMsDKId5VKe3uKPvrKVOyuARa6nXrdhJOOYU9hkKKyQTMru1B8qEP78IAhf/1XnVqKA==", "integrity": "sha512-zbfPtkk7L41ODMJwSp5VbmPozPmMMQrzAc0HAUomVeVIIwlDGs/UCqLJvLNDt4jpWgc21SjjyIn762lNGrMaUA==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -535,9 +535,9 @@
} }
}, },
"node_modules/@next/swc-linux-arm64-musl": { "node_modules/@next/swc-linux-arm64-musl": {
"version": "14.1.4", "version": "14.2.2",
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.1.4.tgz", "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.2.tgz",
"integrity": "sha512-l/kMG+z6MB+fKA9KdtyprkTQ1ihlJcBh66cf0HvqGP+rXBbOXX0dpJatjZbHeunvEHoBBS69GYQG5ry78JMy3g==", "integrity": "sha512-wPbS3pI/JU16rm3XdLvvTmlsmm1nd+sBa2ohXgBZcShX4TgOjD4R+RqHKlI1cjo/jDZKXt6OxmcU0Iys0OC/yg==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -550,9 +550,9 @@
} }
}, },
"node_modules/@next/swc-linux-x64-gnu": { "node_modules/@next/swc-linux-x64-gnu": {
"version": "14.1.4", "version": "14.2.2",
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.1.4.tgz", "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.2.tgz",
"integrity": "sha512-BapIFZ3ZRnvQ1uWbmqEGJuPT9cgLwvKtxhK/L2t4QYO7l+/DxXuIGjvp1x8rvfa/x1FFSsipERZK70pewbtJtw==", "integrity": "sha512-NqWOHqqq8iC9tuHvZxjQ2tX+jWy2X9y8NX2mcB4sj2bIccuCxbIZrU/ThFPZZPauygajZuVQ6zediejQHwZHwQ==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -565,9 +565,9 @@
} }
}, },
"node_modules/@next/swc-linux-x64-musl": { "node_modules/@next/swc-linux-x64-musl": {
"version": "14.1.4", "version": "14.2.2",
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.1.4.tgz", "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.2.tgz",
"integrity": "sha512-mqVxTwk4XuBl49qn2A5UmzFImoL1iLm0KQQwtdRJRKl21ylQwwGCxJtIYo2rbfkZHoSKlh/YgztY0qH3wG1xIg==", "integrity": "sha512-lGepHhwb9sGhCcU7999+iK1ZZT+6rrIoVg40MP7DZski9GIZP80wORSbt5kJzh9v2x2ev2lxC6VgwMQT0PcgTA==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -580,9 +580,9 @@
} }
}, },
"node_modules/@next/swc-win32-arm64-msvc": { "node_modules/@next/swc-win32-arm64-msvc": {
"version": "14.1.4", "version": "14.2.2",
"resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.1.4.tgz", "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.2.tgz",
"integrity": "sha512-xzxF4ErcumXjO2Pvg/wVGrtr9QQJLk3IyQX1ddAC/fi6/5jZCZ9xpuL9Tzc4KPWMFq8GGWFVDMshZOdHGdkvag==", "integrity": "sha512-TZSh/48SfcLEQ4rD25VVn2kdIgUWmMflRX3OiyPwGNXn3NiyPqhqei/BaqCYXViIQ+6QsG9R0C8LftMqy8JPMA==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -595,9 +595,9 @@
} }
}, },
"node_modules/@next/swc-win32-ia32-msvc": { "node_modules/@next/swc-win32-ia32-msvc": {
"version": "14.1.4", "version": "14.2.2",
"resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.1.4.tgz", "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.2.tgz",
"integrity": "sha512-WZiz8OdbkpRw6/IU/lredZWKKZopUMhcI2F+XiMAcPja0uZYdMTZQRoQ0WZcvinn9xZAidimE7tN9W5v9Yyfyw==", "integrity": "sha512-M0tBVNMEBJN2ZNQWlcekMn6pvLria7Sa2Fai5znm7CCJz4pP3lrvlSxhKdkCerk0D9E0bqx5yAo3o2Q7RrD4gA==",
"cpu": [ "cpu": [
"ia32" "ia32"
], ],
@@ -610,9 +610,9 @@
} }
}, },
"node_modules/@next/swc-win32-x64-msvc": { "node_modules/@next/swc-win32-x64-msvc": {
"version": "14.1.4", "version": "14.2.2",
"resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.1.4.tgz", "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.2.tgz",
"integrity": "sha512-4Rto21sPfw555sZ/XNLqfxDUNeLhNYGO2dlPqsnuCg8N8a2a9u1ltqBOPQ4vj1Gf7eJC0W2hHG2eYUHuiXgY2w==", "integrity": "sha512-a/20E/wtTJZ3Ykv3f/8F0l7TtgQa2LWHU2oNB9bsu0VjqGuGGHmm/q6waoUNQYTVPYrrlxxaHjJcDV6aiSTt/w==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -2273,11 +2273,17 @@
"url": "https://github.com/sindresorhus/is?sponsor=1" "url": "https://github.com/sindresorhus/is?sponsor=1"
} }
}, },
"node_modules/@swc/counter": {
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz",
"integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ=="
},
"node_modules/@swc/helpers": { "node_modules/@swc/helpers": {
"version": "0.5.2", "version": "0.5.5",
"resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.2.tgz", "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.5.tgz",
"integrity": "sha512-E4KcWTpoLHqwPHLxidpOqQbcrZVgi0rsmmZXUle1jXmJfuIf/UWpczUJ7MZZ5tlxytgJXyp0w4PGkkeLiuIdZw==", "integrity": "sha512-KGYxvIOXcceOAbEk4bi/dVLEK9z8sZ0uBB3Il5b1rhfClSpcX0yfRO0KmTkqR2cnQDymwLB+25ZyMzICg/cm/A==",
"dependencies": { "dependencies": {
"@swc/counter": "^0.1.3",
"tslib": "^2.4.0" "tslib": "^2.4.0"
} }
}, },
@@ -8086,12 +8092,12 @@
} }
}, },
"node_modules/next": { "node_modules/next": {
"version": "14.1.4", "version": "14.2.2",
"resolved": "https://registry.npmjs.org/next/-/next-14.1.4.tgz", "resolved": "https://registry.npmjs.org/next/-/next-14.2.2.tgz",
"integrity": "sha512-1WTaXeSrUwlz/XcnhGTY7+8eiaFvdet5z9u3V2jb+Ek1vFo0VhHKSAIJvDWfQpttWjnyw14kBeq28TPq7bTeEQ==", "integrity": "sha512-oGwUaa2bCs47FbuxWMpOoXtBMPYpvTPgdZr3UAo+pu7Ns00z9otmYpoeV1HEiYL06AlRQQIA/ypK526KjJfaxg==",
"dependencies": { "dependencies": {
"@next/env": "14.1.4", "@next/env": "14.2.2",
"@swc/helpers": "0.5.2", "@swc/helpers": "0.5.5",
"busboy": "1.6.0", "busboy": "1.6.0",
"caniuse-lite": "^1.0.30001579", "caniuse-lite": "^1.0.30001579",
"graceful-fs": "^4.2.11", "graceful-fs": "^4.2.11",
@@ -8105,18 +8111,19 @@
"node": ">=18.17.0" "node": ">=18.17.0"
}, },
"optionalDependencies": { "optionalDependencies": {
"@next/swc-darwin-arm64": "14.1.4", "@next/swc-darwin-arm64": "14.2.2",
"@next/swc-darwin-x64": "14.1.4", "@next/swc-darwin-x64": "14.2.2",
"@next/swc-linux-arm64-gnu": "14.1.4", "@next/swc-linux-arm64-gnu": "14.2.2",
"@next/swc-linux-arm64-musl": "14.1.4", "@next/swc-linux-arm64-musl": "14.2.2",
"@next/swc-linux-x64-gnu": "14.1.4", "@next/swc-linux-x64-gnu": "14.2.2",
"@next/swc-linux-x64-musl": "14.1.4", "@next/swc-linux-x64-musl": "14.2.2",
"@next/swc-win32-arm64-msvc": "14.1.4", "@next/swc-win32-arm64-msvc": "14.2.2",
"@next/swc-win32-ia32-msvc": "14.1.4", "@next/swc-win32-ia32-msvc": "14.2.2",
"@next/swc-win32-x64-msvc": "14.1.4" "@next/swc-win32-x64-msvc": "14.2.2"
}, },
"peerDependencies": { "peerDependencies": {
"@opentelemetry/api": "^1.1.0", "@opentelemetry/api": "^1.1.0",
"@playwright/test": "^1.41.2",
"react": "^18.2.0", "react": "^18.2.0",
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
"sass": "^1.3.0" "sass": "^1.3.0"
@@ -8125,6 +8132,9 @@
"@opentelemetry/api": { "@opentelemetry/api": {
"optional": true "optional": true
}, },
"@playwright/test": {
"optional": true
},
"sass": { "sass": {
"optional": true "optional": true
} }

View File

@@ -36,7 +36,7 @@
"graphql-request": "^6.1.0", "graphql-request": "^6.1.0",
"graphql-tag": "^2.12.6", "graphql-tag": "^2.12.6",
"libphonenumber-js": "^1.10.60", "libphonenumber-js": "^1.10.60",
"next": "^14.1.0", "next": "^14.2.0",
"next-auth": "^5.0.0-beta.15", "next-auth": "^5.0.0-beta.15",
"react": "^18", "react": "^18",
"react-dom": "^18", "react-dom": "^18",
@@ -67,4 +67,4 @@
"engines": { "engines": {
"node": "18" "node": "18"
} }
} }

View 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 getBreadcrumbsInput = z.object({
href: z.string().min(1, { message: "href is required" }),
locale: z.enum(langs),
})

View File

@@ -1,8 +1,40 @@
import { z } from "zod" import { z } from "zod"
export const validateBreadcrumbsConstenstackSchema = z.object({
all_account_page: z.object({
items: z.array(
z.object({
breadcrumbs: z.object({
title: z.string(),
parents: z.object({
edges: z.array(
z.object({
node: z.object({
breadcrumbs: z.object({
title: z.string(),
}),
system: z.object({
uid: z.string(),
}),
url: z.string(),
}),
})
),
}),
}),
system: z.object({
uid: z.string(),
}),
})
),
total: z.number(),
}),
})
export const getBreadcrumbsSchema = z.array( export const getBreadcrumbsSchema = z.array(
z.object({ z.object({
href: z.string().optional(), href: z.string().optional(),
title: z.string(), title: z.string(),
uid: z.string(),
}) })
) )

View File

@@ -1,43 +1,54 @@
import { z } from "zod" import { badRequestError, internalServerError } from "@/server/errors/trpc"
import { validateBreadcrumbsConstenstackSchema } from "./output"
import { badRequestError } from "@/server/errors/trpc"
import { getBreadcrumbsSchema } from "./output"
import { publicProcedure, router } from "@/server/trpc" import { publicProcedure, router } from "@/server/trpc"
const rootMyPagesBreadcrumb = { import { request } from "@/lib/graphql/request"
href: "/en/my-pages", import { GetMyPagesBreadcrumbs } from "@/lib/graphql/Query/BreadcrumbsMyPages.graphql"
title: "My Pages", import { getBreadcrumbsInput } from "./input"
} import { GetMyPagesBreadcrumbsData } from "@/types/requests/myPages/breadcrumbs"
enum paths {
"/my-pages",
"/my-pages/benefits",
"/my-pages/overview",
"/my-pages/profile",
}
const keys = Object.keys(paths) as [keyof typeof paths]
const possibleBreadcrumbs: Record<string, { title: string; href?: string }[]> =
{
"/my-pages": [
{
title: rootMyPagesBreadcrumb.title,
},
],
"/my-pages/benefits": [rootMyPagesBreadcrumb, { title: "Benefits" }],
"/my-pages/overview": [rootMyPagesBreadcrumb, { title: "Overview" }],
"/my-pages/profile": [rootMyPagesBreadcrumb, { title: "Profile" }],
}
export const breadcrumbsQueryRouter = router({ export const breadcrumbsQueryRouter = router({
get: publicProcedure.input(z.object({ href: z.enum(keys) })).query((opts) => { get: publicProcedure.input(getBreadcrumbsInput).query(async ({ input }) => {
const breadcrumbs = possibleBreadcrumbs[opts.input.href] try {
const validatedBreadcrumbs = getBreadcrumbsSchema.safeParse(breadcrumbs) const response = await request<GetMyPagesBreadcrumbsData>(
if (validatedBreadcrumbs.success) { GetMyPagesBreadcrumbs,
return breadcrumbs { locale: input.locale, url: input.href }
} )
if (!response.data) {
throw badRequestError()
}
throw badRequestError() const validatedBreadcrumbs =
validateBreadcrumbsConstenstackSchema.safeParse(response.data)
if (!validatedBreadcrumbs.success) {
throw badRequestError()
}
const parentBreadcrumbs =
validatedBreadcrumbs.data.all_account_page.items[0].breadcrumbs.parents.edges.map(
(breadcrumb) => {
return {
href: breadcrumb.node.url,
title: breadcrumb.node.breadcrumbs.title,
uid: breadcrumb.node.system.uid,
}
}
)
const pageBreadcrumb =
validatedBreadcrumbs.data.all_account_page.items.map((breadcrumb) => {
return {
href: "",
title: breadcrumb.breadcrumbs.title,
uid: breadcrumb.system.uid,
}
})
const breadcrumbs = [parentBreadcrumbs, pageBreadcrumb].flat()
return breadcrumbs
} catch (error) {
console.info(`Get My Pages Breadcrumbs Error`)
console.error(error)
throw internalServerError()
}
}), }),
}) })

View File

@@ -8,6 +8,7 @@ export const getUserSchema = z.object({
streetAddress: z.string().optional(), streetAddress: z.string().optional(),
zipCode: z.string(), zipCode: z.string(),
}), }),
dateOfBirth: z.string(),
email: z.string().email(), email: z.string().email(),
gender: z.string(), gender: z.string(),
name: z.string(), name: z.string(),

View File

@@ -135,7 +135,6 @@ export const stays = [
] ]
export const extendedUser = { export const extendedUser = {
dob: dt("1977-07-05").format("YYYY-MM-DD"),
journeys: challenges.journeys, journeys: challenges.journeys,
nights: 14, nights: 14,
shortcuts, shortcuts,

2
types/auth.d.ts vendored
View File

@@ -15,7 +15,7 @@ declare module "next-auth" {
* The shape of the account object returned in the OAuth providers' `account` callback, * The shape of the account object returned in the OAuth providers' `account` callback,
* Usually contains information about the provider being used, like OAuth tokens (`access_token`, etc). * Usually contains information about the provider being used, like OAuth tokens (`access_token`, etc).
*/ */
interface Account {} interface Account { }
/** /**
* Returned by `useSession`, `auth`, contains information about the active session. * Returned by `useSession`, `auth`, contains information about the active session.

View File

@@ -4,4 +4,4 @@ export interface RequestOptionsWithJSONBody
} }
export interface RequestOptionsWithOutBody export interface RequestOptionsWithOutBody
extends Omit<RequestInit, "body" | "method"> {} extends Omit<RequestInit, "body" | "method"> { }

View File

@@ -0,0 +1,27 @@
import type { AllRequestResponse } from "../utils/all"
import type { Edges } from "../utils/edges"
interface AccountPageBreadcrumbs {
breadcrumbs: {
title: string
parents: Edges<{
breadcrumbs: {
title: string
}
system: {
uid: string
}
url: string
}>
}
system: {
uid: string
}
}
interface AllAccountPageResponse
extends AllRequestResponse<AccountPageBreadcrumbs> {}
export interface GetMyPagesBreadcrumbsData {
all_account_page: AllAccountPageResponse
}

View File

@@ -26,26 +26,21 @@ interface NavigationLink {
locale: Lang locale: Lang
uid: string uid: string
} }
url: string
title: string title: string
} }
export interface AccountPageLink export interface AccountPageLink
extends NavigationLink, extends NavigationLink,
TypenameInterface<PageLinkEnum.AccountPage> { TypenameInterface<PageLinkEnum.AccountPage> { }
url: string
}
export interface LoyaltyPageLink export interface LoyaltyPageLink
extends NavigationLink, extends NavigationLink,
TypenameInterface<PageLinkEnum.LoyaltyPage> { TypenameInterface<PageLinkEnum.LoyaltyPage> { }
url: string
}
export interface ContentPageLink export interface ContentPageLink
extends NavigationLink, extends NavigationLink,
TypenameInterface<PageLinkEnum.ContentPage> { TypenameInterface<PageLinkEnum.ContentPage> { }
url: string
}
export type PageLink = ContentPageLink | AccountPageLink | LoyaltyPageLink export type PageLink = ContentPageLink | AccountPageLink | LoyaltyPageLink

View File

@@ -1,4 +1,4 @@
export type AllRequestResponse<T> = { export interface AllRequestResponse<T> {
items: T[] items: T[]
total: number total: number
} }

View File

@@ -29,7 +29,6 @@ type Victory = {
* we have to get the values from elsewhere * we have to get the values from elsewhere
*/ */
export interface User extends z.infer<typeof getUserSchema> { export interface User extends z.infer<typeof getUserSchema> {
dob: string
firstName: string firstName: string
journeys: Journey[] journeys: Journey[]
nights: number nights: number