rebreak-monorepo/apps/rebreak-native/components/OnlinePresenceProvider.tsx
chahinebrini 5c539f8937 feat(presence,sheets,chat): tester-build polish bundle
Online-Status (Phase 1+):
- UserAvatar mit 4 Size-Variants (sm/md/lg/xl) + integrierter Online-Dot
- OnlinePresenceProvider: Supabase-Channel + Following-Filter
- ChatHeaderStatus: "Online" neutral / "vor X min" offline
- useLastSeen + Heartbeat (60s interval + AppState-background ping)
- Privatsphäre-Toggle in profile/index

Sheets:
- FormSheet Android-keyboard-fix (Dimensions.get('screen'), kein
  useWindowDimensions-Kollaps), useKeyboardHandler statt manual
  Keyboard.addListener, state-reset on re-open
- PostCommentsSheet same Pattern + close-after-submit + drag bis under
  app-header
- ConnectMailSheet form-view refactor: scrollable, AES-Banner als
  footnote, field-order email→pw→label, fixed 0.85 über alle Steps

Chat:
- DmChatBackground iOS klecks fix (G transform statt nested Svg)
- ChatInput Lyra-1:1 (keyboardWillShow, surfaceElevated bubble,
  arrow-up send, attachment links)
- dm/room/chat headers + conversation-list nutzen UserAvatar
- Foreign-Profile "Nachricht"-Button öffnet richtige DM

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-18 08:06:47 +02:00

63 lines
1.7 KiB
TypeScript

import { createContext, useContext, useMemo } from 'react';
import { OnlinePresenceContext, useOnlinePresenceNode } from '../hooks/useOnlineUsers';
import { useAuthStore } from '../stores/auth';
import { useLastSeenHeartbeat } from '../hooks/useLastSeenHeartbeat';
import { useFollowing } from '../hooks/useFollowing';
export type PresenceContextExtended = {
onlineUserIds: Set<string>;
isOnline: (userId: string) => boolean;
};
export const PresenceVisibilityContext = createContext<{
presenceVisible: boolean;
setPresenceVisible: (v: boolean) => void;
}>({
presenceVisible: true,
setPresenceVisible: () => {},
});
export function usePresenceVisibility() {
return useContext(PresenceVisibilityContext);
}
type Props = {
children: React.ReactNode;
};
export function OnlinePresenceProvider({ children }: Props) {
const user = useAuthStore((s) => s.user);
const ids = useOnlinePresenceNode(user?.id ?? null);
const following = useFollowing();
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(
() => ({
onlineUserIds: ids,
isOnline: (userId: string) => {
if (!user?.id || userId === user.id) return false;
return ids.has(userId) && following.has(userId);
},
}),
[ids, following, user?.id],
);
return (
<OnlinePresenceContext.Provider value={ctx}>
{children}
</OnlinePresenceContext.Provider>
);
}