175 lines
5.8 KiB
TypeScript
175 lines
5.8 KiB
TypeScript
import { z } from "zod"
|
|
|
|
export const pageStatusSchema = z.enum(["draft", "published"])
|
|
export const pageLocaleSchema = z.enum(["de", "en", "es", "fr"])
|
|
|
|
const pageBlockBaseSchema = z.object({
|
|
id: z.string().min(1),
|
|
})
|
|
|
|
export const heroPageBlockSchema = pageBlockBaseSchema.extend({
|
|
type: z.literal("hero"),
|
|
heading: z.string().min(1).max(180),
|
|
subheading: z.string().max(500).nullable().optional(),
|
|
ctaLabel: z.string().max(80).nullable().optional(),
|
|
ctaHref: z.string().max(500).nullable().optional(),
|
|
})
|
|
|
|
export const richTextPageBlockSchema = pageBlockBaseSchema.extend({
|
|
type: z.literal("rich_text"),
|
|
body: z.string().min(1),
|
|
})
|
|
|
|
export const galleryPageBlockSchema = pageBlockBaseSchema.extend({
|
|
type: z.literal("gallery"),
|
|
title: z.string().max(180).nullable().optional(),
|
|
imageIds: z.array(z.string().uuid()).default([]),
|
|
})
|
|
|
|
export const ctaPageBlockSchema = pageBlockBaseSchema.extend({
|
|
type: z.literal("cta"),
|
|
label: z.string().min(1).max(80),
|
|
href: z.string().max(500),
|
|
variant: z.enum(["primary", "secondary"]).default("primary"),
|
|
})
|
|
|
|
export const formPageBlockSchema = pageBlockBaseSchema.extend({
|
|
type: z.literal("form"),
|
|
formKey: z.string().min(1).max(120),
|
|
title: z.string().max(180).nullable().optional(),
|
|
description: z.string().max(500).nullable().optional(),
|
|
})
|
|
|
|
export const priceCardsPageBlockSchema = pageBlockBaseSchema.extend({
|
|
type: z.literal("price_cards"),
|
|
title: z.string().max(180).nullable().optional(),
|
|
cards: z
|
|
.array(
|
|
z.object({
|
|
id: z.string().min(1),
|
|
name: z.string().min(1).max(180),
|
|
price: z.string().max(80).nullable().optional(),
|
|
description: z.string().max(500).nullable().optional(),
|
|
}),
|
|
)
|
|
.default([]),
|
|
})
|
|
|
|
export const pageBlockSchema = z.discriminatedUnion("type", [
|
|
heroPageBlockSchema,
|
|
richTextPageBlockSchema,
|
|
galleryPageBlockSchema,
|
|
ctaPageBlockSchema,
|
|
formPageBlockSchema,
|
|
priceCardsPageBlockSchema,
|
|
])
|
|
|
|
export const pageBlocksSchema = z.array(pageBlockSchema)
|
|
|
|
function isJsonLike(value: string): boolean {
|
|
const trimmed = value.trim()
|
|
return trimmed.startsWith("{") || trimmed.startsWith("[")
|
|
}
|
|
|
|
export function parsePageBlocks(content: string): z.infer<typeof pageBlocksSchema> {
|
|
if (!isJsonLike(content)) {
|
|
return [
|
|
{
|
|
id: "legacy-rich-text",
|
|
type: "rich_text",
|
|
body: content,
|
|
},
|
|
]
|
|
}
|
|
|
|
const parsed = JSON.parse(content)
|
|
|
|
if (!Array.isArray(parsed)) {
|
|
throw new Error("Page block payload must be an array.")
|
|
}
|
|
|
|
return pageBlocksSchema.parse(parsed)
|
|
}
|
|
|
|
export function serializePageBlocks(blocks: z.infer<typeof pageBlocksSchema>): string {
|
|
return JSON.stringify(pageBlocksSchema.parse(blocks))
|
|
}
|
|
|
|
export const createPageInputSchema = z.object({
|
|
title: z.string().min(1).max(180),
|
|
slug: z.string().min(1).max(180),
|
|
status: pageStatusSchema.default("draft"),
|
|
summary: z.string().max(500).nullable().optional(),
|
|
content: z.string().min(1),
|
|
seoTitle: z.string().max(180).nullable().optional(),
|
|
seoDescription: z.string().max(320).nullable().optional(),
|
|
scheduledPublishAt: z.date().nullable().optional(),
|
|
})
|
|
|
|
export const updatePageInputSchema = z.object({
|
|
id: z.string().uuid(),
|
|
title: z.string().min(1).max(180).optional(),
|
|
slug: z.string().min(1).max(180).optional(),
|
|
status: pageStatusSchema.optional(),
|
|
summary: z.string().max(500).nullable().optional(),
|
|
content: z.string().min(1).optional(),
|
|
seoTitle: z.string().max(180).nullable().optional(),
|
|
seoDescription: z.string().max(320).nullable().optional(),
|
|
scheduledPublishAt: z.date().nullable().optional(),
|
|
})
|
|
|
|
export const upsertPageTranslationInputSchema = z.object({
|
|
pageId: z.string().uuid(),
|
|
locale: pageLocaleSchema,
|
|
title: z.string().min(1).max(180),
|
|
summary: z.string().max(500).nullable().optional(),
|
|
content: z.string().min(1),
|
|
seoTitle: z.string().max(180).nullable().optional(),
|
|
seoDescription: z.string().max(320).nullable().optional(),
|
|
})
|
|
|
|
export const createNavigationMenuInputSchema = z.object({
|
|
name: z.string().min(1).max(180),
|
|
slug: z.string().min(1).max(180),
|
|
location: z.string().min(1).max(80).default("primary"),
|
|
isVisible: z.boolean().default(true),
|
|
})
|
|
|
|
export const updateNavigationMenuInputSchema = z.object({
|
|
id: z.string().uuid(),
|
|
name: z.string().min(1).max(180).optional(),
|
|
slug: z.string().min(1).max(180).optional(),
|
|
location: z.string().min(1).max(80).optional(),
|
|
isVisible: z.boolean().optional(),
|
|
})
|
|
|
|
export const createNavigationItemInputSchema = z.object({
|
|
menuId: z.string().uuid(),
|
|
label: z.string().min(1).max(180),
|
|
href: z.string().max(500).nullable().optional(),
|
|
pageId: z.string().uuid().nullable().optional(),
|
|
parentId: z.string().uuid().nullable().optional(),
|
|
sortOrder: z.number().int().min(0).default(0),
|
|
isVisible: z.boolean().default(true),
|
|
})
|
|
|
|
export const updateNavigationItemInputSchema = z.object({
|
|
id: z.string().uuid(),
|
|
label: z.string().min(1).max(180).optional(),
|
|
href: z.string().max(500).nullable().optional(),
|
|
pageId: z.string().uuid().nullable().optional(),
|
|
parentId: z.string().uuid().nullable().optional(),
|
|
sortOrder: z.number().int().min(0).optional(),
|
|
isVisible: z.boolean().optional(),
|
|
})
|
|
|
|
export type CreatePageInput = z.infer<typeof createPageInputSchema>
|
|
export type UpdatePageInput = z.infer<typeof updatePageInputSchema>
|
|
export type UpsertPageTranslationInput = z.infer<typeof upsertPageTranslationInputSchema>
|
|
export type CreateNavigationMenuInput = z.infer<typeof createNavigationMenuInputSchema>
|
|
export type UpdateNavigationMenuInput = z.infer<typeof updateNavigationMenuInputSchema>
|
|
export type CreateNavigationItemInput = z.infer<typeof createNavigationItemInputSchema>
|
|
export type UpdateNavigationItemInput = z.infer<typeof updateNavigationItemInputSchema>
|
|
export type PageBlock = z.infer<typeof pageBlockSchema>
|
|
export type PageBlocks = z.infer<typeof pageBlocksSchema>
|