Continuação direta da leva anterior, sem parar para autorização (a pedido do usuário). 2 subagentes eden-frontend em paralelo. - Cadastro de Cliente: lista, criação direta (PF/PJ + portabilidade), detalhe rico editável por seção (status, endereço, contatos, dados PF/PJ com CPF/CNPJ sempre somente-leitura, portabilidade condicional) + sub-seção de Sócios para PJ. Fecha a pendência da leva anterior: QuoteDetailPage não pede mais UUID colado à mão para fechar negócio, agora é um select real com atalho para criar cadastro novo. - Contratos: lista, criação (itens produto+quantidade, partes contratada/contratante), detalhe com resumo financeiro, aviso de fidelidade sem efeito legal quando não aprovada, histórico de status, e botões de transição limitados aos alvos válidos a partir do status atual (servidor continua sendo a única fonte de verdade real). QuoteDetailPage ganha link "Criar contrato a partir desta oferta" quando a oferta está fechada. Reconciliação manual de App.tsx/AuthenticatedLayout.tsx/QuoteDetailPage.tsx entre os 2 agentes (mais o de Empresas/CRM/Ofertas da leva anterior), um de cada vez, confirmando typecheck/build limpo a cada mesclagem. Verificado: pnpm turbo run typecheck build (28/28); containers eden-api/eden-core reconstruídos; fluxo completo testado ao vivo ATRAVÉS DO PROXY same-origin (porta 3001, não direto na API) — login, criação de cadastro, criação de contrato, transição de status inválida corretamente rejeitada com 409. Claude-Session: https://claude.ai/code/session_01BcWWuKfykGtUweXmHD6cKx Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
52 lines
1.9 KiB
TypeScript
52 lines
1.9 KiB
TypeScript
import { useNavigate } from "react-router-dom";
|
|
import { Link, Outlet, useLocation } from "react-router-dom";
|
|
import { AppShell } from "@eden/ui";
|
|
import type { AppShellNavItem } from "@eden/ui";
|
|
import { useAuth } from "../lib/auth/AuthContext.js";
|
|
|
|
/** `href === "/"` only matches the exact dashboard path — every other item matches by exact path or a `/` prefix boundary (so `/companies` never lights up for `/companies-other`). */
|
|
function isNavItemActive(href: string, pathname: string): boolean {
|
|
if (href === "/") return pathname === "/";
|
|
return pathname === href || pathname.startsWith(`${href}/`);
|
|
}
|
|
|
|
export function AuthenticatedLayout() {
|
|
const { user, logout } = useAuth();
|
|
const navigate = useNavigate();
|
|
const location = useLocation();
|
|
|
|
const navItems: AppShellNavItem[] = [
|
|
{ key: "dashboard", label: "Painel", href: "/" },
|
|
{ key: "companies", label: "Empresas", href: "/companies" },
|
|
{ key: "products", label: "Produtos", href: "/products" },
|
|
{ key: "resellers", label: "Revendas", href: "/resellers" },
|
|
{ key: "leads", label: "CRM", href: "/leads" },
|
|
{ key: "quotes", label: "Ofertas", href: "/quotes" },
|
|
{ key: "client-registrations", label: "Clientes", href: "/client-registrations" },
|
|
{ key: "contracts", label: "Contratos", href: "/contracts" },
|
|
].map((item) => ({ ...item, active: isNavItemActive(item.href, location.pathname) }));
|
|
|
|
async function handleLogout() {
|
|
await logout();
|
|
navigate("/login", { replace: true });
|
|
}
|
|
|
|
return (
|
|
<AppShell
|
|
appName="EDEN Core"
|
|
logoSrc="/eden-logo-horizontal.png"
|
|
navItems={navItems}
|
|
userName={user?.fullName ?? user?.email}
|
|
userRole={user?.roleKey}
|
|
onLogout={handleLogout}
|
|
LinkComponent={({ href, className, children }) => (
|
|
<Link to={href} className={className}>
|
|
{children}
|
|
</Link>
|
|
)}
|
|
>
|
|
<Outlet />
|
|
</AppShell>
|
|
);
|
|
}
|