// Configurações - CATÁLOGO LABERI KIDS const CONFIG = { SUPABASE_URL: 'https://ydhzylfnpqlxnzfcclla.supabase.co', SUPABASE_ANON_KEY: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InlkaHp5bGZucHFseG56ZmNjbGxhIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NjA1NDA1NjIsImV4cCI6MjA3NjExNjU2Mn0.gIHxyAYngqkJ8z2Gt5ESYmG605vhY_LGTQB7Cjp4ZTA', WHATSAPP_NUMBER: '5543999762754', VENDEDORA_NOME: 'Maiara' }; // Estado global let produtos = []; let carrinho = []; let filtros = { tamanho: '', genero: '', destaque: '' }; let supabaseClient = null; let currentUser = null; let catalogoConfig = { catalogoAtivo: false, exibirPrecos: true, exibirEstoque: false, exibirNovidades: true, exibirPromocoes: true }; const atualizarViewportCSSVar = (() => { let rafId = null; const setVar = () => { rafId = null; const viewport = window.visualViewport; const height = viewport && viewport.height ? viewport.height : window.innerHeight; if (!height) { return; } document.documentElement.style.setProperty('--visual-vh', `${height}px`); }; const schedule = () => { if (rafId !== null) { return; } rafId = window.requestAnimationFrame(setVar); }; return { update: schedule, immediate: () => { if (rafId !== null) { cancelAnimationFrame(rafId); rafId = null; } setVar(); } }; })(); atualizarViewportCSSVar.immediate(); window.addEventListener('resize', atualizarViewportCSSVar.update); window.addEventListener('orientationchange', atualizarViewportCSSVar.update); if (window.visualViewport) { window.visualViewport.addEventListener('resize', atualizarViewportCSSVar.update); window.visualViewport.addEventListener('scroll', atualizarViewportCSSVar.update); } // Inicialização document.addEventListener('DOMContentLoaded', async function() { atualizarViewportCSSVar.immediate(); inicializarSupabase(); inicializarEventListeners(); inicializarImageViewer(); carregarCarrinho(); atualizarContadorCarrinho(); await carregarConfiguracoesCatalogo(); await carregarProdutos(); await verificarAutenticacao(); }); // Carregar carrinho do localStorage function carregarCarrinho() { const carrinhoSalvo = localStorage.getItem('liberi_carrinho'); if (carrinhoSalvo) { try { carrinho = JSON.parse(carrinhoSalvo); } catch (error) { console.error('Erro ao carregar carrinho:', error); carrinho = []; } } } function criarDataLocal(date) { if (!date) return new Date(); if (date instanceof Date) { return new Date(date.getFullYear(), date.getMonth(), date.getDate()); } if (typeof date === 'string') { const partes = date.split('-'); if (partes.length === 3) { const [ano, mes, dia] = partes.map((parte) => parseInt(parte, 10)); if (!Number.isNaN(ano) && !Number.isNaN(mes) && !Number.isNaN(dia)) { return new Date(ano, mes - 1, dia); } } } const data = new Date(date); if (Number.isNaN(data.getTime())) { return new Date(); } return new Date(data.getFullYear(), data.getMonth(), data.getDate()); } function formatarDataInput(date) { if (!date) return ''; const data = criarDataLocal(date); const ano = data.getFullYear(); const mes = String(data.getMonth() + 1).padStart(2, '0'); const dia = String(data.getDate()).padStart(2, '0'); return `${ano}-${mes}-${dia}`; } function obterHojeISO() { return formatarDataInput(new Date()); } function adicionarDias(dataBase, dias) { const data = criarDataLocal(dataBase || new Date()); data.setDate(data.getDate() + dias); return formatarDataInput(data); } function formatarMoedaBR(valor) { const numero = Number(valor) || 0; return numero.toLocaleString('pt-BR', { style: 'currency', currency: 'BRL' }); } function formatarDataHumanaBR(date) { const data = criarDataLocal(date); const dia = String(data.getDate()).padStart(2, '0'); const mes = String(data.getMonth() + 1).padStart(2, '0'); const ano = data.getFullYear(); return `${dia}/${mes}/${ano}`; } function gerarIdVendaCatalogo() { const agora = new Date(); const ano = agora.getFullYear(); const mes = String(agora.getMonth() + 1).padStart(2, '0'); const dia = String(agora.getDate()).padStart(2, '0'); const hora = String(agora.getHours()).padStart(2, '0'); const minuto = String(agora.getMinutes()).padStart(2, '0'); const segundo = String(agora.getSeconds()).padStart(2, '0'); return `VDWEB${ano}${mes}${dia}${hora}${minuto}${segundo}`; } // Funções relacionadas a pagamentos foram removidas — o pedido apenas envia mensagem à vendedora. // Inicializar Supabase function inicializarSupabase() { if (!CONFIG.SUPABASE_URL || !CONFIG.SUPABASE_ANON_KEY) { console.error('Configurações do Supabase não encontradas'); return; } if (!window.supabase) { console.error('Biblioteca do Supabase não encontrada'); return; } try { supabaseClient = window.supabase.createClient(CONFIG.SUPABASE_URL, CONFIG.SUPABASE_ANON_KEY); console.log('Supabase inicializado com sucesso'); } catch (error) { console.error('Erro ao inicializar Supabase:', error); } } // Carregar configurações do catálogo async function carregarConfiguracoesCatalogo() { try { if (!supabaseClient) return; const { data, error } = await supabaseClient .from('configuracoes') .select('valor') .eq('chave', 'catalogo_config') .single(); if (!error && data && data.valor) { catalogoConfig = { ...catalogoConfig, ...data.valor }; console.log('Configurações do catálogo carregadas:', catalogoConfig); // Aplicar configurações visuais if (!catalogoConfig.exibirPrecos) { document.body.classList.add('hide-prices'); } } } catch (error) { console.error('Erro ao carregar configurações do catálogo:', error); } } // Event Listeners function inicializarEventListeners() { const filterPanel = document.getElementById('filterPanel'); if (filterPanel) { filterPanel.addEventListener('click', handleFilterChipClick); } } function inicializarImageViewer() { const viewer = document.getElementById('produtoImageViewer'); const viewerImg = document.getElementById('produtoImageViewerImg'); if (!viewer) { return; } viewer.addEventListener('click', event => { if (event.target === viewer) { fecharImagemExpandida(); } }); if (viewerImg) { viewerImg.addEventListener('click', event => { event.stopPropagation(); }); } // Navegação por teclado document.addEventListener('keydown', event => { if (!viewer.classList.contains('active')) return; if (event.key === 'Escape') { fecharImagemExpandida(); } else if (event.key === 'ArrowLeft') { navegarImagemViewer(-1); } else if (event.key === 'ArrowRight') { navegarImagemViewer(1); } }); } function atualizarEstadoFiltro() { const filterBtn = document.querySelector('.filter-btn'); if (!filterBtn) return; const algumFiltroAtivo = Boolean(filtros.tamanho || filtros.genero || filtros.destaque); filterBtn.classList.toggle('has-filter', algumFiltroAtivo); } function escapeHtmlAttr(value = '') { return value .toString() .replace(/&/g, '&') .replace(/"/g, '"') .replace(/'/g, ''') .replace(//g, '>'); } // Carregar produtos async function carregarProdutos() { const loading = document.getElementById('loading'); const grid = document.getElementById('produtosGrid'); const noProducts = document.getElementById('noProducts'); try { mostrarLoading(true); if (supabaseClient) { const { data, error } = await supabaseClient .from('produtos') .select(` *, produto_variacoes ( id, tamanho, cor, quantidade, fotos ) `) .eq('ativo', true) .eq('visivel_catalogo', true) .order('created_at', { ascending: false }); if (error) throw error; // Carregar fotos adicionais do bucket 'catalogo' para cada produto const produtosComFotos = await Promise.all((data || []).map(async (produto) => { try { const { data: fotosAdicionais } = await supabaseClient .storage .from('catalogo') .list(`produto_${produto.id}`, { limit: 10, sortBy: { column: 'name', order: 'asc' } }); if (fotosAdicionais && fotosAdicionais.length > 0) { produto.fotosAdicionais = fotosAdicionais.map(foto => { const { data: urlData } = supabaseClient .storage .from('catalogo') .getPublicUrl(`produto_${produto.id}/${foto.name}`); return urlData.publicUrl; }); } else { produto.fotosAdicionais = []; } } catch (err) { console.log('Sem fotos adicionais para produto', produto.id); produto.fotosAdicionais = []; } return produto; })); produtos = mapearProdutos(produtosComFotos); } if (!produtos.length) { noProducts.style.display = 'block'; grid.innerHTML = ''; } else { noProducts.style.display = 'none'; popularFiltros(); renderizarProdutos(); } } catch (error) { console.error('Erro ao carregar produtos:', error); mostrarPopup('Erro ao carregar produtos: ' + error.message, 'error'); } finally { mostrarLoading(false); } } // Mapear produtos do Supabase function mapearProdutos(produtosData) { return (produtosData || []).map(produto => { const variacoes = (produto.produto_variacoes || []).map(variacao => ({ ...variacao, quantidade: Number(variacao.quantidade || 0), tamanhoNormalizado: (variacao.tamanho || '').toString().toLowerCase() })); const generoLabel = (produto.genero || '').trim(); // Construir galeria de fotos: foto principal + fotos das variações + fotos adicionais const fotosDasVariacoes = variacoes.flatMap(v => v.fotos || []).filter(Boolean); const fotosAdicionais = produto.fotosAdicionais || []; const todasFotos = [ produto.foto_principal, ...fotosDasVariacoes, ...fotosAdicionais ].filter(Boolean); // Remover duplicatas const galeriaFotos = [...new Set(todasFotos)]; return { id: produto.id?.toString() ?? '', id_produto: produto.id_produto || '', codigo: produto.id_produto || '', nome: produto.nome, marca: produto.marca, genero: generoLabel, generoFiltro: generoLabel.toLowerCase(), estacao: produto.estacao, descricao: produto.descricao, preco_venda: Number(produto.valor_revenda ?? produto.valor_compra ?? 0), preco_promocional: produto.preco_promocional ? Number(produto.preco_promocional) : null, em_promocao: produto.em_promocao || false, novidade: produto.novidade || false, variacoes, imagemPrincipal: galeriaFotos[0] || null, galeriaFotos: galeriaFotos, ativo: produto.ativo, visivelCatalogo: produto.visivel_catalogo }; }); } // Renderizar produtos function renderizarProdutos() { const container = document.getElementById('produtosGrid'); if (!container) return; const produtosFiltrados = obterProdutosFiltrados(); const noProducts = document.getElementById('noProducts'); if (!produtosFiltrados.length) { container.innerHTML = ''; if (noProducts) noProducts.style.display = 'block'; return; } if (noProducts) noProducts.style.display = 'none'; container.innerHTML = produtosFiltrados.map(produto => { const variacoesDisponiveis = produto.variacoes || []; const tamanhosDisponiveis = [...new Set(variacoesDisponiveis.map(v => v.tamanho).filter(Boolean))] .sort((a, b) => a.toString().localeCompare(b.toString(), 'pt-BR', { numeric: true, sensitivity: 'base' })); const temEstoque = variacoesDisponiveis.some(v => v.quantidade > 0); // Preços const precoNormal = produto.preco_venda; const precoPromo = produto.preco_promocional; const emPromocao = produto.em_promocao && precoPromo && precoPromo > 0; const precoExibir = emPromocao ? precoPromo : precoNormal; const precoFormatado = `R$ ${precoExibir.toFixed(2).replace('.', ',')}`; const precoNormalFormatado = `R$ ${precoNormal.toFixed(2).replace('.', ',')}`; const tamanhosVisiveis = tamanhosDisponiveis.slice(0, 4); const possuiMaisTamanhos = tamanhosDisponiveis.length > tamanhosVisiveis.length; // Badges const exibirNovidades = catalogoConfig.exibirNovidades !== false; const exibirPromocoes = catalogoConfig.exibirPromocoes !== false; const mostrarBadgeNovidade = produto.novidade && exibirNovidades; const mostrarBadgePromocao = emPromocao && exibirPromocoes; return `
${produto.imagemPrincipal ? `${produto.nome}` : `
` } ${(mostrarBadgePromocao || mostrarBadgeNovidade || !temEstoque) ? `
${!temEstoque ? 'ESGOTADO' : ''} ${mostrarBadgePromocao ? '🏷️ PROMOÇÃO' : ''} ${mostrarBadgeNovidade ? '✨ NOVO' : ''}
` : ''}
${produto.nome}
${emPromocao ? `${precoNormalFormatado}` : ''} ${precoFormatado}
${tamanhosDisponiveis.length ? tamanhosVisiveis.map(tamanho => `${tamanho}`).join('') : 'Único'} ${possuiMaisTamanhos ? '+' : ''}
`; }).join(''); } function obterProdutosFiltrados() { const generoFiltro = filtros.genero; const tamanhoFiltro = filtros.tamanho; const destaqueFiltro = filtros.destaque; return produtos.filter(produto => { const generoConfere = !generoFiltro || produto.generoFiltro === generoFiltro; const tamanhoConfere = !tamanhoFiltro || produto.variacoes.some(variacao => { return (variacao.tamanhoNormalizado || (variacao.tamanho || '').toString().toLowerCase()) === tamanhoFiltro; }); let destaqueConfere = true; if (destaqueFiltro === 'promocao') { destaqueConfere = produto.em_promocao && produto.preco_promocional > 0; } else if (destaqueFiltro === 'novo') { destaqueConfere = produto.novidade; } return generoConfere && tamanhoConfere && destaqueConfere; }); } // Função de extração de cor desativada (não utilizada no layout atual) // function extrairCorDominante(img) { ... } // Verificar autenticação com localStorage async function verificarAutenticacao() { try { // Verificar se há dados salvos no localStorage const savedUser = localStorage.getItem('liberi_user'); if (savedUser) { const userData = JSON.parse(savedUser); // Verificar se o cliente ainda existe no banco const { data: cliente, error } = await supabaseClient .from('clientes') .select('*') .eq('id', userData.cliente.id) .single(); if (!error && cliente) { currentUser = { cliente }; atualizarInterfaceUsuario(true); console.log('✅ Login restaurado:', cliente.nome_completo); return true; } else { // Cliente não existe mais, limpar localStorage localStorage.removeItem('liberi_user'); } } // Não há login salvo ou cliente não existe currentUser = null; atualizarInterfaceUsuario(false); return false; } catch (error) { console.error('Erro ao verificar autenticação:', error); localStorage.removeItem('liberi_user'); currentUser = null; atualizarInterfaceUsuario(false); return false; } } // Atualizar interface do usuário function atualizarInterfaceUsuario(isLoggedIn) { const userNotLogged = document.getElementById('userNotLogged'); const userLogged = document.getElementById('userLogged'); const userName = document.getElementById('userName'); if (isLoggedIn && currentUser?.cliente) { userNotLogged.style.display = 'none'; userLogged.style.display = 'flex'; userName.textContent = currentUser.cliente.nome_completo.split(' ')[0]; } else { userNotLogged.style.display = 'block'; userLogged.style.display = 'none'; } } // Função de login async function handleLogin(event) { event.preventDefault(); const phone = document.getElementById('loginPhone').value.trim(); const password = document.getElementById('loginPassword').value.trim(); const loginBtn = document.getElementById('loginBtn'); if (!phone || !password) { mostrarPopup('Por favor, digite seu WhatsApp e senha', 'error'); return; } const cleanPhone = phone.replace(/\D/g, ''); loginBtn.innerHTML = ' Entrando...'; loginBtn.disabled = true; try { // Buscar cliente na tabela const { data: cliente, error: clienteError } = await supabaseClient .from('clientes') .select('*') .eq('whatsapp', cleanPhone) .single(); if (clienteError || !cliente) { throw new Error('Cliente não encontrado. Verifique seu número ou cadastre-se.'); } // Verificar senha diretamente (sem Supabase Auth) if (cliente.senha_hash !== password) { throw new Error('Senha incorreta. Tente novamente.'); } // Login bem-sucedido currentUser = { cliente }; // Salvar no localStorage para manter login localStorage.setItem('liberi_user', JSON.stringify(currentUser)); // Mostrar popup de confirmação mostrarConfirmacao( 'Login realizado!', `Bem-vindo(a) de volta, ${cliente.nome_completo.split(' ')[0]}!`, () => { closeLoginModal(); atualizarInterfaceUsuario(true); } ); } catch (error) { console.error('Erro no login:', error); mostrarPopup(error.message, 'error'); } finally { loginBtn.innerHTML = ' Entrar'; loginBtn.disabled = false; } } // Função de cadastro async function handleRegister(event) { event.preventDefault(); const formData = { nome_completo: document.getElementById('registerName').value.trim(), email: document.getElementById('registerEmail').value.trim() || null, whatsapp: document.getElementById('registerWhatsapp').value.replace(/\D/g, ''), endereco: document.getElementById('registerAddress').value.trim(), senha: document.getElementById('registerPassword').value.trim() }; const registerBtn = document.getElementById('registerBtn'); if (!formData.nome_completo || !formData.whatsapp || !formData.endereco || !formData.senha) { mostrarPopup('Preencha todos os campos obrigatórios', 'error'); return; } if (formData.senha.length < 6) { mostrarPopup('A senha deve ter pelo menos 6 caracteres', 'error'); return; } registerBtn.innerHTML = ' Criando conta...'; registerBtn.disabled = true; try { const { data: existingClient, error: checkError } = await supabaseClient .from('clientes') .select('id') .eq('whatsapp', formData.whatsapp) .single(); if (existingClient) { throw new Error('Este WhatsApp já está cadastrado. Faça login.'); } // Inserir cliente com senha diretamente na tabela const { data: cliente, error: clienteError } = await supabaseClient .from('clientes') .insert([{ nome_completo: formData.nome_completo, email: formData.email, whatsapp: formData.whatsapp, endereco: formData.endereco, senha_hash: formData.senha }]) .select() .single(); if (clienteError) throw clienteError; // Login automático após cadastro currentUser = { cliente }; // Salvar no localStorage para manter login localStorage.setItem('liberi_user', JSON.stringify(currentUser)); // Mostrar popup de confirmação mostrarConfirmacao( 'Conta criada com sucesso!', `Bem-vindo(a), ${formData.nome_completo.split(' ')[0]}! Sua conta foi criada e você já está logado(a).`, () => { closeRegisterModal(); atualizarInterfaceUsuario(true); } ); } catch (error) { console.error('Erro no cadastro:', error); mostrarPopup(error.message, 'error'); } finally { registerBtn.innerHTML = ' Criar Conta'; registerBtn.disabled = false; } } // Funções dos modais de autenticação com animação function ativarAuthModal(modal) { if (!modal) return; modal.classList.add('pre-active'); requestAnimationFrame(() => { modal.classList.remove('pre-active'); modal.classList.add('active'); }); } function desativarAuthModal(modal) { if (!modal) return; if (!modal.classList.contains('active')) { modal.classList.remove('pre-active'); return; } const finalizar = (event) => { if (event.target !== modal) { return; } modal.removeEventListener('transitionend', finalizar); modal.classList.remove('pre-active'); }; modal.addEventListener('transitionend', finalizar); modal.classList.remove('active'); } function showRegisterModal() { const loginModal = document.getElementById('loginModal'); const registerModal = document.getElementById('registerModal'); if (loginModal) { desativarAuthModal(loginModal); } if (registerModal) { ativarAuthModal(registerModal); } } function closeRegisterModal() { desativarAuthModal(document.getElementById('registerModal')); } function closeLoginModal() { desativarAuthModal(document.getElementById('loginModal')); } // Funções auxiliares function mostrarLoading(show) { const loading = document.getElementById('loading'); const grid = document.getElementById('produtosGrid'); if (loading) loading.style.display = show ? 'block' : 'none'; if (grid) grid.style.display = show ? 'none' : 'grid'; } function atualizarContadorCarrinho() { const cartCount = document.querySelector('.cart-count'); if (cartCount) { const totalItens = carrinho.reduce((sum, item) => sum + item.quantidade, 0); cartCount.textContent = totalItens; } } function popularFiltros() { const tamanhoContainer = document.getElementById('tamanhoFilterChips'); const generoContainer = document.getElementById('generoFilterChips'); if (!tamanhoContainer || !generoContainer) return; const tamanhos = new Set(); const generos = new Set(); produtos.forEach(produto => { (produto.variacoes || []).forEach(variacao => { if (variacao.tamanho) { tamanhos.add(variacao.tamanho.toString()); } }); if (produto.genero) { generos.add(produto.genero); } }); const ordenar = (a, b) => a.toString().localeCompare(b.toString(), 'pt-BR', { numeric: true, sensitivity: 'base' }); const tamanhosOrdenados = Array.from(tamanhos).sort(ordenar); const generosOrdenados = Array.from(generos).sort(ordenar); const construirChips = (valores, tipo) => { const ativo = filtros[tipo] || ''; const itens = [''].concat(valores); return itens.map(valor => { const normalizado = valor ? valor.toString().toLowerCase() : ''; const label = valor || 'Todos'; const ativoChip = normalizado === ativo; return ``; }).join(''); }; tamanhoContainer.innerHTML = construirChips(tamanhosOrdenados, 'tamanho'); generoContainer.innerHTML = construirChips(generosOrdenados, 'genero'); // Atualizar filtros de destaque (Promoção e Novo) const destaquesContainer = document.getElementById('destaquesFilterChips'); if (destaquesContainer) { const destaqueAtivo = filtros.destaque || ''; destaquesContainer.querySelectorAll('.filter-chip').forEach(chip => { const valorChip = (chip.dataset.value || '').toLowerCase(); if (valorChip === destaqueAtivo) { chip.classList.add('active'); } else { chip.classList.remove('active'); } }); } atualizarEstadoFiltro(); } function handleFilterChipClick(event) { const chip = event.target.closest('.filter-chip'); if (!chip) return; const tipo = chip.dataset.filter; if (!tipo) return; const valorOriginal = (chip.dataset.value || '').toString(); const valorNormalizado = valorOriginal.toLowerCase(); if (filtros[tipo] === valorNormalizado) { filtros[tipo] = ''; } else { filtros[tipo] = valorNormalizado; } popularFiltros(); renderizarProdutos(); } // Estado do modal let produtoSelecionado = null; let variacaoSelecionada = null; function abrirProdutoModal(produtoId) { const produto = produtos.find(p => p.id === produtoId); if (!produto) return; produtoSelecionado = produto; variacaoSelecionada = null; const modal = document.getElementById('produtoModal'); const modalImage = document.getElementById('produtoModalImage'); const modalNome = document.getElementById('produtoModalNome'); const modalMarca = document.getElementById('produtoModalMarca'); const modalPreco = document.getElementById('produtoModalPreco'); const modalDescricao = document.getElementById('produtoModalDescricao'); const modalVariacoesGrid = document.getElementById('produtoModalVariacoesGrid'); const modalBotao = document.getElementById('produtoModalBotao'); // Preencher informações básicas modalNome.textContent = produto.nome; modalMarca.textContent = produto.marca; // Preço (considerar promoção) const precoNormal = produto.preco_venda; const precoPromo = produto.preco_promocional; const emPromocao = produto.em_promocao && precoPromo && precoPromo > 0; const precoExibir = emPromocao ? precoPromo : precoNormal; const precoFormatado = `R$ ${precoExibir.toFixed(2).replace('.', ',')}`; if (emPromocao) { const precoNormalFormatado = `R$ ${precoNormal.toFixed(2).replace('.', ',')}`; modalPreco.innerHTML = ` ${precoNormalFormatado} ${precoFormatado} `; } else { modalPreco.textContent = precoFormatado; } modalDescricao.textContent = produto.descricao || 'Produto de qualidade superior para o conforto e estilo do seu filho.'; // Preencher imagem e galeria const galeriaFotos = produto.galeriaFotos || []; const imagemPrincipal = galeriaFotos[0] || ''; if (imagemPrincipal) { const imagemEscapada = escapeHtmlAttr(imagemPrincipal); const nomeEscapado = escapeHtmlAttr(produto.nome || ''); modalImage.dataset.imageUrl = imagemPrincipal; modalImage.innerHTML = ` ${galeriaFotos.length > 1 ? `
${galeriaFotos.map((foto, index) => ` ${nomeEscapado} - Foto ${index + 1} `).join('')}
` : ''} `; const trigger = modalImage.querySelector('.produto-modal-image-trigger'); if (trigger) { trigger.addEventListener('click', expandirImagemProduto); } } else { modalImage.dataset.imageUrl = ''; modalImage.innerHTML = `
`; } // Preencher variações const variacoesComEstoque = produto.variacoes.filter(v => v.quantidade > 0); if (variacoesComEstoque.length > 0) { modalVariacoesGrid.innerHTML = variacoesComEstoque.map(variacao => `
${variacao.tamanho}
${variacao.cor}
${variacao.quantidade > 0 ? `${variacao.quantidade} disponível${variacao.quantidade > 1 ? 'is' : ''}` : 'Esgotado'}
`).join(''); modalBotao.disabled = true; modalBotao.style.opacity = '0.5'; } else { modalVariacoesGrid.innerHTML = '

Produto esgotado

'; modalBotao.disabled = true; modalBotao.style.opacity = '0.5'; } // Exibir modal if (!modal.classList.contains('active')) { modal.classList.add('pre-active'); requestAnimationFrame(() => { modal.classList.remove('pre-active'); modal.classList.add('active'); }); } } function trocarImagemModal(novaUrl, elemento) { const imagemPrincipal = document.getElementById('modalImagemPrincipal'); const modalImage = document.getElementById('produtoModalImage'); if (imagemPrincipal) { imagemPrincipal.src = novaUrl; modalImage.dataset.imageUrl = novaUrl; } // Atualizar classe active nas miniaturas const miniaturas = document.querySelectorAll('.galeria-miniatura'); miniaturas.forEach(min => min.classList.remove('active')); if (elemento) { elemento.classList.add('active'); } } function fecharProdutoModal(event) { if (event) { event.preventDefault(); event.stopPropagation(); } const modal = document.getElementById('produtoModal'); if (modal) { modal.classList.remove('active'); const remover = () => { modal.removeEventListener('transitionend', remover); if (!modal.classList.contains('active')) { modal.style.display = 'none'; void modal.offsetWidth; modal.style.display = ''; } }; modal.addEventListener('transitionend', remover); } fecharImagemExpandida(); produtoSelecionado = null; variacaoSelecionada = null; } function selecionarVariacao(variacaoId) { if (!produtoSelecionado) return; const variacao = produtoSelecionado.variacoes.find(v => v.id.toString() === variacaoId.toString()); if (!variacao || variacao.quantidade === 0) return; // Remover seleção anterior document.querySelectorAll('.variacao-item').forEach(item => { item.classList.remove('selected'); }); // Adicionar seleção atual const item = document.querySelector(`[data-variacao-id="${variacaoId}"]`); if (item) { item.classList.add('selected'); variacaoSelecionada = variacao; const modalImage = document.getElementById('produtoModalImage'); if (modalImage) { const fallbackImagem = produtoSelecionado.imagemPrincipal || (produtoSelecionado.variacoes || []).find(v => Array.isArray(v.fotos) && v.fotos.length)?.fotos?.[0] || ''; const novaImagem = (variacao.fotos && variacao.fotos.length > 0) ? variacao.fotos[0] : fallbackImagem; if (novaImagem) { let trigger = modalImage.querySelector('.produto-modal-image-trigger'); if (!trigger) { const imagemEscapada = escapeHtmlAttr(novaImagem); const nomeEscapado = escapeHtmlAttr(produtoSelecionado.nome || ''); modalImage.innerHTML = ` `; trigger = modalImage.querySelector('.produto-modal-image-trigger'); if (trigger) { trigger.addEventListener('click', expandirImagemProduto); } } const imgElement = modalImage.querySelector('img'); if (imgElement) { modalImage.dataset.imageUrl = novaImagem; imgElement.src = novaImagem; const descricaoImagem = `${produtoSelecionado.nome || ''} - ${variacao.tamanho || ''} ${variacao.cor || ''}`.trim(); if (descricaoImagem) { imgElement.alt = descricaoImagem; } } } else { modalImage.dataset.imageUrl = ''; } } // Habilitar botão const modalBotao = document.getElementById('produtoModalBotao'); modalBotao.disabled = false; modalBotao.style.opacity = '1'; } } let currentImageIndex = 0; let viewerImages = []; function expandirImagemProduto(event) { if (event) { event.preventDefault(); event.stopPropagation(); } const viewer = document.getElementById('produtoImageViewer'); const viewerImg = document.getElementById('produtoImageViewerImg'); const modalImage = document.getElementById('produtoModalImage'); if (!viewer || !viewerImg || !modalImage) { return; } const imageUrl = modalImage.dataset.imageUrl; if (!imageUrl) { return; } // Obter galeria de fotos do produto if (produtoSelecionado && produtoSelecionado.galeriaFotos) { viewerImages = produtoSelecionado.galeriaFotos; currentImageIndex = viewerImages.indexOf(imageUrl); if (currentImageIndex === -1) currentImageIndex = 0; } else { viewerImages = [imageUrl]; currentImageIndex = 0; } viewerImg.src = imageUrl; viewer.classList.add('active'); // Mostrar/ocultar controles de navegação const prevBtn = viewer.querySelector('.viewer-prev'); const nextBtn = viewer.querySelector('.viewer-next'); const counter = viewer.querySelector('.viewer-counter'); if (viewerImages.length > 1) { if (prevBtn) prevBtn.style.display = 'flex'; if (nextBtn) nextBtn.style.display = 'flex'; if (counter) { counter.style.display = 'block'; counter.textContent = `${currentImageIndex + 1} / ${viewerImages.length}`; } } else { if (prevBtn) prevBtn.style.display = 'none'; if (nextBtn) nextBtn.style.display = 'none'; if (counter) counter.style.display = 'none'; } } function navegarImagemViewer(direction) { if (viewerImages.length <= 1) return; currentImageIndex += direction; // Loop circular if (currentImageIndex < 0) { currentImageIndex = viewerImages.length - 1; } else if (currentImageIndex >= viewerImages.length) { currentImageIndex = 0; } const viewerImg = document.getElementById('produtoImageViewerImg'); const counter = document.querySelector('.viewer-counter'); if (viewerImg) { viewerImg.src = viewerImages[currentImageIndex]; } if (counter) { counter.textContent = `${currentImageIndex + 1} / ${viewerImages.length}`; } } function fecharImagemExpandida() { const viewer = document.getElementById('produtoImageViewer'); const viewerImg = document.getElementById('produtoImageViewerImg'); if (!viewer || !viewerImg) { return; } viewer.classList.remove('active'); viewerImg.src = ''; viewerImages = []; currentImageIndex = 0; } function adicionarAoCarrinhoModal() { if (!produtoSelecionado || !variacaoSelecionada) { mostrarPopup('Selecione um tamanho e cor antes de adicionar ao carrinho', 'error'); return; } // Verificar se já existe no carrinho const itemExistente = carrinho.find(item => item.produtoId === produtoSelecionado.id && item.variacaoId === variacaoSelecionada.id ); if (itemExistente) { // Verificar se há estoque disponível if (itemExistente.quantidade < variacaoSelecionada.quantidade) { itemExistente.quantidade++; } else { mostrarPopup('Quantidade máxima em estoque já adicionada', 'error'); return; } } else { // Adicionar novo item carrinho.push({ produtoId: produtoSelecionado.id, variacaoId: variacaoSelecionada.id, codigo: produtoSelecionado.codigo || produtoSelecionado.id_produto || '', nome: `${produtoSelecionado.marca} ${produtoSelecionado.nome}`, tamanho: variacaoSelecionada.tamanho, cor: variacaoSelecionada.cor, preco: produtoSelecionado.preco_venda, quantidade: 1, imagem: produtoSelecionado.imagemPrincipal }); } // Salvar carrinho no localStorage localStorage.setItem('liberi_carrinho', JSON.stringify(carrinho)); // Atualizar interface atualizarContadorCarrinho(); renderizarCarrinho(); // Fechar modal e mostrar confirmação fecharProdutoModal(); mostrarPopup('Produto adicionado ao carrinho!', 'success'); } function toggleFilterPanel() { const panel = document.getElementById('filterPanel'); const filterBtn = document.querySelector('.filter-btn'); if (panel) { const isOpen = panel.classList.toggle('open'); if (filterBtn) { filterBtn.classList.toggle('active', isOpen); } if (isOpen) { window.scrollTo({ top: 0, behavior: 'smooth' }); } } } function toggleCart() { const cartModal = document.getElementById('cartModal'); if (cartModal) { const isOpen = cartModal.classList.contains('active'); if (isOpen) { desativarAuthModal(cartModal); } else { renderizarCarrinho(); ativarAuthModal(cartModal); } } } function renderizarCarrinho() { const cartContent = document.getElementById('cartContent'); const cartFooter = document.getElementById('cartFooter'); const cartTotal = document.getElementById('cartTotal'); if (carrinho.length === 0) { cartContent.innerHTML = `

