Звонки
This commit is contained in:
@@ -8,20 +8,16 @@ import { useAuthStore } from '../../../auth/application/authStore';
|
||||
import { useLang } from '../../../../core/infrastructure/i18n';
|
||||
import { playCallRingtone, stopCallRingtone, playUnavailableSound } from '../../../../core/utils/sounds';
|
||||
import { getMediaUrl } from '../../../../core/utils/utils';
|
||||
import { UserBasic, CallInfo } from '../../../../core/domain/types';
|
||||
|
||||
type CallState = 'idle' | 'calling' | 'incoming' | 'connected' | 'ended';
|
||||
|
||||
interface CallModalProps {
|
||||
isOpen: boolean;
|
||||
onClose: () => void;
|
||||
targetUser: { id: string; displayName?: string; username?: string; avatar?: string | null } | null;
|
||||
targetUser: UserBasic | null;
|
||||
callType: 'voice' | 'video';
|
||||
incoming?: {
|
||||
from: string;
|
||||
offer: RTCSessionDescriptionInit;
|
||||
callType: 'voice' | 'video';
|
||||
callerInfo?: { displayName?: string; username?: string; avatar?: string | null } | null;
|
||||
} | null;
|
||||
incoming?: CallInfo | null;
|
||||
}
|
||||
|
||||
// ICE servers cache (fetched from server)
|
||||
@@ -1614,12 +1610,12 @@ export default function CallModal({ isOpen, onClose, targetUser, callType: initi
|
||||
};
|
||||
|
||||
const displayName = incoming
|
||||
? incoming.callerInfo?.displayName || incoming.callerInfo?.username || '...'
|
||||
: targetUser?.displayName || targetUser?.username || '...';
|
||||
? incoming.callerInfo?.displayName || incoming.callerInfo?.userName || incoming.callerInfo?.username || '...'
|
||||
: targetUser?.displayName || targetUser?.userName || targetUser?.username || '...';
|
||||
|
||||
const displayAvatar = incoming
|
||||
? incoming.callerInfo?.avatar
|
||||
: targetUser?.avatar;
|
||||
? incoming.callerInfo?.avatarUrl || incoming.callerInfo?.avatar
|
||||
: targetUser?.avatarUrl || targetUser?.avatar;
|
||||
|
||||
const initials = displayName
|
||||
.split(' ')
|
||||
@@ -1655,16 +1651,15 @@ export default function CallModal({ isOpen, onClose, targetUser, callType: initi
|
||||
className="fixed bottom-6 right-6 z-[100] flex items-center gap-3 px-4 py-3 rounded-2xl glass-strong shadow-2xl shadow-black/50 border border-white/10 cursor-pointer select-none"
|
||||
onClick={() => setIsMinimized(false)}
|
||||
>
|
||||
{/* Avatar */}
|
||||
<div className="relative">
|
||||
<div className="absolute inset-0 rounded-full bg-knot-500/30 animate-call-wave" />
|
||||
{displayAvatar ? (
|
||||
<img src={displayAvatar} alt="" className="relative w-10 h-10 rounded-full object-cover" />
|
||||
) : (
|
||||
<div className="relative w-10 h-10 rounded-full bg-linear-to-br from-primary/80 to-primary flex items-center justify-center text-on-primary font-black text-sm shadow-inner">
|
||||
{initials}
|
||||
</div>
|
||||
{callState === 'connected' && (
|
||||
<div className="absolute inset-0 rounded-xl bg-knot-500/30 animate-call-wave" />
|
||||
)}
|
||||
<Avatar
|
||||
src={displayAvatar ? getMediaUrl(displayAvatar) : null}
|
||||
name={displayName || '?'}
|
||||
size="md"
|
||||
/>
|
||||
</div>
|
||||
<div className="min-w-0">
|
||||
<p className="text-sm text-white font-medium truncate max-w-[120px]">{displayName}</p>
|
||||
@@ -1801,7 +1796,7 @@ export default function CallModal({ isOpen, onClose, targetUser, callType: initi
|
||||
{(!hasRemoteVideo || remoteIsVideoOffSignal) && !remoteScreenSharing && (
|
||||
<div className="absolute inset-0 flex flex-col items-center justify-center bg-zinc-900/50 backdrop-blur-md z-10">
|
||||
<div className="relative mb-6">
|
||||
<div className="absolute inset-0 rounded-full bg-knot-500/10 animate-pulse" />
|
||||
<div className="absolute inset-0 rounded-[1.5rem] bg-knot-500/10 animate-pulse" />
|
||||
<Avatar
|
||||
src={displayAvatar ? getMediaUrl(displayAvatar) : null}
|
||||
name={displayName || '?'}
|
||||
@@ -1916,17 +1911,17 @@ export default function CallModal({ isOpen, onClose, targetUser, callType: initi
|
||||
<div className="relative mb-8 mt-4">
|
||||
{(callState === 'calling' || callState === 'connected') && (
|
||||
<>
|
||||
<div className="absolute inset-0 rounded-full bg-knot-500/30 animate-call-wave" />
|
||||
<div className="absolute inset-0 rounded-full bg-knot-500/20 animate-call-wave-delayed" />
|
||||
<div className="absolute inset-0 rounded-[1.5rem] bg-knot-500/30 animate-call-wave" />
|
||||
<div className="absolute inset-0 rounded-[1.5rem] bg-knot-500/20 animate-call-wave-delayed" />
|
||||
</>
|
||||
)}
|
||||
{callState === 'incoming' && (
|
||||
<>
|
||||
<div className="absolute inset-0 rounded-full bg-emerald-500/30 animate-call-wave" />
|
||||
<div className="absolute inset-0 rounded-full bg-emerald-500/20 animate-call-wave-delayed" />
|
||||
<div className="absolute inset-0 rounded-[1.5rem] bg-emerald-500/30 animate-call-wave" />
|
||||
<div className="absolute inset-0 rounded-[1.5rem] bg-emerald-500/20 animate-call-wave-delayed" />
|
||||
</>
|
||||
)}
|
||||
<div className="relative z-10 p-1.5 rounded-full bg-gradient-to-br from-white/10 to-transparent backdrop-blur-md border border-white/10 shadow-2xl cursor-pointer">
|
||||
<div className="relative z-10 p-1.5 rounded-[1.5rem] bg-gradient-to-br from-white/10 to-transparent backdrop-blur-md border border-white/10 shadow-2xl cursor-pointer">
|
||||
<Avatar
|
||||
src={displayAvatar ? getMediaUrl(displayAvatar) : null}
|
||||
name={displayName || '?'}
|
||||
|
||||
@@ -12,8 +12,10 @@ import { useLang } from '../../../../core/infrastructure/i18n';
|
||||
interface ParticipantInfo {
|
||||
id: string;
|
||||
username: string;
|
||||
userName?: string;
|
||||
displayName?: string;
|
||||
avatar?: string | null;
|
||||
avatarUrl?: string | null;
|
||||
isSharingScreen?: boolean;
|
||||
isMuted?: boolean;
|
||||
isVideoOff?: boolean;
|
||||
@@ -818,8 +820,8 @@ export default function GroupCallModal({ isOpen, onClose, chatId, chatName, call
|
||||
onClick={() => setIsMinimized(false)}
|
||||
>
|
||||
<div className="relative">
|
||||
<div className="absolute inset-0 rounded-full bg-emerald-500/30 animate-call-wave" />
|
||||
<div className="relative w-10 h-10 rounded-full bg-gradient-to-br from-emerald-500 to-teal-600 flex items-center justify-center text-white font-bold text-sm">
|
||||
<div className="absolute inset-0 rounded-xl bg-emerald-500/30 animate-call-wave" />
|
||||
<div className="relative w-10 h-10 rounded-xl bg-gradient-to-br from-emerald-500 to-teal-600 flex items-center justify-center text-white font-bold text-sm">
|
||||
{participantList.length + 1}
|
||||
</div>
|
||||
</div>
|
||||
@@ -949,7 +951,7 @@ export default function GroupCallModal({ isOpen, onClose, chatId, chatName, call
|
||||
<div className="flex flex-col items-center">
|
||||
<div className="relative mb-2">
|
||||
<Avatar
|
||||
src={p.avatar ? getMediaUrl(p.avatar) : null}
|
||||
src={(p.avatarUrl || p.avatar) ? getMediaUrl(p.avatarUrl || p.avatar) : null}
|
||||
name={t('you') || '?'}
|
||||
size="lg"
|
||||
className="shadow-xl"
|
||||
@@ -968,8 +970,8 @@ export default function GroupCallModal({ isOpen, onClose, chatId, chatName, call
|
||||
<div className="flex flex-col items-center">
|
||||
<div className="relative mb-2">
|
||||
<Avatar
|
||||
src={p.avatar ? getMediaUrl(p.avatar) : null}
|
||||
name={p.displayName || p.username || '?'}
|
||||
src={(p.avatarUrl || p.avatar) ? getMediaUrl(p.avatarUrl || p.avatar) : null}
|
||||
name={p.displayName || p.userName || p.username || '?'}
|
||||
size="lg"
|
||||
className="shadow-xl"
|
||||
/>
|
||||
|
||||
@@ -16,6 +16,8 @@ import GroupCallModal from '../../calls/presentation/components/GroupCallModal';
|
||||
import ContactsSidebar from '../../friends/presentation/components/ContactsSidebar';
|
||||
import SettingsPage from '../../users/presentation/components/SettingsPage';
|
||||
import UserProfile from '../../users/presentation/components/UserProfile';
|
||||
import Avatar from '../../../core/presentation/components/ui/Avatar';
|
||||
import { getMediaUrl } from '../../../core/utils/utils';
|
||||
|
||||
export default function ChatPage() {
|
||||
const {
|
||||
@@ -476,14 +478,13 @@ export default function ChatPage() {
|
||||
className="bg-zinc-900 border border-white/10 p-8 rounded-3xl w-full max-w-sm flex flex-col items-center shadow-2xl"
|
||||
>
|
||||
<div className="relative mb-6">
|
||||
<div className="absolute inset-0 rounded-full bg-emerald-500/20 animate-call-wave" />
|
||||
<div className="relative w-24 h-24 rounded-full bg-linear-to-br from-primary/80 to-primary flex items-center justify-center text-4xl font-black text-on-primary uppercase overflow-hidden shadow-2xl">
|
||||
{incomingGroupCall.callerInfo?.avatar ? (
|
||||
<img src={incomingGroupCall.callerInfo.avatar} className="w-full h-full object-cover" />
|
||||
) : (
|
||||
<>{incomingGroupCall.chatName.charAt(0)}</>
|
||||
)}
|
||||
</div>
|
||||
<div className="absolute inset-0 rounded-[1.5rem] bg-emerald-500/20 animate-call-wave" />
|
||||
<Avatar
|
||||
src={incomingGroupCall.callerInfo?.avatar ? getMediaUrl(incomingGroupCall.callerInfo.avatar) : null}
|
||||
name={incomingGroupCall.chatName || '?'}
|
||||
size="2xl"
|
||||
className="relative shadow-2xl"
|
||||
/>
|
||||
</div>
|
||||
<h2 className="text-2xl text-white font-semibold mb-2 text-center break-words w-full max-w-full">
|
||||
{incomingGroupCall.chatName}
|
||||
|
||||
Reference in New Issue
Block a user