import type { ConversationSummary } from '@chat-app/shared/chat'; import { useTranslation } from 'react-i18next'; import { useCall } from '../context/CallContext'; import { useFriendshipsContext } from '../context/FriendshipsContext'; import { AvatarColorKey, colorKeyFor } from './CallParticipantTile'; import { LockIcon, PhoneIcon, PhoneOffIcon, VideoIcon } from './icons'; interface Props { conversation: ConversationSummary; } const PULSE_BG: Record = { violet: 'bg-violet-200 text-violet-800 dark:bg-violet-900/60 dark:text-violet-200', amber: 'bg-amber-200 text-amber-900 dark:bg-amber-900/60 dark:text-amber-200', rose: 'bg-rose-200 text-rose-900 dark:bg-rose-900/60 dark:text-rose-200', teal: 'bg-teal-200 text-teal-900 dark:bg-teal-900/60 dark:text-teal-200', }; // Docked incoming-call panel: replaces the chat header, chat + composer stay // visible and usable below (per user decision). Full-bleed overlay lives in // the shell-level toast for cross-conversation ring notifications. export function IncomingCallPanel({ conversation }: Props) { const { t } = useTranslation(['app']); const { state, acceptIncoming, rejectIncoming } = useCall(); const { friendships } = useFriendshipsContext(); if (state.kind !== 'incoming' || state.conversationId !== conversation.id) return null; const isGroup = conversation.type === 'group'; const callerProfile = conversation.members.find((m) => m.userId === state.fromUserId)?.profile ?? null; const callerName = callerProfile?.displayName ?? friendships.find((f) => f.peer.userId === state.fromUserId)?.peer.displayName ?? '?'; const groupName = isGroup ? (conversation.name ?? t('app:chats.new_group')) : null; const title = isGroup ? groupName ?? callerName : callerName; const letter = title.trim().charAt(0).toUpperCase() || '?'; const avatarUrl = isGroup ? (conversation.avatarUrl ?? callerProfile?.avatarUrl ?? null) : callerProfile?.avatarUrl ?? null; const colorKey = colorKeyFor(state.fromUserId); const avatarTone = PULSE_BG[colorKey]; const mediaLabel = state.mediaKind === 'video' ? 'Video Call' : 'Voice Call'; return (

{t('app:call.incoming_title')}

{title}

E2E verschlüsselt · {mediaLabel} {isGroup && ( <> {t('app:call.incoming_group_from', { name: callerName, defaultValue: callerName + ' ruft an', })} )}

{state.mediaKind === 'video' && ( )}
); }