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:
2026-08-16 09:41:13 -03:00
co-authored by Claude Sonnet 5
parent f9738e54da
commit 323912748f
179 changed files with 29312 additions and 22 deletions
+58
View File
@@ -0,0 +1,58 @@
import { cn } from '@/lib/utils';
export const STATUS_PILL_TONES = ['success', 'warning', 'danger', 'primary', 'neutral'] as const;
type StatusPillTone = (typeof STATUS_PILL_TONES)[number];
/**
* Status de negócio já existentes no backend (Etapas 1–8) → cor semântica
* + label em português, resolvidos uma única vez aqui para não repetir
* esse mapeamento em cada tela (Etapa 12).
*/
export const STATUS_PILL_MAP = {
pendente: { tone: 'warning', label: 'Pendente' },
pago: { tone: 'success', label: 'Pago' },
atrasado: { tone: 'danger', label: 'Atrasado' },
cancelado: { tone: 'neutral', label: 'Cancelado' },
ativo: { tone: 'success', label: 'Ativo' },
inadimplente: { tone: 'danger', label: 'Inadimplente' },
suspenso: { tone: 'warning', label: 'Suspenso' },
trial: { tone: 'primary', label: 'Trial' },
confirmada: { tone: 'primary', label: 'Confirmada' },
concluida: { tone: 'success', label: 'Concluída' },
orcamento: { tone: 'neutral', label: 'Orçamento' },
cancelada: { tone: 'neutral', label: 'Cancelada' },
} as const satisfies Record<string, { tone: StatusPillTone; label: string }>;
export type BusinessStatus = keyof typeof STATUS_PILL_MAP;
const toneClasses: Record<StatusPillTone, string> = {
success: 'bg-success/10 text-success',
warning: 'bg-warning/10 text-warning',
danger: 'bg-danger/10 text-danger',
primary: 'bg-primary/10 text-primary',
neutral: 'bg-neutral-500/10 text-neutral-500',
};
interface StatusPillProps {
status: BusinessStatus;
className?: string;
}
function StatusPill({ status, className }: StatusPillProps) {
const config = STATUS_PILL_MAP[status];
return (
<span
data-slot="status-pill"
className={cn(
'inline-flex h-5 w-fit shrink-0 items-center justify-center rounded-full px-2 py-0.5 text-xs font-medium whitespace-nowrap',
toneClasses[config.tone],
className,
)}
>
{config.label}
</span>
);
}
export { StatusPill };