feat(products): submenu de Subgrupos aninhado dentro de Grupos

Mesma lógica do submenu "Produtos" já existente: "Grupos" agora expande
seu próprio submenu com "Subgrupos" (AppShell ganha suporte a um
segundo nível de accordion aninhado). Nova tela lista todos os
subgrupos de todos os grupos, com coluna Grupo e criação via dropdown
de grupo explícito — complementa (não substitui) o painel já existente
dentro da tela de um grupo específico.

listProductSubgroups passa a resolver group_name via JOIN.

Suíte: 95/95. pnpm turbo run typecheck build: 28/28 (core-web,
reseller-web e subscriber-web confirmados sem regressão no AppShell
compartilhado).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-18 08:52:19 -03:00
parent f38f2407ff
commit 96200dc2ba
9 changed files with 200 additions and 20 deletions

View File

@@ -12,7 +12,10 @@ export interface AppShellNavItem {
* When present (even if empty), this item renders as an expandable
* accordion group instead of a direct link — `href` is then only a
* placeholder (typically duplicated by the first child) and is never
* navigated to directly. Only one level deep is supported.
* navigated to directly. A child may itself declare `children`, nesting
* another accordion one level deeper (e.g. Produtos > Grupos >
* Subgrupos) — depth beyond that is untested but not structurally
* prevented.
*/
children?: AppShellNavItem[];
}
@@ -101,16 +104,20 @@ function NavGroup({
</button>
{open ? (
<div className="ms-3 mt-1 flex flex-col gap-1 border-s border-border-color ps-3">
{(item.children ?? []).map((child) => (
<LinkComponent
key={child.key}
href={child.href}
className={cn(NAV_LINK_CLASSES, child.active ? NAV_LINK_ACTIVE_CLASSES : NAV_LINK_INACTIVE_CLASSES)}
>
{child.icon}
<span>{child.label}</span>
</LinkComponent>
))}
{(item.children ?? []).map((child) =>
child.children ? (
<NavGroup key={child.key} item={child} LinkComponent={LinkComponent} />
) : (
<LinkComponent
key={child.key}
href={child.href}
className={cn(NAV_LINK_CLASSES, child.active ? NAV_LINK_ACTIVE_CLASSES : NAV_LINK_INACTIVE_CLASSES)}
>
{child.icon}
<span>{child.label}</span>
</LinkComponent>
),
)}
</div>
) : null}
</div>