feat(presence): Online-Presence-Provider + Hooks

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
chahinebrini 2026-05-21 18:09:42 +02:00
parent 29bbf23405
commit 35a71a9068
4 changed files with 2 additions and 22 deletions

View File

@ -32,17 +32,6 @@ export function OnlinePresenceProvider({ children }: Props) {
useLastSeenHeartbeat(!!user); useLastSeenHeartbeat(!!user);
// Debug-Log nur bei tatsächlichen state-changes (size geändert) — sonst
// hängt's an jedem Re-Render und spammed Metro.
useMemo(() => {
console.log(
'[presence] state — self=%s, onlineGlobal=%d, following=%d',
user?.id ?? 'none',
ids.size,
following.size,
);
}, [ids.size, following.size, user?.id]);
const ctx = useMemo( const ctx = useMemo(
() => ({ () => ({
onlineUserIds: ids, onlineUserIds: ids,

View File

@ -7,7 +7,6 @@ export function useFollowing(): Set<string> {
queryKey: ['me-following'], queryKey: ['me-following'],
queryFn: async () => { queryFn: async () => {
const r = await apiFetch<{ userIds: string[] }>('/api/me/following'); const r = await apiFetch<{ userIds: string[] }>('/api/me/following');
console.log('[presence] /api/me/following →', r.userIds?.length ?? 0, 'IDs:', r.userIds);
return r; return r;
}, },
staleTime: 5 * 60_000, staleTime: 5 * 60_000,

View File

@ -4,7 +4,6 @@ import { apiFetch } from '../lib/api';
const ping = (reason: string) => { const ping = (reason: string) => {
apiFetch('/api/me/last-seen', { method: 'POST' }) apiFetch('/api/me/last-seen', { method: 'POST' })
.then((r) => console.log('[presence] heartbeat OK (' + reason + ')', r))
.catch((e) => console.warn('[presence] heartbeat FAIL (' + reason + '):', e?.message ?? e)); .catch((e) => console.warn('[presence] heartbeat FAIL (' + reason + '):', e?.message ?? e));
}; };

View File

@ -27,12 +27,8 @@ function notify() {
} }
function ensureChannel(currentUserId: string) { function ensureChannel(currentUserId: string) {
if (sharedChannel) { if (sharedChannel) return;
console.log('[presence] channel already exists, skip ensure');
return;
}
console.log('[presence] ensureChannel — opening for user', currentUserId);
const ch = supabase.channel('presence:online', { const ch = supabase.channel('presence:online', {
config: { presence: { key: currentUserId } }, config: { presence: { key: currentUserId } },
}); });
@ -43,14 +39,11 @@ function ensureChannel(currentUserId: string) {
const state = ch.presenceState(); const state = ch.presenceState();
const keys = Object.keys(state); const keys = Object.keys(state);
onlineUserIds = new Set(keys); onlineUserIds = new Set(keys);
console.log('[presence] sync — online users:', keys.length, keys);
notify(); notify();
}) })
.subscribe(async (status: string) => { .subscribe(async (status: string) => {
console.log('[presence] subscribe status:', status);
if (status === 'SUBSCRIBED') { if (status === 'SUBSCRIBED') {
const result = await ch.track({ userId: currentUserId, online_at: new Date().toISOString() }); await ch.track({ userId: currentUserId, online_at: new Date().toISOString() });
console.log('[presence] track result:', result);
} }
}); });
} }