const express = require('express'); const cors = require('cors'); const path = require('path'); const pool = require('./db'); const app = express(); const PORT = process.env.PORT || 3001; // Porta do backend app.use(cors()); // Permite que o React (localhost:3000) acesse este servidor app.use(express.json()); // Serve static files from the React app if (process.env.NODE_ENV === 'production') { app.use(express.static(path.join(__dirname, '../dist'))); } // --- Rotas de Usuários --- // Listar Usuários (com filtro opcional de tenant) app.get('/api/users', async (req, res) => { try { const { tenantId } = req.query; let query = 'SELECT * FROM users'; const params = []; if (tenantId && tenantId !== 'all') { query += ' WHERE tenant_id = ?'; params.push(tenantId); } const [rows] = await pool.query(query, params); res.json(rows); } catch (error) { console.error('Erro ao buscar usuários:', error); res.status(500).json({ error: error.message }); } }); // Detalhe do Usuário app.get('/api/users/:id', async (req, res) => { try { const [rows] = await pool.query('SELECT * FROM users WHERE id = ?', [req.params.id]); if (rows.length === 0) return res.status(404).json({ message: 'User not found' }); res.json(rows[0]); } catch (error) { res.status(500).json({ error: error.message }); } }); // --- Rotas de Atendimentos --- // Listar Atendimentos (Dashboard) app.get('/api/attendances', async (req, res) => { try { const { tenantId, userId, teamId, startDate, endDate } = req.query; let query = ` SELECT a.*, u.team_id FROM attendances a JOIN users u ON a.user_id = u.id WHERE a.tenant_id = ? `; const params = [tenantId]; // Filtro de Data if (startDate && endDate) { query += ' AND a.created_at BETWEEN ? AND ?'; params.push(new Date(startDate), new Date(endDate)); } // Filtro de Usuário if (userId && userId !== 'all') { query += ' AND a.user_id = ?'; params.push(userId); } // Filtro de Time (baseado na tabela users ou teams) if (teamId && teamId !== 'all') { query += ' AND u.team_id = ?'; params.push(teamId); } query += ' ORDER BY a.created_at DESC'; const [rows] = await pool.query(query, params); // Tratamento de campos JSON se o MySQL retornar como string const processedRows = rows.map(row => ({ ...row, attention_points: typeof row.attention_points === 'string' ? JSON.parse(row.attention_points) : row.attention_points, improvement_points: typeof row.improvement_points === 'string' ? JSON.parse(row.improvement_points) : row.improvement_points, converted: Boolean(row.converted) // Garantir booleano })); res.json(processedRows); } catch (error) { console.error('Erro ao buscar atendimentos:', error); res.status(500).json({ error: error.message }); } }); // Detalhe do Atendimento app.get('/api/attendances/:id', async (req, res) => { try { const [rows] = await pool.query('SELECT * FROM attendances WHERE id = ?', [req.params.id]); if (rows.length === 0) return res.status(404).json({ message: 'Attendance not found' }); const row = rows[0]; const processedRow = { ...row, attention_points: typeof row.attention_points === 'string' ? JSON.parse(row.attention_points) : row.attention_points, improvement_points: typeof row.improvement_points === 'string' ? JSON.parse(row.improvement_points) : row.improvement_points, converted: Boolean(row.converted) }; res.json(processedRow); } catch (error) { res.status(500).json({ error: error.message }); } }); // --- Rotas de Tenants (Super Admin) --- app.get('/api/tenants', async (req, res) => { try { // Buscar tenants e contar usuários/atendimentos const query = ` SELECT t.*, (SELECT COUNT(*) FROM users u WHERE u.tenant_id = t.id) as user_count, (SELECT COUNT(*) FROM attendances a WHERE a.tenant_id = t.id) as attendance_count FROM tenants t `; const [rows] = await pool.query(query); res.json(rows); } catch (error) { res.status(500).json({ error: error.message }); } }); // Criar Tenant app.post('/api/tenants', async (req, res) => { const { name, slug, admin_email, status } = req.body; const crypto = require('crypto'); const connection = await pool.getConnection(); try { await connection.beginTransaction(); const tenantId = `tenant_${crypto.randomUUID().split('-')[0]}`; // Simple ID generation // 1. Criar Tenant await connection.query( 'INSERT INTO tenants (id, name, slug, admin_email, status) VALUES (?, ?, ?, ?, ?)', [tenantId, name, slug, admin_email, status || 'active'] ); // 2. Criar Usuário Admin Default const userId = `u_${crypto.randomUUID().split('-')[0]}`; await connection.query( 'INSERT INTO users (id, tenant_id, name, email, role, status) VALUES (?, ?, ?, ?, ?, ?)', [userId, tenantId, 'Admin', admin_email, 'admin', 'active'] ); await connection.commit(); res.status(201).json({ message: 'Tenant created successfully', id: tenantId }); } catch (error) { await connection.rollback(); console.error('Erro ao criar tenant:', error); res.status(500).json({ error: error.message }); } finally { connection.release(); } }); // Serve index.html for any unknown routes (for client-side routing) if (process.env.NODE_ENV === 'production') { app.get('*', (req, res) => { res.sendFile(path.join(__dirname, '../dist/index.html')); }); } app.listen(PORT, () => { console.log(`🚀 Servidor Backend rodando em http://localhost:${PORT}`); });