Corrige le Realtime qui ne diffusait aucun événement à travers l'app
Build and deploy / deploy (push) Successful in 37s
Build and deploy / deploy (push) Successful in 37s
Les canaux Realtime (Char, Gardien, classement, journal, calendrier, Icare) s'abonnaient juste après createClient(), avant que la session ne soit chargée de façon asynchrone — le canal rejoignait donc Supabase en rôle "anon" au lieu de "authenticated", et les policies RLS "to authenticated" bloquaient silencieusement tous les événements (l'abonnement lui-même réussissait, ce qui masquait le problème). Ajoute waitForRealtimeAuth() dans src/lib/supabase/client.ts, qui attend la session et pousse explicitement le token avant de s'abonner. Vérifié avec deux sessions navigateur distinctes : les changements se propagent maintenant réellement sans rechargement.
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useMemo, useRef, useState } from "react";
|
||||
import { createClient } from "@/lib/supabase/client";
|
||||
import { createClient, waitForRealtimeAuth } from "@/lib/supabase/client";
|
||||
import { Avatar } from "@/components/avatar";
|
||||
import { Podium } from "@/components/podium";
|
||||
import { JudgePointControls } from "@/components/judge-point-controls";
|
||||
@@ -47,34 +47,41 @@ export function LeaderboardView({
|
||||
|
||||
useEffect(() => {
|
||||
const supabase = createClient();
|
||||
const channel = supabase
|
||||
.channel("leaderboard-profiles")
|
||||
.on(
|
||||
"postgres_changes",
|
||||
{ event: "*", schema: "public", table: "profiles" },
|
||||
(payload) => {
|
||||
if (payload.eventType === "DELETE") return;
|
||||
const row = payload.new as Profile;
|
||||
let channel: ReturnType<typeof supabase.channel> | null = null;
|
||||
let cancelled = false;
|
||||
|
||||
setProfiles((current) => {
|
||||
const exists = current.some((p) => p.id === row.id);
|
||||
return exists
|
||||
? current.map((p) => (p.id === row.id ? { ...p, ...row } : p))
|
||||
: [...current, row];
|
||||
});
|
||||
waitForRealtimeAuth(supabase).then(() => {
|
||||
if (cancelled) return;
|
||||
channel = supabase
|
||||
.channel("leaderboard-profiles")
|
||||
.on(
|
||||
"postgres_changes",
|
||||
{ event: "*", schema: "public", table: "profiles" },
|
||||
(payload) => {
|
||||
if (payload.eventType === "DELETE") return;
|
||||
const row = payload.new as Profile;
|
||||
|
||||
const previousPoints = pointsRef.current.get(row.id);
|
||||
if (previousPoints !== undefined && previousPoints !== row.points) {
|
||||
setFlashingId(row.id);
|
||||
setTimeout(() => setFlashingId((current) => (current === row.id ? null : current)), 900);
|
||||
}
|
||||
pointsRef.current.set(row.id, row.points);
|
||||
},
|
||||
)
|
||||
.subscribe();
|
||||
setProfiles((current) => {
|
||||
const exists = current.some((p) => p.id === row.id);
|
||||
return exists
|
||||
? current.map((p) => (p.id === row.id ? { ...p, ...row } : p))
|
||||
: [...current, row];
|
||||
});
|
||||
|
||||
const previousPoints = pointsRef.current.get(row.id);
|
||||
if (previousPoints !== undefined && previousPoints !== row.points) {
|
||||
setFlashingId(row.id);
|
||||
setTimeout(() => setFlashingId((current) => (current === row.id ? null : current)), 900);
|
||||
}
|
||||
pointsRef.current.set(row.id, row.points);
|
||||
},
|
||||
)
|
||||
.subscribe();
|
||||
});
|
||||
|
||||
return () => {
|
||||
supabase.removeChannel(channel);
|
||||
cancelled = true;
|
||||
if (channel) supabase.removeChannel(channel);
|
||||
};
|
||||
}, []);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user