feat: improve structure and error handling
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
import { mergeRouters } from "@/server/trpc"
|
||||
|
||||
import { accountPageQueryRouter } from "./query"
|
||||
|
||||
export const accountPageRouter = mergeRouters(accountPageQueryRouter)
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
import { z } from "zod"
|
||||
|
||||
import { Lang } from "@/constants/languages"
|
||||
|
||||
export const getAccountPageInput = z.object({
|
||||
url: z.string(),
|
||||
lang: z.nativeEnum(Lang),
|
||||
})
|
||||
@@ -120,24 +120,18 @@ const accountPageContentItem = z.discriminatedUnion("__typename", [
|
||||
])
|
||||
|
||||
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),
|
||||
})
|
||||
),
|
||||
account_page: z.object({
|
||||
url: z.string(),
|
||||
title: z.string(),
|
||||
content: z.array(accountPageContentItem),
|
||||
}),
|
||||
})
|
||||
|
||||
type AccountPageDataRaw = z.infer<typeof validateAccountPageSchema>
|
||||
export type AccountPageDataRaw = z.infer<typeof validateAccountPageSchema>
|
||||
|
||||
type AccountPageRaw = AccountPageDataRaw["all_account_page"]["items"][0]
|
||||
type AccountPageRaw = AccountPageDataRaw["account_page"]
|
||||
|
||||
export type AccountPage = Omit<AccountPageRaw, "content"> & {
|
||||
url: string
|
||||
title: string
|
||||
content: AccountPageContentItem[]
|
||||
}
|
||||
|
||||
@@ -182,16 +176,12 @@ const accountPageContentItemRefs = z.discriminatedUnion("__typename", [
|
||||
])
|
||||
|
||||
export const validateAccountPageRefsSchema = z.object({
|
||||
all_account_page: z.object({
|
||||
items: z.array(
|
||||
z.object({
|
||||
content: z.array(accountPageContentItemRefs),
|
||||
system: z.object({
|
||||
content_type_uid: z.string(),
|
||||
uid: z.string(),
|
||||
}),
|
||||
})
|
||||
),
|
||||
account_page: z.object({
|
||||
content: z.array(accountPageContentItemRefs),
|
||||
system: z.object({
|
||||
content_type_uid: z.string(),
|
||||
uid: z.string(),
|
||||
}),
|
||||
}),
|
||||
})
|
||||
|
||||
|
||||
@@ -3,8 +3,8 @@ import {
|
||||
GetAccountPageRefs,
|
||||
} from "@/lib/graphql/Query/AccountPage.graphql"
|
||||
import { request } from "@/lib/graphql/request"
|
||||
import { badRequestError, internalServerError } from "@/server/errors/trpc"
|
||||
import { publicProcedure, router } from "@/server/trpc"
|
||||
import { internalServerError, notFound } from "@/server/errors/trpc"
|
||||
import { contentstackProcedure, router } from "@/server/trpc"
|
||||
|
||||
import {
|
||||
generateRefsResponseTag,
|
||||
@@ -13,7 +13,6 @@ import {
|
||||
} from "@/utils/generateTag"
|
||||
|
||||
import { removeEmptyObjects } from "../../utils"
|
||||
import { getAccountPageInput } from "./input"
|
||||
import {
|
||||
type AccountPage,
|
||||
AccountPageRefsDataRaw,
|
||||
@@ -28,122 +27,108 @@ import { Edges } from "@/types/requests/utils/edges"
|
||||
import { RTEDocument } from "@/types/rte/node"
|
||||
|
||||
export const accountPageQueryRouter = router({
|
||||
get: publicProcedure.input(getAccountPageInput).query(async ({ input }) => {
|
||||
try {
|
||||
const { lang, url } = input
|
||||
get: contentstackProcedure.query(async ({ ctx }) => {
|
||||
const { lang, uid } = ctx
|
||||
|
||||
const refsResponse = await request<AccountPageRefsDataRaw>(
|
||||
GetAccountPageRefs,
|
||||
{
|
||||
locale: lang,
|
||||
url,
|
||||
const refsResponse = await request<AccountPageRefsDataRaw>(
|
||||
GetAccountPageRefs,
|
||||
{
|
||||
locale: lang,
|
||||
uid,
|
||||
},
|
||||
{
|
||||
next: {
|
||||
tags: [generateRefsResponseTag(lang, uid)],
|
||||
},
|
||||
{
|
||||
next: {
|
||||
tags: [generateRefsResponseTag(lang, "account_page")],
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
if (!refsResponse.data) {
|
||||
console.error("Bad response for `GetAccountPageRefs`")
|
||||
console.error({ refsResponse })
|
||||
throw internalServerError()
|
||||
}
|
||||
)
|
||||
|
||||
// Remove empty objects from a fetched content type. Needed since
|
||||
// Contentstack returns empty objects for all non queried blocks in modular blocks.
|
||||
// This is an ongoing support case in Contentstack, ticker number #00031579
|
||||
const cleanedData = removeEmptyObjects(refsResponse.data)
|
||||
|
||||
const validatedAccountPageRefs =
|
||||
validateAccountPageRefsSchema.safeParse(cleanedData)
|
||||
if (!validatedAccountPageRefs.success) {
|
||||
console.error("Bad validation for `GetAccountPageRefs`")
|
||||
console.error(validatedAccountPageRefs.error)
|
||||
throw badRequestError()
|
||||
}
|
||||
|
||||
const connections = getConnections(validatedAccountPageRefs.data)
|
||||
|
||||
const tags = generateTags(lang, connections)
|
||||
|
||||
tags.push(
|
||||
generateTag(
|
||||
lang,
|
||||
validatedAccountPageRefs.data.all_account_page.items[0].system.uid
|
||||
)
|
||||
)
|
||||
const response = await request<AccountPageRefsDataRaw>(
|
||||
GetAccountPage,
|
||||
{
|
||||
locale: lang,
|
||||
url,
|
||||
},
|
||||
{ next: { tags } }
|
||||
)
|
||||
|
||||
if (!response.data) {
|
||||
throw badRequestError()
|
||||
}
|
||||
|
||||
const validatedAccountPage = validateAccountPageSchema.safeParse(
|
||||
response.data
|
||||
)
|
||||
|
||||
if (!validatedAccountPage.success) {
|
||||
console.info(`Get Account Page Validation Error`)
|
||||
console.error(validatedAccountPage.error)
|
||||
throw badRequestError()
|
||||
}
|
||||
// TODO: Make returned data nicer
|
||||
const content =
|
||||
validatedAccountPage.data.all_account_page.items[0].content.map(
|
||||
(block) => {
|
||||
switch (block.__typename) {
|
||||
case ContentEntries.AccountPageContentDynamicContent:
|
||||
return block
|
||||
case ContentEntries.AccountPageContentShortcuts:
|
||||
return {
|
||||
...block,
|
||||
shortcuts: {
|
||||
...block.shortcuts,
|
||||
shortcuts: block.shortcuts.shortcuts.map((shortcut) => ({
|
||||
text: shortcut.text,
|
||||
openInNewTab: shortcut.open_in_new_tab,
|
||||
...shortcut.linkConnection.edges[0].node,
|
||||
url:
|
||||
shortcut.linkConnection.edges[0].node.original_url ||
|
||||
`/${shortcut.linkConnection.edges[0].node.system.locale}${shortcut.linkConnection.edges[0].node.url}`,
|
||||
})),
|
||||
},
|
||||
}
|
||||
case ContentEntries.AccountPageContentTextContent:
|
||||
return {
|
||||
...block,
|
||||
text_content: {
|
||||
content: {
|
||||
json: block.text_content.content.json as RTEDocument,
|
||||
embedded_itemsConnection: block.text_content.content
|
||||
.embedded_itemsConnection as Edges<Embeds>,
|
||||
},
|
||||
},
|
||||
}
|
||||
default:
|
||||
return null
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
const accountPage = {
|
||||
...validatedAccountPage.data.all_account_page.items[0],
|
||||
content,
|
||||
} as AccountPage
|
||||
return accountPage
|
||||
} catch (error) {
|
||||
console.info(`Get Account Page Overview Error`)
|
||||
console.error(error)
|
||||
throw internalServerError()
|
||||
if (!refsResponse.data) {
|
||||
throw notFound(refsResponse)
|
||||
}
|
||||
|
||||
// Remove empty objects from a fetched content type. Needed since
|
||||
// Contentstack returns empty objects for all non queried blocks in modular blocks.
|
||||
// This is an ongoing support case in Contentstack, ticker number #00031579
|
||||
const cleanedData = removeEmptyObjects(refsResponse.data)
|
||||
|
||||
const validatedAccountPageRefs =
|
||||
validateAccountPageRefsSchema.safeParse(cleanedData)
|
||||
if (!validatedAccountPageRefs.success) {
|
||||
throw internalServerError(validatedAccountPageRefs.error)
|
||||
}
|
||||
|
||||
const connections = getConnections(validatedAccountPageRefs.data)
|
||||
|
||||
const tags = [
|
||||
generateTags(lang, connections),
|
||||
generateTag(lang, validatedAccountPageRefs.data.account_page.system.uid),
|
||||
].flat()
|
||||
|
||||
const response = await request<AccountPageRefsDataRaw>(
|
||||
GetAccountPage,
|
||||
{
|
||||
locale: lang,
|
||||
uid,
|
||||
},
|
||||
{ next: { tags } }
|
||||
)
|
||||
|
||||
if (!response.data) {
|
||||
throw notFound(response)
|
||||
}
|
||||
|
||||
const validatedAccountPage = validateAccountPageSchema.safeParse(
|
||||
response.data
|
||||
)
|
||||
|
||||
if (!validatedAccountPage.success) {
|
||||
throw internalServerError(validatedAccountPage.error)
|
||||
}
|
||||
|
||||
// TODO: Make returned data nicer
|
||||
const content = validatedAccountPage.data.account_page.content.map(
|
||||
(block) => {
|
||||
switch (block.__typename) {
|
||||
case ContentEntries.AccountPageContentDynamicContent:
|
||||
return block
|
||||
case ContentEntries.AccountPageContentShortcuts:
|
||||
return {
|
||||
...block,
|
||||
shortcuts: {
|
||||
...block.shortcuts,
|
||||
shortcuts: block.shortcuts.shortcuts.map((shortcut) => ({
|
||||
text: shortcut.text,
|
||||
openInNewTab: shortcut.open_in_new_tab,
|
||||
...shortcut.linkConnection.edges[0].node,
|
||||
url:
|
||||
shortcut.linkConnection.edges[0].node.original_url ||
|
||||
`/${shortcut.linkConnection.edges[0].node.system.locale}${shortcut.linkConnection.edges[0].node.url}`,
|
||||
})),
|
||||
},
|
||||
}
|
||||
case ContentEntries.AccountPageContentTextContent:
|
||||
return {
|
||||
...block,
|
||||
text_content: {
|
||||
content: {
|
||||
json: block.text_content.content.json as RTEDocument,
|
||||
embedded_itemsConnection: block.text_content.content
|
||||
.embedded_itemsConnection as Edges<Embeds>,
|
||||
},
|
||||
},
|
||||
}
|
||||
default:
|
||||
return null
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
const accountPage = {
|
||||
...validatedAccountPage.data.account_page,
|
||||
content,
|
||||
} as AccountPage
|
||||
|
||||
return accountPage
|
||||
}),
|
||||
})
|
||||
|
||||
@@ -6,28 +6,26 @@ import type { NodeRefs } from "@/types/requests/utils/refs"
|
||||
|
||||
export function getConnections(refs: AccountPageRefsDataRaw) {
|
||||
const connections: Edges<NodeRefs>[] = []
|
||||
refs.all_account_page.items.forEach((ref) => {
|
||||
if (ref.content) {
|
||||
ref.content.forEach((item) => {
|
||||
switch (item.__typename) {
|
||||
case ContentEntries.AccountPageContentShortcuts: {
|
||||
item.shortcuts.shortcuts.forEach((shortcut) => {
|
||||
if (shortcut.linkConnection.edges.length) {
|
||||
connections.push(shortcut.linkConnection)
|
||||
}
|
||||
})
|
||||
break
|
||||
}
|
||||
case ContentEntries.AccountPageContentDynamicContent: {
|
||||
if (item.dynamic_content.link.linkConnection.edges.length) {
|
||||
connections.push(item.dynamic_content.link.linkConnection)
|
||||
if (refs.account_page.content) {
|
||||
refs.account_page.content.forEach((item) => {
|
||||
switch (item.__typename) {
|
||||
case ContentEntries.AccountPageContentShortcuts: {
|
||||
item.shortcuts.shortcuts.forEach((shortcut) => {
|
||||
if (shortcut.linkConnection.edges.length) {
|
||||
connections.push(shortcut.linkConnection)
|
||||
}
|
||||
break
|
||||
}
|
||||
})
|
||||
break
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
case ContentEntries.AccountPageContentDynamicContent: {
|
||||
if (item.dynamic_content.link.linkConnection.edges.length) {
|
||||
connections.push(item.dynamic_content.link.linkConnection)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return connections
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user