5b5393cbd6
Build and deploy / deploy (push) Successful in 37s
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>
112 lines
3.4 KiB
TypeScript
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'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>
|
|
);
|
|
}
|