diff --git a/app/[lang]/(live)/(protected)/my-pages/@breadcrumbs/benefits/default.tsx b/app/[lang]/(live)/(protected)/my-pages/@breadcrumbs/benefits/default.tsx new file mode 100644 index 000000000..86b9e9a38 --- /dev/null +++ b/app/[lang]/(live)/(protected)/my-pages/@breadcrumbs/benefits/default.tsx @@ -0,0 +1,3 @@ +export default function Default() { + return null +} diff --git a/app/[lang]/(live)/(protected)/my-pages/@breadcrumbs/benefits/page.tsx b/app/[lang]/(live)/(protected)/my-pages/@breadcrumbs/benefits/page.tsx new file mode 100644 index 000000000..1310cca51 --- /dev/null +++ b/app/[lang]/(live)/(protected)/my-pages/@breadcrumbs/benefits/page.tsx @@ -0,0 +1,10 @@ +import { serverClient } from "@/lib/trpc/server" + +import Breadcrumbs from "@/components/MyPages/Breadcrumbs" + +export default async function BenefitsBreadcrumbs() { + const breadcrumbs = await serverClient().contentstack.breadcrumbs.get({ + href: "/my-pages/benefits", + }) + return +} diff --git a/app/[lang]/(live)/(protected)/my-pages/@breadcrumbs/default.tsx b/app/[lang]/(live)/(protected)/my-pages/@breadcrumbs/default.tsx new file mode 100644 index 000000000..86b9e9a38 --- /dev/null +++ b/app/[lang]/(live)/(protected)/my-pages/@breadcrumbs/default.tsx @@ -0,0 +1,3 @@ +export default function Default() { + return null +} diff --git a/app/[lang]/(live)/(protected)/my-pages/@breadcrumbs/overview/default.tsx b/app/[lang]/(live)/(protected)/my-pages/@breadcrumbs/overview/default.tsx new file mode 100644 index 000000000..86b9e9a38 --- /dev/null +++ b/app/[lang]/(live)/(protected)/my-pages/@breadcrumbs/overview/default.tsx @@ -0,0 +1,3 @@ +export default function Default() { + return null +} diff --git a/app/[lang]/(live)/(protected)/my-pages/@breadcrumbs/overview/page.tsx b/app/[lang]/(live)/(protected)/my-pages/@breadcrumbs/overview/page.tsx new file mode 100644 index 000000000..4fc49d9aa --- /dev/null +++ b/app/[lang]/(live)/(protected)/my-pages/@breadcrumbs/overview/page.tsx @@ -0,0 +1,10 @@ +import { serverClient } from "@/lib/trpc/server" + +import Breadcrumbs from "@/components/MyPages/Breadcrumbs" + +export default async function OverviewBreadcrumbs() { + const breadcrumbs = await serverClient().contentstack.breadcrumbs.get({ + href: "/my-pages/overview", + }) + return +} diff --git a/app/[lang]/(live)/(protected)/my-pages/@breadcrumbs/page.tsx b/app/[lang]/(live)/(protected)/my-pages/@breadcrumbs/page.tsx new file mode 100644 index 000000000..50eff2e46 --- /dev/null +++ b/app/[lang]/(live)/(protected)/my-pages/@breadcrumbs/page.tsx @@ -0,0 +1,10 @@ +import { serverClient } from "@/lib/trpc/server" + +import Breadcrumbs from "@/components/MyPages/Breadcrumbs" + +export default async function MyPagesBreadcrumbs() { + const breadcrumbs = await serverClient().contentstack.breadcrumbs.get({ + href: "/my-pages", + }) + return +} diff --git a/app/[lang]/(live)/(protected)/my-pages/@breadcrumbs/profile/default.tsx b/app/[lang]/(live)/(protected)/my-pages/@breadcrumbs/profile/default.tsx new file mode 100644 index 000000000..86b9e9a38 --- /dev/null +++ b/app/[lang]/(live)/(protected)/my-pages/@breadcrumbs/profile/default.tsx @@ -0,0 +1,3 @@ +export default function Default() { + return null +} diff --git a/app/[lang]/(live)/(protected)/my-pages/@breadcrumbs/profile/edit/default.tsx b/app/[lang]/(live)/(protected)/my-pages/@breadcrumbs/profile/edit/default.tsx new file mode 100644 index 000000000..86b9e9a38 --- /dev/null +++ b/app/[lang]/(live)/(protected)/my-pages/@breadcrumbs/profile/edit/default.tsx @@ -0,0 +1,3 @@ +export default function Default() { + return null +} diff --git a/app/[lang]/(live)/(protected)/my-pages/@breadcrumbs/profile/edit/page.tsx b/app/[lang]/(live)/(protected)/my-pages/@breadcrumbs/profile/edit/page.tsx new file mode 100644 index 000000000..6db544bc7 --- /dev/null +++ b/app/[lang]/(live)/(protected)/my-pages/@breadcrumbs/profile/edit/page.tsx @@ -0,0 +1,10 @@ +import { serverClient } from "@/lib/trpc/server" + +import Breadcrumbs from "@/components/MyPages/Breadcrumbs" + +export default async function ProfileBreadcrumbs() { + const breadcrumbs = await serverClient().contentstack.breadcrumbs.get({ + href: "/my-pages/profile", + }) + return +} diff --git a/app/[lang]/(live)/(protected)/my-pages/@breadcrumbs/profile/page.tsx b/app/[lang]/(live)/(protected)/my-pages/@breadcrumbs/profile/page.tsx new file mode 100644 index 000000000..6db544bc7 --- /dev/null +++ b/app/[lang]/(live)/(protected)/my-pages/@breadcrumbs/profile/page.tsx @@ -0,0 +1,10 @@ +import { serverClient } from "@/lib/trpc/server" + +import Breadcrumbs from "@/components/MyPages/Breadcrumbs" + +export default async function ProfileBreadcrumbs() { + const breadcrumbs = await serverClient().contentstack.breadcrumbs.get({ + href: "/my-pages/profile", + }) + return +} diff --git a/app/[lang]/(live)/(protected)/my-pages/layout.tsx b/app/[lang]/(live)/(protected)/my-pages/layout.tsx index e83d541ba..cb519ab45 100644 --- a/app/[lang]/(live)/(protected)/my-pages/layout.tsx +++ b/app/[lang]/(live)/(protected)/my-pages/layout.tsx @@ -1,24 +1,23 @@ import { firaMono, firaSans } from "@/app/[lang]/(live)/fonts" -import { breadcrumbs } from "./_constants" -import Breadcrumbs from "@/components/MyPages/Breadcrumbs" import Header from "@/components/MyPages/Header" import Sidebar from "@/components/MyPages/Sidebar" import styles from "./layout.module.css" -import type { LangParams, LayoutArgs } from "@/types/params" +import type { MyPagesLayoutProps } from "@/types/components/myPages/layout" export default async function MyPagesLayout({ + breadcrumbs, children, params, -}: React.PropsWithChildren>) { +}: React.PropsWithChildren) { return (
- + {breadcrumbs}
{children} diff --git a/app/[lang]/(live)/(protected)/my-pages/profile/@view/edit/page.tsx b/app/[lang]/(live)/(protected)/my-pages/profile/@view/edit/page.tsx new file mode 100644 index 000000000..fe4978be0 --- /dev/null +++ b/app/[lang]/(live)/(protected)/my-pages/profile/@view/edit/page.tsx @@ -0,0 +1,3 @@ +export default function EditPage() { + return null +} diff --git a/components/MyPages/Breadcrumbs/Breadcrumb.tsx b/components/MyPages/Breadcrumbs/Breadcrumb.tsx new file mode 100644 index 000000000..a0f9e5401 --- /dev/null +++ b/components/MyPages/Breadcrumbs/Breadcrumb.tsx @@ -0,0 +1,9 @@ +import styles from "./breadcrumbs.module.css" + +export default function Breadcrumb({ children }: React.PropsWithChildren) { + return ( +
  • +

    {children}

    +
  • + ) +} diff --git a/components/MyPages/Breadcrumbs/BreadcrumbWithLink.tsx b/components/MyPages/Breadcrumbs/BreadcrumbWithLink.tsx new file mode 100644 index 000000000..a5da13776 --- /dev/null +++ b/components/MyPages/Breadcrumbs/BreadcrumbWithLink.tsx @@ -0,0 +1,17 @@ +import Link from "@/components/TempDesignSystem/Link" + +import styles from "./breadcrumbs.module.css" + +export default function BreadcrumbsWithLink({ + children, + href, +}: React.PropsWithChildren<{ href: string }>) { + return ( +
  • + + {children} + + +
  • + ) +} diff --git a/components/MyPages/Breadcrumbs/Client.tsx b/components/MyPages/Breadcrumbs/Client.tsx deleted file mode 100644 index c678216e7..000000000 --- a/components/MyPages/Breadcrumbs/Client.tsx +++ /dev/null @@ -1,49 +0,0 @@ -"use client" -import { Fragment } from "react" -import { usePathname } from "next/navigation" - -import Link from "@/components/TempDesignSystem/Link" - -import styles from "./breadcrumbs.module.css" - -import type { BreadcrumbsProps } from "@/types/components/myPages/breadcrumbs" - -export default function ClientBreadcrumbs({ breadcrumbs, lang }: BreadcrumbsProps) { - const pathname = usePathname() - /** Temp solution until we can get breadcrumbs from CS */ - const path = pathname.replace(`/${lang}`, '') - const currentBreadcrumbs = breadcrumbs?.[path] - if (!currentBreadcrumbs?.length) { - return null - } - - return ( - <> -
  • - / -
  • - {currentBreadcrumbs.map(breadcrumb => { - if (breadcrumb.href) { - return ( - -
  • - - {breadcrumb.title} - -
  • -
  • - / -
  • -
    - ) - } - - return ( -
  • -

    {breadcrumb.title}

    -
  • - ) - })} - - ) -} diff --git a/components/MyPages/Breadcrumbs/breadcrumbs.module.css b/components/MyPages/Breadcrumbs/breadcrumbs.module.css index 746a35a12..a4111ad72 100644 --- a/components/MyPages/Breadcrumbs/breadcrumbs.module.css +++ b/components/MyPages/Breadcrumbs/breadcrumbs.module.css @@ -27,6 +27,11 @@ line-height: 1.56rem; } +.listItem { + display: flex; + gap: 0.4rem; +} + .currentPage { margin: 0; } @@ -37,4 +42,4 @@ padding-left: 2.4rem; padding-top: 2rem; } -} \ No newline at end of file +} diff --git a/components/MyPages/Breadcrumbs/index.tsx b/components/MyPages/Breadcrumbs/index.tsx index 3933f4de7..afe919a16 100644 --- a/components/MyPages/Breadcrumbs/index.tsx +++ b/components/MyPages/Breadcrumbs/index.tsx @@ -1,20 +1,31 @@ -import ClientBreadcrumbs from "./Client" -import Link from "@/components/TempDesignSystem/Link" +import { _ } from "@/lib/translation" + +import Breadcrumb from "./Breadcrumb" +import BreadcrumbsWithLink from "./BreadcrumbWithLink" import styles from "./breadcrumbs.module.css" import type { BreadcrumbsProps } from "@/types/components/myPages/breadcrumbs" -export default function Breadcrumbs({ breadcrumbs, lang }: BreadcrumbsProps) { +export default function Breadcrumbs({ breadcrumbs }: BreadcrumbsProps) { return ( ) diff --git a/components/MyPages/Sidebar/helpers.ts b/components/MyPages/Sidebar/helpers.ts index 37fed8490..b9492db78 100644 --- a/components/MyPages/Sidebar/helpers.ts +++ b/components/MyPages/Sidebar/helpers.ts @@ -24,7 +24,7 @@ export function mapMenuItems(navigationItems: NavigationItem[]) { lang: node.system.locale, subItems: item.sub_items ? mapMenuItems(item.sub_items) : null, uid: node.system.uid, - url: `/${node.system.locale}/${getURL(node)}`.replaceAll("//+", "/"), + url: `/${node.system.locale}/${getURL(node)}`.replaceAll(/\/\/+/g, "/"), } }) } diff --git a/components/MyPages/Sidebar/index.tsx b/components/MyPages/Sidebar/index.tsx index 62fa54e4c..2f9f6fdd6 100644 --- a/components/MyPages/Sidebar/index.tsx +++ b/components/MyPages/Sidebar/index.tsx @@ -30,21 +30,22 @@ export default async function Sidebar({ lang }: SidebarProps) { {menuItems.map((item) => ( - + {item.linkText} {item.subItems ? item.subItems.map((subItem) => { - return ( - - {subItem.linkText} - - ) - }) + return ( + + {subItem.linkText} + + ) + }) : null} ))} diff --git a/components/TempDesignSystem/Link/index.tsx b/components/TempDesignSystem/Link/index.tsx index 01cd813d3..6d7cac359 100644 --- a/components/TempDesignSystem/Link/index.tsx +++ b/components/TempDesignSystem/Link/index.tsx @@ -10,12 +10,16 @@ import type { LinkProps } from "./link" export default function Link({ className, href, + partialMatch = false, size, variant, ...props }: LinkProps) { const currentPageSlug = usePathname() - const isActive = currentPageSlug === href + let isActive = currentPageSlug === href + if (partialMatch && !isActive) { + isActive = currentPageSlug.startsWith(href) + } const classNames = linkVariants({ active: isActive, className, diff --git a/components/TempDesignSystem/Link/link.ts b/components/TempDesignSystem/Link/link.ts index 64476aa44..77a1069c3 100644 --- a/components/TempDesignSystem/Link/link.ts +++ b/components/TempDesignSystem/Link/link.ts @@ -4,6 +4,7 @@ import type { VariantProps } from "class-variance-authority" export interface LinkProps extends React.AnchorHTMLAttributes, - VariantProps { + VariantProps { href: string + partialMatch?: boolean } diff --git a/env/server.ts b/env/server.ts index 3a35cf4bf..084f79cd9 100644 --- a/env/server.ts +++ b/env/server.ts @@ -2,6 +2,11 @@ import { createEnv } from "@t3-oss/env-nextjs" import { z } from "zod" export const env = createEnv({ + /** + * Due to t3-env only checking typeof window === "undefined" + * and Netlify running Deno, window is never "undefined" + * https://github.com/t3-oss/t3-env/issues/154 + */ isServer: typeof window === "undefined" || "Deno" in window, server: { ADOBE_SCRIPT_SRC: z.string().optional(), diff --git a/server/index.ts b/server/index.ts index 0893360bd..f9aa0e258 100644 --- a/server/index.ts +++ b/server/index.ts @@ -1,9 +1,11 @@ import { router } from "./trpc" /** Routers */ +import { contentstackRouter } from "./routers/contentstack" import { userRouter } from "./routers/user" export const appRouter = router({ + contentstack: contentstackRouter, user: userRouter, }) diff --git a/server/routers/contentstack/breadcrumbs/index.ts b/server/routers/contentstack/breadcrumbs/index.ts new file mode 100644 index 000000000..fe82072dc --- /dev/null +++ b/server/routers/contentstack/breadcrumbs/index.ts @@ -0,0 +1,5 @@ +import { mergeRouters } from "@/server/trpc" + +import { breadcrumbsQueryRouter } from "./query" + +export const breadcrumbsRouter = mergeRouters(breadcrumbsQueryRouter) diff --git a/server/routers/contentstack/breadcrumbs/output.ts b/server/routers/contentstack/breadcrumbs/output.ts new file mode 100644 index 000000000..3cfcf28bb --- /dev/null +++ b/server/routers/contentstack/breadcrumbs/output.ts @@ -0,0 +1,8 @@ +import { z } from "zod" + +export const getBreadcrumbsSchema = z.array( + z.object({ + href: z.string().optional(), + title: z.string(), + }) +) diff --git a/server/routers/contentstack/breadcrumbs/query.ts b/server/routers/contentstack/breadcrumbs/query.ts new file mode 100644 index 000000000..6e318652a --- /dev/null +++ b/server/routers/contentstack/breadcrumbs/query.ts @@ -0,0 +1,43 @@ +import { z } from "zod" + +import { badRequestError } from "@/server/errors/trpc" +import { getBreadcrumbsSchema } from "./output" +import { publicProcedure, router } from "@/server/trpc" + +const rootMyPagesBreadcrumb = { + href: "/en/my-pages", + title: "My Pages", +} + +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 = + { + "/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({ + get: publicProcedure.input(z.object({ href: z.enum(keys) })).query((opts) => { + const breadcrumbs = possibleBreadcrumbs[opts.input.href] + const validatedBreadcrumbs = getBreadcrumbsSchema.safeParse(breadcrumbs) + if (validatedBreadcrumbs.success) { + return breadcrumbs + } + + throw badRequestError() + }), +}) diff --git a/server/routers/contentstack/index.ts b/server/routers/contentstack/index.ts new file mode 100644 index 000000000..8098575a0 --- /dev/null +++ b/server/routers/contentstack/index.ts @@ -0,0 +1,7 @@ +import { router } from "@/server/trpc" + +import { breadcrumbsRouter } from "./breadcrumbs" + +export const contentstackRouter = router({ + breadcrumbs: breadcrumbsRouter, +}) diff --git a/stores/edit-profile.ts b/stores/edit-profile.ts index b77890a68..1abce359b 100644 --- a/stores/edit-profile.ts +++ b/stores/edit-profile.ts @@ -12,7 +12,7 @@ interface EditProfileActions { export interface EditProfileStore extends EditProfileActions, - EditProfileState {} + EditProfileState { } export const useProfileStore = create()((set) => ({ pending: false, diff --git a/types/breadcrumbs.ts b/types/breadcrumbs.ts new file mode 100644 index 000000000..b79abcbb4 --- /dev/null +++ b/types/breadcrumbs.ts @@ -0,0 +1,5 @@ +import { z } from "zod" + +import { getBreadcrumbsSchema } from "@/server/routers/contentstack/breadcrumbs/output" + +export interface Breadcrumbs extends z.infer {} diff --git a/types/components/myPages/breadcrumbs.ts b/types/components/myPages/breadcrumbs.ts index 953a2a5f8..0d50f0e89 100644 --- a/types/components/myPages/breadcrumbs.ts +++ b/types/components/myPages/breadcrumbs.ts @@ -1,10 +1,5 @@ -import type { LangParams } from "@/types/params" +import type { Breadcrumbs } from "@/types/breadcrumbs" -type Breadcrumb = { - href?: string - title: string +export type BreadcrumbsProps = { + breadcrumbs: Breadcrumbs } - -export type BreadcrumbsProps = LangParams & { - breadcrumbs: Record -} \ No newline at end of file diff --git a/types/components/myPages/layout.ts b/types/components/myPages/layout.ts new file mode 100644 index 000000000..ba85df203 --- /dev/null +++ b/types/components/myPages/layout.ts @@ -0,0 +1,5 @@ +import type { LangParams, LayoutArgs } from "@/types/params" + +export interface MyPagesLayoutProps extends LayoutArgs { + breadcrumbs: React.ReactNode +}