"use client"; import { useCallback, useEffect, useState } from "react"; import { Avatar } from "@/components/avatar"; import { createClient, waitForRealtimeAuth } from "@/lib/supabase/client"; import type { CitizenRow, MyVoteRow } from "./page"; function CitizenVoteRow({ citizen, onVote }: { citizen: CitizenRow; onVote: () => void }) { const [confirming, setConfirming] = useState(false); return (
  • {citizen.pseudo} {confirming ? ( ) : ( )}
  • ); } export function UrneView({ isJudge, currentUserId, citizens, initialVoteCounts, initialMyVoteToday, }: { isJudge: boolean; currentUserId: string; citizens: CitizenRow[]; initialVoteCounts: Record; initialMyVoteToday: MyVoteRow | null; }) { const [voteCounts, setVoteCounts] = useState(initialVoteCounts); const [myVoteToday, setMyVoteToday] = useState(initialMyVoteToday); const [error, setError] = useState(null); const refetch = useCallback(async () => { const supabase = createClient(); const [{ data: counts }, { data: myVotes }] = await Promise.all([ supabase.rpc("urn_vote_counts"), isJudge ? Promise.resolve({ data: null }) : supabase .from("urn_votes") .select("target_id, created_at") .eq("voter_id", currentUserId) .order("created_at", { ascending: false }), ]); if (counts) { const next: Record = {}; for (const row of counts) next[row.target_id] = row.votes; setVoteCounts(next); } if (myVotes) { const today = new Date().toLocaleDateString("sv-SE", { timeZone: "Europe/Paris" }); setMyVoteToday( myVotes.find( (v) => new Date(v.created_at).toLocaleDateString("sv-SE", { timeZone: "Europe/Paris" }) === today, ) ?? null, ); } }, [isJudge, currentUserId]); useEffect(() => { const supabase = createClient(); let channel: ReturnType | null = null; let cancelled = false; waitForRealtimeAuth(supabase).then(() => { if (cancelled) return; channel = supabase .channel("urn-votes-changes") .on("postgres_changes", { event: "*", schema: "public", table: "urn_votes" }, refetch) .subscribe(); }); return () => { cancelled = true; if (channel) supabase.removeChannel(channel); }; }, [refetch]); async function handleVote(targetId: string) { setError(null); const supabase = createClient(); const { error: rpcError } = await supabase.rpc("cast_urn_vote", { p_target_id: targetId }); if (rpcError) { setError( rpcError.message.includes("already voted") ? "Tu as déjà voté aujourd'hui." : "Une erreur est survenue, réessaie.", ); refetch(); return; } refetch(); } const sortedCitizens = [...citizens].sort((a, b) => { const diff = (voteCounts[b.id] ?? 0) - (voteCounts[a.id] ?? 0); return diff !== 0 ? diff : a.pseudo.localeCompare(b.pseudo); }); const myVoteTarget = myVoteToday ? citizens.find((c) => c.id === myVoteToday.target_id) : null; const otherCitizens = citizens.filter((c) => c.id !== currentUserId); return (

    Classement

      {sortedCitizens.map((citizen) => { const count = voteCounts[citizen.id] ?? 0; return (
    • {citizen.pseudo} {count > 0 ? `×${count}` : "—"}
    • ); })}
    {!isJudge && (
    {myVoteToday ? (

    Tu as voté pour {myVoteTarget?.pseudo ?? "quelqu'un"} aujourd'hui.

    Reviens demain pour déposer un nouveau jeton.

    ) : ( <>

    Déposer un jeton

    {error && (

    {error}

    )}
      {otherCitizens.map((citizen) => ( handleVote(citizen.id)} /> ))}
    )}
    )}
    ); }