Merged in feat/revalidate-account-loyalty (pull request #174)
Feat/revalidate account loyalty Approved-by: Michael Zetterberg
This commit is contained in:
@@ -2,6 +2,11 @@
|
|||||||
#import "../Fragments/MyPages/AccountPage/AccountPageContentShortcuts.graphql"
|
#import "../Fragments/MyPages/AccountPage/AccountPageContentShortcuts.graphql"
|
||||||
#import "../Fragments/MyPages/AccountPage/AccountPageContentTextContent.graphql"
|
#import "../Fragments/MyPages/AccountPage/AccountPageContentTextContent.graphql"
|
||||||
|
|
||||||
|
#import "../Fragments/Refs/AccountPage.graphql"
|
||||||
|
#import "../Fragments/Refs/ContentPage.graphql"
|
||||||
|
#import "../Fragments/Refs/LoyaltyPage.graphql"
|
||||||
|
#import "../Fragments/Refs/System.graphql"
|
||||||
|
|
||||||
query GetAccountPage($locale: String!, $url: String!) {
|
query GetAccountPage($locale: String!, $url: String!) {
|
||||||
all_account_page(limit: 1, locale: $locale, where: { url: $url }) {
|
all_account_page(limit: 1, locale: $locale, where: { url: $url }) {
|
||||||
items {
|
items {
|
||||||
@@ -17,3 +22,48 @@ query GetAccountPage($locale: String!, $url: String!) {
|
|||||||
total
|
total
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
query GetAccountPageRefs($locale: String!, $url: String!) {
|
||||||
|
all_account_page(limit: 1, locale: $locale, where: { url: $url }) {
|
||||||
|
items {
|
||||||
|
content {
|
||||||
|
... on AccountPageContentDynamicContent {
|
||||||
|
__typename
|
||||||
|
dynamic_content {
|
||||||
|
link {
|
||||||
|
linkConnection {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
__typename
|
||||||
|
...AccountPageRef
|
||||||
|
...LoyaltyPageRef
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
... on AccountPageContentShortcuts {
|
||||||
|
__typename
|
||||||
|
shortcuts {
|
||||||
|
shortcuts {
|
||||||
|
linkConnection {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
__typename
|
||||||
|
...AccountPageRef
|
||||||
|
...ContentPageRef
|
||||||
|
...LoyaltyPageRef
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
system {
|
||||||
|
...System
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,6 +3,11 @@
|
|||||||
#import "../Fragments/PageLink/ContentPageLink.graphql"
|
#import "../Fragments/PageLink/ContentPageLink.graphql"
|
||||||
#import "../Fragments/PageLink/LoyaltyPageLink.graphql"
|
#import "../Fragments/PageLink/LoyaltyPageLink.graphql"
|
||||||
|
|
||||||
|
#import "../Fragments/Refs/AccountPage.graphql"
|
||||||
|
#import "../Fragments/Refs/ContentPage.graphql"
|
||||||
|
#import "../Fragments/Refs/LoyaltyPage.graphql"
|
||||||
|
#import "../Fragments/Refs/System.graphql"
|
||||||
|
|
||||||
query GetLoyaltyPage($locale: String!, $url: String!) {
|
query GetLoyaltyPage($locale: String!, $url: String!) {
|
||||||
all_loyalty_page(where: { url: $url }, locale: $locale) {
|
all_loyalty_page(where: { url: $url }, locale: $locale) {
|
||||||
items {
|
items {
|
||||||
@@ -145,3 +150,119 @@ query GetLoyaltyPage($locale: String!, $url: String!) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
query GetLoyaltyPageRefs($locale: String!, $url: String!) {
|
||||||
|
all_loyalty_page(where: { url: $url }, locale: $locale) {
|
||||||
|
items {
|
||||||
|
blocks {
|
||||||
|
... on LoyaltyPageBlocksShortcuts {
|
||||||
|
__typename
|
||||||
|
shortcuts {
|
||||||
|
shortcuts {
|
||||||
|
linkConnection {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
__typename
|
||||||
|
...AccountPageRef
|
||||||
|
...ContentPageRef
|
||||||
|
...LoyaltyPageRef
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
... on LoyaltyPageBlocksDynamicContent {
|
||||||
|
__typename
|
||||||
|
dynamic_content {
|
||||||
|
link {
|
||||||
|
pageConnection {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
__typename
|
||||||
|
...ContentPageRef
|
||||||
|
...LoyaltyPageRef
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
... on LoyaltyPageBlocksCardGrid {
|
||||||
|
__typename
|
||||||
|
card_grid {
|
||||||
|
cards {
|
||||||
|
referenceConnection {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
__typename
|
||||||
|
...AccountPageRef
|
||||||
|
...ContentPageRef
|
||||||
|
...LoyaltyPageRef
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
... on LoyaltyPageBlocksContent {
|
||||||
|
__typename
|
||||||
|
content {
|
||||||
|
content {
|
||||||
|
embedded_itemsConnection {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
# No fragments used since we want to include __typename for each type to avoid fetching SystemAsset
|
||||||
|
... on ContentPage {
|
||||||
|
__typename
|
||||||
|
system {
|
||||||
|
...System
|
||||||
|
}
|
||||||
|
}
|
||||||
|
... on LoyaltyPage {
|
||||||
|
__typename
|
||||||
|
system {
|
||||||
|
...System
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sidebar {
|
||||||
|
... on LoyaltyPageSidebarContent {
|
||||||
|
__typename
|
||||||
|
content {
|
||||||
|
content {
|
||||||
|
embedded_itemsConnection {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
# No fragments used since we want to include __typename for each type to avoid fetching SystemAsset
|
||||||
|
... on ContentPage {
|
||||||
|
__typename
|
||||||
|
system {
|
||||||
|
...System
|
||||||
|
}
|
||||||
|
}
|
||||||
|
... on LoyaltyPage {
|
||||||
|
__typename
|
||||||
|
system {
|
||||||
|
...System
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
system {
|
||||||
|
...System
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
29
package-lock.json
generated
29
package-lock.json
generated
@@ -21,6 +21,7 @@
|
|||||||
"@trpc/react-query": "^11.0.0-next-beta.318",
|
"@trpc/react-query": "^11.0.0-next-beta.318",
|
||||||
"@trpc/server": "^11.0.0-next-beta.318",
|
"@trpc/server": "^11.0.0-next-beta.318",
|
||||||
"class-variance-authority": "^0.7.0",
|
"class-variance-authority": "^0.7.0",
|
||||||
|
"clean-deep": "^3.4.0",
|
||||||
"dayjs": "^1.11.10",
|
"dayjs": "^1.11.10",
|
||||||
"deepmerge": "^4.3.1",
|
"deepmerge": "^4.3.1",
|
||||||
"graphql": "^16.8.1",
|
"graphql": "^16.8.1",
|
||||||
@@ -3494,6 +3495,19 @@
|
|||||||
"url": "https://joebell.co.uk"
|
"url": "https://joebell.co.uk"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/clean-deep": {
|
||||||
|
"version": "3.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/clean-deep/-/clean-deep-3.4.0.tgz",
|
||||||
|
"integrity": "sha512-Lo78NV5ItJL/jl+B5w0BycAisaieJGXK1qYi/9m4SjR8zbqmrUtO7Yhro40wEShGmmxs/aJLI/A+jNhdkXK8mw==",
|
||||||
|
"dependencies": {
|
||||||
|
"lodash.isempty": "^4.4.0",
|
||||||
|
"lodash.isplainobject": "^4.0.6",
|
||||||
|
"lodash.transform": "^4.6.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/clean-stack": {
|
"node_modules/clean-stack": {
|
||||||
"version": "2.2.0",
|
"version": "2.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz",
|
||||||
@@ -7503,6 +7517,16 @@
|
|||||||
"integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==",
|
"integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/lodash.isempty": {
|
||||||
|
"version": "4.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash.isempty/-/lodash.isempty-4.4.0.tgz",
|
||||||
|
"integrity": "sha512-oKMuF3xEeqDltrGMfDxAPGIVMSSRv8tbRSODbrs4KGsRRLEhrW8N8Rd4DRgB2+621hY8A8XwwrTVhXWpxFvMzg=="
|
||||||
|
},
|
||||||
|
"node_modules/lodash.isplainobject": {
|
||||||
|
"version": "4.0.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
|
||||||
|
"integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA=="
|
||||||
|
},
|
||||||
"node_modules/lodash.merge": {
|
"node_modules/lodash.merge": {
|
||||||
"version": "4.6.2",
|
"version": "4.6.2",
|
||||||
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
|
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
|
||||||
@@ -7521,6 +7545,11 @@
|
|||||||
"integrity": "sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==",
|
"integrity": "sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/lodash.transform": {
|
||||||
|
"version": "4.6.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash.transform/-/lodash.transform-4.6.0.tgz",
|
||||||
|
"integrity": "sha512-LO37ZnhmBVx0GvOU/caQuipEh4GN82TcWv3yHlebGDgOxbxiwwzW5Pcx2AcvpIv2WmvmSMoC492yQFNhy/l/UQ=="
|
||||||
|
},
|
||||||
"node_modules/log-symbols": {
|
"node_modules/log-symbols": {
|
||||||
"version": "4.1.0",
|
"version": "4.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz",
|
||||||
|
|||||||
@@ -34,6 +34,7 @@
|
|||||||
"@trpc/react-query": "^11.0.0-next-beta.318",
|
"@trpc/react-query": "^11.0.0-next-beta.318",
|
||||||
"@trpc/server": "^11.0.0-next-beta.318",
|
"@trpc/server": "^11.0.0-next-beta.318",
|
||||||
"class-variance-authority": "^0.7.0",
|
"class-variance-authority": "^0.7.0",
|
||||||
|
"clean-deep": "^3.4.0",
|
||||||
"dayjs": "^1.11.10",
|
"dayjs": "^1.11.10",
|
||||||
"deepmerge": "^4.3.1",
|
"deepmerge": "^4.3.1",
|
||||||
"graphql": "^16.8.1",
|
"graphql": "^16.8.1",
|
||||||
@@ -73,4 +74,4 @@
|
|||||||
"engines": {
|
"engines": {
|
||||||
"node": "18"
|
"node": "18"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import {
|
|||||||
DynamicContentComponents,
|
DynamicContentComponents,
|
||||||
} from "@/types/components/myPages/myPage/enums"
|
} from "@/types/components/myPages/myPage/enums"
|
||||||
import { Embeds } from "@/types/requests/embeds"
|
import { Embeds } from "@/types/requests/embeds"
|
||||||
|
import { PageLinkEnum } from "@/types/requests/pageLinks"
|
||||||
import { Edges } from "@/types/requests/utils/edges"
|
import { Edges } from "@/types/requests/utils/edges"
|
||||||
import { RTEDocument } from "@/types/rte/node"
|
import { RTEDocument } from "@/types/rte/node"
|
||||||
|
|
||||||
@@ -139,3 +140,61 @@ export type AccountPage = Omit<AccountPageRaw, "content"> & {
|
|||||||
title: string
|
title: string
|
||||||
content: AccountPageContentItem[]
|
content: AccountPageContentItem[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Refs types
|
||||||
|
const pageConnectionRefs = z.object({
|
||||||
|
edges: z.array(
|
||||||
|
z.object({
|
||||||
|
node: z.object({
|
||||||
|
__typename: z.nativeEnum(PageLinkEnum),
|
||||||
|
system: z.object({
|
||||||
|
content_type_uid: z.string(),
|
||||||
|
uid: z.string(),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
),
|
||||||
|
})
|
||||||
|
|
||||||
|
const accountPageShortcutsRefs = z.object({
|
||||||
|
__typename: z.literal(ContentEntries.AccountPageContentShortcuts),
|
||||||
|
shortcuts: z.object({
|
||||||
|
shortcuts: z.array(
|
||||||
|
z.object({
|
||||||
|
linkConnection: pageConnectionRefs,
|
||||||
|
})
|
||||||
|
),
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
|
||||||
|
const accountPageDynamicContentRefs = z.object({
|
||||||
|
__typename: z.literal(ContentEntries.AccountPageContentDynamicContent),
|
||||||
|
dynamic_content: z.object({
|
||||||
|
link: z.object({
|
||||||
|
linkConnection: pageConnectionRefs,
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
|
||||||
|
const accountPageContentItemRefs = z.discriminatedUnion("__typename", [
|
||||||
|
accountPageDynamicContentRefs,
|
||||||
|
accountPageShortcutsRefs,
|
||||||
|
])
|
||||||
|
|
||||||
|
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(),
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
),
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
|
||||||
|
export type AccountPageRefsDataRaw = z.infer<
|
||||||
|
typeof validateAccountPageRefsSchema
|
||||||
|
>
|
||||||
|
|||||||
@@ -1,10 +1,26 @@
|
|||||||
import GetAccountPage from "@/lib/graphql/Query/AccountPage.graphql"
|
import {
|
||||||
|
GetAccountPage,
|
||||||
|
GetAccountPageRefs,
|
||||||
|
} from "@/lib/graphql/Query/AccountPage.graphql"
|
||||||
import { request } from "@/lib/graphql/request"
|
import { request } from "@/lib/graphql/request"
|
||||||
import { badRequestError, internalServerError } from "@/server/errors/trpc"
|
import { badRequestError, internalServerError } from "@/server/errors/trpc"
|
||||||
import { publicProcedure, router } from "@/server/trpc"
|
import { publicProcedure, router } from "@/server/trpc"
|
||||||
|
|
||||||
|
import {
|
||||||
|
generateRefsResponseTag,
|
||||||
|
generateTag,
|
||||||
|
generateTags,
|
||||||
|
} from "@/utils/generateTag"
|
||||||
|
|
||||||
|
import { removeEmptyObjects } from "../../utils"
|
||||||
import { getAccountPageInput } from "./input"
|
import { getAccountPageInput } from "./input"
|
||||||
import { type AccountPage, validateAccountPageSchema } from "./output"
|
import {
|
||||||
|
type AccountPage,
|
||||||
|
AccountPageRefsDataRaw,
|
||||||
|
validateAccountPageRefsSchema,
|
||||||
|
validateAccountPageSchema,
|
||||||
|
} from "./output"
|
||||||
|
import { getConnections } from "./utils"
|
||||||
|
|
||||||
import { ContentEntries } from "@/types/components/myPages/myPage/enums"
|
import { ContentEntries } from "@/types/components/myPages/myPage/enums"
|
||||||
import { Embeds } from "@/types/requests/embeds"
|
import { Embeds } from "@/types/requests/embeds"
|
||||||
@@ -14,10 +30,58 @@ import { RTEDocument } from "@/types/rte/node"
|
|||||||
export const accountPageQueryRouter = router({
|
export const accountPageQueryRouter = router({
|
||||||
get: publicProcedure.input(getAccountPageInput).query(async ({ input }) => {
|
get: publicProcedure.input(getAccountPageInput).query(async ({ input }) => {
|
||||||
try {
|
try {
|
||||||
const response = await request<AccountPage>(GetAccountPage, {
|
const { lang, url } = input
|
||||||
locale: input.lang,
|
|
||||||
url: input.url,
|
const refsResponse = await request<AccountPageRefsDataRaw>(
|
||||||
})
|
GetAccountPageRefs,
|
||||||
|
{
|
||||||
|
locale: lang,
|
||||||
|
url,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
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) {
|
if (!response.data) {
|
||||||
throw badRequestError()
|
throw badRequestError()
|
||||||
|
|||||||
33
server/routers/contentstack/accountPage/utils.ts
Normal file
33
server/routers/contentstack/accountPage/utils.ts
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
import { AccountPageRefsDataRaw } from "./output"
|
||||||
|
|
||||||
|
import { ContentEntries } from "@/types/components/myPages/myPage/enums"
|
||||||
|
import type { Edges } from "@/types/requests/utils/edges"
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return connections
|
||||||
|
}
|
||||||
@@ -9,6 +9,7 @@ import {
|
|||||||
SidebarTypenameEnum,
|
SidebarTypenameEnum,
|
||||||
} from "@/types/components/loyalty/enums"
|
} from "@/types/components/loyalty/enums"
|
||||||
import { Embeds } from "@/types/requests/embeds"
|
import { Embeds } from "@/types/requests/embeds"
|
||||||
|
import { PageLinkEnum } from "@/types/requests/pageLinks"
|
||||||
import { EdgesWithTotalCount } from "@/types/requests/utils/edges"
|
import { EdgesWithTotalCount } from "@/types/requests/utils/edges"
|
||||||
import { RTEDocument } from "@/types/rte/node"
|
import { RTEDocument } from "@/types/rte/node"
|
||||||
|
|
||||||
@@ -262,3 +263,99 @@ export type LoyaltyPage = Omit<LoyaltyPageRaw, "blocks" | "sidebar"> & {
|
|||||||
blocks: Block[]
|
blocks: Block[]
|
||||||
sidebar: Sidebar[]
|
sidebar: Sidebar[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Refs types
|
||||||
|
const pageConnectionRefs = z.object({
|
||||||
|
edges: z.array(
|
||||||
|
z.object({
|
||||||
|
node: z.object({
|
||||||
|
__typename: z.nativeEnum(PageLinkEnum),
|
||||||
|
system: z.object({
|
||||||
|
content_type_uid: z.string(),
|
||||||
|
uid: z.string(),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
),
|
||||||
|
})
|
||||||
|
|
||||||
|
const loyaltyPageBlockCardGridRefs = z.object({
|
||||||
|
__typename: z.literal(LoyaltyBlocksTypenameEnum.LoyaltyPageBlocksCardGrid),
|
||||||
|
card_grid: z.object({
|
||||||
|
cards: z.array(
|
||||||
|
z.object({
|
||||||
|
referenceConnection: pageConnectionRefs,
|
||||||
|
})
|
||||||
|
),
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
|
||||||
|
const loyaltyPageDynamicContentRefs = z.object({
|
||||||
|
__typename: z.literal(
|
||||||
|
LoyaltyBlocksTypenameEnum.LoyaltyPageBlocksDynamicContent
|
||||||
|
),
|
||||||
|
dynamic_content: z.object({
|
||||||
|
link: z.object({
|
||||||
|
pageConnection: pageConnectionRefs,
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
|
||||||
|
const loyaltyPageShortcutsRefs = z.object({
|
||||||
|
__typename: z.literal(LoyaltyBlocksTypenameEnum.LoyaltyPageBlocksShortcuts),
|
||||||
|
shortcuts: z.object({
|
||||||
|
shortcuts: z.array(
|
||||||
|
z.object({
|
||||||
|
linkConnection: pageConnectionRefs,
|
||||||
|
})
|
||||||
|
),
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
|
||||||
|
const loyaltyPageBlockTextContentRefs = z.object({
|
||||||
|
__typename: z.literal(LoyaltyBlocksTypenameEnum.LoyaltyPageBlocksContent),
|
||||||
|
content: z.object({
|
||||||
|
content: z.object({
|
||||||
|
embedded_itemsConnection: pageConnectionRefs,
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
|
||||||
|
const loyaltyPageBlocRefsItem = z.discriminatedUnion("__typename", [
|
||||||
|
loyaltyPageBlockCardGridRefs,
|
||||||
|
loyaltyPageDynamicContentRefs,
|
||||||
|
loyaltyPageBlockTextContentRefs,
|
||||||
|
loyaltyPageShortcutsRefs,
|
||||||
|
])
|
||||||
|
|
||||||
|
const loyaltyPageSidebarTextContentRef = z.object({
|
||||||
|
__typename: z.literal(SidebarTypenameEnum.LoyaltyPageSidebarContent),
|
||||||
|
content: z.object({
|
||||||
|
content: z.object({
|
||||||
|
embedded_itemsConnection: pageConnectionRefs,
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
|
||||||
|
const loyaltyPageSidebarRefsItem = z.discriminatedUnion("__typename", [
|
||||||
|
loyaltyPageSidebarTextContentRef,
|
||||||
|
])
|
||||||
|
|
||||||
|
export const validateLoyaltyPageRefsSchema = z.object({
|
||||||
|
all_loyalty_page: z.object({
|
||||||
|
items: z.array(
|
||||||
|
z.object({
|
||||||
|
blocks: z.array(loyaltyPageBlocRefsItem).nullable(),
|
||||||
|
sidebar: z.array(loyaltyPageSidebarRefsItem).nullable(),
|
||||||
|
system: z.object({
|
||||||
|
content_type_uid: z.string(),
|
||||||
|
uid: z.string(),
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
),
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
|
||||||
|
export type LoyaltyPageRefsDataRaw = z.infer<
|
||||||
|
typeof validateLoyaltyPageRefsSchema
|
||||||
|
>
|
||||||
|
|||||||
@@ -1,15 +1,28 @@
|
|||||||
import GetLoyaltyPage from "@/lib/graphql/Query/LoyaltyPage.graphql"
|
import {
|
||||||
|
GetLoyaltyPage,
|
||||||
|
GetLoyaltyPageRefs,
|
||||||
|
} from "@/lib/graphql/Query/LoyaltyPage.graphql"
|
||||||
import { request } from "@/lib/graphql/request"
|
import { request } from "@/lib/graphql/request"
|
||||||
import { _ } from "@/lib/translation"
|
import { _ } from "@/lib/translation"
|
||||||
import { badRequestError } from "@/server/errors/trpc"
|
import { badRequestError, internalServerError } from "@/server/errors/trpc"
|
||||||
import { publicProcedure, router } from "@/server/trpc"
|
import { publicProcedure, router } from "@/server/trpc"
|
||||||
|
|
||||||
|
import {
|
||||||
|
generateRefsResponseTag,
|
||||||
|
generateTag,
|
||||||
|
generateTags,
|
||||||
|
} from "@/utils/generateTag"
|
||||||
|
|
||||||
|
import { removeEmptyObjects } from "../../utils"
|
||||||
import { getLoyaltyPageInput } from "./input"
|
import { getLoyaltyPageInput } from "./input"
|
||||||
import {
|
import {
|
||||||
type LoyaltyPage,
|
type LoyaltyPage,
|
||||||
type LoyaltyPageDataRaw,
|
type LoyaltyPageDataRaw,
|
||||||
|
type LoyaltyPageRefsDataRaw,
|
||||||
|
validateLoyaltyPageRefsSchema,
|
||||||
validateLoyaltyPageSchema,
|
validateLoyaltyPageSchema,
|
||||||
} from "./output"
|
} from "./output"
|
||||||
|
import { getConnections } from "./utils"
|
||||||
|
|
||||||
import {
|
import {
|
||||||
LoyaltyBlocksTypenameEnum,
|
LoyaltyBlocksTypenameEnum,
|
||||||
@@ -22,10 +35,59 @@ import { RTEDocument } from "@/types/rte/node"
|
|||||||
export const loyaltyPageQueryRouter = router({
|
export const loyaltyPageQueryRouter = router({
|
||||||
get: publicProcedure.input(getLoyaltyPageInput).query(async ({ input }) => {
|
get: publicProcedure.input(getLoyaltyPageInput).query(async ({ input }) => {
|
||||||
try {
|
try {
|
||||||
const loyaltyPageRes = await request<LoyaltyPageDataRaw>(GetLoyaltyPage, {
|
const { locale } = input
|
||||||
locale: input.locale,
|
|
||||||
url: input.href,
|
const refsResponse = await request<LoyaltyPageRefsDataRaw>(
|
||||||
})
|
GetLoyaltyPageRefs,
|
||||||
|
{
|
||||||
|
locale,
|
||||||
|
url: input.href,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
next: {
|
||||||
|
tags: [generateRefsResponseTag(locale, "loyalty_page")],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
if (!refsResponse.data) {
|
||||||
|
console.error("Bad response for `GetLoyaltyPageRefs`")
|
||||||
|
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 validatedLoyaltyPageRefs =
|
||||||
|
validateLoyaltyPageRefsSchema.safeParse(cleanedData)
|
||||||
|
if (!validatedLoyaltyPageRefs.success) {
|
||||||
|
console.error("Bad validation for `GetLoyaltyPageRefs`")
|
||||||
|
console.error(validatedLoyaltyPageRefs.error)
|
||||||
|
throw badRequestError()
|
||||||
|
}
|
||||||
|
|
||||||
|
const connections = getConnections(validatedLoyaltyPageRefs.data)
|
||||||
|
|
||||||
|
const tags = generateTags(locale, connections)
|
||||||
|
|
||||||
|
tags.push(
|
||||||
|
generateTag(
|
||||||
|
locale,
|
||||||
|
validatedLoyaltyPageRefs.data.all_loyalty_page.items[0].system.uid
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
const loyaltyPageRes = await request<LoyaltyPageDataRaw>(
|
||||||
|
GetLoyaltyPage,
|
||||||
|
{
|
||||||
|
locale,
|
||||||
|
url: input.href,
|
||||||
|
},
|
||||||
|
{ next: { tags } }
|
||||||
|
)
|
||||||
|
|
||||||
if (!loyaltyPageRes.data) {
|
if (!loyaltyPageRes.data) {
|
||||||
throw badRequestError()
|
throw badRequestError()
|
||||||
|
|||||||
54
server/routers/contentstack/loyaltyPage/utils.ts
Normal file
54
server/routers/contentstack/loyaltyPage/utils.ts
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
import { LoyaltyPageRefsDataRaw } from "./output"
|
||||||
|
|
||||||
|
import { LoyaltyBlocksTypenameEnum } from "@/types/components/loyalty/enums"
|
||||||
|
import type { Edges } from "@/types/requests/utils/edges"
|
||||||
|
import type { NodeRefs } from "@/types/requests/utils/refs"
|
||||||
|
|
||||||
|
export function getConnections(refs: LoyaltyPageRefsDataRaw) {
|
||||||
|
const connections: Edges<NodeRefs>[] = []
|
||||||
|
refs.all_loyalty_page.items.forEach((ref) => {
|
||||||
|
if (ref.blocks) {
|
||||||
|
ref.blocks.forEach((item) => {
|
||||||
|
switch (item.__typename) {
|
||||||
|
case LoyaltyBlocksTypenameEnum.LoyaltyPageBlocksContent: {
|
||||||
|
if (item.content.content.embedded_itemsConnection.edges.length) {
|
||||||
|
connections.push(item.content.content.embedded_itemsConnection)
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case LoyaltyBlocksTypenameEnum.LoyaltyPageBlocksCardGrid: {
|
||||||
|
item.card_grid.cards.forEach((card) => {
|
||||||
|
if (card.referenceConnection.edges.length) {
|
||||||
|
connections.push(card.referenceConnection)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case LoyaltyBlocksTypenameEnum.LoyaltyPageBlocksShortcuts: {
|
||||||
|
item.shortcuts.shortcuts.forEach((shortcut) => {
|
||||||
|
if (shortcut.linkConnection.edges.length) {
|
||||||
|
connections.push(shortcut.linkConnection)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case LoyaltyBlocksTypenameEnum.LoyaltyPageBlocksDynamicContent: {
|
||||||
|
if (item.dynamic_content.link.pageConnection.edges.length) {
|
||||||
|
connections.push(item.dynamic_content.link.pageConnection)
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if (ref.sidebar) {
|
||||||
|
ref.sidebar?.forEach((item) => {
|
||||||
|
if (item.content.content.embedded_itemsConnection.edges.length) {
|
||||||
|
connections.push(item.content.content.embedded_itemsConnection)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return connections
|
||||||
|
}
|
||||||
@@ -2,7 +2,7 @@ import { z } from "zod"
|
|||||||
|
|
||||||
import { Lang } from "@/constants/languages"
|
import { Lang } from "@/constants/languages"
|
||||||
|
|
||||||
import { PageLinkEnum } from "@/types/requests/myPages/navigation"
|
import { PageLinkEnum } from "@/types/requests/pageLinks"
|
||||||
|
|
||||||
const pageConnection = z.object({
|
const pageConnection = z.object({
|
||||||
edges: z.array(
|
edges: z.array(
|
||||||
|
|||||||
15
server/routers/utils/index.ts
Normal file
15
server/routers/utils/index.ts
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import cleaner from "clean-deep"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function to remove empty objects from a fetched content type.
|
||||||
|
* Used since Contentstack returns empty objects for all non
|
||||||
|
* queried in modular blocks.
|
||||||
|
*/
|
||||||
|
export function removeEmptyObjects<T>(obj: T) {
|
||||||
|
return cleaner(obj, {
|
||||||
|
emptyArrays: false,
|
||||||
|
emptyStrings: false,
|
||||||
|
nullValues: false,
|
||||||
|
undefinedValues: false,
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -1,15 +1,11 @@
|
|||||||
|
import { PageLinkEnum } from "../pageLinks"
|
||||||
|
|
||||||
import type { Lang } from "@/constants/languages"
|
import type { Lang } from "@/constants/languages"
|
||||||
import type { System } from "../system"
|
import type { System } from "../system"
|
||||||
import type { AllRequestResponse } from "../utils/all"
|
import type { AllRequestResponse } from "../utils/all"
|
||||||
import type { Edges } from "../utils/edges"
|
import type { Edges } from "../utils/edges"
|
||||||
import type { TypenameInterface } from "../utils/typename"
|
import type { TypenameInterface } from "../utils/typename"
|
||||||
|
|
||||||
export enum PageLinkEnum {
|
|
||||||
AccountPage = "AccountPage",
|
|
||||||
ContentPage = "ContentPage",
|
|
||||||
LoyaltyPage = "LoyaltyPage",
|
|
||||||
}
|
|
||||||
|
|
||||||
export type MenuItem = {
|
export type MenuItem = {
|
||||||
lang: Lang
|
lang: Lang
|
||||||
linkText: string
|
linkText: string
|
||||||
|
|||||||
5
types/requests/pageLinks.ts
Normal file
5
types/requests/pageLinks.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
export enum PageLinkEnum {
|
||||||
|
AccountPage = "AccountPage",
|
||||||
|
ContentPage = "ContentPage",
|
||||||
|
LoyaltyPage = "LoyaltyPage",
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user