Seu carrinho está vazio

Adicione produtos para começar!
`; cartFooter.style.display = 'none'; if (cartTotal) { cartTotal.textContent = '0,00'; } return; } let total = 0; cartContent.innerHTML = carrinho.map((item, index) => { const subtotal = item.preco * item.quantidade; total += subtotal; return `
${item.imagem ? `${item.nome}` : `` }

${item.nome}

${item.tamanho} - ${item.cor}

R$ ${item.preco.toFixed(2).replace('.', ',')}
${item.quantidade}
`; }).join(''); if (cartTotal) { cartTotal.textContent = total.toFixed(2).replace('.', ','); } cartFooter.style.display = 'flex'; } function alterarQuantidade(index, delta) { if (index < 0 || index >= carrinho.length) return; const item = carrinho[index]; const produto = produtos.find(p => p.id === item.produtoId); const variacao = produto?.variacoes.find(v => v.id === item.variacaoId); const novaQuantidade = item.quantidade + delta; if (novaQuantidade <= 0) { removerDoCarrinho(index); return; } if (variacao && novaQuantidade > variacao.quantidade) { mostrarPopup('Quantidade máxima em estoque atingida', 'error'); return; } item.quantidade = novaQuantidade; localStorage.setItem('liberi_carrinho', JSON.stringify(carrinho)); atualizarContadorCarrinho(); renderizarCarrinho(); } function removerDoCarrinho(index) { if (index < 0 || index >= carrinho.length) return; carrinho.splice(index, 1); localStorage.setItem('liberi_carrinho', JSON.stringify(carrinho)); atualizarContadorCarrinho(); renderizarCarrinho(); if (carrinho.length === 0) { toggleCart(); } } async function finalizarPedido() { if (!currentUser) { toggleCart(); mostrarPopup('Faça login para finalizar seu pedido', 'error'); setTimeout(() => showLoginModal(), 500); return; } if (carrinho.length === 0) { mostrarPopup('Adicione produtos ao carrinho antes de finalizar', 'error'); return; } const checkoutBtn = document.querySelector('.checkout-btn'); const btnOriginalHTML = checkoutBtn ? checkoutBtn.innerHTML : null; if (checkoutBtn) { checkoutBtn.disabled = true; checkoutBtn.innerHTML = ' Enviando...'; } const cliente = currentUser.cliente; const totalPedido = carrinho.reduce((sum, item) => sum + (item.preco * item.quantidade), 0); let mensagem = `*Novo Pedido - Liberi Kids*\n\n`; mensagem += `*Cliente:* ${cliente.nome_completo}\n`; mensagem += `*WhatsApp:* ${cliente.whatsapp}\n`; if (cliente.endereco) { mensagem += `*Endereço:* ${cliente.endereco}\n`; } mensagem += `\n*Itens do Pedido:*\n`; carrinho.forEach((item, index) => { const subtotal = item.preco * item.quantidade; const codigoItem = item.codigo || item.produtoId || 'N/A'; mensagem += `\n${index + 1}. ${item.nome}\n`; mensagem += ` ID: ${codigoItem}\n`; mensagem += ` Tamanho: ${item.tamanho} | Cor: ${item.cor}\n`; mensagem += ` Qtd: ${item.quantidade} x ${formatarMoedaBR(item.preco)} = ${formatarMoedaBR(subtotal)}\n`; }); mensagem += `\n*Total:* ${formatarMoedaBR(totalPedido)}\n`; mensagem += `\nPor favor, confirme o pagamento com a vendedora. Obrigado!`; const pedidoPayload = { cliente: { nome: cliente.nome_completo, whatsapp: cliente.whatsapp, endereco: cliente.endereco || null }, itens: carrinho.map((item) => ({ nome: item.nome, codigo: item.codigo || item.produtoId || null, tamanho: item.tamanho, cor: item.cor, quantidade: item.quantidade, preco: Number(item.preco) || 0, subtotal: Number((item.preco * item.quantidade).toFixed(2)) })), total: totalPedido, mensagem }; try { const response = await fetch('/api/catalogo/pedidos', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(pedidoPayload) }); if (!response.ok) { const erroServidor = await response.json().catch(() => ({})); throw new Error(erroServidor.error || 'Não foi possível registrar o pedido no sistema.'); } } catch (error) { console.error('Erro ao salvar pedido do catálogo:', error); mostrarPopup('Pedido enviado para a vendedora, mas não foi possível registrar na plataforma. ' + (error.message || ''), 'error'); } const mensagemCodificada = encodeURIComponent(mensagem); const whatsappUrl = `https://wa.me/${CONFIG.WHATSAPP_NUMBER}?text=${mensagemCodificada}`; window.open(whatsappUrl, '_blank'); mostrarConfirmacao( 'Pedido enviado!', 'A vendedora receberá os detalhes do pedido e entrará em contato com você pelo WhatsApp.', () => { carrinho = []; localStorage.setItem('liberi_carrinho', JSON.stringify(carrinho)); atualizarContadorCarrinho(); renderizarCarrinho(); toggleCart(); } ); if (checkoutBtn) { checkoutBtn.disabled = false; checkoutBtn.innerHTML = btnOriginalHTML || ' Finalizar Pedido'; } } function abrirWhatsApp() { const whatsappUrl = `https://wa.me/${CONFIG.WHATSAPP_NUMBER}?text=Olá! Gostaria de saber mais sobre os produtos da Laberi Kids.`; window.open(whatsappUrl, '_blank'); } // ======================================== // SISTEMA DE POPUPS E NOTIFICAÇÕES // ======================================== // Função para mostrar popup de erro/sucesso function mostrarPopup(mensagem, tipo = 'info', callback = null) { // Remover popup existente se houver const existingPopup = document.querySelector('.custom-popup'); if (existingPopup) { existingPopup.remove(); } // Criar popup const popup = document.createElement('div'); popup.className = `custom-popup ${tipo}`; const icon = tipo === 'error' ? 'fas fa-exclamation-circle' : tipo === 'success' ? 'fas fa-check-circle' : 'fas fa-info-circle'; popup.innerHTML = `
`; document.body.appendChild(popup); // Animar entrada setTimeout(() => popup.classList.add('show'), 10); // Callback se fornecido if (callback) { popup.setAttribute('data-callback', 'true'); popup.callback = callback; } } // Função para fechar popup function fecharPopup(btn) { const popup = btn.closest('.custom-popup'); if (popup) { popup.classList.remove('show'); setTimeout(() => { if (popup.callback) { popup.callback(); } popup.remove(); }, 300); } } // Função para mostrar confirmação function mostrarConfirmacao(titulo, mensagem, callback = null) { mostrarPopup(`${titulo}
${mensagem}`, 'success', callback); } // Melhorar função de login para verificar se já está logado function showLoginModal() { // Se já estiver logado, mostrar status if (currentUser) { const nomeUsuario = currentUser.cliente.nome_completo.split(' ')[0]; mostrarPopupConfirmacao( 'Você já está logado!', `Olá, ${nomeUsuario}! 👋

