-
🎙️ ${labelName}
-
|
+
+ ${labelName}
+ |
@@ -477,7 +475,13 @@ export function addOrUpdateCandidateInterviewerTile(peerId, stream, labelName =
camIcon.title = camOnVal ? 'Camera On' : 'Camera Off';
}
if (placeholderEl) {
- placeholderEl.style.display = camOnVal ? 'none' : 'flex';
+ if (camOnVal) {
+ placeholderEl.classList.add('hidden');
+ placeholderEl.classList.remove('flex');
+ } else {
+ placeholderEl.classList.remove('hidden');
+ placeholderEl.classList.add('flex');
+ }
}
}
@@ -492,7 +496,7 @@ export function addOrUpdateCandidateInterviewerTile(peerId, stream, labelName =
const badge = document.getElementById('call-status-badge');
if (badge) {
- badge.innerText = '🟢 CALL CONNECTED (LIVE)';
+ badge.innerHTML = '
CALL LIVE';
badge.style.background = 'rgba(16,185,129,0.3)';
badge.style.color = '#34d399';
}
@@ -516,11 +520,11 @@ export function removeCandidateInterviewerTile(peerId) {
const badge = document.getElementById('call-status-badge');
if (badge) {
if (latestCallStatus === 'ended') {
- badge.innerText = 'CALL ENDED BY HOST';
+ badge.innerText = 'CALL ENDED';
badge.style.background = 'rgba(239,68,68,0.2)';
badge.style.color = '#fca5a5';
} else {
- badge.innerText = 'READY (Waiting for Interviewer)';
+ badge.innerText = 'READY';
badge.style.background = 'rgba(16,185,129,0.2)';
badge.style.color = '#34d399';
}
@@ -550,7 +554,7 @@ export function triggerCandidateRing(offer = null, callStartedAt = null) {
const badge = document.getElementById('call-status-badge');
if (badge) {
- badge.innerText = '🔔 INCOMING CALL... RINGING';
+ badge.innerHTML = '
INCOMING CALL... RINGING';
badge.style.background = 'rgba(234,179,8,0.3)';
badge.style.color = '#fde047';
}
@@ -618,7 +622,7 @@ export function showCandidateJoinOption() {
}
const badge = document.getElementById('call-status-badge');
if (badge) {
- badge.innerText = '📞 CALL IN PROGRESS';
+ badge.innerText = 'CALL IN PROGRESS';
badge.style.background = 'rgba(59,130,246,0.3)';
badge.style.color = '#93c5fd';
}
@@ -626,7 +630,7 @@ export function showCandidateJoinOption() {
if (joinBtn) {
joinBtn.style.display = 'block';
joinBtn.disabled = false;
- joinBtn.innerText = '🟢 📞 Call in Progress • Join Call Now';
+ joinBtn.innerHTML = '
Join Call Now';
}
}
@@ -679,7 +683,7 @@ export async function acceptCandidateCall() {
const badge = document.getElementById('call-status-badge');
if (badge) {
- badge.innerText = '🟢 CALL CONNECTED (LIVE)';
+ badge.innerText = 'CALL CONNECTED';
badge.style.background = 'rgba(16,185,129,0.3)';
badge.style.color = '#34d399';
}
@@ -791,7 +795,7 @@ export function candidateLeaveCall(isEndedByHost = false) {
}
} else {
if (joinBtn) {
- joinBtn.innerText = '🟢 📞 Rejoin Call Now';
+ joinBtn.innerHTML = '
Rejoin Call Now';
joinBtn.style.display = 'block';
joinBtn.disabled = false;
}
@@ -1088,9 +1092,10 @@ export function toggleMic() {
audioTracks[0].enabled = isCandidateMicEnabled;
const btn = document.getElementById('toggle-mic-btn');
if (btn) {
- btn.innerText = isCandidateMicEnabled ? '🎤 Mic On' : '🔇 Mic Muted';
+ btn.innerHTML = `
${isCandidateMicEnabled ? 'Mic On' : 'Mic Off'}`;
btn.style.background = isCandidateMicEnabled ? 'rgba(16,185,129,0.2)' : 'rgba(239,68,68,0.2)';
btn.style.borderColor = isCandidateMicEnabled ? '#10b981' : '#ef4444';
+ btn.className = `flex-1 py-2 px-2 text-xs font-semibold rounded-lg ${isCandidateMicEnabled ? 'bg-emerald-500/20 border-emerald-500 text-emerald-300 hover:bg-emerald-500/30' : 'bg-red-500/20 border-red-500 text-red-300 hover:bg-red-500/30'} border transition-all cursor-pointer flex items-center justify-center gap-1.5`;
}
const icon = document.getElementById('cand-self-mic-icon');
if (icon) {
@@ -1111,9 +1116,10 @@ export function toggleCam() {
videoTracks[0].enabled = isCandidateCamEnabled;
const btn = document.getElementById('toggle-cam-btn');
if (btn) {
- btn.innerText = isCandidateCamEnabled ? '📷 Cam On' : '🚫 Cam Off';
+ btn.innerHTML = `
${isCandidateCamEnabled ? 'Cam On' : 'Cam Off'}`;
btn.style.background = isCandidateCamEnabled ? 'rgba(16,185,129,0.2)' : 'rgba(239,68,68,0.2)';
btn.style.borderColor = isCandidateCamEnabled ? '#10b981' : '#ef4444';
+ btn.className = `flex-1 py-2 px-2 text-xs font-semibold rounded-lg ${isCandidateCamEnabled ? 'bg-emerald-500/20 border-emerald-500 text-emerald-300 hover:bg-emerald-500/30' : 'bg-red-500/20 border-red-500 text-red-300 hover:bg-red-500/30'} border transition-all cursor-pointer flex items-center justify-center gap-1.5`;
}
if (avatarPlaceholder) avatarPlaceholder.style.display = isCandidateCamEnabled ? 'none' : 'flex';
}
diff --git a/resources/js/interview-call.js b/resources/js/interview-call.js
index a3baa1c..b8bdd93 100644
--- a/resources/js/interview-call.js
+++ b/resources/js/interview-call.js
@@ -362,8 +362,71 @@ export function updateScreenshotToggleBtnUI(enabled) {
}
}
-export function switchIdeTab(tab) {
- const tabs = ['code', 'notes', 'drawing', 'recordings', 'screenshots'];
+let currentInspectorTab = null;
+
+export function closeInspectorPanel() {
+ currentInspectorTab = null;
+ try {
+ if (currentInterviewId) {
+ sessionStorage.removeItem('interview_inspector_tab_' + currentInterviewId);
+ }
+ } catch(e) {}
+
+ const details = document.getElementById('inspector-details');
+ if (details) details.open = false;
+
+ const tabs = ['logs', 'code', 'notes', 'drawing', 'recordings', 'screenshots'];
+ tabs.forEach(t => {
+ const contentEl = document.getElementById(`tab-content-${t}`);
+ const btnEl = document.getElementById(`tab-btn-${t}`);
+ if (contentEl) contentEl.style.display = 'none';
+ if (btnEl) {
+ btnEl.classList.remove('bg-indigo-600', 'text-white');
+ btnEl.classList.add('text-slate-400', 'hover:bg-white/5');
+ }
+ });
+}
+
+export function switchIdeTab(tab, event = null) {
+ if (event) {
+ event.stopPropagation();
+ }
+
+ const details = document.getElementById('inspector-details');
+
+ // If user clicks the currently active open tab button, toggle it collapsed
+ if (currentInspectorTab === tab && details && details.open) {
+ closeInspectorPanel();
+ return;
+ }
+
+ currentInspectorTab = tab;
+ try {
+ if (currentInterviewId) {
+ sessionStorage.setItem('interview_inspector_tab_' + currentInterviewId, tab);
+ }
+ } catch(e) {}
+
+ if (details) details.open = true;
+
+ const tabs = ['logs', 'code', 'notes', 'drawing', 'recordings', 'screenshots'];
+ const tabMeta = {
+ logs: { title: 'Proctoring Logs', icon: 'fa-solid fa-shield-halved' },
+ notes: { title: 'Candidate Notepad', icon: 'fa-solid fa-note-sticky' },
+ drawing: { title: 'Candidate Drawing Board', icon: 'fa-solid fa-pen' },
+ recordings: { title: 'Saved Video Recordings', icon: 'fa-solid fa-film' },
+ screenshots: { title: 'Tab Switch Screenshots', icon: 'fa-solid fa-image' },
+ code: { title: 'Candidate Code', icon: 'fa-solid fa-code' }
+ };
+
+ const floatingTitle = document.getElementById('inspector-floating-text');
+ const floatingIcon = document.getElementById('inspector-floating-icon');
+
+ if (tabMeta[tab]) {
+ if (floatingTitle) floatingTitle.innerText = tabMeta[tab].title;
+ if (floatingIcon) floatingIcon.className = `${tabMeta[tab].icon} text-indigo-400`;
+ }
+
tabs.forEach(t => {
const contentEl = document.getElementById(`tab-content-${t}`);
const btnEl = document.getElementById(`tab-btn-${t}`);
@@ -372,16 +435,26 @@ export function switchIdeTab(tab) {
}
if (btnEl) {
if (t === tab) {
- btnEl.classList.add('bg-indigo-600', 'text-white', 'border-indigo-500');
- btnEl.classList.remove('bg-white/5', 'text-slate-400', 'border-slate-700/60');
+ btnEl.classList.add('bg-indigo-600', 'text-white');
+ btnEl.classList.remove('text-slate-400', 'hover:bg-white/5');
} else {
- btnEl.classList.remove('bg-indigo-600', 'text-white', 'border-indigo-500');
- btnEl.classList.add('bg-white/5', 'text-slate-400', 'border-slate-700/60');
+ btnEl.classList.remove('bg-indigo-600', 'text-white');
+ btnEl.classList.add('text-slate-400', 'hover:bg-white/5');
}
}
});
}
+// Click outside to dismiss floating inspector details
+if (typeof document !== 'undefined') {
+ document.addEventListener('click', function(e) {
+ const details = document.getElementById('inspector-details');
+ if (details && details.open && !details.contains(e.target)) {
+ closeInspectorPanel();
+ }
+ });
+}
+
export function triggerIncomingCallRing(callData, isRealtimeBroadcast = false) {
if (!callData || !callData.id) return;
if (typeof document !== 'undefined' && document.body && document.body.dataset.interviewId) return;
@@ -609,7 +682,24 @@ export function openReviewModal(id, name, uid, autoJoinCall = false) {
if (reviewModal) reviewModal.classList.add('active');
resetZoomScreen();
- switchIdeTab('code');
+ if (document.getElementById('inspector-content-container')) {
+ let savedInspectorTab = null;
+ try {
+ savedInspectorTab = sessionStorage.getItem('interview_inspector_tab_' + id);
+ } catch(e) {}
+
+ if (savedInspectorTab) {
+ switchIdeTab(savedInspectorTab);
+ } else {
+ closeInspectorPanel();
+ }
+ } else if (document.getElementById('tab-btn-logs')) {
+ switchIdeTab('logs');
+ } else if (document.getElementById('tab-btn-notes')) {
+ switchIdeTab('notes');
+ } else {
+ switchIdeTab('code');
+ }
updateCandidateStatusIcons(false, false, false);
initInterviewerSigChannel();
@@ -783,6 +873,9 @@ export function pollReviewData() {
const screenPlace = document.getElementById('screen-video-placeholder');
if (screenVid) screenVid.srcObject = null;
if (screenPlace) screenPlace.style.display = 'flex';
+ if (typeof window.updateScreenShareLayout === 'function') {
+ window.updateScreenShareLayout(false);
+ }
panelistMeshTiles.forEach((_, pid) => {
removePanelistTile(pid);
@@ -957,7 +1050,7 @@ export function pollReviewData() {
const badgeLabel = isCand ? 'Candidate' : 'Panelist';
const badgeClass = isCand ? 'bg-sky-500/20 text-sky-300 border-sky-500/30' : 'bg-indigo-500/20 text-indigo-300 border-indigo-500/30';
- chatHtml += `
+ chatHtml += `
@@ -969,11 +1062,11 @@ export function pollReviewData() {
${w.message}
`;
});
- chatHistory.className = 'bg-[#0d1220] border border-[#1b2233] rounded-[9px] h-[150px] overflow-y-auto p-3 flex flex-col gap-2 mb-2.5';
+ chatHistory.className = 'bg-[#0d1220] border border-[#1b2233] rounded-[9px] h-full overflow-y-auto p-3 flex flex-col gap-2 mb-2.5';
chatHistory.innerHTML = chatHtml;
chatHistory.scrollTop = chatHistory.scrollHeight;
} else {
- chatHistory.className = 'bg-[#0d1220] border border-[#1b2233] rounded-[9px] h-[150px] overflow-y-auto p-3 mb-2.5';
+ chatHistory.className = 'bg-[#0d1220] border border-[#1b2233] rounded-[9px] h-full overflow-y-auto p-3 mb-2.5';
chatHistory.innerHTML = '
No chat history. Send a message below.
';
}
}
@@ -1419,7 +1512,7 @@ export function addOrUpdatePanelistTile(peerId, stream, name = 'Panelist', micOn
if (!tile) {
tile = document.createElement('div');
tile.id = 'panelist-tile-' + peerId;
- tile.className = 'video-tile relative aspect-[16/11] bg-[#0d1220] border border-[#1b2233] rounded-[10px] overflow-hidden flex flex-col items-center justify-center transition-all';
+ tile.className = 'video-tile relative w-[220px] aspect-video shrink-0 bg-[#0d1220] border border-[#1b2233] rounded-[10px] overflow-hidden flex flex-col items-center justify-center transition-all';
tile.innerHTML = `
@@ -1513,6 +1606,18 @@ export async function initInterviewerPeer() {
console.log('[WebRTC Screen] Attaching incoming screen stream to video element');
const screenVid = document.getElementById('interviewer-screen-video');
const placeholder = document.getElementById('screen-video-placeholder');
+ if (typeof window.updateScreenShareLayout === 'function') {
+ window.updateScreenShareLayout(true);
+ }
+ if (screenStream && screenStream.getVideoTracks) {
+ screenStream.getVideoTracks().forEach(track => {
+ track.onended = () => {
+ if (typeof window.updateScreenShareLayout === 'function') {
+ window.updateScreenShareLayout(false);
+ }
+ };
+ });
+ }
if (screenVid && screenStream) {
screenVid.muted = true;
if (screenVid.srcObject !== screenStream) {
@@ -2355,6 +2460,7 @@ if (typeof window !== 'undefined') {
window.closeReviewModal = closeReviewModal;
window.sendSilentWarning = sendSilentWarning;
window.setCurrentInterviewId = setCurrentInterviewId;
+ window.closeInspectorPanel = closeInspectorPanel;
// Attach listeners
['click', 'keydown', 'touchstart'].forEach(evt => {
diff --git a/resources/views/components/audit-log.blade.php b/resources/views/components/audit-log.blade.php
index 21000a0..3e047f2 100644
--- a/resources/views/components/audit-log.blade.php
+++ b/resources/views/components/audit-log.blade.php
@@ -2,7 +2,7 @@
'logs' => [],
])
-
merge(['class' => 'bg-[#0d1220] border border-[#1b2233] rounded-[9px] max-h-[260px] overflow-y-auto']) }}>
+
twMerge(['class' => 'bg-[#0d1220] border border-[#1b2233] rounded-[9px] overflow-y-auto']) }}>
@if(is_array($logs) && count($logs) > 0)
@foreach($logs as $log)
merge(['class' => $classes]) }}>
+