86 lines
3.3 KiB
TypeScript
86 lines
3.3 KiB
TypeScript
import { PortfolioAssetKind, PortfolioSectionType } from "@prisma/client";
|
|
import { z } from "zod";
|
|
|
|
import { mediaFieldInputSchema } from "./media-validation";
|
|
|
|
const requiredText = (label: string) =>
|
|
z
|
|
.string()
|
|
.trim()
|
|
.min(1, `${label} is required.`);
|
|
|
|
const optionalTrimmedText = z.string().trim().optional().transform((value) => value ?? "");
|
|
|
|
export const categoryInputSchema = z.object({
|
|
id: z.string().trim().optional(),
|
|
slug: requiredText("Category slug")
|
|
.regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/, "Category slug must be lowercase and hyphenated."),
|
|
nameAr: requiredText("Category nameAr"),
|
|
nameEn: requiredText("Category nameEn"),
|
|
nameDe: requiredText("Category nameDe"),
|
|
descriptionAr: requiredText("Category descriptionAr"),
|
|
descriptionEn: requiredText("Category descriptionEn"),
|
|
descriptionDe: requiredText("Category descriptionDe"),
|
|
sortOrder: z.coerce.number().int().min(0).max(9999),
|
|
isActive: z.boolean(),
|
|
});
|
|
|
|
export const sectionInputSchema = z.object({
|
|
id: z.string().trim().optional(),
|
|
type: z.nativeEnum(PortfolioSectionType),
|
|
titleAr: requiredText("Section titleAr"),
|
|
titleEn: requiredText("Section titleEn"),
|
|
titleDe: requiredText("Section titleDe"),
|
|
bodyAr: requiredText("Section bodyAr"),
|
|
bodyEn: requiredText("Section bodyEn"),
|
|
bodyDe: requiredText("Section bodyDe"),
|
|
imagePath: optionalTrimmedText,
|
|
media: mediaFieldInputSchema.optional(),
|
|
linkUrl: optionalTrimmedText.refine(
|
|
(value) => value === "" || /^https?:\/\//.test(value) || value.startsWith("/"),
|
|
"Section linkUrl must be an absolute URL or start with /.",
|
|
),
|
|
sortOrder: z.coerce.number().int().min(0).max(9999),
|
|
});
|
|
|
|
export const assetInputSchema = z.object({
|
|
id: z.string().trim().optional(),
|
|
kind: z.nativeEnum(PortfolioAssetKind),
|
|
filePath: optionalTrimmedText,
|
|
fileFieldName: optionalTrimmedText,
|
|
media: mediaFieldInputSchema.optional(),
|
|
altAr: requiredText("Asset altAr"),
|
|
altEn: requiredText("Asset altEn"),
|
|
altDe: requiredText("Asset altDe"),
|
|
sortOrder: z.coerce.number().int().min(0).max(9999),
|
|
});
|
|
|
|
export const projectInputSchema = z.object({
|
|
id: z.string().trim().optional(),
|
|
categoryId: requiredText("Project categoryId"),
|
|
slug: requiredText("Project slug")
|
|
.regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/, "Project slug must be lowercase and hyphenated."),
|
|
titleAr: requiredText("Project titleAr"),
|
|
titleEn: requiredText("Project titleEn"),
|
|
titleDe: requiredText("Project titleDe"),
|
|
summaryAr: requiredText("Project summaryAr"),
|
|
summaryEn: requiredText("Project summaryEn"),
|
|
summaryDe: requiredText("Project summaryDe"),
|
|
clientName: requiredText("Project clientName"),
|
|
projectYear: z.coerce.number().int().min(2000).max(2100),
|
|
serviceLabelAr: requiredText("Project serviceLabelAr"),
|
|
serviceLabelEn: requiredText("Project serviceLabelEn"),
|
|
serviceLabelDe: requiredText("Project serviceLabelDe"),
|
|
previewUrl: optionalTrimmedText.refine(
|
|
(value) => value === "" || /^https?:\/\//.test(value),
|
|
"Project previewUrl must be an absolute URL.",
|
|
),
|
|
currentCoverImagePath: optionalTrimmedText,
|
|
coverMedia: mediaFieldInputSchema.optional(),
|
|
sortOrder: z.coerce.number().int().min(0).max(9999),
|
|
isFeatured: z.boolean(),
|
|
isPublished: z.boolean(),
|
|
sections: z.array(sectionInputSchema),
|
|
assets: z.array(assetInputSchema),
|
|
});
|