Попытка

This commit is contained in:
Халимов Рустам
2026-03-11 16:38:35 +03:00
parent 0f89b21dd4
commit 0a38d5e6fd
2 changed files with 26 additions and 43 deletions

View File

@@ -1,18 +0,0 @@
# Server
PORT=3001
JWT_SECRET=your-secure-random-secret-key-here
CORS_ORIGINS=http://localhost:5173,http://localhost:3000
# Database (PostgreSQL)
DATABASE_URL=postgresql://user:password@localhost:5432/vortex
# Message encryption (AES-256-GCM) — 64-char hex key (32 bytes)
# Generate with: node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
# WARNING: if you lose this key, all encrypted messages become unreadable!
ENCRYPTION_KEY=
# TURN server for voice/video calls (optional, recommended for production)
# Install coturn: sudo apt install coturn
# TURN_URL=turn:your-domain.com:3478
# TURN_SECRET=your-coturn-shared-secret
# STUN_URLS=stun:stun.l.google.com:19302,stun:stun1.l.google.com:19302

View File

@@ -1576,37 +1576,38 @@ export default function CallModal({ isOpen, onClose, targetUser, callType: initi
</div>
</>
)}
{/* === Main Content Area === */}
<div className="flex-1 flex flex-col relative overflow-hidden">
{/*
CRITICAL: Single stable remote video element.
We keep it always mounted so WebRTC srcObject is never lost
during transitions between voice and video modes.
*/}
<video
ref={remoteVideoRef}
autoPlay
playsInline
className={`
bg-black transition-all duration-500
${showVideoArea
? 'w-full h-full object-contain'
: 'w-0 h-0 opacity-0 absolute pointer-events-none'
}
`}
onContextMenu={(e) => { e.preventDefault(); setShowVolumeSlider(true); }}
/>
{showVideoArea ? (
{/* === Main Content Area === */}
<div className="flex-1 flex flex-col relative overflow-hidden bg-black min-h-[400px]">
{showVideoArea && (
<div
ref={videoContainerRef}
className="absolute inset-0 flex items-center justify-center bg-black"
className="absolute inset-0 flex items-center justify-center z-0"
>
{/* Placeholder shown when video track is not yet arrived or muted */}
<video
ref={remoteVideoRef}
autoPlay
playsInline
className="w-full h-full object-contain"
onContextMenu={(e) => { e.preventDefault(); setShowVolumeSlider(true); }}
/>
{/* Placeholder shown ONLY when track is not yet ready */}
{!hasRemoteVideo && (
<div className="absolute inset-0 flex flex-col items-center justify-center bg-zinc-900/50 backdrop-blur-sm z-10">
<div className="absolute inset-0 flex flex-col items-center justify-center bg-zinc-900 z-10">
<div className="relative mb-6">
<div className="absolute inset-0 rounded-full bg-vortex-500/20 animate-ping" />
{displayAvatar ? (
<img src={displayAvatar} alt="" className="relative w-32 h-32 rounded-full object-cover border-4 border-vortex-500/30" />
) : (
<div className="relative w-32 h-32 rounded-full bg-gradient-to-br from-vortex-500 to-purple-600 flex items-center justify-center text-white text-4xl font-bold border-4 border-vortex-500/30">
{initials}
</div>
)}
</div>
<VideoOff size={48} className="text-zinc-500 mb-2" />
<span className="text-sm text-zinc-500">{displayName}</span>
<span className="text-xl text-white font-medium mb-1">{displayName}</span>
<span className="text-sm text-zinc-500 animate-pulse">Соединение...</span>
</div>
)}