Pular para o conteúdo principal

Análise de Produto

Última atualização: 15 de julho de 2026

Visão Geral​

"Análise de Produto" é acessível pelo menu de mais opções do catálogo, atrás da flag cfg-ativaranalisedeprodutos, e também a partir do modal de detalhes de um produto específico. A ideia do recurso é mostrar, para um produto escolhido, um resumo de vendas: ticket médio, quantidade vendida, um gráfico mensal, uma tabela de vendas por cliente, um ranking dos dez maiores compradores, clientes recorrentes e clientes que nunca compraram aquele produto. Vale saber antes de continuar: hoje essa tela inteira opera sobre dados de exemplo, não sobre a base real do vendedor.

Arquivos-chave​

ArquivoResponsabilidade
app/catalog/analise-produto.tsx + app/catalog/analise-produto-detalhe.tsxRotas de pilha
features/catalog/subscreens/product-analysis/product-analysis.controller.tsBusca e ordenação da lista de produtos para análise
features/catalog/subscreens/product-analysis/product-analysis-detail.controller.tsResolve os dados de análise de um produto específico
features/catalog/subscreens/product-analysis/product-analysis-detail.mock.tsFonte dos dados exibidos na análise, inteiramente sintética
__mocks__/products.mock.tsFonte da lista de produtos pesquisável na tela de análise

A lista de produtos para análise vem de um mock, não do repositório​

A busca, os campos pesquisáveis e a ordenação dessa tela são, na prática, uma reimplementação em memória do mesmo tipo de busca já visto no restante do catálogo, incluindo relevância ponderada por campo:

// product-analysis.controller.ts
import { productsMock } from "@/__mocks__/products.mock";

const filteredProducts = useMemo(() => {
if (!hasSearched) return [];
const matchingProducts = productsMock.filter((product) =>
matchesSearch(product, search, searchBy),
);
return sortProducts(matchingProducts, search, searchBy, orderBy);
}, [hasSearched, orderBy, search, searchBy]);

O algoritmo de relevância em si é genuíno e bem construído, não é um placeholder: ele dá peso maior a campos mais relevantes (código antes de descrição, por exemplo), soma bônus por casar a palavra inteira, por casar como prefixo, e por posição do termo dentro do campo:

const getRelevanceScore = (product, query, searchBy) => {
// ...
fields.forEach((field, index) => {
let score = (fields.length - index) * 1000;
if (value === normalizedQuery) score += 2000;
if (value.startsWith(normalizedQuery)) score += 900;
// ... bônus por posição de cada termo dentro do valor do campo
});
};

O que falta aqui não é lógica de busca, é a fonte de dados: em vez de productService.searchAndList (o mesmo usado pelo resto do catálogo), essa tela filtra e ordena a lista fixa de productsMock. Qualquer produto que exista na base real do vendedor mas não esteja nesse mock simplesmente não aparece na busca de análise.

O detalhe de um produto também é inteiramente sintético​

Ao escolher um produto na lista de análise, ou ao abrir a análise a partir do modal de detalhes de um produto no catálogo, a tela de detalhe busca os dados por productId numa função local:

// product-analysis-detail.controller.ts
const detailData = useMemo(
() => getProductAnalysisDetailData(productId ?? ""),
[productId],
);

O formato dos dados é rico e bem modelado, cobrindo exatamente o que a tela promete mostrar:

// product-analysis-detail.mock.ts
export type ProductAnalysisDetailData = {
product: ProductAnalysisProduct;
displayName: string;
summary: { averageTicket: string; quantity: string; totalValue: string };
monthlySales: ProductAnalysisBarPoint[];
salesByClient: { fields: ProductAnalysisTableField[]; rows: ProductAnalysisTableRow[] };
top10ByClient: { fields: ProductAnalysisTableField[]; rows: ProductAnalysisTableRow[] };
recurringClients: { fields: ProductAnalysisTableField[]; rows: ProductAnalysisTableRow[] };
neverBoughtClients: { fields: ProductAnalysisTableField[]; rows: ProductAnalysisTableRow[] };
};

Mas os valores vêm de listas fixas no próprio arquivo do mock, como nomes de clientes fictícios ("Loja Real Ltda", "Rei do Baiao", "RGK Recife") e meses fixos de Janeiro a Junho, não de uma consulta ao histórico de vendas do produto. Não existe, hoje, nenhuma ligação entre essa tela e o repositório de vendas ou de itens vendidos.

Duas formas de entrar na análise de um produto, uma delas mais restrita​

O parâmetro entrySource diferencia se o usuário chegou pela lista de análise ("analysis-list") ou direto do modal de detalhes de um produto no catálogo ("product-details"). Só no primeiro caso é permitido voltar e escolher outro produto sem sair da análise:

const canSelectAnotherProduct = entrySource === "analysis-list";

const onPressSelectAnotherProduct = () => {
if (!canSelectAnotherProduct) return;
router.back();
};

Isso faz sentido: quem entrou já com um produto específico em mãos, pelo modal de detalhes, não tem uma lista de análise por trás para voltar.

Armadilhas conhecidas​

Não trate um resultado vazio ou incompleto na análise de um produto real como um bug de consulta. Enquanto essa tela depender de productsMock e de product-analysis-detail.mock.ts, o comportamento esperado é mesmo esse: só os produtos e os dados sintéticos presentes nesses arquivos aparecem. Antes de estender esse recurso, o trabalho necessário é trocar as duas fontes de dados por consultas reais (produto via productService, histórico de vendas via algum repositório de pedidos), preservando a lógica de busca, relevância e o formato de ProductAnalysisDetailData, que já estão prontos.