chahinebrini fb2d90b947 fix(calls): no duplicate incoming-call notifications
- backend: skip Expo alert push to iOS devices that already received VoIP push
  (CallKit + banner = double ring)
- native: receiveIncoming no longer triggers InCallManager.startRingtone —
  CallKit/ConnectionService play their own ring. Dedup if same callId
  arrives twice (Realtime + VoIP-Push race).
2026-06-04 18:28:00 +02:00

49 lines
1.8 KiB
TypeScript

import { Text } from 'react-native';
import { useTranslation } from 'react-i18next';
import { useOnlineUsers } from '../../hooks/useOnlineUsers';
import { useLastSeenBatch } from '../../hooks/useLastSeenBatch';
type Props = {
userId: string;
};
const STATUS_COLOR = '#a3a3a3';
function formatLastSeen(ts: string, t: (key: string, opts?: Record<string, unknown>) => string): string {
const diff = Date.now() - new Date(ts).getTime();
if (diff < 60_000) return t('presence.just_now');
if (diff < 3_600_000) return t('presence.minutes_ago', { minutes: Math.floor(diff / 60_000) });
if (diff < 86_400_000) return t('presence.hours_ago', { hours: Math.floor(diff / 3_600_000) });
return t('presence.days_ago', { days: Math.floor(diff / 86_400_000) });
}
export function ChatHeaderStatus({ userId }: Props) {
const { t } = useTranslation();
// DM-Header zeigt den ECHTEN Presence-Status des Partners (wie WhatsApp) —
// NICHT die following-gated `isOnline`-Variante aus dem Feed/Profil. Wer dir
// schreibt, sieht ohnehin via Typing-Indicator dass du da bist. `onlineUserIds`
// ist der rohe Presence-Set → updatet live über den Presence-Sync-Channel.
const { onlineUserIds } = useOnlineUsers();
const online = onlineUserIds.has(userId);
const lastSeenMap = useLastSeenBatch(online ? [] : [userId]);
if (online) {
// User-Wunsch: „Online"-Text zeigen, aber NICHT grün (Dot im Avatar reicht
// als Farb-Signal). Neutraler `textMuted`-Grau-Ton.
return (
<Text style={{ fontSize: 12, fontFamily: 'Nunito_400Regular', color: STATUS_COLOR }}>
{t('presence.online')}
</Text>
);
}
const lastSeen = lastSeenMap[userId];
if (!lastSeen) return null;
return (
<Text style={{ fontSize: 12, fontFamily: 'Nunito_400Regular', color: STATUS_COLOR }}>
{formatLastSeen(lastSeen, t)}
</Text>
);
}