fix issue

This commit is contained in:
subhajit 2026-08-03 13:46:39 +05:30
parent e3e1e8aaf5
commit 3b82f4c453

View File

@ -1069,14 +1069,25 @@ class CandRingtoneEngine {
let candidateDeclinedOrLeftCall = false;
let pendingOffer = null;
let candRingTimer = null;
let latestCallStartedAt = null;
function getCallSessionKey(timestamp) {
return 'handled_call_' + interviewId + '_' + (timestamp || latestCallStartedAt || 'active');
}
function triggerCandidateRing(offer = null, callStartedAt = null) {
if (isCandidateCallConnected) return;
if (latestCallStatus === 'ended' || latestCallStatus === 'idle') return;
if (candidateDeclinedOrLeftCall) {
if (callStartedAt) latestCallStartedAt = callStartedAt;
const sessionKey = getCallSessionKey(callStartedAt);
const isHandled = sessionStorage.getItem(sessionKey) === 'handled';
if (isHandled || candidateDeclinedOrLeftCall) {
showCandidateJoinOption();
return;
}
if (offer) pendingOffer = offer;
const badge = document.getElementById('call-status-badge');
@ -1105,6 +1116,8 @@ function declineCandidateCall() {
clearTimeout(candRingTimer);
candRingTimer = null;
}
const sessionKey = getCallSessionKey();
sessionStorage.setItem(sessionKey, 'handled');
const modal = document.getElementById('candidate-incoming-modal');
if (modal) {
modal.style.opacity = '0';
@ -1120,6 +1133,8 @@ function stopCandidateRing() {
clearTimeout(candRingTimer);
candRingTimer = null;
}
const sessionKey = getCallSessionKey();
sessionStorage.setItem(sessionKey, 'handled');
const modal = document.getElementById('candidate-incoming-modal');
if (modal) {
modal.style.opacity = '0';
@ -1154,6 +1169,9 @@ function showCandidateJoinOption() {
}
async function acceptCandidateCall() {
const sessionKey = getCallSessionKey();
sessionStorage.setItem(sessionKey, 'handled');
candidateDeclinedOrLeftCall = false;
candRingtone.stop();
if (candRingTimer) {
@ -1201,25 +1219,41 @@ function showCandidateJoinOption() {
badge.style.color = '#34d399';
}
// Push candidate camera & microphone tracks to active WebRTC peer connection
if (localMediaStream && activeCallInstance && activeCallInstance.peerConnection) {
localMediaStream.getTracks().forEach(track => {
const senders = activeCallInstance.peerConnection.getSenders();
const sender = senders.find(s => s.track && s.track.kind === track.kind);
if (sender) {
sender.replaceTrack(track).catch(e => {});
} else {
try { activeCallInstance.peerConnection.addTrack(track, localMediaStream); } catch(e) {}
}
});
// Dual 2-Way Connection: Answer incoming call AND establish connection to interviewer peer
const stream = localMediaStream || new MediaStream();
if (activeCallInstance) {
try { activeCallInstance.answer(stream); } catch(e) {}
}
// Signal candidate ready via WebRTC BroadcastChannel
callSigChannel.postMessage({ type: 'candidate_ready', sender: 'candidate' });
if (pendingOffer) {
await handleInterviewerOffer(pendingOffer);
pendingOffer = null;
}
// Automatically capture candidate system screenshot on call start (if screenshot feature enabled)
// Call interviewer peer directly if interviewer registered
if (peerInstance) {
const interviewerPeerId = 'interviewer_' + interviewId;
try {
const outCall = peerInstance.call(interviewerPeerId, stream);
if (outCall) {
outCall.on('stream', remoteStream => {
const remoteVideo = document.getElementById('interviewer-video');
const placeholder = document.getElementById('interviewer-video-placeholder');
if (remoteVideo) {
remoteVideo.srcObject = remoteStream;
remoteVideo.play().catch(e => console.log('Remote video play error:', e));
}
if (placeholder) placeholder.style.display = 'none';
});
}
} catch(e) {}
}
// Automatically capture candidate system screenshot on call start (if enabled)
if (!hasCapturedCallStartScreenshot && isTabSwitchScreenshotEnabled) {
hasCapturedCallStartScreenshot = true;
setTimeout(() => {
@ -1777,41 +1811,25 @@ function pollCandidateChat() {
return;
}
if (data.call_status === 'active') {
latestCallStatus = 'active';
if (!isCandidateCallConnected) {
if (candidateDeclinedOrLeftCall) {
showCandidateJoinOption();
} else {
triggerCandidateRing(null, data.call_started_at || null);
}
if (data.warnings && Array.isArray(data.warnings)) {
if (data.warnings.length === 0) {
chatHistory.innerHTML = '<div style="color: #94a3b8; font-style: italic; text-align: center; padding-top: 40px;">No messages yet. Send a message below.</div>';
return;
}
} else if (data.call_status === 'ended' || data.call_status === 'idle') {
latestCallStatus = data.call_status;
candidateDeclinedOrLeftCall = false;
candidateLeaveCall(true);
const badge = document.getElementById('call-status-badge');
if (badge) {
badge.innerText = 'CALL ENDED BY HOST';
badge.style.background = 'rgba(239,68,68,0.2)';
badge.style.color = '#fca5a5';
}
}
if (data.warnings && data.warnings.length > 0) {
let html = '';
data.warnings.forEach(w => {
const isInterviewer = w.sent_by !== null;
const senderName = isInterviewer ? (w.sender ? w.sender.name : 'Interviewer / Panelist') : 'You (Candidate)';
const badgeColor = isInterviewer ? '#6366f1' : '#38bdf8';
const bgColor = isInterviewer ? 'rgba(99,102,241,0.1)' : 'rgba(56,189,248,0.1)';
const bgColor = isInterviewer ? 'rgba(99,102,241,0.15)' : 'rgba(56,189,248,0.15)';
html += `<div style="margin-bottom:8px; background:${bgColor}; padding:8px 10px; border-radius:8px; border-left:3px solid ${badgeColor};">
html += `<div style="margin-bottom:8px; background:${bgColor}; padding:8px 10px; border-radius:8px; border-left:3px solid ${badgeColor}; text-align: left;">
<div style="display:flex; justify-content:space-between; align-items:center; margin-bottom:4px;">
<strong style="color:${badgeColor}; font-size:0.75rem;">${senderName}</strong>
<span style="font-size:0.65rem; color:#94a3b8;">${new Date(w.created_at || Date.now()).toLocaleTimeString()}</span>
</div>
<div style="color: #ffffff !important; font-size:0.85rem; font-weight:500; line-height:1.4;">${w.message}</div>
<div style="color: #ffffff !important; font-size:0.85rem; font-weight:500; line-height:1.4; word-break: break-word;">${w.message}</div>
</div>`;
});
chatHistory.innerHTML = html;
@ -1820,7 +1838,7 @@ function pollCandidateChat() {
})
.catch(() => {});
}
setInterval(pollCandidateChat, 1000);
setInterval(pollCandidateChat, 600);
pollCandidateChat();
function sendCandidateMessage() {
@ -1982,23 +2000,41 @@ function saveCanvasDrawing(force = false) {
if (data.call_status === 'active') {
latestCallStatus = 'active';
if (data.call_started_at) latestCallStartedAt = data.call_started_at;
if (!hasCapturedCallStartScreenshot && isTabSwitchScreenshotEnabled) {
hasCapturedCallStartScreenshot = true;
setTimeout(() => {
captureAndUploadTabScreenshot('call_start');
}, 1200);
}
if (!isCandidateCallConnected && !candidateDeclinedOrLeftCall) {
triggerCandidateRing(null, data.call_started_at);
const sessionKey = getCallSessionKey(data.call_started_at);
const isHandledInSession = sessionStorage.getItem(sessionKey) === 'handled';
if (!isCandidateCallConnected) {
if (isHandledInSession || candidateDeclinedOrLeftCall) {
showCandidateJoinOption();
} else {
triggerCandidateRing(null, data.call_started_at);
}
}
} else if (data.call_status === 'ended' || data.call_status === 'idle') {
latestCallStatus = data.call_status;
hasCapturedCallStartScreenshot = false;
lastRungCallStartedAt = null;
candidateDeclinedOrLeftCall = false;
candRingtone.stop();
if (candRingTimer) clearTimeout(candRingTimer);
isCandidateCallConnected = false;
// Clear session storage handled keys for ended/idle call sessions
for (let i = sessionStorage.length - 1; i >= 0; i--) {
const key = sessionStorage.key(i);
if (key && key.startsWith('handled_call_' + interviewId)) {
sessionStorage.removeItem(key);
}
}
const modal = document.getElementById('candidate-incoming-modal');
if (modal) {
modal.style.opacity = '0';
@ -2018,7 +2054,7 @@ function saveCanvasDrawing(force = false) {
}
})
.catch(() => {});
}, 1000);
}, 800);
</script>
</body>
</html>