fix: sync totalRounds changes to server, filter geographic admin articles, validate user exists before saving game

This commit is contained in:
jessy-david-dev
2026-04-13 15:42:00 +02:00
parent 79d90b75c4
commit 2a3dd6be56
7 changed files with 121 additions and 29 deletions
+8
View File
@@ -20,6 +20,14 @@ export async function POST(req: NextRequest) {
won: boolean;
};
const userExists = await prisma.user.findUnique({
where: { id: session.user.id },
select: { id: true },
});
if (!userExists) {
return NextResponse.json({ error: "Utilisateur introuvable" }, { status: 401 });
}
const game = await prisma.game.create({
data: {
userId: session.user.id,
+31 -5
View File
@@ -69,7 +69,10 @@ function calcPlayerPoints(player: Player, room: Room): number {
let timePts: number;
if (room.timeLimit > 0) {
const timeLeft = room.timeLimit * 1000 - elapsed;
timePts = Math.max(0, Math.floor((timeLeft / (room.timeLimit * 1000)) * 10));
timePts = Math.max(
0,
Math.floor((timeLeft / (room.timeLimit * 1000)) * 10),
);
} else {
timePts = Math.max(0, 10 - Math.floor(elapsed / 30000));
}
@@ -355,7 +358,10 @@ export async function PATCH(
case "setGameMode": {
const host = room.players.find((p) => p.id === playerId);
if (!host?.isHost) {
return Response.json({ error: "Seul l'hôte peut modifier ce paramètre" }, { status: 403 });
return Response.json(
{ error: "Seul l'hôte peut modifier ce paramètre" },
{ status: 403 },
);
}
if (value === "race" || value === "all_finish") {
room.gameMode = value;
@@ -364,18 +370,38 @@ export async function PATCH(
return Response.json({ room });
}
// Hôte change le nombre de manches
case "setTotalRounds": {
const host = room.players.find((p) => p.id === playerId);
if (!host?.isHost) {
return Response.json(
{ error: "Seul l'hôte peut modifier ce paramètre" },
{ status: 403 },
);
}
if (typeof value === "number") {
room.totalRounds = Math.min(Math.max(Math.floor(value), 1), 10);
await saveRoom(room);
}
return Response.json({ room });
}
// Hôte change la limite de temps
case "setTimeLimit": {
const host = room.players.find((p) => p.id === playerId);
if (!host?.isHost) {
return Response.json({ error: "Seul l'hôte peut modifier ce paramètre" }, { status: 403 });
return Response.json(
{ error: "Seul l'hôte peut modifier ce paramètre" },
{ status: 403 },
);
}
room.timeLimit = typeof value === "number" ? Math.max(0, Math.floor(value)) : 0;
room.timeLimit =
typeof value === "number" ? Math.max(0, Math.floor(value)) : 0;
await saveRoom(room);
return Response.json({ room });
}
// Fin du temps imparti déclenché par le client qui détecte l'expiration
// Fin du temps imparti - déclenché par le client qui détecte l'expiration
case "timeUp": {
if (room.phase !== "playing") {
return Response.json({ room });
+2 -4
View File
@@ -24,9 +24,7 @@ const FORBIDDEN_NAMESPACES = [
"WP:",
];
const REMOVED_SECTION_IDS = [
"Liens_externes",
];
const REMOVED_SECTION_IDS = ["Liens_externes"];
function getHeadingId(el: Element): string {
// Nouvelle structure Wikipedia : <div class="mw-heading"><h2 id="...">
@@ -72,7 +70,7 @@ function cleanWikiHtml(container: HTMLElement): void {
}
});
// Supprimer les sections indésirables supporte ancienne et nouvelle structure Wikipedia
// Supprimer les sections indésirables - supporte ancienne et nouvelle structure Wikipedia
// Nouvelle : <div class="mw-heading mw-heading2"> / Ancienne : <h2><span id="...">
const headingSelectors = "h2, h3, .mw-heading";
container.querySelectorAll(headingSelectors).forEach((heading) => {
+4 -2
View File
@@ -19,6 +19,7 @@ type LobbyScreenProps = {
gameMode: Room["gameMode"];
setGameMode: (v: Room["gameMode"]) => void;
onSetGameMode: (v: Room["gameMode"]) => void;
onSetTotalRounds: (v: number) => void;
onSetSearchAllowed: (v: boolean) => void;
onSetTimeLimit: (v: number) => void;
};
@@ -39,6 +40,7 @@ export function LobbyScreen({
gameMode,
setGameMode,
onSetGameMode,
onSetTotalRounds,
onSetSearchAllowed,
onSetTimeLimit,
}: LobbyScreenProps) {
@@ -180,8 +182,8 @@ export function LobbyScreen({
<div className="flex-1 flex flex-col gap-1.5">
<span className="text-xs text-[#888]">Manches</span>
<select
value={totalRounds}
onChange={(e) => setTotalRounds(Number(e.target.value))}
value={room.totalRounds}
onChange={(e) => { const v = Number(e.target.value); setTotalRounds(v); onSetTotalRounds(v); }}
className="w-full min-h-11 px-2 bg-[#0f0f0f] border border-[#2e2e2e] rounded-xl text-sm text-[#f0f0f0] outline-none focus:border-[#7c3aed] cursor-pointer transition-colors"
>
{[1, 2, 3, 4, 5, 7, 10].map((n) => (
+1
View File
@@ -159,6 +159,7 @@ export function ScreenRouter({
gameMode={gameMode}
setGameMode={setGameMode}
onSetGameMode={(v) => multi.setGameMode(v)}
onSetTotalRounds={(v) => multi.setTotalRounds(v)}
onSetSearchAllowed={(v) => multi.setSearchAllowed(v)}
onSetTimeLimit={(v) => multi.setTimeLimit(v)}
/>