Files
tiagoandClaude Sonnet 5 323912748f 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>
2026-08-16 09:41:13 -03:00

114 lines
4.1 KiB
TypeScript

import { apiClient } from '@/lib/api/client';
import { buildQuery, type PaginatedResult } from '@/lib/api/types';
/** Espelha `alert-template-tipos.ts` do backend. */
export const TIPOS_TEMPLATE = [
'mensalidade_tenant',
'cobranca_cliente',
'venda_confirmada',
'lembrete_vencimento',
] as const;
export type TipoTemplate = (typeof TIPOS_TEMPLATE)[number];
export const CANAIS_TEMPLATE = ['whatsapp', 'email'] as const;
export type CanalTemplate = (typeof CANAIS_TEMPLATE)[number];
export const TIPO_TEMPLATE_LABEL: Record<TipoTemplate, string> = {
mensalidade_tenant: 'Mensalidade do tenant',
cobranca_cliente: 'Cobrança ao cliente',
venda_confirmada: 'Venda confirmada',
lembrete_vencimento: 'Lembrete de vencimento',
};
export const CANAL_TEMPLATE_LABEL: Record<CanalTemplate, string> = {
whatsapp: 'WhatsApp',
email: 'E-mail',
};
interface PlaceholderDoc {
chave: string;
descricao: string;
}
/**
* Espelha `src/modules/alerts/placeholders.ts` (`PLACEHOLDERS_POR_TIPO`) —
* não existe endpoint que exponha isso (é uma constante interna do
* backend, nunca importada por nenhum controller), então é replicada aqui
* manualmente para o editor de template desta etapa. Se o backend mudar
* essa lista, esta cópia precisa ser atualizada junto.
*/
export const PLACEHOLDERS_POR_TIPO: Record<TipoTemplate, PlaceholderDoc[]> = {
mensalidade_tenant: [
{ chave: 'nome', descricao: 'Nome fantasia (ou razão social) do tenant' },
{ chave: 'valor', descricao: 'Valor da fatura, formatado como "R$ 199,90"' },
{ chave: 'vencimento', descricao: 'Data de vencimento da fatura, formato dd/mm/aaaa' },
{ chave: 'referencia', descricao: 'Mês/ano de referência da fatura, formato aaaa-mm' },
],
cobranca_cliente: [
{ chave: 'nome', descricao: 'Nome fantasia (ou razão social) do customer' },
{ chave: 'valor', descricao: 'Valor da parcela, formatado como "R$ 199,90"' },
{ chave: 'vencimento', descricao: 'Data de vencimento da parcela, formato dd/mm/aaaa' },
{ chave: 'numero_venda', descricao: 'Número sequencial da venda' },
{ chave: 'numero_parcela', descricao: 'Número da parcela dentro da venda (1, 2, 3...)' },
],
venda_confirmada: [
{ chave: 'nome', descricao: 'Nome fantasia (ou razão social) do customer' },
{ chave: 'numero_venda', descricao: 'Número sequencial da venda' },
{ chave: 'valor', descricao: 'Valor total da venda, formatado como "R$ 199,90"' },
],
lembrete_vencimento: [
{ chave: 'nome', descricao: 'Nome fantasia (ou razão social) do customer' },
{ chave: 'valor', descricao: 'Valor da parcela, formatado como "R$ 199,90"' },
{ chave: 'vencimento', descricao: 'Data de vencimento da parcela, formato dd/mm/aaaa' },
],
};
/** Espelha o model `alert_templates` (sempre `tenant_id: null` em `/master`). */
export interface AlertTemplate {
id: string;
tenant_id: string | null;
tipo: TipoTemplate;
canal: CanalTemplate;
assunto: string | null;
corpo: string;
ativo: boolean;
criado_em: string;
}
/** Espelha `CreateMasterAlertTemplateDto`/`UpdateMasterAlertTemplateDto`. */
export interface AlertTemplateInput {
tipo: TipoTemplate;
canal: CanalTemplate;
/** Obrigatório só quando `canal === 'email'`. */
assunto?: string;
corpo: string;
ativo?: boolean;
}
export interface ListAlertTemplatesParams {
tipo?: TipoTemplate;
canal?: CanalTemplate;
ativo?: boolean;
page?: number;
limit?: number;
}
export function listAlertTemplates(params: ListAlertTemplatesParams) {
return apiClient.get<PaginatedResult<AlertTemplate>>(
`/master/alertas/templates${buildQuery(params)}`,
);
}
export function createAlertTemplate(input: AlertTemplateInput) {
return apiClient.post<AlertTemplate>('/master/alertas/templates', input);
}
export function updateAlertTemplate(id: string, input: Partial<AlertTemplateInput>) {
return apiClient.put<AlertTemplate>(`/master/alertas/templates/${id}`, input);
}
/** Soft delete no backend (`ativo: false`) — não remove o registro. */
export function deleteAlertTemplate(id: string) {
return apiClient.delete<AlertTemplate>(`/master/alertas/templates/${id}`);
}