diff --git a/app/Models/Interview.php b/app/Models/Interview.php
index 2c158c3..a81f96b 100644
--- a/app/Models/Interview.php
+++ b/app/Models/Interview.php
@@ -101,4 +101,44 @@ public function isAssignedInterviewer($userId): bool
$interviewers = array_map('strval', (array) $this->assigned_interviewers);
return in_array((string) $userId, $interviewers, true);
}
+
+ /**
+ * Get computed initials for candidate (e.g. "John Doe" -> "JD").
+ */
+ public function getCandidateInitialsAttribute(): string
+ {
+ $parts = preg_split('/\s+/', trim($this->candidate_name ?? ''));
+ if (count($parts) >= 2) {
+ return strtoupper(substr($parts[0], 0, 1) . substr(end($parts), 0, 1));
+ }
+ $nameStr = trim($this->candidate_name ?? '');
+ return strtoupper(substr($nameStr, 0, 1) . (strlen($nameStr) > 1 ? substr($nameStr, -1) : ''));
+ }
+
+ /**
+ * Get proctoring alert metrics summary.
+ */
+ public function getProctorMetricsAttribute(): array
+ {
+ $logs = $this->proctor_logs ?? [];
+ return [
+ 'tab_switches' => count(array_filter($logs, fn($l) => ($l['type'] ?? '') === 'tab_switch')),
+ 'focus_lost' => count(array_filter($logs, fn($l) => ($l['type'] ?? '') === 'focus_lost')),
+ 'gaze_alerts' => count(array_filter($logs, fn($l) => in_array($l['type'] ?? '', ['gaze_anomaly', 'gaze_fixed_staring', 'looking_away']))),
+ 'lower_gaze' => count(array_filter($logs, fn($l) => ($l['type'] ?? '') === 'gaze_lower_device')),
+ 'question_repeat' => count(array_filter($logs, fn($l) => in_array($l['type'] ?? '', ['question_repeat_lower', 'question_repetition']))),
+ 'external_ai' => count(array_filter($logs, fn($l) => ($l['type'] ?? '') === 'external_ai_detected')),
+ 'paste_events' => count(array_filter($logs, fn($l) => ($l['type'] ?? '') === 'paste_event')),
+ 'total_incidents' => count($logs),
+ ];
+ }
+
+ /**
+ * Format timeline string: "M d, H:i – H:i".
+ */
+ public function getFormattedTimelineAttribute(): string
+ {
+ $start = $this->scheduled_at ?? $this->created_at;
+ return $start->format('M d, H:i') . ' – ' . $this->expires_at->format('H:i');
+ }
}
diff --git a/resources/views/components/alert.blade.php b/resources/views/components/alert.blade.php
new file mode 100644
index 0000000..8e13cf5
--- /dev/null
+++ b/resources/views/components/alert.blade.php
@@ -0,0 +1,32 @@
+@props([
+ 'variant' => 'info', // success, danger, warning, info
+ 'icon' => null,
+])
+
+@php
+ $variants = [
+ 'success' => 'bg-emerald-500/15 border-emerald-500/30 text-emerald-300',
+ 'danger' => 'bg-red-500/15 border-red-500/30 text-red-300',
+ 'warning' => 'bg-amber-500/15 border-amber-500/30 text-amber-300',
+ 'info' => 'bg-sky-500/15 border-sky-500/30 text-sky-300',
+ ];
+
+ $defaultIcons = [
+ 'success' => 'fa-solid fa-circle-check',
+ 'danger' => 'fa-solid fa-triangle-exclamation',
+ 'warning' => 'fa-solid fa-circle-exclamation',
+ 'info' => 'fa-solid fa-circle-info',
+ ];
+
+ $selectedIcon = $icon ?? ($defaultIcons[$variant] ?? $defaultIcons['info']);
+ $variantClass = $variants[$variant] ?? $variants['info'];
+@endphp
+
+
merge(['class' => "flex items-start gap-2.5 px-4 py-3 border rounded-xl text-xs font-medium {$variantClass}"]) }}>
+ @if($selectedIcon)
+
+ @endif
+
+ {{ $slot }}
+
+
diff --git a/resources/views/components/input.blade.php b/resources/views/components/input.blade.php
new file mode 100644
index 0000000..0a18193
--- /dev/null
+++ b/resources/views/components/input.blade.php
@@ -0,0 +1,29 @@
+@props([
+ 'type' => 'text',
+ 'name' => null,
+ 'value' => null,
+ 'placeholder' => null,
+ 'required' => false,
+ 'disabled' => false,
+ 'size' => 'md', // sm, md, lg
+])
+
+@php
+ $sizeClasses = [
+ 'sm' => 'px-2.5 py-1.5 text-xs',
+ 'md' => 'px-3 py-2 text-xs',
+ 'lg' => 'px-3.5 py-2.5 text-sm',
+ ];
+
+ $classes = 'w-full bg-white/5 border border-slate-700/60 rounded-lg text-white outline-none focus:border-indigo-500 focus:ring-1 focus:ring-indigo-500/40 placeholder-slate-500 transition-colors disabled:opacity-50 disabled:cursor-not-allowed ' . ($sizeClasses[$size] ?? $sizeClasses['md']);
+@endphp
+
+merge(['class' => $classes]) }}
+/>
diff --git a/resources/views/components/interview/admin-settings-card.blade.php b/resources/views/components/interview/admin-settings-card.blade.php
new file mode 100644
index 0000000..a4eb9fd
--- /dev/null
+++ b/resources/views/components/interview/admin-settings-card.blade.php
@@ -0,0 +1,71 @@
+
+
+
+
+ Global Admin Proctoring & System Settings
+
+
Master control panel for candidate assessment rules, system screen capturing, and module toggles
+
+
+ ADMIN CONTROL PANEL
+
+
+
+
+
diff --git a/resources/views/components/interview/call-controls.blade.php b/resources/views/components/interview/call-controls.blade.php
new file mode 100644
index 0000000..c331795
--- /dev/null
+++ b/resources/views/components/interview/call-controls.blade.php
@@ -0,0 +1,40 @@
+@props([
+ 'interview',
+])
+
+
+
+
+
+
+
+
+
+ @if($interview->call_status === 'ended')
+
+ Call Ended
+
+ @elseif($interview->call_status === 'active')
+
+ Join Call
+
+ @else
+
+ Start Call
+
+ @endif
+
+
+
+ Record Call (Silent)
+
+
+
+
+
+ Leave Call
+
+
+
+
+
diff --git a/resources/views/components/interview/candidate-header.blade.php b/resources/views/components/interview/candidate-header.blade.php
new file mode 100644
index 0000000..f1086d1
--- /dev/null
+++ b/resources/views/components/interview/candidate-header.blade.php
@@ -0,0 +1,75 @@
+@props([
+ 'interview',
+])
+
+
+
+
+
+ {{ $interview->candidate_initials }}
+
+
+
+
{{ $interview->candidate_name }}
+
+ Not Joined
+
+
+
{{ $interview->candidate_email }} · {{ $interview->candidate_phone }}
+
+
+
+
+ @if($interview->isExpired())
+
Expired
+ @elseif($interview->status === 'completed')
+
Completed
+ @elseif($interview->call_status === 'active')
+
Call in progress
+ @elseif($interview->isActiveTimeline())
+
Timeline live
+ @else
+
Scheduled
+ @endif
+
+
+
+
+
+ SOS auto-trigger
+
+
+
+
+
Password
+
PDF report
+
Block
+
+
+
+
+
+
+
+ Show submission details
+
+
+
+
Submission ID
+
{{ $interview->submission_unique_id }}
+
+
+
Temp Pass
+
{{ $interview->temp_password }}
+
+
+
Language
+
{{ $interview->language }}
+
+
+
Timeline
+
{{ $interview->formatted_timeline }}
+
+
+
+
diff --git a/resources/views/components/interview/candidate/drawing-modal.blade.php b/resources/views/components/interview/candidate/drawing-modal.blade.php
new file mode 100644
index 0000000..00620d0
--- /dev/null
+++ b/resources/views/components/interview/candidate/drawing-modal.blade.php
@@ -0,0 +1,19 @@
+
+
+
+ 🎨
+ Candidate Live Drawing Board
+
+
+
+
+
+
+
+
+
+
+
+ 🎨 Draw architecture / logic diagrams (Auto-synced to Interviewer)
+
+
diff --git a/resources/views/components/interview/candidate/ide-header.blade.php b/resources/views/components/interview/candidate/ide-header.blade.php
new file mode 100644
index 0000000..acbfdc0
--- /dev/null
+++ b/resources/views/components/interview/candidate/ide-header.blade.php
@@ -0,0 +1,48 @@
+@props([
+ 'interview',
+])
+
+
diff --git a/resources/views/components/interview/candidate/incoming-overlay.blade.php b/resources/views/components/interview/candidate/incoming-overlay.blade.php
new file mode 100644
index 0000000..08adc90
--- /dev/null
+++ b/resources/views/components/interview/candidate/incoming-overlay.blade.php
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
+ The interviewer panel has initiated a live 2-way call.
+
+
+
+
+
+
+
+
diff --git a/resources/views/components/interview/candidate/notepad-modal.blade.php b/resources/views/components/interview/candidate/notepad-modal.blade.php
new file mode 100644
index 0000000..446acf9
--- /dev/null
+++ b/resources/views/components/interview/candidate/notepad-modal.blade.php
@@ -0,0 +1,17 @@
+@props([
+ 'notes' => '',
+])
+
+
+
+
+ 📝
+ Candidate Notepad (Synced)
+
+
+
+
+
+ ✓ Auto-saved to interviewer portal
+
+
diff --git a/resources/views/components/interview/candidate/proctor-sidebar.blade.php b/resources/views/components/interview/candidate/proctor-sidebar.blade.php
new file mode 100644
index 0000000..96c515a
--- /dev/null
+++ b/resources/views/components/interview/candidate/proctor-sidebar.blade.php
@@ -0,0 +1,94 @@
+@props([
+ 'interview',
+])
+
+
diff --git a/resources/views/components/interview/candidate/terminal.blade.php b/resources/views/components/interview/candidate/terminal.blade.php
new file mode 100644
index 0000000..b2fd9c8
--- /dev/null
+++ b/resources/views/components/interview/candidate/terminal.blade.php
@@ -0,0 +1,7 @@
+
+
+ EXECUTION OUTPUT TERMINAL (STDOUT / STDERR)
+ Ready
+
+
// Press 'Run Code' to execute candidate solution live...
+
diff --git a/resources/views/components/interview/incoming-call-modal.blade.php b/resources/views/components/interview/incoming-call-modal.blade.php
new file mode 100644
index 0000000..29a813d
--- /dev/null
+++ b/resources/views/components/interview/incoming-call-modal.blade.php
@@ -0,0 +1,36 @@
+
+
+
+
+
+ ⚡ Incoming Assessment Call
+
+
+
+ Candidate Name
+
+
+
+ Initiated by Panelist
+
+
+
+ Another interviewer has started calling the candidate. Click Accept Call to join live, or Decline if busy.
+
+
+
+
+ Decline / Miss
+
+
+
+
+
diff --git a/resources/views/components/interview/navbar.blade.php b/resources/views/components/interview/navbar.blade.php
new file mode 100644
index 0000000..cc5afc4
--- /dev/null
+++ b/resources/views/components/interview/navbar.blade.php
@@ -0,0 +1,35 @@
+@props([
+ 'activeNav' => 'interview',
+])
+
+
diff --git a/resources/views/components/interview/proctor-badges.blade.php b/resources/views/components/interview/proctor-badges.blade.php
new file mode 100644
index 0000000..979fccf
--- /dev/null
+++ b/resources/views/components/interview/proctor-badges.blade.php
@@ -0,0 +1,39 @@
+@props([
+ 'metrics' => [],
+])
+
+@php
+ $tabSwitches = $metrics['tab_switches'] ?? 0;
+ $focusLost = $metrics['focus_lost'] ?? 0;
+ $gazeAlerts = $metrics['gaze_alerts'] ?? 0;
+ $lowerGaze = $metrics['lower_gaze'] ?? 0;
+ $questionRepeat = $metrics['question_repeat'] ?? 0;
+ $externalAi = $metrics['external_ai'] ?? 0;
+@endphp
+
+merge(['class' => 'flex flex-col gap-0.5 text-xs']) }}>
+
+ Tab Switches: {{ $tabSwitches }}
+
+
+ Focus Loss / Overlay: {{ $focusLost }}
+
+
+ Eye Gaze Anomaly: {{ $gazeAlerts }}
+
+ @if($lowerGaze > 0)
+
+ Lower Gaze (>10s): {{ $lowerGaze }}
+
+ @endif
+ @if($questionRepeat > 0)
+
+ Question Repetition: {{ $questionRepeat }}
+
+ @endif
+ @if($externalAi > 0)
+
+ @endif
+
diff --git a/resources/views/components/interview/report/artifacts-section.blade.php b/resources/views/components/interview/report/artifacts-section.blade.php
new file mode 100644
index 0000000..c73a1d7
--- /dev/null
+++ b/resources/views/components/interview/report/artifacts-section.blade.php
@@ -0,0 +1,55 @@
+@props([
+ 'interview',
+])
+
+@if(!empty($interview->candidate_notes) || !empty($interview->interviewer_notes) || !empty($interview->candidate_drawing) || (is_array($interview->formatted_recordings) && count($interview->formatted_recordings) > 0))
+
+ 📝 Workspace Artifacts, Evaluation Notes & Call Session Recordings
+
+
+ @if(!empty($interview->candidate_notes))
+
+ CANDIDATE NOTEPAD NOTES (UNIQUE ID SYNCED):
+
+
{{ $interview->candidate_notes }}
+ @endif
+
+ @if(!empty($interview->interviewer_notes))
+
+ INTERVIEWER EVALUATION NOTES (STORED BY UNIQUE ID):
+
+
{{ $interview->interviewer_notes }}
+ @endif
+
+ @if(!empty($interview->candidate_drawing))
+
+ CANDIDATE DRAWING DIAGRAM:
+
+

