"use client"; import React, { createContext, useContext, useState, useEffect, ReactNode, } from "react"; import { produtoService } from "@/services/produtoService"; import { ProdutoCompleto } from "@/services/produtosVendaService"; import { carrinhoApiService } from "@/services/carrinhoApiService"; import { toast } from "react-hot-toast"; interface ItemCarrinho { produto: ProdutoCompleto; quantidade: number; } interface CarrinhoContextType { itens: ItemCarrinho[]; totalItens: number; valorTotal: number; carrinhoId: string | null; sincronizandoApi: boolean; adicionarItem: ( produto: ProdutoCompleto, quantidade?: number ) => Promise; removerItem: (produtoId: string) => Promise; atualizarQuantidade: (produtoId: string, quantidade: number) => Promise; limparCarrinho: (restaurarEstoque?: boolean) => Promise; isCarrinhoAberto: boolean; setIsCarrinhoAberto: (aberto: boolean) => void; } const CarrinhoContext = createContext( undefined ); export { CarrinhoContext }; export const useCarrinho = () => { const context = useContext(CarrinhoContext); if (!context) { throw new Error("useCarrinho deve ser usado dentro de um CarrinhoProvider"); } return context; }; interface CarrinhoProviderProps { children: ReactNode; } // Função para obter o preço do produto de forma consistente const obterPreco = (produto: ProdutoCompleto): number => { const produtoData = produto as any; // Retorna apenas o preco_final, se não existir retorna 0 return produtoData.preco_final || 0; }; export const CarrinhoProvider: React.FC = ({ children, }) => { const [itens, setItens] = useState([]); const [isCarrinhoAberto, setIsCarrinhoAberto] = useState(false); const [carrinhoId, setCarrinhoId] = useState(null); const [sincronizandoApi, setSincronizandoApi] = useState(false); // Carregar carrinho do localStorage ao inicializar useEffect(() => { setTimeout(() => { try { const carrinhoSalvo = localStorage.getItem("carrinho-saveinmed"); const carrinhoIdSalvo = localStorage.getItem("carrinho-id"); if (carrinhoSalvo) { const carrinhoParsed = JSON.parse(carrinhoSalvo); setItens(carrinhoParsed); } if (carrinhoIdSalvo) { setCarrinhoId(carrinhoIdSalvo); } } catch (error) { } }, 100); }, []); // Salvar carrinho no localStorage sempre que houver mudanças useEffect(() => { localStorage.setItem("carrinho-saveinmed", JSON.stringify(itens)); }, [itens]); // Sincronizar com API BFF quando itens mudam (com debounce) useEffect(() => { if (itens.length === 0 && carrinhoId) { // Verificar se estamos em páginas de checkout/pagamento const isCheckoutPage = typeof window !== 'undefined' && (window.location.pathname.includes('/checkout') || window.location.pathname.includes('/pagamento')); if (!isCheckoutPage) { // Se não há itens mas há carrinho na API, excluir (apenas se não estamos no checkout) setSincronizandoApi(true); carrinhoApiService.excluir(carrinhoId) .then(response => { if (response.success) { setCarrinhoId(null); localStorage.removeItem("carrinho-id"); } else { console.error("❌ [CARRINHO API] Erro ao excluir:", response.error); } }) .catch(error => { console.error("💥 [CARRINHO API] Erro na exclusão:", error); }) .finally(() => { setSincronizandoApi(false); }); } else { } return; } if (itens.length === 0) return; // Não fazer nada se não há itens // Debounce: aguardar 1 segundo sem mudanças antes de sincronizar const timeoutId = setTimeout(() => { setSincronizandoApi(true); if (carrinhoId) { // Atualizar carrinho existente carrinhoApiService.atualizar(carrinhoId, itens) .then(response => { if (response.success) { } else { console.error("❌ [CARRINHO API] Erro ao atualizar:", response.error); } }) .catch(error => { console.error("💥 [CARRINHO API] Erro na atualização:", error); }) .finally(() => { setSincronizandoApi(false); }); } else { // Criar novo carrinho carrinhoApiService.criar(itens) .then(response => { if (response.success && response.data) { const novoCarrinhoId = response.data.$id || response.data.id; if (novoCarrinhoId) { setCarrinhoId(novoCarrinhoId); localStorage.setItem("carrinho-id", novoCarrinhoId); } } else { console.error("❌ [CARRINHO API] Erro ao criar:", response.error); } }) .catch(error => { console.error("💥 [CARRINHO API] Erro na criação:", error); }) .finally(() => { setSincronizandoApi(false); }); } }, 1000); return () => clearTimeout(timeoutId); }, [itens, carrinhoId]); const adicionarItem = async ( produto: ProdutoCompleto, quantidade: number = 1 ) => { // Obter estoque disponível do produto const estoqueDisponivel = produto.quantidade_estoque || 0; setItens((prevItens) => { const itemExistente = prevItens.find( (item) => item.produto.id === produto.id ); if (itemExistente) { const novaQuantidade = itemExistente.quantidade + quantidade; // Verificar se a nova quantidade não excede o estoque if (novaQuantidade > estoqueDisponivel) { console.warn( `Tentativa de adicionar mais itens do que disponível em estoque. Disponível: ${estoqueDisponivel}, Tentando adicionar: ${novaQuantidade}` ); toast.error( `Estoque insuficiente! Disponível: ${estoqueDisponivel} unidades` ); return prevItens; // Não adiciona se exceder o estoque } toast.success("Produto adicionado ao carrinho!"); return prevItens.map((item) => item.produto.id === produto.id ? { ...item, quantidade: novaQuantidade } : item ); } else { // Verificar se a quantidade inicial não excede o estoque if (quantidade > estoqueDisponivel) { console.warn( `Tentativa de adicionar mais itens do que disponível em estoque. Disponível: ${estoqueDisponivel}, Tentando adicionar: ${quantidade}` ); toast.error( `Estoque insuficiente! Disponível: ${estoqueDisponivel} unidades` ); return prevItens; // Não adiciona se exceder o estoque } toast.success("Produto adicionado ao carrinho!"); return [...prevItens, { produto, quantidade }]; } }); }; const removerItem = async (produtoId: string) => { toast.success("Item removido do carrinho!"); setItens((prevItens) => prevItens.filter((item) => item.produto.id !== produtoId) ); }; const atualizarQuantidade = async (produtoId: string, quantidade: number) => { if (quantidade <= 0) { await removerItem(produtoId); return; } // Encontrar o item atual const itemAtual = itens.find((item) => item.produto.id === produtoId); if (itemAtual) { // Verificar se há estoque suficiente para a nova quantidade const estoqueDisponivel = itemAtual.produto.quantidade_estoque || 0; if (quantidade > estoqueDisponivel) { toast.error( `Estoque insuficiente! Disponível: ${estoqueDisponivel} unidades` ); return; } setItens((prevItens) => prevItens.map((item) => { if (item.produto.id === produtoId) { return { ...item, quantidade }; } return item; }) ); toast.success("Quantidade atualizada!"); } }; const limparCarrinho = async (restaurarEstoque: boolean = false) => { // Primeiro, excluir carrinho da API se existir if (carrinhoId) { try { setSincronizandoApi(true); const response = await carrinhoApiService.excluir(carrinhoId); if (response.success) { } else { console.error("❌ [CARRINHO API] Erro ao excluir:", response.error); } } catch (error) { console.error("💥 [CARRINHO API] Erro na exclusão:", error); } finally { setSincronizandoApi(false); } setCarrinhoId(null); localStorage.removeItem("carrinho-id"); } setItens([]); toast.success("Carrinho limpo!"); }; const totalItens = itens.reduce((total, item) => total + item.quantidade, 0); // Atualizar o cálculo do valor total para usar a nova função de preço const valorTotal = itens.reduce((total, item) => { const preco = obterPreco(item.produto); return total + preco * item.quantidade; }, 0); const value: CarrinhoContextType = { itens, totalItens, valorTotal, carrinhoId, sincronizandoApi, adicionarItem, removerItem, atualizarQuantidade, limparCarrinho, isCarrinhoAberto, setIsCarrinhoAberto, }; return ( {children} ); };