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 { 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): 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 export type UpdatePageInput = z.infer export type UpsertPageTranslationInput = z.infer export type CreateNavigationMenuInput = z.infer export type UpdateNavigationMenuInput = z.infer export type CreateNavigationItemInput = z.infer export type UpdateNavigationItemInput = z.infer export type PageBlock = z.infer export type PageBlocks = z.infer