Frontend completo (Etapas 11-18) e extensões de backend (Etapas 13 e 18)
Adiciona o frontend Next.js em frontend/ (setup, design system, autenticação/tema, layout/navegação, área master, área tenant completa: clientes, produtos, vendas, recebimentos, whatsapp, e-mail, alertas, equipe e perfil). Estende o backend de forma aditiva e autorizada: cookie httpOnly para refresh token (Etapa 13) e CRUD de equipe + edição de perfil do tenant (Etapa 18, módulo src/modules/equipe/ novo e PUT /tenant/perfil). Detalhes completos em Etapas/V2/*. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,23 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
/**
|
||||
* Campos numéricos ficam como `z.number()` puro (sem `coerce`/`preprocess`)
|
||||
* de propósito — a conversão string→number do `<input type="number">`
|
||||
* acontece no `register(...)` do react-hook-form (`valueAsNumber`/
|
||||
* `setValueAs`), não no schema. Misturar as duas coisas faz o tipo de
|
||||
* entrada do formulário (`z.input`) divergir do tipo de saída (`z.infer`) e
|
||||
* quebra a inferência de tipos do `zodResolver`.
|
||||
*/
|
||||
const optionalInt = z.number().int().min(1, 'Deve ser pelo menos 1').optional();
|
||||
|
||||
/** Espelha `CreatePlanoDto`/`UpdatePlanoDto` (`src/modules/planos/dto/`). */
|
||||
export const planoSchema = z.object({
|
||||
nome: z.string().min(2, 'Informe pelo menos 2 caracteres'),
|
||||
descricao: z.string().optional(),
|
||||
valor_mensal: z.number('Informe um valor').positive('O valor deve ser maior que zero'),
|
||||
limite_customers: optionalInt,
|
||||
limite_usuarios: optionalInt,
|
||||
limite_instancias_whatsapp: optionalInt,
|
||||
});
|
||||
|
||||
export type PlanoFormValues = z.infer<typeof planoSchema>;
|
||||
Reference in New Issue
Block a user