# 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 o `idCart` gerado - Quando existe: Backend adiciona o item ao carrinho existente - **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 o `id` (UUID) gerado - Quando existe: Backend atualiza o item existente - **IMPORTANTE**: Sempre enviar `id: null` para 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) ```typescript { "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 1. **`id` e `idCart`**: Sempre presentes no payload, mesmo que sejam `null` 2. **`smallDescription`**: Usar apenas o campo `smallDescription` do produto (não usar `description` como fallback) 3. **`promotion`**: - Se produto tem `promotion > 0`: usar esse valor - Se `price < listPrice`: usar `price` como `promotion` - Caso contrário: usar `0` 4. **`image`**: String vazia `""` quando não há imagem (não `null`) 5. **`color`**: Remover do payload se for `null` (não incluir o campo) ## 🔧 Uso do Hook `useCart` ### Importação ```typescript import { useCart } from './src/hooks/useCart'; ``` ### Uso Básico ```typescript 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 updateQuantity, // (id: string, delta: number) => Promise removeFromCart, // (id: string) => Promise refreshCart, // () => Promise clearCart, // () => void } = useCart(); ``` ### Exemplo Completo ```typescript 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 ( ); } ``` ## 🛠️ Uso do Serviço `shoppingService` ### Métodos Principais #### 1. `createItemShopping(item: ShoppingItem): Promise` Adiciona um item ao carrinho. ```typescript 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.idCart` existe: Backend adiciona ao carrinho existente - Sempre retorna o `idCart` (novo ou existente) - Remove `paymentPlan` e `billing` do localStorage após sucesso #### 2. `productToShoppingItem(product: Product | OrderItem): ShoppingItem` Converte um `Product` ou `OrderItem` para `ShoppingItem`. ```typescript 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 de `product.idProduct`, `product.id` ou `product.code` - `description`: `product.name` ou `product.description` - `smallDescription`: Apenas `product.smallDescription` (sem fallback) - `promotion`: Calculado conforme regras acima - `ean`: `product.ean` ou `idProduct` como fallback - `idCart`: Obtido do `localStorage.getItem("cart")` (pode ser `null`) #### 3. `updateQuantityItemShopping(item: ShoppingItem): Promise` Atualiza a quantidade de um item no carrinho. ```typescript 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` Remove um item do carrinho. ```typescript // IMPORTANTE: id deve ser o UUID do item (não idProduct) await shoppingService.deleteItemShopping(itemId); ``` #### 5. `getShoppingItems(idCart: string): Promise` Obtém todos os itens de um carrinho. ```typescript 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). ```typescript // 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 `idProduct` como `id` do item do carrinho ### 3. ID do Carrinho - **Primeiro item**: `idCart: null` → Backend cria novo carrinho - **Itens subsequentes**: `idCart: ` → Backend adiciona ao carrinho existente - **Armazenamento**: Sempre salvar o `idCart` retornado no `localStorage` ## 🔍 Debugging ### Logs do Serviço O serviço gera logs detalhados com prefixo `🛒 [SHOPPING]`: ```typescript 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 ```typescript // 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: ```powershell # 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**: 1. `idCart` sendo enviado como string vazia `""` em vez de `null` 2. `smallDescription` usando `description` como fallback (muito longo) 3. `promotion` calculado incorretamente 4. 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**: 1. `idCart` não foi salvo no `localStorage` 2. `refreshCart()` não foi chamado após adicionar item 3. Hook `useCart` não está recarregando itens **Solução**: Verificar se `result.idCart` foi salvo e se `loadCartItems()` foi chamado. ### Erro ao remover item **Causas possíveis**: 1. `id` do item não é um UUID válido 2. `id` está usando `idProduct` em 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: - [ ] `id` e `idCart` sempre presentes no payload (mesmo que `null`) - [ ] `smallDescription` usa apenas campo do produto (sem fallback) - [ ] `promotion` calculado corretamente - [ ] `idCart` salvo no `localStorage` após criação - [ ] `refreshCart()` 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 ```typescript // 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