feat: revalidate my pages breadcrumbs on demand
This commit is contained in:
committed by
Michael Zetterberg
parent
ba13a00b63
commit
0c4aa592cc
@@ -1,7 +1,7 @@
|
||||
import { TRPCError } from "@trpc/server"
|
||||
import {
|
||||
TRPC_ERROR_CODES_BY_NUMBER,
|
||||
TRPC_ERROR_CODES_BY_KEY,
|
||||
TRPC_ERROR_CODES_BY_NUMBER,
|
||||
} from "@trpc/server/rpc"
|
||||
|
||||
export function unauthorizedError() {
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
import { z } from "zod";
|
||||
import { z } from "zod"
|
||||
|
||||
import { Lang } from "@/constants/languages";
|
||||
|
||||
const langs = Object.keys(Lang) as [keyof typeof Lang]
|
||||
import { Lang } from "@/constants/languages"
|
||||
|
||||
export const getBreadcrumbsInput = z.object({
|
||||
href: z.string().min(1, { message: "href is required" }),
|
||||
locale: z.enum(langs),
|
||||
locale: z.nativeEnum(Lang),
|
||||
})
|
||||
|
||||
@@ -1,12 +1,40 @@
|
||||
import { Lang } from "@/constants/languages"
|
||||
import { z } from "zod"
|
||||
|
||||
export const validateBreadcrumbsRefsConstenstackSchema = z.object({
|
||||
all_account_page: z.object({
|
||||
items: z.array(
|
||||
z.object({
|
||||
breadcrumbs: z.object({
|
||||
parentsConnection: z.object({
|
||||
edges: z.array(
|
||||
z.object({
|
||||
node: z.object({
|
||||
system: z.object({
|
||||
content_type_uid: z.string(),
|
||||
uid: z.string(),
|
||||
}),
|
||||
}),
|
||||
})
|
||||
),
|
||||
}),
|
||||
}),
|
||||
system: z.object({
|
||||
content_type_uid: z.string(),
|
||||
uid: z.string(),
|
||||
}),
|
||||
})
|
||||
),
|
||||
}),
|
||||
})
|
||||
|
||||
export const validateBreadcrumbsConstenstackSchema = z.object({
|
||||
all_account_page: z.object({
|
||||
items: z.array(
|
||||
z.object({
|
||||
breadcrumbs: z.object({
|
||||
title: z.string(),
|
||||
parents: z.object({
|
||||
parentsConnection: z.object({
|
||||
edges: z.array(
|
||||
z.object({
|
||||
node: z.object({
|
||||
@@ -14,6 +42,7 @@ export const validateBreadcrumbsConstenstackSchema = z.object({
|
||||
title: z.string(),
|
||||
}),
|
||||
system: z.object({
|
||||
locale: z.nativeEnum(Lang),
|
||||
uid: z.string(),
|
||||
}),
|
||||
url: z.string(),
|
||||
|
||||
@@ -1,51 +1,120 @@
|
||||
import { GetMyPagesBreadcrumbs } from "@/lib/graphql/Query/BreadcrumbsMyPages.graphql"
|
||||
import {
|
||||
GetMyPagesBreadcrumbs,
|
||||
GetMyPagesBreadcrumbsRefs,
|
||||
} from "@/lib/graphql/Query/BreadcrumbsMyPages.graphql"
|
||||
import { request } from "@/lib/graphql/request"
|
||||
import { badRequestError, internalServerError } from "@/server/errors/trpc"
|
||||
import { publicProcedure, router } from "@/server/trpc"
|
||||
|
||||
import { getBreadcrumbsInput } from "./input"
|
||||
import { validateBreadcrumbsConstenstackSchema } from "./output"
|
||||
import {
|
||||
generateRefsResponseTag,
|
||||
generateTag,
|
||||
generateTags,
|
||||
} from "@/utils/generateTag"
|
||||
import { removeMultipleSlashes } from "@/utils/url"
|
||||
|
||||
import { GetMyPagesBreadcrumbsData } from "@/types/requests/myPages/breadcrumbs"
|
||||
import { getBreadcrumbsInput } from "./input"
|
||||
import {
|
||||
getBreadcrumbsSchema,
|
||||
validateBreadcrumbsConstenstackSchema,
|
||||
validateBreadcrumbsRefsConstenstackSchema,
|
||||
} from "./output"
|
||||
import { affix, getConnections, homeBreadcrumbs } from "./utils"
|
||||
|
||||
import type {
|
||||
GetMyPagesBreadcrumbsData,
|
||||
GetMyPagesBreadcrumbsRefsData,
|
||||
} from "@/types/requests/myPages/breadcrumbs"
|
||||
|
||||
export const breadcrumbsQueryRouter = router({
|
||||
get: publicProcedure.input(getBreadcrumbsInput).query(async ({ input }) => {
|
||||
try {
|
||||
const response = await request<GetMyPagesBreadcrumbsData>(
|
||||
GetMyPagesBreadcrumbs,
|
||||
{ locale: input.locale, url: input.href }
|
||||
const refsResponse = await request<GetMyPagesBreadcrumbsRefsData>(
|
||||
GetMyPagesBreadcrumbsRefs,
|
||||
{ locale: input.locale, url: input.href },
|
||||
{
|
||||
next: {
|
||||
tags: [generateRefsResponseTag(input.locale, input.href, affix)],
|
||||
},
|
||||
}
|
||||
)
|
||||
if (!response.data) {
|
||||
|
||||
if (!refsResponse.data) {
|
||||
console.error("Bad response for `GetMyPagesBreadcrumbsRefs`")
|
||||
console.error({ refsResponse })
|
||||
throw internalServerError()
|
||||
}
|
||||
|
||||
const validatedRefsData =
|
||||
validateBreadcrumbsRefsConstenstackSchema.safeParse(refsResponse.data)
|
||||
if (!validatedRefsData.success) {
|
||||
console.info("Bad validation for `GetMyPagesBreadcrumbsRefs`")
|
||||
console.error(validatedRefsData.error)
|
||||
throw badRequestError()
|
||||
}
|
||||
|
||||
const validatedBreadcrumbs =
|
||||
const connections = getConnections(validatedRefsData.data)
|
||||
const tags = generateTags(input.locale, connections)
|
||||
const page = validatedRefsData.data.all_account_page.items[0]
|
||||
tags.push(generateTag(input.locale, page.system.uid, affix))
|
||||
|
||||
const response = await request<GetMyPagesBreadcrumbsData>(
|
||||
GetMyPagesBreadcrumbs,
|
||||
{ locale: input.locale, url: input.href },
|
||||
{ next: { tags } }
|
||||
)
|
||||
|
||||
if (!response.data) {
|
||||
console.error("Bad response for `GetMyPagesBreadcrumbs`")
|
||||
console.error({ input })
|
||||
console.error({ response })
|
||||
throw internalServerError()
|
||||
}
|
||||
|
||||
const validatedBreadcrumbsData =
|
||||
validateBreadcrumbsConstenstackSchema.safeParse(response.data)
|
||||
if (!validatedBreadcrumbs.success) {
|
||||
if (!validatedBreadcrumbsData.success) {
|
||||
console.error("Bad validation for `GetMyPagesBreadcrumbs`")
|
||||
console.error(validatedBreadcrumbsData.error)
|
||||
throw badRequestError()
|
||||
}
|
||||
|
||||
const parentBreadcrumbs =
|
||||
validatedBreadcrumbs.data.all_account_page.items[0].breadcrumbs.parents.edges.map(
|
||||
validatedBreadcrumbsData.data.all_account_page.items[0].breadcrumbs.parentsConnection.edges.map(
|
||||
(breadcrumb) => {
|
||||
return {
|
||||
href: breadcrumb.node.url,
|
||||
href: removeMultipleSlashes(
|
||||
`/${breadcrumb.node.system.locale}/${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
|
||||
const pageBreadcrumb =
|
||||
validatedBreadcrumbsData.data.all_account_page.items.map(
|
||||
(breadcrumb) => {
|
||||
return {
|
||||
title: breadcrumb.breadcrumbs.title,
|
||||
uid: breadcrumb.system.uid,
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
const breadcrumbs = [
|
||||
homeBreadcrumbs[input.locale],
|
||||
parentBreadcrumbs,
|
||||
pageBreadcrumb,
|
||||
].flat()
|
||||
const validatedBreadcrumbs = getBreadcrumbsSchema.safeParse(breadcrumbs)
|
||||
if (!validatedBreadcrumbs.success) {
|
||||
console.info("Bad validation for `validatedBreadcrumbs`")
|
||||
console.error(validatedBreadcrumbs.error)
|
||||
throw badRequestError()
|
||||
}
|
||||
|
||||
return validatedBreadcrumbs.data
|
||||
} catch (error) {
|
||||
console.info(`Get My Pages Breadcrumbs Error`)
|
||||
console.error(error)
|
||||
|
||||
50
server/routers/contentstack/breadcrumbs/utils.ts
Normal file
50
server/routers/contentstack/breadcrumbs/utils.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
import { Lang } from "@/constants/languages"
|
||||
|
||||
import type { GetMyPagesBreadcrumbsRefsData } from "@/types/requests/myPages/breadcrumbs"
|
||||
import type { Edges } from "@/types/requests/utils/edges"
|
||||
import type { NodeRefs } from "@/types/requests/utils/refs"
|
||||
|
||||
export function getConnections(refs: GetMyPagesBreadcrumbsRefsData) {
|
||||
const connections: Edges<NodeRefs>[] = []
|
||||
refs.all_account_page.items.forEach((ref) => {
|
||||
connections.push(ref.breadcrumbs.parentsConnection)
|
||||
})
|
||||
|
||||
return connections
|
||||
}
|
||||
|
||||
export const affix = "breadcrumbs"
|
||||
|
||||
// TODO: Make these editable in CMS?
|
||||
export const homeBreadcrumbs = {
|
||||
[Lang.da]: {
|
||||
href: "/da",
|
||||
title: "Hjem",
|
||||
uid: "da",
|
||||
},
|
||||
[Lang.de]: {
|
||||
href: "/de",
|
||||
title: "Heim",
|
||||
uid: "de",
|
||||
},
|
||||
[Lang.en]: {
|
||||
href: "/en",
|
||||
title: "Home",
|
||||
uid: "en",
|
||||
},
|
||||
[Lang.fi]: {
|
||||
href: "/fi",
|
||||
title: "Koti",
|
||||
uid: "fi",
|
||||
},
|
||||
[Lang.no]: {
|
||||
href: "/no",
|
||||
title: "Hjem",
|
||||
uid: "no",
|
||||
},
|
||||
[Lang.sv]: {
|
||||
href: "/sv",
|
||||
title: "Hem",
|
||||
uid: "sv",
|
||||
},
|
||||
}
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
generateTag,
|
||||
generateTags,
|
||||
} from "@/utils/generateTag"
|
||||
import { removeMultipleSlashes } from "@/utils/url"
|
||||
|
||||
import { getNavigationInputSchema } from "./input"
|
||||
import {
|
||||
@@ -35,7 +36,7 @@ export function mapMenuItems(navigationItems: NavigationItem[]) {
|
||||
lang: node.system.locale,
|
||||
linkText: item.link_text || node.title,
|
||||
uid: node.system.uid,
|
||||
url: `/${node.system.locale}/${node.url}`.replaceAll(/\/\/+/g, "/"),
|
||||
url: removeMultipleSlashes(`/${node.system.locale}/${node.url}`),
|
||||
}
|
||||
|
||||
if ("sub_items" in item) {
|
||||
@@ -54,12 +55,16 @@ export const navigationQueryRouter = router({
|
||||
const refsResponse = await request<GetNavigationMyPagesRefsData>(
|
||||
GetNavigationMyPagesRefs,
|
||||
{ locale: lang },
|
||||
{ tags: [generateRefsResponseTag(lang, "navigation_my_pages")] }
|
||||
{
|
||||
next: {
|
||||
tags: [generateRefsResponseTag(lang, "navigation_my_pages")],
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
if (!refsResponse.data) {
|
||||
console.error("Bad response for `GetNavigationMyPagesRefs`")
|
||||
console.error(refsResponse)
|
||||
console.error({ refsResponse })
|
||||
throw internalServerError()
|
||||
}
|
||||
|
||||
@@ -80,12 +85,13 @@ export const navigationQueryRouter = router({
|
||||
const response = await request<GetNavigationMyPagesData>(
|
||||
GetNavigationMyPages,
|
||||
{ locale: lang },
|
||||
{ tags }
|
||||
{ next: { tags } }
|
||||
)
|
||||
|
||||
if (!response.data) {
|
||||
console.error("Bad response for `GetNavigationMyPages`")
|
||||
console.error(response)
|
||||
console.error({ input: lang })
|
||||
console.error({ response })
|
||||
throw internalServerError()
|
||||
}
|
||||
|
||||
|
||||
@@ -31,7 +31,6 @@ export const userQueryRouter = router({
|
||||
get: protectedProcedure.query(async function ({ ctx }) {
|
||||
try {
|
||||
const apiResponse = await api.get(api.endpoints.v0.profile, {
|
||||
cache: "no-store",
|
||||
headers: {
|
||||
Authorization: `Bearer ${ctx.session.token.access_token}`,
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user