Files
THE-TIP-TOP/backend/src/controllers/admin.controller.js
Emma781227 902e304a5e changement
2026-07-23 13:45:53 +02:00

329 lines
7.8 KiB
JavaScript

const bcrypt = require("bcrypt");
const prisma = require("../config/prisma");
const { getGameWindow, expireOverdueClaims } = require("../utils/gameWindow");
const AGE_BRACKETS = ["-18", "18-24", "25-34", "35-44", "45-54", "55-64", "65+"];
function getAgeBracket(birthdate) {
if (!birthdate) return "unknown";
const now = new Date();
let age = now.getFullYear() - birthdate.getFullYear();
const hasHadBirthdayThisYear =
now.getMonth() > birthdate.getMonth() ||
(now.getMonth() === birthdate.getMonth() && now.getDate() >= birthdate.getDate());
if (!hasHadBirthdayThisYear) age -= 1;
if (age < 18) return "-18";
if (age <= 24) return "18-24";
if (age <= 34) return "25-34";
if (age <= 44) return "35-44";
if (age <= 54) return "45-54";
if (age <= 64) return "55-64";
return "65+";
}
function computeAgeStats(users) {
const counts = Object.fromEntries([...AGE_BRACKETS, "unknown"].map((b) => [b, 0]));
for (const user of users) {
counts[getAgeBracket(user.birthdate)] += 1;
}
return counts;
}
const getStats = async (req, res) => {
try {
await expireOverdueClaims();
const gameWindow = await getGameWindow();
const [
ticketsTotal,
ticketsUsed,
participations,
claimsPending,
claimsDelivered,
claimsCancelled,
users,
men,
women,
clientsWithBirthdate,
] = await Promise.all([
prisma.ticket.count(),
prisma.ticket.count({ where: { isUsed: true } }),
prisma.participation.count(),
prisma.claim.count({ where: { status: "PENDING" } }),
prisma.claim.count({ where: { status: "DELIVERED" } }),
prisma.claim.count({ where: { status: "CANCELLED" } }),
prisma.user.count({ where: { role: "CLIENT" } }),
prisma.user.count({ where: { role: "CLIENT", gender: "Homme" } }),
prisma.user.count({ where: { role: "CLIENT", gender: "Femme" } }),
prisma.user.findMany({ where: { role: "CLIENT" }, select: { birthdate: true } }),
]);
const lotsStats = await prisma.lot.findMany({
select: {
id: true,
name: true,
percentage: true,
_count: {
select: {
tickets: true,
participations: true,
},
},
},
});
return res.json({
ticketsTotal,
ticketsUsed,
ticketsRemaining: ticketsTotal - ticketsUsed,
participations,
claimsPending,
claimsDelivered,
claimsCancelled,
users,
gameWindow,
ageStats: computeAgeStats(clientsWithBirthdate),
genderStats: {
men,
women,
other: users - men - women,
},
lotsStats,
});
} catch (error) {
console.error("Erreur stats admin:", error);
return res.status(500).json({
message: "Erreur serveur lors de la récupération des statistiques.",
});
}
};
const getUsers = async (req, res) => {
try {
const users = await prisma.user.findMany({
where: { role: "CLIENT" },
select: {
id: true,
firstname: true,
lastname: true,
email: true,
gender: true,
birthdate: true,
marketingOptIn: true,
createdAt: true,
_count: {
select: {
participations: true,
},
},
},
orderBy: {
createdAt: "desc",
},
});
return res.json({ users });
} catch (error) {
console.error("Erreur liste utilisateurs:", error);
return res.status(500).json({
message: "Erreur serveur lors de la récupération des utilisateurs.",
});
}
};
const getEmailingContacts = async (req, res) => {
try {
const contacts = await prisma.user.findMany({
where: {
role: "CLIENT",
marketingOptIn: true,
},
select: {
firstname: true,
lastname: true,
email: true,
createdAt: true,
},
orderBy: {
createdAt: "desc",
},
});
return res.json({
total: contacts.length,
contacts,
});
} catch (error) {
console.error("Erreur emailing:", error);
return res.status(500).json({
message: "Erreur serveur lors de la récupération des contacts emailing.",
});
}
};
const createEmployee = async (req, res) => {
try {
const { firstname, lastname, email, password, birthdate, gender } = req.body;
const existingUser = await prisma.user.findUnique({
where: { email },
});
if (existingUser) {
return res.status(409).json({
message: "Un compte existe déjà avec cet email.",
});
}
const hashedPassword = await bcrypt.hash(password, 10);
const employee = await prisma.user.create({
data: {
firstname,
lastname,
email,
password: hashedPassword,
birthdate: birthdate ? new Date(birthdate) : null,
gender,
role: "EMPLOYEE",
marketingOptIn: false,
},
select: {
id: true,
firstname: true,
lastname: true,
email: true,
role: true,
createdAt: true,
},
});
return res.status(201).json({
message: "Employé créé avec succès.",
employee,
});
} catch (error) {
console.error("Erreur création employé:", error);
return res.status(500).json({
message: "Erreur serveur lors de la création de l'employé.",
});
}
};
const drawWinner = async (req, res) => {
try {
const existingWinner = await prisma.grandPrizeWinner.findFirst({
include: {
user: {
select: {
id: true,
firstname: true,
lastname: true,
email: true,
},
},
},
});
if (existingWinner) {
return res.status(409).json({
message: "Le tirage au sort a déjà été effectué.",
winner: existingWinner,
});
}
const participants = await prisma.user.findMany({
where: {
role: "CLIENT",
participations: {
some: {},
},
},
select: {
id: true,
firstname: true,
lastname: true,
email: true,
},
});
if (participants.length === 0) {
return res.status(400).json({
message: "Aucun participant disponible pour le tirage.",
});
}
const randomIndex = Math.floor(Math.random() * participants.length);
const winner = participants[randomIndex];
const savedWinner = await prisma.grandPrizeWinner.create({
data: {
userId: winner.id,
},
include: {
user: {
select: {
id: true,
firstname: true,
lastname: true,
email: true,
},
},
},
});
return res.status(201).json({
message: "Tirage au sort effectué avec succès.",
totalEligibleParticipants: participants.length,
winner: savedWinner,
});
} catch (error) {
console.error("Erreur tirage au sort:", error);
return res.status(500).json({
message: "Erreur serveur lors du tirage au sort.",
});
}
};
const getGrandPrizeWinner = async (req, res) => {
try {
const winner = await prisma.grandPrizeWinner.findFirst({
include: {
user: {
select: {
id: true,
firstname: true,
lastname: true,
email: true,
},
},
},
});
if (!winner) {
return res.status(404).json({
message: "Aucun gagnant du gros lot n'a encore été tiré.",
});
}
return res.json({
winner,
});
} catch (error) {
console.error("Erreur récupération gagnant:", error);
return res.status(500).json({
message: "Erreur serveur lors de la récupération du gagnant.",
});
}
};
module.exports = {
getStats,
getUsers,
getEmailingContacts,
createEmployee,
drawWinner,
getGrandPrizeWinner,
};