const pool = require('../config/db'); exports.dashboard = async (req, res) => { try { const { filter } = req.query; let dateCondition; const now = new Date(); const year = now.getFullYear(); const month = String(now.getMonth() + 1).padStart(2, '0'); if (filter === 'year') { dateCondition = `r.date >= '${year}-01-01'`; } else if (filter === 'month') { dateCondition = `r.date >= '${year}-${month}-01'`; } else { dateCondition = `r.date >= DATE_SUB(CURDATE(), INTERVAL 12 MONTH)`; } const nextEventPromise = pool.query(` SELECT e.date, e.nom_evenement, (SELECT COUNT(*) FROM invites WHERE date_club = e.date) AS invites, (SELECT SUM(statut = 'acceptee') FROM invites WHERE date_club = e.date) AS acceptees, (SELECT SUM(statut = 'refusee') FROM invites WHERE date_club = e.date) AS refusees, (SELECT SUM(visit_number >= 2) FROM invites WHERE date_club = e.date) AS secondes_visites FROM evenements e WHERE e.nom_evenement = 'Club d''Affaires' AND e.date >= CURDATE() ORDER BY e.date ASC LIMIT 1 `); const honorsPromise = pool.query( "SELECT mh.*, u.prenom, u.nom, u.societe AS membre_societe FROM mises_en_honneur mh LEFT JOIN users u ON u.id = mh.membre_id WHERE mh.date >= CURDATE() ORDER BY mh.date ASC LIMIT 5" ); const eventsPromise = pool.query( 'SELECT * FROM evenements WHERE date >= CURDATE() ORDER BY date ASC LIMIT 3' ); const recsPromise = pool.query(` SELECT r.id, r.date, r.nom_prospect, r.type, r.transformee, r.ca_realise, m.prenom AS membre_prenom, m.nom AS membre_nom, d.prenom AS dest_prenom, d.nom AS dest_nom FROM recommandations r LEFT JOIN users m ON m.id = r.membre_id LEFT JOIN users d ON d.id = r.destinataire_id WHERE ${dateCondition} ORDER BY r.date DESC `); const countPromise = pool.query(` SELECT COUNT(*) AS total, SUM(CASE WHEN r.type='donnee' THEN 1 ELSE 0 END) AS donnees, SUM(CASE WHEN r.type='recue' THEN 1 ELSE 0 END) AS recues, SUM(r.transformee) AS transformees, SUM(COALESCE(r.ca_realise,0)) AS ca_total FROM recommandations r WHERE ${dateCondition} `); const memberRecsPromise = pool.query(` SELECT u.id, u.prenom, u.nom, u.societe, COUNT(r.id) AS total_recs, SUM(r.transformee) AS total_transformees, SUM(COALESCE(r.ca_realise,0)) AS total_ca FROM users u LEFT JOIN recommandations r ON r.membre_id = u.id AND ${dateCondition} WHERE u.actif = 1 GROUP BY u.id ORDER BY total_recs DESC `); const guestCountPromise = pool.query(` SELECT i.invite_par_id, u.prenom, u.nom, COUNT(i.id) AS total_invites FROM invites i JOIN users u ON u.id = i.invite_par_id WHERE i.date_club >= DATE_SUB(CURDATE(), INTERVAL 12 MONTH) GROUP BY i.invite_par_id, u.prenom, u.nom ORDER BY total_invites DESC `); const echeancePromise = pool.query( "SELECT id, prenom, nom, societe, date_echeance FROM users WHERE actif = 1 AND date_echeance IS NOT NULL AND date_echeance BETWEEN CURDATE() AND DATE_ADD(CURDATE(), INTERVAL 30 DAY) ORDER BY date_echeance ASC" ); const [nextEvent] = await nextEventPromise; const [honors] = await honorsPromise; const [events] = await eventsPromise; const [recs] = await recsPromise; const [counts] = await countPromise; const [memberRecs] = await memberRecsPromise; const [guestCounts] = await guestCountPromise; const guestMetricsPromise = pool.query(` SELECT COUNT(*) AS total_invites, SUM(CASE WHEN statut = 'acceptee' THEN 1 ELSE 0 END) AS acceptees, SUM(CASE WHEN statut = 'refusee' THEN 1 ELSE 0 END) AS refusees, SUM(CASE WHEN visit_number >= 2 THEN 1 ELSE 0 END) AS secondes_visites FROM invites `); const [echeances] = await echeancePromise; const [guestMetricsRows] = await guestMetricsPromise; let top_absences = []; if (req.user.role === 'admin') { const [absRows] = await pool.query(` SELECT u.id, u.prenom, u.nom, COUNT(a.id) AS total_absences FROM users u LEFT JOIN absences a ON a.membre_id = u.id WHERE u.actif = 1 GROUP BY u.id HAVING total_absences > 0 ORDER BY total_absences DESC LIMIT 5 `); top_absences = absRows; } let top_conversion = []; const [convRows] = await pool.query(` SELECT u.id, u.prenom, u.nom, COUNT(m.id) AS total_convertis FROM users u JOIN users m ON m.invite_par_id = u.id WHERE u.actif = 1 GROUP BY u.id ORDER BY total_convertis DESC LIMIT 15 `); top_conversion = convRows; const [candRows] = await pool.query( 'SELECT id, prenom, nom, societe, created_at FROM invites WHERE statut_candidature = ? ORDER BY created_at DESC', ['candidature'] ); const candidatures = candRows; const total = Number(counts[0].total) || 0; const transformees = Number(counts[0].transformees) || 0; const tauxTransformation = total > 0 ? ((transformees / total) * 100).toFixed(1) : 0; const topDonnees = [...memberRecs].filter(m => m.total_recs > 0).sort((a, b) => b.total_recs - a.total_recs).slice(0, 15); const topInvites = [...guestCounts].sort((a, b) => b.total_invites - a.total_invites).slice(0, 15); const flopDonnees = [...memberRecs].sort((a, b) => a.total_recs - b.total_recs).slice(0, 5); res.json({ prochaine_seance: nextEvent.length > 0 ? { date: nextEvent[0].date, nom: nextEvent[0].nom_evenement, invites: Number(nextEvent[0].invites) || 0, acceptees: Number(nextEvent[0].acceptees) || 0, refusees: Number(nextEvent[0].refusees) || 0, secondes_visites: Number(nextEvent[0].secondes_visites) || 0, } : null, counts: { total, donnees: Number(counts[0].donnees) || 0, recues: Number(counts[0].recues) || 0, transformees, ca_total: Number(counts[0].ca_total) || 0, taux_transformation: tauxTransformation, }, top_donnees: topDonnees, top_invites: topInvites, flop_donnees: flopDonnees, prochaines_honors: honors, prochains_evenements: events, alertes_echeance: echeances, guest_metrics: { total_invites: Number(guestMetricsRows[0].total_invites) || 0, acceptees: Number(guestMetricsRows[0].acceptees) || 0, refusees: Number(guestMetricsRows[0].refusees) || 0, secondes_visites: Number(guestMetricsRows[0].secondes_visites) || 0, }, top_absences, top_conversion, candidatures, }); } catch (err) { console.error(err); res.status(500).json({ error: 'Server error' }); } }; exports.memberStats = async (req, res) => { try { const userId = req.params.id || req.user.id; const [recs] = await pool.query(` SELECT r.*, d.prenom AS dest_prenom, d.nom AS dest_nom FROM recommandations r LEFT JOIN users d ON d.id = r.destinataire_id WHERE r.membre_id = ? ORDER BY r.date DESC `, [userId]); const [guests] = await pool.query( 'SELECT * FROM invites WHERE invite_par_id = ? ORDER BY created_at DESC', [userId] ); res.json({ recommandations: recs, invites: guests }); } catch (err) { console.error(err); res.status(500).json({ error: 'Server error' }); } };