aboutsummaryrefslogtreecommitdiff
path: root/api/src/modules/categories/categories.schema.ts
diff options
context:
space:
mode:
Diffstat (limited to 'api/src/modules/categories/categories.schema.ts')
-rw-r--r--api/src/modules/categories/categories.schema.ts76
1 files changed, 76 insertions, 0 deletions
diff --git a/api/src/modules/categories/categories.schema.ts b/api/src/modules/categories/categories.schema.ts
new file mode 100644
index 0000000..6e11d8c
--- /dev/null
+++ b/api/src/modules/categories/categories.schema.ts
@@ -0,0 +1,76 @@
+/**
+ * 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<typeof createCategoryBodySchema>;
+
+// ─── 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<typeof updateCategoryBodySchema>;
+
+// ─── Parâmetros de rota ───────────────────────────────────────────────────────
+
+export const categoryParamsSchema = z.object({
+ id: z.coerce.number().int().positive(),
+});
+
+export type CategoryParams = z.infer<typeof categoryParamsSchema>;
+
+// ─── 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<typeof categoryResponseSchema>;