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.