feat(presence): Online-Presence-Provider + Hooks
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
29bbf23405
commit
35a71a9068
@ -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,
|
||||||
|
|||||||
@ -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,
|
||||||
|
|||||||
@ -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));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -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);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user