Files
tribunal-app/src/app/char/questions/page.tsx
T
Valentin ROBIN 5b5393cbd6
Build and deploy / deploy (push) Successful in 37s
Ajoute glisser-déposer, randomisation et tags @pseudo sur /char/questions
Réordonnancement par glisser-déposer (@dnd-kit, support tactile natif
pour une page pilotée depuis un téléphone) en complément des flèches
existantes, bouton de randomisation de l'ordre (confirmation à deux
temps), et tags @pseudo dans le texte des questions — détectés par
correspondance de texte (aucune colonne dédiée), avec autocomplétion
à la frappe, mise en évidence dans la liste et sur /char, et un
panneau de répartition des tags par membre.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-27 17:35:13 +02:00

112 lines
3.4 KiB
TypeScript

import Link from "next/link";
import { redirect } from "next/navigation";
import { createClient } from "@/lib/supabase/server";
import { QuestionsView } from "./questions-view";
export type QuestionRow = {
id: string;
text: string;
position: number;
created_at: string;
};
export type SubmissionRow = {
user_id: string;
text: string;
updated_at: string;
profiles: { pseudo: string; avatar_url: string | null } | null;
};
export type SubmissionHistoryRow = {
user_id: string;
text: string;
created_at: string;
};
export type ProfileRow = {
id: string;
pseudo: string;
avatar_url: string | null;
};
export default async function CharQuestionsPage() {
const supabase = await createClient();
const {
data: { user },
} = await supabase.auth.getUser();
if (!user) {
redirect("/login");
}
const { data: callerProfile } = await supabase
.from("profiles")
.select("role")
.eq("id", user.id)
.single();
// Page entièrement réservée aux Archontes : contrairement à /char (projeté,
// partagé avec tous), rien ici n'a de sens pour un Citoyen — et exposer la
// liste complète des questions à venir serait un spoiler du jeu en cours.
if (callerProfile?.role !== "judge") {
redirect("/char");
}
const { data: questions } = await supabase
.from("chariot_questions")
.select("id, text, position, created_at")
.order("position", { ascending: true })
.order("created_at", { ascending: true });
const { data: settings } = await supabase
.from("settings")
.select("chariot_revealed_question_id")
.eq("id", true)
.single();
const { data: submissions } = await supabase
.from("chariot_submissions")
.select("user_id, text, updated_at, profiles(pseudo, avatar_url)")
.order("updated_at", { ascending: true })
.returns<SubmissionRow[]>();
// Versions précédentes des propositions (chariot_submissions ne garde que
// la version actuelle) — pour la section "Historique" de la modération.
const { data: submissionHistory } = await supabase
.from("chariot_submission_history")
.select("user_id, text, created_at")
.order("created_at", { ascending: false });
// Tout le monde (Archontes compris, comme pour les emplacements du Char
// lui-même — voir chariot_slots) peut être visé par un tag "@pseudo" dans
// une question.
const { data: profiles } = await supabase
.from("profiles")
.select("id, pseudo, avatar_url")
.order("pseudo", { ascending: true });
return (
<div className="mx-auto w-full max-w-2xl px-4 py-8">
<div className="mb-6 text-center">
<h1 className="font-heading text-2xl tracking-[0.1em] text-gold-bright uppercase">Les Questions du Char</h1>
<p className="font-serif text-sm text-marble/60 italic">
Réservé aux Archontes /char (projetée) n&apos;affiche que la question choisie ici.
</p>
<Link
href="/char"
className="mt-2 inline-block text-xs font-medium text-marble/60 underline hover:text-gold-bright"
>
Retourner au Char
</Link>
</div>
<QuestionsView
initialQuestions={questions ?? []}
initialRevealedId={settings?.chariot_revealed_question_id ?? null}
initialSubmissions={submissions ?? []}
initialSubmissionHistory={submissionHistory ?? []}
profiles={profiles ?? []}
/>
</div>
);
}