Produtos do tipo Kit
Um produto do tipo Kit é um produto composto por outros produtos vinculados, vendido como uma unidade única. Esta funcionalidade detecta automaticamente esses produtos, destaca-os visualmente em todas as telas relevantes e permite ao usuário visualizar os itens inclusos sem sair do contexto atual.
Visão geral
A partir desta versão, produtos podem possuir uma propriedade COMPONENTE contendo uma lista de itens
vinculados. Quando essa propriedade está populada, o produto é tratado como um Kit: um produto que,
quando comprado, entrega múltiplos produtos para o cliente.
Exemplo prático:
O produto
CANETA CROWN AMSTERDAN ESF PRATA DI11451Spossui como componente o itemESTOJO SONETO DI11451S. Ao adicionar a caneta no pedido, o estojo acompanha automaticamente.
Disponibilidade
A feature pode ser habilitada por cliente de duas formas (descritas em detalhe na seção Habilitando para novos clientes):
| Mecanismo | Como funciona |
|---|---|
UTILKIT no Sankhya | Parâmetro configurado diretamente no ERP, sem deploy de código. |
hasKitFeature() no código | Método no permission.ts que identifica clientes por lógica de negócio (ex: isCanetasCrown()). |
Clientes ativos atualmente:
| Cliente | Mecanismo ativo |
|---|---|
| Canetas Crown | hasKitFeature() |
| Outros clientes | Configurar UTILKIT = S no Sankhya |
Onde a feature aparece
A identidade de Kit é apresentada de forma consistente em quatro contextos distintos do sistema:
1. Catálogo — modo Lista
Na visualização em tabela do catálogo, produtos do tipo Kit exibem um badge "Kit" dentro da célula de descrição, ao lado do nome do produto.
Ao clicar no badge, uma linha de expansão abre logo abaixo, mostrando todos os itens inclusos no kit com suas respectivas quantidades.
┌──────┬────────────────────────────────────────────┬───────────┐
│ Cód │ Descrição │ Preço │
├──────┼────────────────────────────────────────────┼───────────┤
│ 35907│ CANETA CROWN AMSTERDAN [▦ Kit · 2 itens ▾] │ R$ 49,90 │
│ │ ⤷ Itens inclusos neste kit: │ │
│ │ ┌─────────────────────────────────────┐ │ │
│ │ │ 📷 ESTOJO SONETO DI11451S │ │ │
│ │ │ 1 UN · cód. 35908 [👁] │ │ │
│ │ └─────────────────────────────────────┘ │ │
└──────┴────────────────────────────────────────────┴───────────┘
Screenshot:
Substitua o placeholder acima por screenshots reais ao publicar a doc.
2. Catálogo — modo Grid
No modo cards do catálogo, o badge "Kit" aparece no canto superior do card, ao lado do indicador de "Destaque". Ao clicar no badge, um painel expansível mostra os itens inclusos diretamente no card, sem abrir nenhum modal.
Screenshot:

3. Modal de Detalhes do Produto
Ao abrir o modal de detalhes de um produto Kit, duas coisas mudam:
- Badge "Kit · N itens" aparece no cabeçalho do modal, junto com badges existentes como "Em promoção" e "Destaque".
- Uma seção promocional dedicada (card com banner gradient azul) é renderizada listando todos os componentes do kit em formato visual rico, com imagens dos produtos.
┌─────────────────────────────────────────────────────────────────┐
│ ╔═══════════════════════════════════════════════════════════╗ │
│ ║ ◯ Este produto é um KIT ║ │ ← Banner gradient
│ ║ ▣ 3 produtos inclusos ║ │
│ ╚═══════════════════════════════════════════════════════════╝ │
│ │
│ COMPOSIÇÃO │
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ [📷] ESTOJO SONETO DI11451S [👁] │ │ ← Card por item
│ │ 1 UN · cód. 35908 │ │ (com imagem e
│ └─────────────────────────────────────────────────────┘ │ botão detalhes)
│ ┌─────────────────────────────────────────────────────┐ │
│ │ [📷] CAIXA DE PRESENTE BRANCA [👁] │ │
│ │ 1 UN · cód. 35910 │ │
│ └─────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
Screenshot:

