fix(products): rótulo "Nome do X" nos formulários de catálogo + verificação em navegador real

CatalogCreateForm/SimpleCatalogCard ganham nameLabel (default "Nome"),
propagado aos 5 catálogos: "Nome do tipo/grupo/subgrupo", "Nome da
marca/unidade".

Verificado desta vez em navegador real (Playwright headless, sem a
extensão claude-in-chrome disponível nesta sessão) em vez de só por
API — pegou um bug real que a verificação anterior não pegaria: o prop
nameLabel tinha sido adicionado à assinatura mas esquecido de usar no
JSX, então nenhum rótulo mudava apesar do build passar limpo. Corrigido
e reverificado.

Suíte: 95/95. pnpm turbo run typecheck build: 28/28.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-18 11:04:39 -03:00
parent 96200dc2ba
commit 4e4de2c259
9 changed files with 29 additions and 2 deletions

View File

@@ -26,6 +26,7 @@ export function BrandsListPage() {
onCreate={create} onCreate={create}
onToggleActive={toggleActive} onToggleActive={toggleActive}
namePlaceholder="ex.: Intelbras" namePlaceholder="ex.: Intelbras"
nameLabel="Nome da marca"
createLabel="Adicionar marca" createLabel="Adicionar marca"
emptyMessage="Nenhuma marca cadastrada." emptyMessage="Nenhuma marca cadastrada."
/> />

View File

@@ -6,12 +6,14 @@ import { Alert, Button, Input } from "@eden/ui";
export function CatalogCreateForm({ export function CatalogCreateForm({
placeholder, placeholder,
buttonLabel = "Adicionar", buttonLabel = "Adicionar",
nameLabel = "Nome",
creating, creating,
error, error,
onCreate, onCreate,
}: { }: {
placeholder: string; placeholder: string;
buttonLabel?: string; buttonLabel?: string;
nameLabel?: string;
creating: boolean; creating: boolean;
error: string | null; error: string | null;
onCreate: (name: string) => Promise<boolean>; onCreate: (name: string) => Promise<boolean>;
@@ -36,7 +38,7 @@ export function CatalogCreateForm({
<form className="flex flex-col gap-3 sm:flex-row sm:items-end" onSubmit={handleSubmit}> <form className="flex flex-col gap-3 sm:flex-row sm:items-end" onSubmit={handleSubmit}>
<div className="flex-1"> <div className="flex-1">
<Input <Input
label="Nome" label={nameLabel}
placeholder={placeholder} placeholder={placeholder}
value={name} value={name}
onChange={(e) => setName(e.target.value)} onChange={(e) => setName(e.target.value)}

View File

@@ -36,6 +36,7 @@ export function GroupSubgroupsPanel({ group }: { group: ProductGroupRow }) {
) : null} ) : null}
<CatalogCreateForm <CatalogCreateForm
placeholder="ex.: Fibra residencial" placeholder="ex.: Fibra residencial"
nameLabel="Nome do subgrupo"
buttonLabel="Adicionar subgrupo" buttonLabel="Adicionar subgrupo"
creating={creating} creating={creating}
error={formError} error={formError}

View File

@@ -57,6 +57,7 @@ export function ProductGroupsListPage() {
) : null} ) : null}
<CatalogCreateForm <CatalogCreateForm
placeholder="ex.: Banda larga" placeholder="ex.: Banda larga"
nameLabel="Nome do grupo"
buttonLabel="Adicionar grupo" buttonLabel="Adicionar grupo"
creating={creating} creating={creating}
error={formError} error={formError}

View File

@@ -29,6 +29,7 @@ export function ProductTypesListPage() {
onCreate={create} onCreate={create}
onToggleActive={toggleActive} onToggleActive={toggleActive}
namePlaceholder="ex.: Internet" namePlaceholder="ex.: Internet"
nameLabel="Nome do tipo"
createLabel="Adicionar tipo" createLabel="Adicionar tipo"
emptyMessage="Nenhum tipo de produto cadastrado." emptyMessage="Nenhum tipo de produto cadastrado."
/> />

View File

@@ -14,6 +14,7 @@ export function SimpleCatalogCard<T extends SimpleCatalogRow>({
onCreate, onCreate,
onToggleActive, onToggleActive,
namePlaceholder, namePlaceholder,
nameLabel,
createLabel, createLabel,
emptyMessage, emptyMessage,
extraColumn, extraColumn,
@@ -26,6 +27,7 @@ export function SimpleCatalogCard<T extends SimpleCatalogRow>({
onCreate: (name: string) => Promise<boolean>; onCreate: (name: string) => Promise<boolean>;
onToggleActive: (item: T) => void; onToggleActive: (item: T) => void;
namePlaceholder: string; namePlaceholder: string;
nameLabel?: string;
createLabel?: string; createLabel?: string;
emptyMessage?: string; emptyMessage?: string;
extraColumn?: TableColumn<T>; extraColumn?: TableColumn<T>;
@@ -39,6 +41,7 @@ export function SimpleCatalogCard<T extends SimpleCatalogRow>({
) : null} ) : null}
<CatalogCreateForm <CatalogCreateForm
placeholder={namePlaceholder} placeholder={namePlaceholder}
nameLabel={nameLabel}
buttonLabel={createLabel} buttonLabel={createLabel}
creating={creating} creating={creating}
error={formError} error={formError}

View File

@@ -105,7 +105,7 @@ export function SubgroupsListPage() {
</div> </div>
<div className="flex-1"> <div className="flex-1">
<Input <Input
label="Nome" label="Nome do subgrupo"
placeholder="ex.: Fibra residencial" placeholder="ex.: Fibra residencial"
value={name} value={name}
onChange={(e) => setName(e.target.value)} onChange={(e) => setName(e.target.value)}

View File

@@ -29,6 +29,7 @@ export function UnitsListPage() {
onCreate={create} onCreate={create}
onToggleActive={toggleActive} onToggleActive={toggleActive}
namePlaceholder="ex.: Unidade" namePlaceholder="ex.: Unidade"
nameLabel="Nome da unidade"
createLabel="Adicionar unidade" createLabel="Adicionar unidade"
emptyMessage="Nenhuma unidade cadastrada." emptyMessage="Nenhuma unidade cadastrada."
/> />

View File

@@ -661,3 +661,20 @@ Pequeno complemento de backend necessário para a coluna "Grupo" da tela nova: `
### Verificação ### Verificação
`pnpm turbo run typecheck build` 28/28 (os 3 apps que usam `@eden/ui` — `core-web`/`reseller-web`/`subscriber-web` — confirmados sem regressão). Teste novo em `apps/api/test/product-catalogs.spec.ts` cobrindo `group_name` resolvido tanto na listagem filtrada por `groupId` quanto na geral. Suíte completa: 95/95 verdes. Testado ao vivo via `curl` contra `eden-api`/`eden-core` reconstruídos: rota `/products/subgroups` responde 200, criação de subgrupo segue funcionando, listagem geral resolve `group_name` corretamente. Interação de clique no accordion aninhado (abrir "Grupos" → ver "Subgrupos" → navegar) não foi possível verificar via browser automatizado (nenhuma ferramenta desse tipo disponível neste ambiente) — verificação limitada a build/tipos/API real, mesma limitação já registrada pelo agente de frontend na leva anterior. `pnpm turbo run typecheck build` 28/28 (os 3 apps que usam `@eden/ui` — `core-web`/`reseller-web`/`subscriber-web` — confirmados sem regressão). Teste novo em `apps/api/test/product-catalogs.spec.ts` cobrindo `group_name` resolvido tanto na listagem filtrada por `groupId` quanto na geral. Suíte completa: 95/95 verdes. Testado ao vivo via `curl` contra `eden-api`/`eden-core` reconstruídos: rota `/products/subgroups` responde 200, criação de subgrupo segue funcionando, listagem geral resolve `group_name` corretamente. Interação de clique no accordion aninhado (abrir "Grupos" → ver "Subgrupos" → navegar) não foi possível verificar via browser automatizado (nenhuma ferramenta desse tipo disponível neste ambiente) — verificação limitada a build/tipos/API real, mesma limitação já registrada pelo agente de frontend na leva anterior.
---
## Rótulo "Nome do X" nos formulários de catálogo de Produto + verificação real em navegador
Data: 2026-09-18. Usuário pediu duas coisas na sequência: (1) verificar no navegador se a leva anterior (submenu de Subgrupos) está funcionando de verdade, e (2) trocar o rótulo genérico "Nome" por "Nome do subgrupo" no formulário de criação — e, logo em seguida, "usar a mesma lógica para o Grupo", interpretado (e confirmado fazendo) como aplicar o mesmo padrão aos 5 catálogos: "Nome do tipo"/"Nome do grupo"/"Nome do subgrupo"/"Nome da marca"/"Nome da unidade" (sem dois-pontos no final — nenhum outro rótulo do app usa, mantido consistente).
### Verificação real em navegador (não só API)
Nenhuma ferramenta de browser automation (`claude-in-chrome`) estava disponível nesta sessão. Em vez de reportar como não verificável (mesma limitação que os agentes de frontend já haviam registrado nas levas anteriores), usei o Playwright que já existe no monorepo (`packages/integrations` depende dele para renderização de PDF; o Chromium já estava em cache local de builds anteriores) para abrir o Chromium de verdade, logar como super_admin e navegar pelas telas reais. Isso capturou um bug real que a verificação só por API/build nunca pegaria: o menu aninhado Produtos → Grupos → Subgrupos realmente expande e navega corretamente (confirmado via dump do texto do DOM da sidebar), mas o rótulo do campo de criação continuava mostrando "Nome" em vez de "Nome do grupo"/"Nome do tipo"/etc — o prop `nameLabel` tinha sido adicionado à assinatura de `CatalogCreateForm.tsx` mas esquecido de usar de fato no JSX (`<Input label="Nome" .../>` continuava hardcoded). Corrigido, reconstruído, reverificado com o mesmo script Playwright — os 5 rótulos batem exatamente com o esperado.
### Mudança
`CatalogCreateForm.tsx`/`SimpleCatalogCard.tsx` ganharam o prop `nameLabel` (default `"Nome"`, sem quebrar nada que não o passe); os 5 pontos de uso (`ProductTypesListPage`, `ProductGroupsListPage`, `GroupSubgroupsPanel`, `BrandsListPage`, `UnitsListPage`) e o formulário manual de `SubgroupsListPage.tsx` passaram o rótulo específico de cada catálogo.
### Verificação
`pnpm turbo run typecheck build` 28/28. Suíte 95/95 (uma corrida isolada apresentou uma falha pontual num `afterAll` de outro spec depois de várias execuções seguidas da suíte hoje contra o mesmo Postgres compartilhado — não reproduziu nas execuções seguintes, tratado como ambiental, não investigado a fundo). Verificação em navegador real via Playwright headless: dump de DOM confirmando os 5 rótulos corretos em `/products/{types,groups,subgroups,brands,units}`, screenshots confirmando visualmente o submenu aninhado "Grupos" expandido mostrando "Grupos"/"Subgrupos", a tela de Subgrupos com dropdown "Grupo" + campo "Nome do subgrupo" + coluna "Grupo" na tabela, e o painel "Ver subgrupos" dentro de um grupo específico também com "Nome do subgrupo". Linhas de teste acumuladas nos 5 catálogos ao longo do dia (múltiplas rodadas de suíte + smoke tests) desativadas ao final — só sobraram duas linhas de subgrupo não reconhecidas como teste automatizado ("teste"/"qqweqw", possivelmente exploração manual do próprio usuário) deliberadamente preservadas, não mexidas.