feat(WEB-304): remaning UI from design system primitives

This commit is contained in:
Simon Emanuelsson
2024-06-07 10:36:23 +02:00
parent 6737970f54
commit 7c4b8401e9
228 changed files with 3516 additions and 3237 deletions
@@ -0,0 +1,5 @@
import { mergeRouters } from "@/server/trpc"
import { baseQueryRouter } from "./query"
export const baseRouter = mergeRouters(baseQueryRouter)
+256
View File
@@ -0,0 +1,256 @@
import { z } from "zod"
import { Image } from "@/types/image"
// Help me write this zod schema based on the type ContactConfig
export const validateContactConfigSchema = z.object({
all_contact_config: z.object({
items: z.array(
z.object({
email: z.object({
name: z.string().nullable(),
address: z.string().nullable(),
}),
email_loyalty: z.object({
name: z.string().nullable(),
address: z.string().nullable(),
}),
mailing_address: z.object({
zip: z.string().nullable(),
street: z.string().nullable(),
name: z.string().nullable(),
city: z.string().nullable(),
country: z.string().nullable(),
}),
phone: z.object({
number: z.string().nullable(),
name: z.string().nullable(),
}),
phone_loyalty: z.object({
number: z.string().nullable(),
name: z.string().nullable(),
}),
visiting_address: z.object({
zip: z.string().nullable(),
country: z.string().nullable(),
city: z.string().nullable(),
street: z.string().nullable(),
}),
})
),
}),
})
export enum ContactFieldGroupsEnum {
email = "email",
email_loyalty = "email_loyalty",
mailing_address = "mailing_address",
phone = "phone",
phone_loyalty = "phone_loyalty",
visiting_address = "visiting_address",
}
export type ContactFieldGroups = keyof typeof ContactFieldGroupsEnum
export type ContactConfigData = z.infer<typeof validateContactConfigSchema>
export type ContactConfig = ContactConfigData["all_contact_config"]["items"][0]
export type ContactFields = {
display_text: string | null
contact_field: string
}
export const validateHeaderConfigSchema = z.object({
all_current_header: z.object({
items: z.array(
z.object({
frontpage_link_text: z.string(),
logoConnection: z.object({
edges: z.array(
z.object({
node: z.object({
description: z.string().optional().nullable(),
dimension: z.object({
height: z.number(),
width: z.number(),
}),
metadata: z.any().nullable(),
system: z.object({
uid: z.string(),
}),
title: z.string().nullable(),
url: z.string().nullable(),
}),
})
),
}),
menu: z.object({
links: z.array(
z.object({
href: z.string(),
title: z.string(),
})
),
}),
top_menu: z.object({
links: z.array(
z.object({
link: z.object({
href: z.string(),
title: z.string(),
}),
show_on_mobile: z.boolean(),
sort_order_mobile: z.number(),
})
),
}),
})
),
}),
})
export type HeaderDataRaw = z.infer<typeof validateHeaderConfigSchema>
export type HeaderData = Omit<
HeaderDataRaw["all_current_header"]["items"][0],
"logoConnection"
> & {
logo: Image
}
const validateHeaderRefConfigSchema = z.object({
all_current_header: z.object({
items: z.array(
z.object({
system: z.object({
content_type_uid: z.string(),
uid: z.string(),
}),
})
),
}),
})
export type HeaderRefDataRaw = z.infer<typeof validateHeaderRefConfigSchema>
const validateAppDownload = z.object({
href: z.string(),
imageConnection: z.object({
edges: z.array(
z.object({
node: z.object({
description: z.string().optional().nullable(),
dimension: z.object({
height: z.number(),
width: z.number(),
}),
metadata: z.any().nullable(),
system: z.object({
uid: z.string(),
}),
title: z.string(),
url: z.string(),
}),
})
),
}),
})
const validateNavigationItem = z.object({
links: z.array(z.object({ href: z.string(), title: z.string() })),
title: z.string(),
})
export type NavigationItem = z.infer<typeof validateNavigationItem>
export const validateFooterConfigSchema = z.object({
all_current_footer: z.object({
items: z.array(
z.object({
title: z.string(),
about: z.object({
title: z.string(),
text: z.string(),
}),
app_downloads: z.object({
title: z.string(),
app_store: validateAppDownload,
google_play: validateAppDownload,
}),
logoConnection: z.object({
edges: z.array(
z.object({
node: z.object({
description: z.string().optional().nullable(),
dimension: z.object({
height: z.number(),
width: z.number(),
}),
metadata: z.any().nullable(),
system: z.object({
uid: z.string(),
}),
title: z.string(),
url: z.string(),
}),
})
),
}),
navigation: z.array(validateNavigationItem),
social_media: z.object({
title: z.string(),
facebook: z.object({ href: z.string(), title: z.string() }),
instagram: z.object({ href: z.string(), title: z.string() }),
twitter: z.object({ href: z.string(), title: z.string() }),
}),
trip_advisor: z.object({
title: z.string(),
logoConnection: z.object({
edges: z.array(
z.object({
node: z.object({
description: z.string().optional().nullable(),
dimension: z.object({
height: z.number(),
width: z.number(),
}),
metadata: z.any().nullable(),
system: z.object({
uid: z.string(),
}),
title: z.string(),
url: z.string(),
}),
})
),
}),
}),
})
),
}),
})
export type FooterDataRaw = z.infer<typeof validateFooterConfigSchema>
export type FooterData = Omit<
FooterDataRaw["all_current_footer"]["items"][0],
"logoConnection"
> & {
logo: Image
}
const validateFooterRefConfigSchema = z.object({
all_current_footer: z.object({
items: z.array(
z.object({
system: z.object({
content_type_uid: z.string(),
uid: z.string(),
}),
})
),
}),
})
export type FooterRefDataRaw = z.infer<typeof validateFooterRefConfigSchema>
+123
View File
@@ -0,0 +1,123 @@
import { GetContactConfig } from "@/lib/graphql/Query/ContactConfig.graphql"
import {
GetCurrentFooter,
GetCurrentFooterRef,
} from "@/lib/graphql/Query/CurrentFooter.graphql"
import {
GetCurrentHeader,
GetCurrentHeaderRef,
} from "@/lib/graphql/Query/CurrentHeader.graphql"
import { request } from "@/lib/graphql/request"
import { internalServerError, notFound } from "@/server/errors/trpc"
import { contentstackBaseProcedure, router } from "@/server/trpc"
import { generateTag } from "@/utils/generateTag"
import {
type ContactConfigData,
FooterDataRaw,
FooterRefDataRaw,
HeaderData,
HeaderDataRaw,
HeaderRefDataRaw,
validateContactConfigSchema,
validateFooterConfigSchema,
validateHeaderConfigSchema,
} from "./output"
export const baseQueryRouter = router({
contact: contentstackBaseProcedure.query(async ({ ctx }) => {
const { lang } = ctx
const response = await request<ContactConfigData>(GetContactConfig, {
locale: lang,
})
if (!response.data) {
throw notFound(response)
}
const validatedContactConfigConfig = validateContactConfigSchema.safeParse(
response.data
)
if (!validatedContactConfigConfig.success) {
throw internalServerError(validatedContactConfigConfig.error)
}
return validatedContactConfigConfig.data.all_contact_config.items[0]
}),
header: contentstackBaseProcedure.query(async ({ ctx }) => {
const responseRef = await request<HeaderRefDataRaw>(GetCurrentHeaderRef, {
locale: ctx.lang,
})
const response = await request<HeaderDataRaw>(
GetCurrentHeader,
{ locale: ctx.lang },
{
next: {
tags: [
generateTag(
ctx.lang,
responseRef.data.all_current_header.items[0].system.uid
),
],
},
}
)
if (!response.data) {
throw notFound(response)
}
const validatedHeaderConfig = validateHeaderConfigSchema.safeParse(
response.data
)
if (!validatedHeaderConfig.success) {
throw internalServerError(validatedHeaderConfig.error)
}
const logo =
validatedHeaderConfig.data.all_current_header.items[0].logoConnection
.edges?.[0]?.node
return {
...validatedHeaderConfig.data.all_current_header.items[0],
logo,
} as HeaderData
}),
footer: contentstackBaseProcedure.query(async ({ ctx }) => {
const responseRef = await request<FooterRefDataRaw>(GetCurrentFooterRef, {
locale: ctx.lang,
})
const response = await request<FooterDataRaw>(
GetCurrentFooter,
{
locale: ctx.lang,
},
{
next: {
tags: [
generateTag(
ctx.lang,
responseRef.data.all_current_footer.items[0].system.uid
),
],
},
}
)
const validatedFooterConfig = validateFooterConfigSchema.safeParse(
response.data
)
if (!validatedFooterConfig.success) {
throw internalServerError(validatedFooterConfig.error)
}
return validatedFooterConfig.data.all_current_footer.items[0]
}),
})