feat(web): telas de negócio reais no EDEN Core (Empresas, Produtos, Revendas, CRM, Ofertas)
Prioriza a parte web a pedido do usuário. 2 subagentes eden-frontend em paralelo sobre o shell autenticado já pronto: - Empresas/Produtos/Revendas: CRUD completo (lista + criar/editar), layout modelado nas páginas reais do tema DreamsERP comprado (purchase/vendors.tsx, inventory/products.tsx) — máscara de moeda para as 5 faixas de preço + implantação. Novo componente Table<T> genérico em packages/ui. - CRM: Leads (lista, criar/editar, converter em oportunidade) e Oportunidades, modelados em crm/leads.tsx/dealsDetails.tsx. - Ofertas/Quotes: o módulo mais rico — criação com lista dinâmica de itens produto/quantidade, fidelidade reduzida opcional, desconto opcional, totais calculados pelo servidor; detalhe com aprovar/rejeitar e fechar negócio. Modelado em sales/salesQuotes*.tsx. Novo componente Select em packages/ui. Correção de instrução no meio da leva: usuário pediu para seguir de perto o layout real do tema comprado, não só os tokens visuais já extraídos — as páginas React relevantes do tema foram extraídas para .tmp/theme-reference/ (nunca versionado) em cada worktree e os agentes já em execução foram redirecionados via mensagem (não relançados). Bug real do próprio agente, corrigindo meu brief: Leads/Opportunities respondem em camelCase (mapLead/mapOpportunity), não snake_case como o resto da API — verificado contra o código-fonte real antes de aceitar. Integração manual: um dos 2 agentes não conseguiu git merge no próprio sandbox e restaurou o shell existente por leitura+escrita — cada arquivo restaurado foi comparado byte a byte contra main (diff -rq) antes de aceitar. App.tsx/AuthenticatedLayout.tsx/packages/ui/index.ts reconciliados manualmente juntando as rotas/exports dos dois agentes. Verificado: pnpm turbo run typecheck build (28/28); containers eden-api/eden-core reconstruídos; bundle de produção contém todas as novas telas; login simulando Origin de browser real; listagens retornando dados reais; criação de lead confirmando o formato camelCase. Claude-Session: https://claude.ai/code/session_01BcWWuKfykGtUweXmHD6cKx Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
37
apps/core-web/src/components/Breadcrumb.tsx
Normal file
37
apps/core-web/src/components/Breadcrumb.tsx
Normal file
@@ -0,0 +1,37 @@
|
||||
import { Link } from "react-router-dom";
|
||||
|
||||
export interface BreadcrumbItem {
|
||||
label: string;
|
||||
href?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Visual reference: DreamsERP theme detail pages
|
||||
* (.tmp/theme-reference/sales/salesQuotesDetails.tsx,
|
||||
* .tmp/theme-reference/crm/dealsDetails.tsx) — a small "Back link ›
|
||||
* Current page" trail above the page title on every detail/form screen.
|
||||
* Lives in core-web (not packages/ui) because it needs react-router's
|
||||
* `Link`, which the shared Design System deliberately avoids depending on
|
||||
* (see AppShell's router-agnostic `LinkComponent` prop).
|
||||
*/
|
||||
export function Breadcrumb({ items }: { items: BreadcrumbItem[] }) {
|
||||
return (
|
||||
<nav aria-label="Navegação" className="mb-1 flex flex-wrap items-center gap-2 text-sm text-default">
|
||||
{items.map((item, index) => {
|
||||
const isLast = index === items.length - 1;
|
||||
return (
|
||||
<span key={`${item.label}-${index}`} className="flex items-center gap-2">
|
||||
{index > 0 ? <span aria-hidden="true">/</span> : null}
|
||||
{isLast || !item.href ? (
|
||||
<span className={isLast ? "text-title font-medium" : undefined}>{item.label}</span>
|
||||
) : (
|
||||
<Link to={item.href} className="hover:text-primary">
|
||||
{item.label}
|
||||
</Link>
|
||||
)}
|
||||
</span>
|
||||
);
|
||||
})}
|
||||
</nav>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user