1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
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>;
|