const express = require('express'); const cors = require('cors'); const path = require('path'); const multer = require('multer'); const { createClient } = require('@supabase/supabase-js'); const { v4: uuidv4 } = require('uuid'); require('dotenv').config(); const app = express(); const PORT = process.env.PORT || 5000; app.use(cors()); app.use(express.json()); app.use('/uploads', express.static('uploads')); app.use(express.static(path.join(__dirname, 'client/build'))); // Configuração do Supabase const supabaseUrl = 'https://ydhzylfnpqlxnzfcclla.supabase.co' const supabaseKey = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InlkaHp5bGZucHFseG56ZmNjbGxhIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NjA1NDA1NjIsImV4cCI6MjA3NjExNjU2Mn0.gIHxyAYngqkJ8z2Gt5ESYmG605vhY_LGTQB7Cjp4ZTA' const supabase = createClient(supabaseUrl, supabaseKey) // Configuração do Multer para upload de arquivos const storage = multer.diskStorage({ destination: (req, file, cb) => { cb(null, 'uploads/'); }, filename: (req, file, cb) => { const uniqueName = `${Date.now()}-${uuidv4()}${path.extname(file.originalname)}`; cb(null, uniqueName); } }); const upload = multer({ storage: storage, fileFilter: (req, file, cb) => { if (file.mimetype.startsWith('image/')) { cb(null, true); } else { cb(new Error('Apenas imagens são permitidas!'), false); } }, limits: { fileSize: 5 * 1024 * 1024 } // 5MB }); console.log('🚀 Servidor configurado para usar Supabase!') console.log('📊 Banco de dados:', supabaseUrl) // Rotas da API // === PRODUTOS === app.get('/api/produtos', async (req, res) => { try { const { data: produtos, error } = await supabase .from('produtos') .select(` *, fornecedores(nome), produto_variacoes(id, quantidade) `) .order('created_at', { ascending: false }) if (error) throw error // Calcular estatísticas const produtosComEstatisticas = produtos.map(produto => ({ ...produto, fornecedor_nome: produto.fornecedores?.nome || null, total_variacoes: produto.produto_variacoes?.length || 0, estoque_total: produto.produto_variacoes?.reduce((total, variacao) => total + (variacao.quantidade || 0), 0) || 0 })) res.json(produtosComEstatisticas) } catch (error) { console.error('Erro ao buscar produtos:', error) res.status(500).json({ error: error.message }) } }); app.post('/api/produtos', upload.any(), async (req, res) => { try { console.log('Recebendo requisição para criar produto:', req.body); console.log('Arquivos recebidos:', req.files ? req.files.length : 0); const { id_produto, marca, nome, estacao, genero, fornecedor_id, valor_compra, valor_revenda, variacoes_data } = req.body; // Validações básicas if (!marca || !nome || !estacao || !valor_compra || !valor_revenda) { return res.status(400).json({ error: 'Campos obrigatórios não preenchidos' }); } // Parse das variações let variacoes = []; try { if (variacoes_data) { variacoes = JSON.parse(variacoes_data); } } catch (error) { console.error('Erro ao fazer parse das variações:', error); return res.status(400).json({ error: 'Dados de variações inválidos' }); } if (variacoes.length === 0) { return res.status(400).json({ error: 'Pelo menos uma variação é obrigatória' }); } // Inserir produto no Supabase const { data: produto, error: produtoError } = await supabase .from('produtos') .insert([{ id_produto, marca, nome, estacao, genero: genero || 'Unissex', fornecedor_id: fornecedor_id || null, valor_compra: parseFloat(valor_compra), valor_revenda: parseFloat(valor_revenda) }]) .select() .single() if (produtoError) throw produtoError console.log('Produto inserido com sucesso, processando variações...'); // Inserir variações const variacoesParaInserir = variacoes.map(variacao => ({ produto_id: produto.id, tamanho: variacao.tamanho, cor: variacao.cor, quantidade: parseInt(variacao.quantidade) })) const { error: variacoesError } = await supabase .from('produto_variacoes') .insert(variacoesParaInserir) if (variacoesError) throw variacoesError console.log('Produto criado com sucesso!'); res.json({ id: produto.id, message: 'Produto criado com sucesso!' }); } catch (error) { console.error('Erro ao criar produto:', error); res.status(500).json({ error: error.message }); } }); // === VARIAÇÕES DE PRODUTOS === app.get('/api/produtos/:id/variacoes', async (req, res) => { try { const { id } = req.params; const { data: variacoes, error } = await supabase .from('produto_variacoes') .select('*') .eq('produto_id', id) .order('tamanho') .order('cor') if (error) throw error res.json(variacoes) } catch (error) { console.error('Erro ao buscar variações:', error) res.status(500).json({ error: error.message }) } }); app.post('/api/produtos/:id/variacoes', async (req, res) => { try { const { id } = req.params; const { tamanho, cor, quantidade } = req.body; const { data: variacao, error } = await supabase .from('produto_variacoes') .insert([{ produto_id: id, tamanho, cor, quantidade: parseInt(quantidade) }]) .select() .single() if (error) throw error res.json({ id: variacao.id, message: 'Variação adicionada com sucesso!' }) } catch (error) { console.error('Erro ao criar variação:', error) res.status(500).json({ error: error.message }) } }); // === CLIENTES === app.get('/api/clientes', async (req, res) => { try { const { data: clientes, error } = await supabase .from('clientes') .select('*') .order('nome_completo') if (error) throw error res.json(clientes) } catch (error) { console.error('Erro ao buscar clientes:', error) res.status(500).json({ error: error.message }) } }); app.post('/api/clientes', async (req, res) => { try { const { nome_completo, email, whatsapp, endereco } = req.body; const { data: cliente, error } = await supabase .from('clientes') .insert([{ nome_completo, email: email || null, whatsapp, endereco }]) .select() .single() if (error) throw error res.json({ id: cliente.id, message: 'Cliente cadastrado com sucesso!' }) } catch (error) { console.error('Erro ao criar cliente:', error) res.status(500).json({ error: error.message }) } }); // === FORNECEDORES === app.get('/api/fornecedores', async (req, res) => { try { const { data: fornecedores, error } = await supabase .from('fornecedores') .select('*') .order('nome') if (error) throw error res.json(fornecedores) } catch (error) { console.error('Erro ao buscar fornecedores:', error) res.status(500).json({ error: error.message }) } }); app.post('/api/fornecedores', async (req, res) => { try { const { nome, cnpj, telefone, email, endereco } = req.body; const { data: fornecedor, error } = await supabase .from('fornecedores') .insert([{ nome, cnpj: cnpj || null, telefone: telefone || null, email: email || null, endereco: endereco || null }]) .select() .single() if (error) throw error res.json({ id: fornecedor.id, message: 'Fornecedor cadastrado com sucesso!' }) } catch (error) { console.error('Erro ao criar fornecedor:', error) res.status(500).json({ error: error.message }) } }); // === TIPOS DE DESPESAS === app.get('/api/tipos-despesas', async (req, res) => { try { const { data: tipos, error } = await supabase .from('tipos_despesa') .select('*') .order('nome') if (error) throw error res.json(tipos) } catch (error) { console.error('Erro ao buscar tipos de despesa:', error) res.status(500).json({ error: error.message }) } }); app.post('/api/tipos-despesas', async (req, res) => { try { const { nome } = req.body; const { data: tipo, error } = await supabase .from('tipos_despesa') .insert([{ nome }]) .select() .single() if (error) throw error res.json({ id: tipo.id, message: 'Tipo de despesa criado com sucesso!' }) } catch (error) { console.error('Erro ao criar tipo de despesa:', error) res.status(500).json({ error: error.message }) } }); // === TESTE === app.get('/api/test', (req, res) => { res.json({ message: 'API funcionando com Supabase!', timestamp: new Date(), database: 'Supabase' }); }); // === DASHBOARD === app.get('/api/dashboard', async (req, res) => { try { const [ { count: totalProdutos }, { count: totalClientes }, { count: totalFornecedores } ] = await Promise.all([ supabase.from('produtos').select('*', { count: 'exact', head: true }), supabase.from('clientes').select('*', { count: 'exact', head: true }), supabase.from('fornecedores').select('*', { count: 'exact', head: true }) ]) res.json({ totalProdutos: { count: totalProdutos }, totalClientes: { count: totalClientes }, totalFornecedores: { count: totalFornecedores }, vendasMes: { count: 0, total: 0 }, estoqueTotal: { total: 0 }, despesasMes: { total: 0 } }) } catch (error) { console.error('Erro no dashboard:', error) res.status(500).json({ error: error.message }) } }); // Servir arquivos estáticos do React app.get('*', (req, res) => { res.sendFile(path.join(__dirname, 'client/build', 'index.html')); }); // Criar diretório de uploads se não existir const fs = require('fs'); if (!fs.existsSync('uploads')) { fs.mkdirSync('uploads'); } app.listen(PORT, () => { console.log(`Servidor rodando na porta ${PORT}`); }); module.exports = app;