From 840a20c4c14e5b2848a621ca3f2ca730a9b78418 Mon Sep 17 00:00:00 2001 From: Arvid Norlin Date: Thu, 25 Apr 2024 14:25:11 +0200 Subject: [PATCH] fix: improve accountPage tRPC query --- .../routers/contentstack/accountPage/input.ts | 5 + .../contentstack/accountPage/output.ts | 122 ++++++++++++++++++ .../routers/contentstack/accountPage/query.ts | 102 +++++++++------ 3 files changed, 193 insertions(+), 36 deletions(-) create mode 100644 server/routers/contentstack/accountPage/input.ts create mode 100644 server/routers/contentstack/accountPage/output.ts diff --git a/server/routers/contentstack/accountPage/input.ts b/server/routers/contentstack/accountPage/input.ts new file mode 100644 index 000000000..3643659b8 --- /dev/null +++ b/server/routers/contentstack/accountPage/input.ts @@ -0,0 +1,5 @@ +import { z } from "zod" + +import { Lang } from "@/constants/languages" + +export const getAccountPageInput = z.object({ lang: z.nativeEnum(Lang) }) diff --git a/server/routers/contentstack/accountPage/output.ts b/server/routers/contentstack/accountPage/output.ts new file mode 100644 index 000000000..a9a5896dc --- /dev/null +++ b/server/routers/contentstack/accountPage/output.ts @@ -0,0 +1,122 @@ +import { z } from "zod" + +import { + ContentEntries, + DynamicContentComponents, +} from "@/types/requests/myPages/accountpage" + +const accountPageShortcuts = z.object({ + __typename: z.literal(ContentEntries.AccountPageContentShortcuts), + title: z.string().optional(), + preamble: z.string().optional(), + shortcuts: z.object({ + title: z.string().optional(), + preamble: z.string().optional(), + shortcuts: z.array( + z.object({ + linkConnection: z.object({ + edges: z.array( + z.object({ + node: z.object({ + system: z.object({ + uid: z.string(), + locale: z.string(), + }), + url: z.string(), + title: z.string(), + }), + }) + ), + }), + text: z.string().optional(), + open_in_new_tab: z.boolean(), + }) + ), + }), +}) + +const accountPageDynamicContent = z.object({ + __typename: z.literal(ContentEntries.AccountPageContentDynamicContent), + dynamic_content: z.object({ + title: z.string().optional(), + preamble: z.string().optional(), + component: z.nativeEnum(DynamicContentComponents), + link: z + .object({ + linkConnection: z.object({ + edges: z.array( + z.object({ + node: z.object({ + system: z.object({ + uid: z.string(), + locale: z.string(), + }), + url: z.string(), + title: z.string(), + }), + }) + ), + }), + }) + .optional(), + }), +}) + +// To validate the JSON content +// https://zod.dev/?id=json-type +const literalSchema = z.union([z.string(), z.number(), z.boolean(), z.null()]) +type Literal = z.infer +type Json = Literal | { [key: string]: Json } | Json[] +const jsonSchema: z.ZodType = z.lazy(() => + z.union([literalSchema, z.array(jsonSchema), z.record(jsonSchema)]) +) + +const accountPageTextContent = z.object({ + __typename: z.literal(ContentEntries.AccountPageContentTextContent), + text_content: z.object({ + content: z.object({ + json: jsonSchema, + }), + }), +}) + +const accountPageContentItem = z.discriminatedUnion("__typename", [ + accountPageShortcuts, + accountPageDynamicContent, + accountPageTextContent, +]) + +export const validateAccountPageSchema = z.object({ + all_account_page: z.object({ + items: z.array( + z.object({ + url: z.string(), + title: z.string(), + content: z.array(accountPageContentItem), + }) + ), + }), +}) + +export const validateAccountPageOverviewSchema = z.object({ + all_account_page: z.object({ + items: z.array( + z.object({ + url: z.string(), + title: z.string(), + content: z.array(accountPageContentItem), + }) + ), + }), +}) +export const validateAccountPageBenefitsSchema = z.object({ + all_account_page: z.object({ + items: z.array( + z.object({ + url: z.string(), + title: z.string(), + content: z.array(z.object({})), + }) + ), + }), +}) diff --git a/server/routers/contentstack/accountPage/query.ts b/server/routers/contentstack/accountPage/query.ts index 15b51f926..087d49cb8 100644 --- a/server/routers/contentstack/accountPage/query.ts +++ b/server/routers/contentstack/accountPage/query.ts @@ -1,52 +1,82 @@ -import { z } from "zod" - -import { Lang } from "@/constants/languages" import GetAccountPage from "@/lib/graphql/Query/AccountPage.graphql" import { request } from "@/lib/graphql/request" -import { badRequestError } from "@/server/errors/trpc" +import { badRequestError, internalServerError } from "@/server/errors/trpc" import { publicProcedure, router } from "@/server/trpc" +import { getAccountPageInput } from "./input" +import { validateAccountPageSchema } from "./output" + import type { GetAccountPageData } from "@/types/requests/myPages/accountpage" export const accountPageQueryRouter = router({ getOverview: publicProcedure - .input(z.object({ lang: z.nativeEnum(Lang) })) + .input(getAccountPageInput) .query(async ({ input }) => { - const url = "/my-pages/overview" - const accountPage = await request( - GetAccountPage, - { - locale: input.lang, - url, - }, - { - tags: [`${url}-${input.lang}`], - } - ) - if (accountPage.data && accountPage.data.all_account_page.total) { - return accountPage.data.all_account_page.items[0] - } + try { + const url = "/my-pages/overview" + const response = await request( + GetAccountPage, + { + locale: input.lang, + url, + }, + { + tags: [`${url}-${input.lang}`], + } + ) - throw badRequestError() + if (!response.data) { + throw badRequestError() + } + + const validatedAccountPage = validateAccountPageSchema.safeParse( + response.data + ) + + if (!validatedAccountPage.success) { + throw badRequestError() + } + + return response.data.all_account_page.items[0] + } catch (error) { + console.info(`Get Account Page Overview Error`) + console.error(error) + throw internalServerError() + } }), getBenefits: publicProcedure - .input(z.object({ lang: z.nativeEnum(Lang) })) + .input(getAccountPageInput) .query(async ({ input }) => { - const url = "/my-pages/benefits" - const accountPage = await request( - GetAccountPage, - { - locale: input.lang, - url, - }, - { - tags: [`${url}-${input.lang}`], - } - ) - if (accountPage.data && accountPage.data.all_account_page.total) { - return accountPage.data.all_account_page.items[0] - } + try { + const url = "/my-pages/benefits" + const response = await request( + GetAccountPage, + { + locale: input.lang, + url, + }, + { + tags: [`${url}-${input.lang}`], + } + ) - throw badRequestError() + if (!response.data) { + throw badRequestError() + } + + const validatedAccountPage = validateAccountPageSchema.safeParse( + response.data + ) + + if (!validatedAccountPage.success) { + throw badRequestError() + } + + return response.data.all_account_page.items[0] + } catch (error) { + console.info(`Get Account Page Benefits Error`) + console.error(error) + throw internalServerError() + } }), })