Deseja sair da sua conta?`, () => logout() ); return; } // Se não estiver logado, mostrar modal de login const loginModal = document.getElementById('loginModal'); const registerModal = document.getElementById('registerModal'); if (registerModal) { desativarAuthModal(registerModal); } if (loginModal) { ativarAuthModal(loginModal); } } // Função para popup de confirmação com Sim/Não function mostrarPopupConfirmacao(titulo, mensagem, callbackSim = null, callbackNao = null) { // Remover popup existente se houver const existingPopup = document.querySelector('.custom-popup'); if (existingPopup) { existingPopup.remove(); } // Criar popup de confirmação const popup = document.createElement('div'); popup.className = 'custom-popup confirmation'; popup.innerHTML = `
`; document.body.appendChild(popup); // Animar entrada setTimeout(() => popup.classList.add('show'), 10); // Callbacks popup.callbackSim = callbackSim; popup.callbackNao = callbackNao; } // Função para fechar popup de confirmação function fecharPopupConfirmacao(btn, resposta) { const popup = btn.closest('.custom-popup'); if (popup) { popup.classList.remove('show'); setTimeout(() => { if (resposta && popup.callbackSim) { popup.callbackSim(); } else if (!resposta && popup.callbackNao) { popup.callbackNao(); } popup.remove(); }, 300); } } // Função de logout melhorada (substituindo a anterior) function logout() { // Limpar dados locais e localStorage currentUser = null; carrinho = []; localStorage.removeItem('liberi_user'); atualizarInterfaceUsuario(false); atualizarContadorCarrinho(); mostrarPopup('Você saiu da sua conta com sucesso!', 'success'); }