Interview module is refactored to use layouts and re-usable components along with domain components. Style remains identitical to previous design.
140 lines
6.6 KiB
PHP
140 lines
6.6 KiB
PHP
<x-layouts.interview
|
|
:title="$interview->candidate_name . ' - Assessment Review'"
|
|
data-interview-id="{{ $interview->id }}"
|
|
data-submission-id="{{ $interview->submission_unique_id }}"
|
|
>
|
|
@push('head-scripts')
|
|
<script src="https://unpkg.com/peerjs@1.5.2/dist/peerjs.min.js"></script>
|
|
<script src="//cdn.metered.ca/sdk/video/1.4.6/sdk.min.js"></script>
|
|
@endpush
|
|
|
|
<!-- Candidate Session Summary Card -->
|
|
<x-interview.candidate-header :interview="$interview" />
|
|
|
|
<!-- Video & Screen Call Panel -->
|
|
<x-card>
|
|
<x-slot:headerExtra>
|
|
<x-interview.call-controls :interview="$interview" />
|
|
</x-slot:headerExtra>
|
|
|
|
<!-- Video Grid -->
|
|
<div class="grid grid-cols-1 md:grid-cols-3 gap-3.5 p-5">
|
|
<!-- Candidate Video -->
|
|
<x-video-tile
|
|
id="cand-video-wrapper"
|
|
videoId="interviewer-cand-video"
|
|
placeholderId="cand-video-placeholder"
|
|
badgeText="Candidate video"
|
|
micStatusId="cand-mic-status"
|
|
camStatusId="cand-cam-status"
|
|
showZoom="true"
|
|
zoomInFn="zoomCandVideo(0.25)"
|
|
zoomOutFn="zoomCandVideo(-0.25)"
|
|
zoomResetFn="zoomCandVideo(0)"
|
|
avatarCircleId="modal-cand-avatar-circle"
|
|
avatarNameId="cand-avatar-name"
|
|
avatarTitle="{{ $interview->candidate_name }}"
|
|
initials="{{ $interview->candidate_initials }}">
|
|
<span id="cand-status-text">Waiting for candidate…</span>
|
|
</x-video-tile>
|
|
|
|
<!-- Candidate Shared Screen -->
|
|
<x-video-tile
|
|
id="screen-wrapper"
|
|
videoId="interviewer-screen-video"
|
|
placeholderId="screen-video-placeholder"
|
|
badgeText="Shared screen"
|
|
focused="true"
|
|
showZoom="true"
|
|
showFullscreen="true"
|
|
zoomInFn="zoomScreen(0.25)"
|
|
zoomOutFn="zoomScreen(-0.25)"
|
|
zoomResetFn="resetZoomScreen()"
|
|
fullscreenFn="toggleFullscreenScreen()"
|
|
containerId="screen-zoom-container"
|
|
avatarTitle="Candidate live screen"
|
|
initials="CD">
|
|
Waiting for candidate to share screen…
|
|
</x-video-tile>
|
|
|
|
<!-- Panelist Self -->
|
|
@php
|
|
$usrWords = preg_split('/\s+/', trim(Auth::user()->name ?? 'Interviewer'));
|
|
$usrInitials = count($usrWords) >= 2 ? strtoupper(substr($usrWords[0],0,1).substr(end($usrWords),0,1)) : strtoupper(substr(trim(Auth::user()->name ?? 'IV'),0,2));
|
|
@endphp
|
|
<x-video-tile
|
|
id="self-video-wrapper"
|
|
videoId="interviewer-self-video"
|
|
placeholderId="self-video-placeholder"
|
|
badgeText="Panelist self"
|
|
micStatusId="self-mic-status"
|
|
camStatusId="self-cam-status"
|
|
avatarTitle="{{ Auth::user()->name ?? 'Interviewer' }}"
|
|
initials="{{ $usrInitials }}">
|
|
Panelist (self)
|
|
</x-video-tile>
|
|
</div>
|
|
|
|
<!-- Multi-Party Panelist Video Grid -->
|
|
<div id="panelist-mesh-grid" class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-3.5 px-5 pb-5"></div>
|
|
</x-card>
|
|
|
|
<!-- Inspector Panel (Tabs & Audit Log / Live Chat) -->
|
|
<x-card>
|
|
<div class="inline-flex gap-1 p-1 bg-[#0d1220] border border-[#1b2233] rounded-[10px] mx-5 mt-4">
|
|
<x-tab-button id="tab-btn-code" tabKey="code" active="true" icon="fa-solid fa-code" onclick="switchIdeTab('code')">Live IDE code</x-tab-button>
|
|
<x-tab-button id="tab-btn-notes" tabKey="notes" active="false" icon="fa-solid fa-note-sticky" onclick="switchIdeTab('notes')">Candidate notepad</x-tab-button>
|
|
<x-tab-button id="tab-btn-drawing" tabKey="drawing" active="false" icon="fa-solid fa-pen" onclick="switchIdeTab('drawing')">Candidate drawing</x-tab-button>
|
|
<x-tab-button id="tab-btn-recordings" tabKey="recordings" active="false" icon="fa-solid fa-film" onclick="switchIdeTab('recordings')">Saved recordings</x-tab-button>
|
|
<x-tab-button id="tab-btn-screenshots" tabKey="screenshots" active="false" icon="fa-solid fa-image" onclick="switchIdeTab('screenshots')">Tab switch screenshots</x-tab-button>
|
|
</div>
|
|
|
|
<div class="grid grid-cols-1 lg:grid-cols-5 gap-4 p-5">
|
|
<!-- Left 3 Cols: Tab Content Panes -->
|
|
<div class="lg:col-span-3">
|
|
<x-interview.tabs.code-tab />
|
|
<x-interview.tabs.notes-tab />
|
|
<x-interview.tabs.drawing-tab />
|
|
<x-interview.tabs.recordings-tab />
|
|
<x-interview.tabs.screenshots-tab />
|
|
</div>
|
|
|
|
<!-- Right 2 Cols: Audit Log & Chat -->
|
|
<div class="lg:col-span-2">
|
|
<h3 class="text-[12.5px] font-semibold text-white mb-2.5 flex items-center gap-2 m-0">
|
|
Proctoring logs
|
|
</h3>
|
|
|
|
<x-audit-log id="modal-logs-display" :logs="$interview->proctor_logs ?? []" />
|
|
|
|
<div class="mt-4">
|
|
<h3 class="text-[12.5px] font-semibold text-white mb-2.5 flex items-center gap-2 m-0">
|
|
Live Chat
|
|
</h3>
|
|
<x-chat-panel id="interviewer-chat-history" class="mb-2.5" :warnings="$interview->warnings ?? []" :candidateName="$interview->candidate_name" />
|
|
<div class="flex gap-2">
|
|
<input type="text" id="warning-input" placeholder="Type message to candidate…" onkeydown="if(event.key==='Enter') sendSilentWarning()" class="flex-1 bg-[#0d1220] border border-[#232b3d] rounded-lg px-3 py-2 text-white text-xs outline-none focus:border-[rgba(75,130,247,0.35)] placeholder-[#5b637a]">
|
|
<x-button onclick="sendSilentWarning()" variant="primary" icon="fa-solid fa-paper-plane">Send</x-button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</x-card>
|
|
|
|
<!-- SOS Cheating Alert Modal -->
|
|
<x-interview.sos-modal />
|
|
|
|
@push('scripts')
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
openReviewModal(
|
|
{{ $interview->id }},
|
|
"{{ addslashes($interview->candidate_name) }}",
|
|
"{{ $interview->submission_unique_id }}",
|
|
{{ request('join_call') == '1' ? 'true' : 'false' }}
|
|
);
|
|
});
|
|
</script>
|
|
@endpush
|
|
</x-layouts.interview>
|