Initial commit: Club DynaSQY
This commit is contained in:
@@ -0,0 +1,203 @@
|
||||
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' });
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user