/** * categories.schema.ts * Schemas Zod para o CRUD de categorias. */ import { z } from 'zod'; // ─── Helper: gerador de slug ────────────────────────────────────────────────── // Converte "Hardware e Periféricos" → "hardware-e-perifericos" function toSlug(name: string): string { return name .toLowerCase() .normalize('NFD') .replace(/[\u0300-\u036f]/g, '') // remove acentos .replace(/[^a-z0-9\s-]/g, '') // remove caracteres especiais .trim() .replace(/\s+/g, '-'); // espaços → hífens } // ─── Criação ────────────────────────────────────────────────────────────────── export const createCategoryBodySchema = z.object({ name: z .string({ required_error: 'Nome é obrigatório' }) .min(2, 'Nome deve ter no mínimo 2 caracteres') .max(80) .trim(), // Se não informado, será gerado automaticamente a partir do name slug: z .string() .min(2) .max(80) .regex(/^[a-z0-9-]+$/, 'Slug deve conter apenas letras minúsculas, números e hífens') .optional(), description: z.string().max(300).trim().optional(), }).transform((data) => ({ ...data, // Garante que slug sempre exista — gerado do name se ausente slug: data.slug ?? toSlug(data.name), })); export type CreateCategoryBody = z.infer; // ─── Atualização (PATCH parcial) ────────────────────────────────────────────── export const updateCategoryBodySchema = z.object({ name: z.string().min(2).max(80).trim().optional(), slug: z.string().min(2).max(80) .regex(/^[a-z0-9-]+$/, 'Slug inválido').optional(), description: z.string().max(300).trim().nullable().optional(), }); export type UpdateCategoryBody = z.infer; // ─── Parâmetros de rota ─────────────────────────────────────────────────────── export const categoryParamsSchema = z.object({ id: z.coerce.number().int().positive(), }); export type CategoryParams = z.infer; // ─── Resposta ───────────────────────────────────────────────────────────────── export const categoryResponseSchema = z.object({ id: z.number(), name: z.string(), slug: z.string(), description: z.string().nullable(), createdAt: z.string(), updatedAt: z.string(), }); export type CategoryResponse = z.infer;