+ @endif
+
+ @if(is_array($interview->formatted_recordings) && count($interview->formatted_recordings) > 0)
+
+ 📹 STORED CALL SESSION RECORDINGS ({{ count($interview->formatted_recordings) }} RECORDINGS):
+ 📜 Scroll to view all
+
+
+ @foreach($interview->formatted_recordings as $displayIdx => $rec)
+
+
+
Recording #{{ count($interview->formatted_recordings) - $displayIdx }} ({{ $rec['created_at'] }})
+
+ 📥 Download MP4 Video
+
+
+
+
+ @endforeach
+
+ @endif
+
+@endif
diff --git a/resources/views/components/interview/report/audit-table.blade.php b/resources/views/components/interview/report/audit-table.blade.php
new file mode 100644
index 0000000..0e48f26
--- /dev/null
+++ b/resources/views/components/interview/report/audit-table.blade.php
@@ -0,0 +1,37 @@
+@props([
+ 'logs' => [],
+])
+
+@if(is_array($logs) && count($logs) > 0)
+
+
+
+
+ | Timestamp |
+ Violation Category |
+ Audit Details |
+
+
+
+ @foreach($logs as $log)
+
+ |
+ {{ isset($log['timestamp']) ? \Carbon\Carbon::parse($log['timestamp'])->format('H:i:s T') : '--:--:--' }}
+ |
+
+ {{ str_replace('_', ' ', $log['type'] ?? 'Violation') }}
+ |
+
+ {{ $log['details'] ?? 'Incident flagged by proctoring engine.' }}
+ |
+
+ @endforeach
+
+
+
+@else
+
+
+ Zero proctoring violations or malpractice detected during the session.
+
+@endif
diff --git a/resources/views/components/interview/report/code-section.blade.php b/resources/views/components/interview/report/code-section.blade.php
new file mode 100644
index 0000000..8cb4397
--- /dev/null
+++ b/resources/views/components/interview/report/code-section.blade.php
@@ -0,0 +1,21 @@
+@props([
+ 'code' => null,
+ 'output' => null,
+ 'language' => 'code',
+])
+
+
+
+ 💻 Submitted Code Solution ({{ strtoupper($language) }})
+
+
+{{ $code ?? '// No code solution submitted by candidate.' }}
+
+
+
+
+ 🖥️ Engine Execution Stdout Output
+
+
+{{ $output ?? 'No execution output recorded.' }}
+
diff --git a/resources/views/components/interview/report/header.blade.php b/resources/views/components/interview/report/header.blade.php
new file mode 100644
index 0000000..29ed349
--- /dev/null
+++ b/resources/views/components/interview/report/header.blade.php
@@ -0,0 +1,39 @@
+@props([
+ 'interview',
+])
+
+
+
+
+
+ Executive Assessment Performance Report
+
+
+
+
+
+
+
+
+
+ Candidate Technical Competency & Behavioral Audit Report
+
+
+
+
+
+ Executive Summary
+
+
+ Report ID: RPT-{{ $interview->submission_unique_id }}
+
+
+ Date: {{ now()->format('M d, Y - H:i:s T') }}
+
+
+
diff --git a/resources/views/components/interview/report/incident-grid.blade.php b/resources/views/components/interview/report/incident-grid.blade.php
new file mode 100644
index 0000000..23403f3
--- /dev/null
+++ b/resources/views/components/interview/report/incident-grid.blade.php
@@ -0,0 +1,43 @@
+@props([
+ 'metrics' => [],
+])
+
+@php
+ $tabSwitches = $metrics['tab_switches'] ?? 0;
+ $focusLosses = $metrics['focus_lost'] ?? 0;
+ $gazeAnomalies = $metrics['gaze_alerts'] ?? 0;
+ $pasteEvents = $metrics['paste_events'] ?? 0;
+ $lowerGaze = $metrics['lower_gaze'] ?? 0;
+ $questionRepeat = $metrics['question_repeat'] ?? 0;
+@endphp
+
+
+ 🔍 Behavioral Audit & Proctoring Incident Breakdown
+
+
+
diff --git a/resources/views/components/interview/report/meta-grid.blade.php b/resources/views/components/interview/report/meta-grid.blade.php
new file mode 100644
index 0000000..ca125b3
--- /dev/null
+++ b/resources/views/components/interview/report/meta-grid.blade.php
@@ -0,0 +1,32 @@
+@props([
+ 'interview',
+])
+
+@php
+ $statusColor = match($interview->status) {
+ 'completed' => 'text-emerald-600',
+ 'blocked' => 'text-red-600',
+ default => 'text-indigo-600',
+ };
+@endphp
+
+
+
+
+ {{ $interview->candidate_name }}
+
+
+
+ {{ $interview->candidate_email }}
+
+
+
+ {{ $interview->language }}
+
+
+
+
+
+
diff --git a/resources/views/components/interview/report/score-card.blade.php b/resources/views/components/interview/report/score-card.blade.php
new file mode 100644
index 0000000..31d152f
--- /dev/null
+++ b/resources/views/components/interview/report/score-card.blade.php
@@ -0,0 +1,46 @@
+@props([
+ 'integrityScore' => 100,
+ 'integrityLabel' => 'Optimal Candidate Trust',
+ 'integrityColor' => '#10b981',
+ 'incidentCount' => 0,
+ 'codeScore' => 0,
+ 'hasSubmittedCode' => false,
+])
+
+@php
+ $codeLabel = $codeScore >= 80 ? 'Strong Technical Match' : ($codeScore >= 50 ? 'Moderate Competency' : 'Needs Further Review');
+@endphp
+
+
+
+
+
+ 🛡️ Behavioral Integrity Rating
+
+
+
+ {{ $integrityLabel }}
+
+
+ Recorded Violations: {{ $incidentCount }} incident(s)
+
+
+
+
+
+
+ 💻 Technical Code Competency
+
+
+
+ {{ $codeLabel }}
+
+
+ Solution Code: {{ $hasSubmittedCode ? 'Submitted' : 'Pending' }}
+
+
+
diff --git a/resources/views/components/interview/report/signoff.blade.php b/resources/views/components/interview/report/signoff.blade.php
new file mode 100644
index 0000000..169092a
--- /dev/null
+++ b/resources/views/components/interview/report/signoff.blade.php
@@ -0,0 +1,23 @@
+@props([
+ 'recommended' => true,
+])
+
+
+
+
+ HR & Lead Panel Approval
+
+
+ SingleLogin Enterprise HR Board
+
+
+
+
+
+ Final Recommendation
+
+
+
+
diff --git a/resources/views/components/interview/schedule-modal.blade.php b/resources/views/components/interview/schedule-modal.blade.php
new file mode 100644
index 0000000..8c5af67
--- /dev/null
+++ b/resources/views/components/interview/schedule-modal.blade.php
@@ -0,0 +1,75 @@
+@props([
+ 'interviewers' => [],
+])
+
+
+
+
diff --git a/resources/views/components/interview/session-row.blade.php b/resources/views/components/interview/session-row.blade.php
new file mode 100644
index 0000000..34936e1
--- /dev/null
+++ b/resources/views/components/interview/session-row.blade.php
@@ -0,0 +1,89 @@
+@props([
+ 'interview',
+])
+
+@php
+ $metrics = $interview->proctor_metrics;
+@endphp
+
+
+
+
+
+ {{ $interview->candidate_name }}
+ {{ $interview->candidate_email }} • {{ $interview->candidate_phone }}
+
+
+ Temp Pass: {{ $interview->temp_password }}
+
+
+
+
+ |
+
+
+
+
+ {{ $interview->submission_unique_id }}
+
+ |
+
+
+
+ @if($interview->isExpired())
+ EXPIRED
+ @elseif($interview->status === 'completed')
+ COMPLETED
+ @elseif($interview->call_status === 'active')
+
+ @elseif($interview->isActiveTimeline())
+ TIMELINE LIVE
+ @else
+ SCHEDULED
+ @endif
+
+ Timeline: {{ $interview->formatted_timeline }}
+
+ |
+
+
+
+
+ {{ $interview->language }}
+
+ |
+
+
+
+
+ |
+
+
+
+
+ |
+
diff --git a/resources/views/components/interview/sos-modal.blade.php b/resources/views/components/interview/sos-modal.blade.php
new file mode 100644
index 0000000..9388c32
--- /dev/null
+++ b/resources/views/components/interview/sos-modal.blade.php
@@ -0,0 +1,13 @@
+
+
+ Violation details loading...
+
+
+
+ Acknowledge Alert
+
+
+ Acknowledge & Disable SOS
+
+
+
diff --git a/resources/views/components/interview/tabs/code-tab.blade.php b/resources/views/components/interview/tabs/code-tab.blade.php
new file mode 100644
index 0000000..22a1001
--- /dev/null
+++ b/resources/views/components/interview/tabs/code-tab.blade.php
@@ -0,0 +1,7 @@
+
+
Current code solution — visible even if candidate does not share screen
+
+
+
Execution stdout / stderr
+
+
diff --git a/resources/views/components/interview/tabs/drawing-tab.blade.php b/resources/views/components/interview/tabs/drawing-tab.blade.php
new file mode 100644
index 0000000..3955662
--- /dev/null
+++ b/resources/views/components/interview/tabs/drawing-tab.blade.php
@@ -0,0 +1,7 @@
+
+
Candidate live drawing / architecture diagram
+
+
![Candidate Drawing Board]()
+
No drawing data submitted by candidate yet.
+
+
diff --git a/resources/views/components/interview/tabs/notes-tab.blade.php b/resources/views/components/interview/tabs/notes-tab.blade.php
new file mode 100644
index 0000000..069386c
--- /dev/null
+++ b/resources/views/components/interview/tabs/notes-tab.blade.php
@@ -0,0 +1,4 @@
+
+
Candidate live notepad notes (auto-synced)
+
+
diff --git a/resources/views/components/interview/tabs/recordings-tab.blade.php b/resources/views/components/interview/tabs/recordings-tab.blade.php
new file mode 100644
index 0000000..a502d68
--- /dev/null
+++ b/resources/views/components/interview/tabs/recordings-tab.blade.php
@@ -0,0 +1,6 @@
+
+
Saved candidate video sessions (sorted by newest first)
+
+
No video recordings saved for this candidate yet.
+
+
diff --git a/resources/views/components/interview/tabs/screenshots-tab.blade.php b/resources/views/components/interview/tabs/screenshots-tab.blade.php
new file mode 100644
index 0000000..e54f06f
--- /dev/null
+++ b/resources/views/components/interview/tabs/screenshots-tab.blade.php
@@ -0,0 +1,9 @@
+
+
+
+
+
+
Coming Soon
+
Tab switch screenshot capturing and inspection is currently under maintenance.
+
+
diff --git a/resources/views/components/label.blade.php b/resources/views/components/label.blade.php
new file mode 100644
index 0000000..904db63
--- /dev/null
+++ b/resources/views/components/label.blade.php
@@ -0,0 +1,10 @@
+@props([
+ 'required' => false,
+])
+
+
diff --git a/resources/views/components/layouts/candidate.blade.php b/resources/views/components/layouts/candidate.blade.php
new file mode 100644
index 0000000..cda65ec
--- /dev/null
+++ b/resources/views/components/layouts/candidate.blade.php
@@ -0,0 +1,37 @@
+@props([
+ 'title' => 'Live Assessment Room',
+])
+
+
+
+
+
+
+
+ {{ $title }} | SingleLogin
+ @vite(['resources/css/app.css', 'resources/js/app.js'])
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ @stack('styles')
+ @stack('head-scripts')
+
+merge(['class' => "bg-[#080c14] text-white h-screen flex flex-col font-['Instrument_Sans',sans-serif] overflow-hidden antialiased select-none"]) }}>
+
+ {{ $slot }}
+
+ @stack('scripts')
+
+
diff --git a/resources/views/components/layouts/guest.blade.php b/resources/views/components/layouts/guest.blade.php
new file mode 100644
index 0000000..4210489
--- /dev/null
+++ b/resources/views/components/layouts/guest.blade.php
@@ -0,0 +1,32 @@
+@props([
+ 'title' => 'Candidate Portal',
+])
+
+
+
+
+
+
+
+ {{ $title }} | SingleLogin
+ @vite(['resources/css/app.css', 'resources/js/app.js'])
+
+
+
+
+
+ @stack('styles')
+ @stack('head-scripts')
+
+merge(['class' => "bg-[#0b0f19] text-white min-h-screen flex items-center justify-center p-4 relative overflow-hidden font-['Instrument_Sans',sans-serif] antialiased"]) }}>
+
+
+
+
+
+ {{ $slot }}
+
+
+ @stack('scripts')
+
+
diff --git a/resources/views/components/layouts/interview.blade.php b/resources/views/components/layouts/interview.blade.php
new file mode 100644
index 0000000..655d366
--- /dev/null
+++ b/resources/views/components/layouts/interview.blade.php
@@ -0,0 +1,57 @@
+@props([
+ 'title' => 'Candidate Live Assessment Portal',
+ 'activeNav' => 'interview',
+])
+
+
+
+
+
+
+
+ {{ $title }} | SingleLogin
+ @vite(['resources/css/app.css', 'resources/js/app.js'])
+
+
+
+
+
+
+
+ @stack('styles')
+ @stack('head-scripts')
+
+merge(['class' => "bg-[#0a0e17] text-white min-h-screen flex flex-col font-['Instrument_Sans',sans-serif] antialiased"]) }}>
+
+
+
+
+ @if(session('success'))
+
+ {{ session('success') }}
+
+ @endif
+
+ @if(session('error'))
+
+ {{ session('error') }}
+
+ @endif
+
+ {{ $slot }}
+
+
+
+
+
+
+
+ @stack('scripts')
+
+
diff --git a/resources/views/components/layouts/report.blade.php b/resources/views/components/layouts/report.blade.php
new file mode 100644
index 0000000..3ba7f0f
--- /dev/null
+++ b/resources/views/components/layouts/report.blade.php
@@ -0,0 +1,26 @@
+@props([
+ 'title' => 'Executive Evaluation Report',
+])
+
+
+
+
+
+
+ {{ $title }} | SingleLogin
+ @vite(['resources/css/app.css', 'resources/js/app.js'])
+
+
+
+
+
+ @stack('styles')
+ @stack('head-scripts')
+
+merge(['class' => "bg-slate-100 text-slate-900 leading-normal p-5 md:p-10 font-['Instrument_Sans',sans-serif] antialiased print:bg-white print:p-0 print:text-black"]) }}>
+
+ {{ $slot }}
+
+ @stack('scripts')
+
+
diff --git a/resources/views/components/select.blade.php b/resources/views/components/select.blade.php
new file mode 100644
index 0000000..5be7854
--- /dev/null
+++ b/resources/views/components/select.blade.php
@@ -0,0 +1,25 @@
+@props([
+ 'name' => null,
+ 'required' => false,
+ 'disabled' => false,
+ 'size' => 'md',
+])
+
+@php
+ $sizeClasses = [
+ 'sm' => 'px-2.5 py-1.5 text-xs',
+ 'md' => 'px-3 py-2 text-xs',
+ 'lg' => 'px-3.5 py-2.5 text-sm',
+ ];
+
+ $classes = 'w-full bg-slate-900 border border-slate-700/60 rounded-lg text-white outline-none focus:border-indigo-500 focus:ring-1 focus:ring-indigo-500/40 transition-colors disabled:opacity-50 disabled:cursor-not-allowed ' . ($sizeClasses[$size] ?? $sizeClasses['md']);
+@endphp
+
+
diff --git a/resources/views/interview/candidate_login.blade.php b/resources/views/interview/candidate_login.blade.php
index a83ae78..d1f947b 100644
--- a/resources/views/interview/candidate_login.blade.php
+++ b/resources/views/interview/candidate_login.blade.php
@@ -1,103 +1,40 @@
-
-
-
-
-
- Candidate Assessment Login | SingleLogin
- @vite(['resources/css/app.css', 'resources/js/app.js'])
-
-
-
-
-
-
-
-
-
+
+
+
+
⚡
-
Candidate Assessment Portal
-
Enter temporary login credentials provided by HR
+
Candidate Assessment Portal
+
Enter temporary login credentials provided by HR
@if(session('error'))
-
+
{{ session('error') }}
-
+
@endif
-
-
-
+
diff --git a/resources/views/interview/candidate_room.blade.php b/resources/views/interview/candidate_room.blade.php
index 6f739a5..7d18f09 100644
--- a/resources/views/interview/candidate_room.blade.php
+++ b/resources/views/interview/candidate_room.blade.php
@@ -1,430 +1,40 @@
-
-
-
-
-
-
-
Live Assessment Room - {{ $interview->candidate_name }} | SingleLogin
- @vite(['resources/css/app.css', 'resources/js/app.js'])
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
📝 Candidate Notepad (Synced)
-
-
-
-
- ✓ Auto-saved to interviewer portal
-
-
+
+
-
-
-
🎨 Candidate Live Drawing Board
-
-
-
-
-
-
-
-
-
-
- 🎨 Draw architecture / logic diagrams (Auto-synced to Interviewer)
-
-
+
-
-
+
+
-
-
+
+
-
-
-
// Press 'Run Code' to execute candidate solution live...
-
+
- @php
- $words = preg_split('/\s+/', trim($interview->candidate_name));
- if (count($words) >= 2) {
- $candInitials = strtoupper(substr($words[0], 0, 1) . substr(end($words), 0, 1));
- } else {
- $nameStr = trim($interview->candidate_name);
- $candInitials = strtoupper(substr($nameStr, 0, 1) . (strlen($nameStr) > 1 ? substr($nameStr, -1) : ''));
- }
- @endphp
-
-
-
+
+
-
-
+
+
-
-
-
-
- ⚡ INCOMING INTERVIEW CALL
-
-
-
- Interviewer Panel Calling...
-
-
-
- The interviewer panel has initiated a live 2-way call.
-
-
-
-
-
-
-
-
-
-
+ @push('scripts')
+
+
+ @endpush
+
diff --git a/resources/views/interview/expired.blade.php b/resources/views/interview/expired.blade.php
index b2ffdc9..0529b37 100644
--- a/resources/views/interview/expired.blade.php
+++ b/resources/views/interview/expired.blade.php
@@ -1,44 +1,12 @@
-
-
-
-
-
-
Assessment Access Expired | SingleLogin
- @vite(['resources/css/app.css', 'resources/js/app.js'])
-
-
-
-
-
-
-
-
⌛
-
Assessment Access Expired
-
- The temporary access window for {{ $interview->candidate_name }} expired on {{ $interview->expires_at->format('Y-m-d H:i T') }}.
+
+
+
⌛
+
Assessment Access Expired
+
+ The temporary access window for {{ $interview->candidate_name }} expired on {{ $interview->expires_at->format('Y-m-d H:i T') }}.
-
- Unique Submission ID:
{{ $interview->submission_unique_id }}
+
+ Unique Submission ID: {{ $interview->submission_unique_id }}
-
-
+
diff --git a/resources/views/interview/index.blade.php b/resources/views/interview/index.blade.php
index 4d46feb..414aff8 100644
--- a/resources/views/interview/index.blade.php
+++ b/resources/views/interview/index.blade.php
@@ -1,395 +1,48 @@
-
-
-
-
-
-
Candidate Live Assessment Portal | SingleLogin
- @vite(['resources/css/app.css', 'resources/js/app.js'])
-
-
-
-
-
-
-
-
+
+
+
-
-
-
-
-
-
-
-
Candidate Live Assessment Portal
-
Proctored IDE & Code Submissions
-
+
+
+
+
Live Interview Assessments
+
Temporary Candidate Access, Real-Time Proctored IDE, and Unique Code Records
-
-
+
+ Schedule Candidate Interview
+
+
-
- @if(session('success'))
-
- {{ session('success') }}
-
- @endif
-
-
-
-
-
-
- Global Admin Proctoring & System Settings
-
-
Master control panel for candidate assessment rules, system screen capturing, and module toggles
-
-
- ADMIN CONTROL PANEL
-
-
-
-
-
-
-
-
-
-
Live Interview Assessments
-
Temporary Candidate Access, Real-Time Proctored IDE, and Unique Code Records
-
-
-
- Schedule Candidate Interview
-
-
-
-
-
-
-
-
-
- | Candidate & Temp Pass |
- Unique Submission ID |
- Status & Validity |
- Language |
- Proctoring Alerts |
- Review & Actions |
+
+
+
+
+
+
+ | Candidate & Temp Pass |
+ Unique Submission ID |
+ Status & Validity |
+ Language |
+ Proctoring Alerts |
+ Review & Actions |
+
+
+
+ @forelse($interviews as $inv)
+
+ @empty
+
+ |
+ No candidate interview sessions found. Click "+ Schedule Candidate Interview" above to create one.
+ |
-
-
- @forelse($interviews as $inv)
- @php
- $logs = $inv->proctor_logs ?? [];
- $tabSwitches = count(array_filter($logs, fn($l) => ($l['type'] ?? '') === 'tab_switch'));
- $focusLost = count(array_filter($logs, fn($l) => ($l['type'] ?? '') === 'focus_lost'));
- $gazeAlerts = count(array_filter($logs, fn($l) => in_array($l['type'] ?? '', ['gaze_anomaly', 'gaze_fixed_staring'])));
- $lowerGaze = count(array_filter($logs, fn($l) => ($l['type'] ?? '') === 'gaze_lower_device'));
- $questionRepeat = count(array_filter($logs, fn($l) => in_array($l['type'] ?? '', ['question_repeat_lower', 'question_repetition'])));
- $externalAi = count(array_filter($logs, fn($l) => ($l['type'] ?? '') === 'external_ai_detected'));
- @endphp
-
-
-
- {{ $inv->candidate_name }}
- {{ $inv->candidate_email }} • {{ $inv->candidate_phone }}
-
-
- Temp Pass: {{ $inv->temp_password }}
-
-
-
-
- |
-
-
- {{ $inv->submission_unique_id }}
-
- |
-
- @if($inv->isExpired())
- EXPIRED
- @elseif($inv->status === 'completed')
- COMPLETED
- @elseif($inv->call_status === 'active')
-
- @elseif($inv->isActiveTimeline())
- TIMELINE LIVE
- @else
- SCHEDULED
- @endif
-
- Timeline: {{ ($inv->scheduled_at ?? $inv->created_at)->format('M d, H:i') }} – {{ $inv->expires_at->format('H:i') }}
-
- |
-
-
- {{ $inv->language }}
-
- |
-
-
-
- Tab Switches: {{ $tabSwitches }}
-
-
- Focus Loss / Overlay: {{ $focusLost }}
-
-
- Eye Gaze Anomaly: {{ $gazeAlerts }}
-
- @if($lowerGaze > 0)
-
- Lower Gaze (>10s): {{ $lowerGaze }}
-
- @endif
- @if($questionRepeat > 0)
-
- Question Repetition: {{ $questionRepeat }}
-
- @endif
- @if($externalAi > 0)
-
- @endif
-
- |
-
-
-
- |
-
- @empty
-
- |
- No candidate interview sessions found. Click "+ Schedule Candidate Interview" above to create one.
- |
-
- @endforelse
-
-
-
+ @endforelse
+
+
-
+
-
-
-
-
-
-
-
-
-
-
- ⚡ Incoming Assessment Call
-
-
-
- Candidate Name
-
-
-
- Initiated by Panelist
-
-
-
- Another interviewer has started calling the candidate. Click Accept Call to join live, or Decline if busy.
-
-
-
-
- Decline / Miss
-
-
-
-
-
-
-
-
-
+
+
diff --git a/resources/views/interview/report.blade.php b/resources/views/interview/report.blade.php
index 4b4121c..8b846fb 100644
--- a/resources/views/interview/report.blade.php
+++ b/resources/views/interview/report.blade.php
@@ -1,451 +1,53 @@
-
-
-
-
-
-
Executive Evaluation Report - {{ $interview->candidate_name }} | SingleLogin
-
-
-
-
-
-
-
-
-