4. Nova Venda — Tabela de Produtos
Na tela de criação de venda, uma coluna dedicada (entre o código do produto e a descrição) exibe o badge "Kit" apenas para os produtos que se qualificam. A coluna é automaticamente ocultada para clientes que não têm a feature ativa.
Ao posicionar o mouse sobre o badge, um popover aparece mostrando todos os itens inclusos no kit — útil para conferência rápida durante a montagem do pedido.
┌──────┬───────┬─────────────────────────────────────┬──────┐
│ Cód │ Kit │ Descrição │ Qtd │
├──────┼───────┼─────────────────────────────────────┼──────┤
│ 35907│ [▣Kit]│ CANETA CROWN AMSTERDAN ESF PRATA │ 1 │
│ 35351│ — │ CARGA ESF CS C/1 BLISTADA CROWN │ 5 │
└──────┴───────┴─────────────────────────────────────┴──────┘
↓ hover no badge
╔═════════════════════════════════════╗
║ Itens inclusos neste kit ║
║ ║
║ [📷] ESTOJO SONETO DI11451S ║
║ 1 UN · cód. 35908 ║
╚═════════════════════════════════════╝
Screenshot:

Interações disponíveis
Em qualquer contexto onde os componentes do kit são listados, o usuário pode:
Ampliar imagem do componente
Cada componente exibe a foto do produto (48×48px). Ao clicar na imagem, o
visualizador de imagens do sistema (ImageViewer) abre em tela maior. Útil quando o
usuário quer verificar visualmente o que está incluso.
Quando o produto incluso não possui imagem cadastrada, o sistema exibe automaticamente um ícone de "pacote" (📦) como fallback visual, em vez da imagem padrão de "sem foto".
Abrir detalhes do produto incluso
À direita de cada item do kit há um botão com ícone de olho (👁️). Ao clicar:
- Abre o Modal de Detalhes do Produto para aquele item específico do kit.
- Útil para conferir descrição completa, preços, estoque, histórico de vendas do componente individualmente.
- O botão dispara a ação Redux
setProductModal(CODPROD)que é capturada pelo listener globalViewModal.
Quando o usuário já está no Modal de Detalhes de um Kit e clica em "Ver detalhes" de um componente, o modal atualmente substitui o produto exibido (não empilha modais). Para retornar ao produto Kit original, o usuário precisa fechar e reabri-lo a partir da listagem.
Estrutura de dados
A entidade Product recebe a propriedade opcional COMPONENTE:
interface ProductKitComponent {
CODPROD: number; // Código do produto incluso
DESCRPROD: string; // Descrição do produto incluso
CODVOL?: string; // Unidade de venda (ex: "UN", "PC")
SEQUENCIA: number; // Ordem de exibição (sort ascendente)
QUANTIDADE: number; // Quantidade do componente no kit
}
interface Product {
// ... campos existentes
COMPONENTE?: ProductKitComponent[];
}
Regras:
COMPONENTEé opcional. Se ausente ou array vazio, o produto é tratado como produto comum.- Componentes são sempre renderizados ordenados por
SEQUENCIAascendente. QUANTIDADEé umnumberdireto (anteriormente um objeto{ source, parsedValue }— alterado para refletir o contrato real da API).- Quando
CODVOLestá ausente, a unidade é omitida na exibição (mostra apenas a quantidade).
Exemplo de payload
{
"CODPROD": 35907,
"DESCRPROD": "CANETA CROWN AMSTERDAN ESF PRATA DI11451S",
"COMPONENTE": [
{
"CODPROD": 35908,
"DESCRPROD": "ESTOJO SONETO DI11451S",
"CODVOL": "UN",
"QUANTIDADE": 1,
"SEQUENCIA": 1
}
]
}
Arquitetura técnica
A feature foi construída em três camadas para garantir reutilização e manutenção fácil:
Camada 1 — Componentes UI (puros e agnósticos de cliente)
Componentes em src/components/Kit/:
| Arquivo | Responsabilidade |
|---|---|
KitBadge.tsx | Renderiza o badge "Kit" com ícone Boxes e contagem opcional. |
KitComponentsList.tsx | Lista visual dos componentes (imagem, descrição, quantidade, ações). |
index.ts | Barrel export para consumo via @/components/Kit. |
Nenhum desses componentes conhece o conceito de "cliente Canetas Crown". Eles recebem dados como props e renderizam. Isso garante que a UI seja reutilizável em qualquer contexto.
Camada 2 — Feature gate (única fonte de verdade)
O helper hasKitFeatureEnabled resolve a feature como true se qualquer uma das duas condições abaixo for satisfeita:
Mecanismo 1 — hasKitFeature() no código
Localização: src/utils/permission.ts:144.
hasKitFeature = () => this.isCanetasCrown();
Ativado por lógica de negócio embutida no front-end. Requer deploy para adicionar ou remover clientes.
Mecanismo 2 — parâmetro UTILKIT no Sankhya
O campo UTILKIT é retornado pela API junto com os dados de permissão do usuário. Quando seu valor é 'S', a feature é habilitada sem necessidade de alteração de código ou deploy.
// src/utils/kit.utils.ts
export function hasKitFeatureEnabled(permission: any): boolean {
return (
permission?.permissionByCompany?.hasKitFeature?.() ||
permission?.UTILKIT === "S"
);
}
Helpers em src/utils/kit.utils.ts:
// Verifica se um produto específico deve ser exibido como Kit
// (cliente tem feature + produto tem componentes)
isKitProduct(product, permission): boolean
// Conta quantos componentes o produto tem
getKitComponentCount(product): number
// Verifica apenas se a feature está ativa para o cliente
// (sem considerar produtos)
hasKitFeatureEnabled(permission): boolean
Camada 3 — Integração nas telas
Cada tela importa os componentes UI e o gate, e renderiza condicionalmente:
import { KitBadge, KitComponentsList } from "@/components/Kit";
import { isKitProduct, getKitComponentCount } from "@/utils/kit.utils";
// Em qualquer tela:
{
isKitProduct(product, permission) && (
<KitBadge componentCount={getKitComponentCount(product)} />
);
}
Fluxo de dados
Renderização do badge
Interação: ver detalhes de um componente
Carregamento da imagem do componente
Habilitando para novos clientes
A feature pode ser ativada de duas formas, dependendo se você prefere uma configuração no ERP sem deploy ou uma alteração de código.
Opção 1 — Parâmetro UTILKIT no Sankhya (recomendado)
Esta é a forma mais rápida e não requer deploy de código. Basta configurar o parâmetro diretamente no Sankhya:
- Acesse as configurações de parâmetros do cliente no Sankhya.
- Localize o parâmetro
UTILKIT. - Defina o valor como
S.
Após a configuração, na próxima autenticação do usuário daquele cliente, a feature já estará ativa em todas as quatro telas automaticamente.
A API precisa estar enviando a propriedade COMPONENTE populada nos produtos do cliente.
Sem dados, a feature gate retorna true mas nenhum produto será detectado como Kit.
Para desativar, basta alterar o valor de UTILKIT para qualquer valor diferente de 'S' (ex: 'N').
Opção 2 — Método hasKitFeature() no código
Use esta opção quando a regra de ativação for baseada em lógica de negócio (ex: identificar o cliente por tipo de empresa).
Passos:
- Abrir
src/utils/permission.ts. - Localizar o método
hasKitFeature(linha 144 aproximadamente). - Adicionar o cliente ao OR:
Antes:
hasKitFeature = () => this.isCanetasCrown();
Depois (exemplo habilitando "Vinicola Garibaldi"):
hasKitFeature = () => this.isCanetasCrown() || this.isVinicolaGaribaldi();
Após o deploy:
- Todas as 4 telas passam a exibir Kits automaticamente para o novo cliente.
- A coluna
KIT_FLAGda Nova Venda passa a aparecer automaticamente. - Nenhuma outra mudança de código é necessária.
Verificação após habilitar (ambas as opções)
- Fazer login com um usuário do cliente habilitado.
- Abrir o catálogo e verificar que produtos com
COMPONENTEexibem o badge "Kit". - Abrir o modal de detalhes e confirmar que a seção promocional "Itens do Kit" aparece.
- Ir para Nova Venda e confirmar que a coluna "Kit" foi adicionada à tabela.
Configuração visual
A identidade visual do Kit usa a cor institucional #1C73C3 (azul) e o ícone Boxes da
biblioteca Lucide. A tabela abaixo documenta os tokens visuais:
| Elemento | Valor |
|---|---|
| Cor primária | #1C73C3 |
| Cor secundária (gradient) | #0d5ea0 |
| Background da tag | bg-blue-50 · #EFF6FF |
| Borda da tag | border-blue-100 · #DBEAFE |
| Ícone do badge | Boxes (lucide-react) |
| Ícone fallback | Package (lucide-react) |
| Ícone "ver detalhes" | Eye (lucide-react) |
| Variantes da lista | inline (padrão) · cards (modal promocional) |
Acessibilidade
A feature segue boas práticas de a11y:
- O
KitBadgeinterativo é renderizado como<button type="button">comaria-expandedearia-label="Ver itens do kit". - Imagens dos componentes têm
alt={DESCRPROD}descritivo. - Quando a imagem está em fallback, o container do ícone tem
aria-label="Imagem de [Produto] indisponível". - O botão "Ver detalhes" tem
aria-labelcom o nome do produto. - Lista de componentes usa estrutura semântica
<ul><li>...</li></ul>. - Tooltips do popover são acessíveis via teclado (foco) e leitores de tela.
Testes
A feature possui 32 testes unitários cobrindo:
| Arquivo | Testes | Foco |
|---|---|---|
src/utils/kit.utils.test.ts | 16 | Gates isKitProduct, getKitComponentCount, hasKitFeatureEnabled (incluindo cenários com UTILKIT) |
src/components/Kit/KitBadge.test.tsx | 8 | Renderização do badge, variantes, acessibilidade |
src/components/Kit/KitComponentsList.test.tsx | 8 | Renderização da lista, variantes, fallback de imagem |
Executar:
npm test
Cobertura específica:
npm run test:coverage
Limitações conhecidas
Ao clicar em "Ver detalhes" de um componente quando já está dentro do modal de detalhes, o modal substitui o produto exibido em vez de empilhar. O usuário perde o contexto do produto Kit original.
Workaround atual: fechar o modal e reabrir o Kit a partir da listagem.
Solução futura: transformar state.modal.product em uma pilha (array) para permitir
"voltar" para o produto anterior. Requer mudança arquitetural no slice modal e no
ViewModal.
Para produtos com imagem cadastrada, durante a janela de fetch assíncrono pode haver
um breve flash do ícone Package antes da imagem real aparecer. Em conexões rápidas
é imperceptível.
Solução futura: pré-carregar imagens via Image() ou aplicar uma transição de
opacidade no swap.
Atualmente o sistema não suporta um componente do kit ser também um kit.
Se um produto COMPONENTE[N] também tiver sua própria propriedade COMPONENTE,
essa estrutura não é renderizada recursivamente.
Os componentes do kit são exibidos somente para leitura. Não é possível editar quantidades de componentes individuais nem remover componentes do kit pelo front-end — essas operações devem ser feitas pelo ERP.
FAQ
Por que o badge "Kit" não aparece para meu produto?
Verifique:
- O usuário está logado em um cliente onde a feature está ativa? Pode ser via
UTILKIT = Sno Sankhya ou viahasKitFeature()no código (atualmente: Canetas Crown). - O produto possui a propriedade
COMPONENTEpopulada? Cheque a resposta da API ou o estado Redux. - O array
COMPONENTEtem pelo menos 1 item? Arrays vazios não disparam o badge.
Qual a diferença entre ativar pelo Sankhya e pelo código?
Ativar pelo parâmetro UTILKIT = S no Sankhya não requer deploy — a mudança é imediata na próxima autenticação do usuário. Já a ativação via hasKitFeature() no código exige alteração no permission.ts, build e deploy. Use o Sankhya quando possível; use o código quando a regra de ativação for baseada em lógica de negócio que não existe como parâmetro no ERP.
Como o sistema decide entre mostrar a imagem ou o ícone fallback?
A lógica está em KitItemRow dentro de KitComponentsList.tsx:
- O hook
useProductImageé chamado comfallbackSrc: ''(string vazia). - Se a URL retornada é vazia OU
onErrorda<AppImage>é disparado, o estadohasLoadErrorviratrue. - Quando
hasLoadError === trueouimageUrl === '', renderiza o íconePackage. - Caso contrário, renderiza
<AppImage>com a URL.
Posso desabilitar a coluna "Kit" da tabela de Nova Venda?
A coluna é automaticamente ocultada quando hasKitFeatureEnabled(permission) retorna false.
Ou seja, ela só aparece para clientes que têm a feature ativada (via código ou via UTILKIT). Não é necessária ação manual.
O popover do badge funciona em mobile?
Sim. O <Tooltip> do MUI suporta long-press em dispositivos touch (enterTouchDelay={300}).
O que acontece se um cliente tiver COMPONENTE mas não tiver feature ativa?
A feature gate isKitProduct(product, permission) retorna false, então nenhum tratamento
visual de Kit é aplicado. O produto aparece como um produto comum em todas as telas.
Referências internas
- Ticket: FORCEWEB-1754
- Branch:
customization/FORCEWEB-1754-exibir-componentes-do-kit-no-call
Arquivos-chave
| Camada | Arquivo |
|---|---|
| Tipo | src/types/product/product.types.ts |
| Gate | src/utils/permission.ts |
| Helpers | src/utils/kit.utils.ts |
| UI | src/components/Kit/KitBadge.tsx |
| UI | src/components/Kit/KitComponentsList.tsx |
| Integração 1 | src/screens/catalogo/components/TableRow/index.tsx |
| Integração 2 | src/screens/catalogo/components/ProductsGrid/components/ProductCard/index.tsx |
| Integração 3 | src/screens/nova-venda/.../KitFlag/NewSaleProductsKitFlag.tsx |
| Integração 4 | src/screens/catalogo/components/ProductModal/index.tsx |
Changelog
| Versão | Data | Mudança |
|---|---|---|
| 1.1.0 | 2026-05-22 | Suporte ao parâmetro UTILKIT do Sankhya como segundo mecanismo de ativação da feature, sem necessidade de deploy. |
| Initial | 2026-05-22 | Feature inicial — badge, expansão, popover, modal promocional, ícone Package fallback, click-to-zoom, botão "Ver detalhes". |