12 KiB
Guia de Uso do Carrinho de Compras - VendaWeb React
📋 Visão Geral
Este documento descreve como funciona o sistema de carrinho de compras no frontend React, baseado na implementação funcional do portal Angular. O guia cobre desde a adição de itens até a gestão completa do carrinho.
🏗️ Arquitetura
vendaweb_react/
├── src/
│ ├── hooks/
│ │ └── useCart.ts # Hook customizado para gerenciar estado do carrinho
│ ├── services/
│ │ └── shopping.service.ts # Serviço para interações com a API do carrinho
│ └── contexts/
│ └── AuthContext.tsx # Contexto de autenticação (necessário para token)
├── components/
│ └── CartDrawer.tsx # Componente visual do carrinho
└── views/
└── CheckoutView.tsx # View de checkout
🔑 Conceitos Fundamentais
1. ID do Carrinho (idCart)
- Tipo:
string | null - Armazenamento:
localStorage.getItem("cart") - Comportamento:
- Quando
null: Backend cria um novo carrinho e retorna oidCartgerado - Quando existe: Backend adiciona o item ao carrinho existente
- Quando
- IMPORTANTE: Sempre enviar
idCart: null(não string vazia) quando não há carrinho
2. ID do Item (id)
- Tipo:
string | null - Comportamento:
- Quando
null: Backend cria um novo item e retorna oid(UUID) gerado - Quando existe: Backend atualiza o item existente
- Quando
- IMPORTANTE: Sempre enviar
id: nullpara novos itens
3. Fluxo de Adição de Item
1. Usuário seleciona produto
↓
2. productToShoppingItem() converte Product → ShoppingItem
↓
3. createItemShopping() envia POST /shopping/item
↓
4. Backend cria/atualiza carrinho e retorna idCart
↓
5. Frontend salva idCart no localStorage
↓
6. useCart hook recarrega itens do carrinho
📝 Estrutura do Payload
Payload para Adicionar Item (POST /shopping/item)
{
"id": null, // Sempre null para novos itens
"idCart": null, // null se não há carrinho, UUID se existe
"invoiceStore": "4", // Código da loja
"idProduct": 25960, // ID do produto (número)
"description": "Nome do Produto",
"image": "http://...", // URL da imagem ou "" se não houver
"productType": "S", // Tipo do produto
"percentUpQuantity": 0, // Sempre 0
"upQuantity": 0, // Sempre 0
"quantity": 1, // Quantidade
"price": 20.99, // Preço de venda
"deliveryType": "EN", // Tipo de entrega
"stockStore": "4", // Código da loja de estoque
"seller": 1, // ID do vendedor
"discount": 0, // Desconto percentual (sempre 0 inicialmente)
"discountValue": 0, // Valor do desconto (sempre 0 inicialmente)
"ean": 7895024019601, // Código EAN (ou idProduct se não houver)
"promotion": 20.99, // Preço promocional (0 se não houver promoção)
"listPrice": 33.9, // Preço de tabela
"userDiscount": null, // Sempre null
"mutiple": 1, // Múltiplo de venda
"auxDescription": null, // Descrição auxiliar (cor para tintométrico)
"smallDescription": "#ARG...", // Descrição curta (NÃO usar description como fallback)
"brand": "PORTOKOLL", // Marca
"base": "N", // Base tintométrica (S/N)
"line": null, // Linha tintométrica
"can": null, // Lata
"letter": null // Letra tintométrica
}
Regras Importantes
ideidCart: Sempre presentes no payload, mesmo que sejamnullsmallDescription: Usar apenas o camposmallDescriptiondo produto (não usardescriptioncomo fallback)promotion:- Se produto tem
promotion > 0: usar esse valor - Se
price < listPrice: usarpricecomopromotion - Caso contrário: usar
0
- Se produto tem
image: String vazia""quando não há imagem (nãonull)color: Remover do payload se fornull(não incluir o campo)
🔧 Uso do Hook useCart
Importação
import { useCart } from './src/hooks/useCart';
Uso Básico
const {
cart, // OrderItem[] - Itens do carrinho
cartId, // string | null - ID do carrinho
isLoading, // boolean - Estado de carregamento
error, // string | null - Mensagem de erro
addToCart, // (product: Product | OrderItem) => Promise<void>
updateQuantity, // (id: string, delta: number) => Promise<void>
removeFromCart, // (id: string) => Promise<void>
refreshCart, // () => Promise<void>
clearCart, // () => void
} = useCart();
Exemplo Completo
import { useCart } from './src/hooks/useCart';
import { Product } from './types';
function ProductCard({ product }: { product: Product }) {
const { addToCart, isLoading } = useCart();
const handleAddToCart = async () => {
try {
await addToCart(product);
// Item adicionado com sucesso
// O hook automaticamente:
// 1. Cria o item no backend
// 2. Salva o idCart retornado no localStorage
// 3. Recarrega os itens do carrinho
} catch (error) {
console.error('Erro ao adicionar item:', error);
}
};
return (
<button onClick={handleAddToCart} disabled={isLoading}>
{isLoading ? 'Adicionando...' : 'Adicionar ao Carrinho'}
</button>
);
}
🛠️ Uso do Serviço shoppingService
Métodos Principais
1. createItemShopping(item: ShoppingItem): Promise<ShoppingItem>
Adiciona um item ao carrinho.
import { shoppingService } from './src/services/shopping.service';
import { Product } from './types';
// Converter Product para ShoppingItem
const shoppingItem = shoppingService.productToShoppingItem(product);
// Criar item no carrinho
const result = await shoppingService.createItemShopping(shoppingItem);
// O idCart será salvo automaticamente no localStorage
// Se result.idCart existir, será salvo
Comportamento:
- Se
item.idCarténull: Backend cria novo carrinho - Se
item.idCartexiste: Backend adiciona ao carrinho existente - Sempre retorna o
idCart(novo ou existente) - Remove
paymentPlanebillingdo localStorage após sucesso
2. productToShoppingItem(product: Product | OrderItem): ShoppingItem
Converte um Product ou OrderItem para ShoppingItem.
const product: Product = {
id: "123",
code: "25960",
name: "Produto Exemplo",
price: 20.99,
// ... outros campos
};
const shoppingItem = shoppingService.productToShoppingItem(product);
// Retorna ShoppingItem pronto para ser enviado ao backend
Regras de Conversão:
idProduct: Extraído deproduct.idProduct,product.idouproduct.codedescription:product.nameouproduct.descriptionsmallDescription: Apenasproduct.smallDescription(sem fallback)promotion: Calculado conforme regras acimaean:product.eanouidProductcomo fallbackidCart: Obtido dolocalStorage.getItem("cart")(pode sernull)
3. updateQuantityItemShopping(item: ShoppingItem): Promise<void>
Atualiza a quantidade de um item no carrinho.
const item = cart.find(i => i.id === itemId);
const shoppingItem = shoppingService.productToShoppingItem({
...item,
quantity: newQuantity
});
shoppingItem.id = item.id; // IMPORTANTE: Usar o UUID do item
shoppingItem.idCart = cartId;
await shoppingService.updateQuantityItemShopping(shoppingItem);
4. deleteItemShopping(id: string): Promise<void>
Remove um item do carrinho.
// IMPORTANTE: id deve ser o UUID do item (não idProduct)
await shoppingService.deleteItemShopping(itemId);
5. getShoppingItems(idCart: string): Promise<ShoppingItem[]>
Obtém todos os itens de um carrinho.
const cartId = shoppingService.getCart();
if (cartId) {
const items = await shoppingService.getShoppingItems(cartId);
}
⚠️ Validações e Regras de Negócio
1. Produto Tintométrico
Produtos com base === "S" requerem auxDescription (cor selecionada).
// Validação automática em createItemShopping()
if (base === "S" && auxDescription === "") {
throw new Error("Esse produto só pode ser adicionado com coloração selecionada");
}
2. IDs dos Itens
- Novos itens: Sempre enviar
id: null - Itens existentes: Usar o UUID retornado pelo backend
- IMPORTANTE: Não usar
idProductcomoiddo item do carrinho
3. ID do Carrinho
- Primeiro item:
idCart: null→ Backend cria novo carrinho - Itens subsequentes:
idCart: <UUID>→ Backend adiciona ao carrinho existente - Armazenamento: Sempre salvar o
idCartretornado nolocalStorage
🔍 Debugging
Logs do Serviço
O serviço gera logs detalhados com prefixo 🛒 [SHOPPING]:
console.log("🛒 [SHOPPING] createItemShopping: " + JSON.stringify(cleanItem));
console.log("🛒 [SHOPPING] Item criado com sucesso:", result);
console.log("🛒 [SHOPPING] idCart retornado:", result.idCart);
Verificar Estado do Carrinho
// No console do navegador
localStorage.getItem("cart"); // ID do carrinho
localStorage.getItem("token"); // Token de autenticação
Testar Requisição Manualmente
Use o script test_add_item.ps1 para testar a adição de itens via curl:
# 1. Obter token do localStorage
# 2. Editar test_add_item.ps1 com o token
# 3. Executar: .\test_add_item.ps1
🐛 Problemas Comuns e Soluções
Erro 400: "Erro ao criar item no carrinho de compras"
Causas possíveis:
idCartsendo enviado como string vazia""em vez denullsmallDescriptionusandodescriptioncomo fallback (muito longo)promotioncalculado incorretamente- Campos obrigatórios faltando ou com valores inválidos
Solução: Verificar logs do console e comparar payload com o exemplo funcional.
Item não aparece no carrinho após adicionar
Causas possíveis:
idCartnão foi salvo nolocalStoragerefreshCart()não foi chamado após adicionar item- Hook
useCartnão está recarregando itens
Solução: Verificar se result.idCart foi salvo e se loadCartItems() foi chamado.
Erro ao remover item
Causas possíveis:
iddo item não é um UUID válidoidestá usandoidProductem vez do UUID do backend
Solução: Garantir que item.id seja o UUID retornado pelo backend, não idProduct.
📚 Referências
- Backend API:
POST /api/v1/shopping/item - Angular Reference:
vendaweb_portal/src/app/sales/product-detail/product-detail.component.ts - Backend Service:
vendaweb_api/src/sales/shopping/shopping.service.ts
✅ Checklist de Implementação
Ao implementar funcionalidades de carrinho, verificar:
ideidCartsempre presentes no payload (mesmo quenull)smallDescriptionusa apenas campo do produto (sem fallback)promotioncalculado corretamenteidCartsalvo nolocalStorageapós criaçãorefreshCart()chamado após modificações- Validação de produto tintométrico implementada
- IDs dos itens são UUIDs (não
idProduct) - Tratamento de erros implementado
- Logs de debug adicionados
🔄 Fluxo Completo de Exemplo
// 1. Usuário seleciona produto
const product: Product = await productService.getProductDetail(storeId, productId);
// 2. Adicionar ao carrinho usando hook
const { addToCart } = useCart();
await addToCart(product);
// 3. Hook internamente:
// - Converte Product → ShoppingItem
// - Envia POST /shopping/item com idCart: null (se primeiro item)
// - Backend cria carrinho e retorna idCart
// - Salva idCart no localStorage
// - Recarrega itens do carrinho
// 4. Atualizar quantidade
const { updateQuantity } = useCart();
await updateQuantity(itemId, 1); // +1
// 5. Remover item
const { removeFromCart } = useCart();
await removeFromCart(itemId);
// 6. Limpar carrinho
const { clearCart } = useCart();
clearCart(); // Limpa estado e localStorage
Última atualização: 2026-01-06
Versão: 1.0
Autor: Sistema de Documentação Automática