407 lines
15 KiB
PHP
407 lines
15 KiB
PHP
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Executive Evaluation Report - {{ $interview->candidate_name }} | SingleLogin</title>
|
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
<link href="https://fonts.googleapis.com/css2?family=Instrument+Sans:wght@400;500;600;700&family=Outfit:wght@500;600;700;800&family=Fira+Code:wght@400;500&display=swap" rel="stylesheet">
|
|
|
|
<style>
|
|
:root {
|
|
--primary: #0f172a;
|
|
--accent: #6366f1;
|
|
--text-dark: #0f172a;
|
|
--text-muted: #64748b;
|
|
--card-bg: #f8fafc;
|
|
--border: #e2e8f0;
|
|
}
|
|
|
|
* {
|
|
box-sizing: border-box;
|
|
margin: 0;
|
|
padding: 0;
|
|
}
|
|
|
|
body {
|
|
font-family: 'Instrument Sans', sans-serif;
|
|
background-color: #f1f5f9;
|
|
color: var(--text-dark);
|
|
line-height: 1.5;
|
|
padding: 40px 20px;
|
|
}
|
|
|
|
.report-container {
|
|
max-width: 900px;
|
|
margin: 0 auto;
|
|
background: white;
|
|
border-radius: 16px;
|
|
box-shadow: 0 20px 40px rgba(0,0,0,0.08);
|
|
border: 1px solid var(--border);
|
|
padding: 40px;
|
|
position: relative;
|
|
}
|
|
|
|
.header-bar {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: flex-start;
|
|
border-bottom: 2px solid var(--accent);
|
|
padding-bottom: 20px;
|
|
margin-bottom: 24px;
|
|
}
|
|
|
|
.brand-title {
|
|
font-family: 'Outfit', sans-serif;
|
|
font-size: 1.6rem;
|
|
font-weight: 800;
|
|
color: var(--primary);
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 10px;
|
|
}
|
|
|
|
.report-badge {
|
|
background: rgba(99,102,241,0.1);
|
|
color: var(--accent);
|
|
font-size: 0.75rem;
|
|
font-weight: 700;
|
|
padding: 4px 12px;
|
|
border-radius: 999px;
|
|
text-transform: uppercase;
|
|
}
|
|
|
|
.meta-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(4, 1fr);
|
|
gap: 16px;
|
|
background: var(--card-bg);
|
|
border-radius: 12px;
|
|
padding: 16px;
|
|
border: 1px solid var(--border);
|
|
margin-bottom: 28px;
|
|
}
|
|
|
|
.meta-item label {
|
|
display: block;
|
|
font-size: 0.7rem;
|
|
text-transform: uppercase;
|
|
font-weight: 700;
|
|
color: var(--text-muted);
|
|
margin-bottom: 4px;
|
|
}
|
|
|
|
.meta-item span {
|
|
font-weight: 700;
|
|
font-size: 0.9rem;
|
|
color: var(--primary);
|
|
}
|
|
|
|
.score-grid {
|
|
display: grid;
|
|
grid-template-columns: 1fr 1fr;
|
|
gap: 20px;
|
|
margin-bottom: 28px;
|
|
}
|
|
|
|
.score-card {
|
|
background: var(--card-bg);
|
|
border: 1px solid var(--border);
|
|
border-radius: 14px;
|
|
padding: 20px;
|
|
position: relative;
|
|
}
|
|
|
|
.score-val {
|
|
font-family: 'Outfit', sans-serif;
|
|
font-size: 2.4rem;
|
|
font-weight: 800;
|
|
margin-top: 6px;
|
|
}
|
|
|
|
.section-heading {
|
|
font-family: 'Outfit', sans-serif;
|
|
font-size: 1.1rem;
|
|
font-weight: 700;
|
|
color: var(--primary);
|
|
margin-bottom: 12px;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
}
|
|
|
|
.audit-table {
|
|
width: 100%;
|
|
border-collapse: collapse;
|
|
margin-bottom: 28px;
|
|
font-size: 0.8rem;
|
|
}
|
|
|
|
.audit-table th {
|
|
background: #f1f5f9;
|
|
color: var(--text-muted);
|
|
font-weight: 700;
|
|
text-align: left;
|
|
padding: 10px;
|
|
border-bottom: 1px solid var(--border);
|
|
}
|
|
|
|
.audit-table td {
|
|
padding: 10px;
|
|
border-bottom: 1px solid #edf2f7;
|
|
}
|
|
|
|
.code-box {
|
|
background: #0f172a;
|
|
color: #38bdf8;
|
|
border-radius: 12px;
|
|
padding: 18px;
|
|
font-family: 'Fira Code', monospace;
|
|
font-size: 0.8rem;
|
|
white-space: pre-wrap;
|
|
margin-bottom: 20px;
|
|
max-height: 300px;
|
|
overflow-y: auto;
|
|
}
|
|
|
|
.output-box {
|
|
background: #050811;
|
|
color: #34d399;
|
|
border-radius: 10px;
|
|
padding: 14px;
|
|
font-family: 'Fira Code', monospace;
|
|
font-size: 0.75rem;
|
|
white-space: pre-wrap;
|
|
margin-bottom: 28px;
|
|
}
|
|
|
|
.print-btn {
|
|
position: fixed;
|
|
bottom: 30px;
|
|
right: 30px;
|
|
background: var(--accent);
|
|
color: white;
|
|
border: none;
|
|
padding: 14px 28px;
|
|
border-radius: 999px;
|
|
font-weight: 700;
|
|
font-size: 0.9rem;
|
|
box-shadow: 0 10px 25px rgba(99,102,241,0.4);
|
|
cursor: pointer;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
z-index: 100;
|
|
}
|
|
|
|
@media print {
|
|
body {
|
|
background: white;
|
|
padding: 0;
|
|
}
|
|
.report-container {
|
|
box-shadow: none;
|
|
border: none;
|
|
max-width: 100%;
|
|
padding: 0;
|
|
}
|
|
.print-btn {
|
|
display: none;
|
|
}
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
|
|
<button onclick="window.print()" class="print-btn">
|
|
📥 Download / Print Executive PDF Report
|
|
</button>
|
|
|
|
<div class="report-container">
|
|
<!-- Header -->
|
|
<div class="header-bar">
|
|
<div>
|
|
<div class="brand-title">
|
|
⚡ SingleLogin Enterprise Assessment
|
|
</div>
|
|
<div style="font-size: 0.8rem; color: var(--text-muted); margin-top: 4px;">
|
|
Candidate Technical Competency & Behavioral Audit Report
|
|
</div>
|
|
</div>
|
|
|
|
<div style="text-align: right;">
|
|
<span class="report-badge">Executive Summary</span>
|
|
<div style="font-size: 0.7rem; color: var(--text-muted); margin-top: 6px;">
|
|
Report ID: RPT-{{ $interview->submission_unique_id }}
|
|
</div>
|
|
<div style="font-size: 0.7rem; color: var(--text-muted);">
|
|
Date: {{ now()->format('M d, Y - H:i:s T') }}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Meta Grid -->
|
|
<div class="meta-grid">
|
|
<div class="meta-item">
|
|
<label>Candidate Name</label>
|
|
<span>{{ $interview->candidate_name }}</span>
|
|
</div>
|
|
<div class="meta-item">
|
|
<label>Email Address</label>
|
|
<span style="font-size: 0.8rem;">{{ $interview->candidate_email }}</span>
|
|
</div>
|
|
<div class="meta-item">
|
|
<label>Language & Tech</label>
|
|
<span>{{ strtoupper($interview->language) }}</span>
|
|
</div>
|
|
<div class="meta-item">
|
|
<label>Assessment Status</label>
|
|
<span style="color: {{ $interview->status === 'completed' ? '#10b981' : ($interview->status === 'blocked' ? '#ef4444' : '#6366f1') }};">
|
|
{{ strtoupper($interview->status) }}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Scores Summary Grid -->
|
|
<div class="score-grid">
|
|
<!-- Behavioral Integrity Score -->
|
|
<div class="score-card" style="border-left: 5px solid {{ $integrityColor }};">
|
|
<div style="font-size: 0.75rem; font-weight: 700; color: var(--text-muted); text-transform: uppercase;">
|
|
🛡️ Behavioral Integrity Rating
|
|
</div>
|
|
<div class="score-val" style="color: {{ $integrityColor }};">
|
|
{{ $integrityScore }}%
|
|
</div>
|
|
<div style="font-size: 0.8rem; font-weight: 700; color: {{ $integrityColor }}; margin-top: 4px;">
|
|
{{ $integrityLabel }}
|
|
</div>
|
|
<div style="font-size: 0.7rem; color: var(--text-muted); margin-top: 6px;">
|
|
Recorded Violations: <strong>{{ count($logs) }} incident(s)</strong>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Technical Score -->
|
|
<div class="score-card" style="border-left: 5px solid #6366f1;">
|
|
<div style="font-size: 0.75rem; font-weight: 700; color: var(--text-muted); text-transform: uppercase;">
|
|
💻 Technical Code Competency
|
|
</div>
|
|
<div class="score-val" style="color: #6366f1;">
|
|
{{ $codeScore }} / 100
|
|
</div>
|
|
<div style="font-size: 0.8rem; font-weight: 700; color: #6366f1; margin-top: 4px;">
|
|
{{ $codeScore >= 80 ? 'Strong Technical Match' : ($codeScore >= 50 ? 'Moderate Competency' : 'Needs Further Review') }}
|
|
</div>
|
|
<div style="font-size: 0.7rem; color: var(--text-muted); margin-top: 6px;">
|
|
Solution Code: <strong>{{ !empty($interview->submitted_code) ? 'Submitted' : 'Pending' }}</strong>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Proctoring Violation Metrics & Breakdown -->
|
|
<div class="section-heading">
|
|
🔍 Behavioral Audit & Proctoring Incident Breakdown
|
|
</div>
|
|
<div style="display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px; margin-bottom: 20px;">
|
|
<div style="background: var(--card-bg); padding: 12px; border-radius: 10px; border: 1px solid var(--border); text-align: center;">
|
|
<div style="font-size: 1.2rem; font-weight: 800; color: #ef4444;">{{ $tabSwitches }}</div>
|
|
<div style="font-size: 0.65rem; color: var(--text-muted); font-weight: 700;">Tab Switches</div>
|
|
</div>
|
|
<div style="background: var(--card-bg); padding: 12px; border-radius: 10px; border: 1px solid var(--border); text-align: center;">
|
|
<div style="font-size: 1.2rem; font-weight: 800; color: #f59e0b;">{{ $focusLosses }}</div>
|
|
<div style="font-size: 0.65rem; color: var(--text-muted); font-weight: 700;">Focus Lost</div>
|
|
</div>
|
|
<div style="background: var(--card-bg); padding: 12px; border-radius: 10px; border: 1px solid var(--border); text-align: center;">
|
|
<div style="font-size: 1.2rem; font-weight: 800; color: #38bdf8;">{{ $gazeAnomalies }}</div>
|
|
<div style="font-size: 0.65rem; color: var(--text-muted); font-weight: 700;">Gaze Anomalies</div>
|
|
</div>
|
|
<div style="background: var(--card-bg); padding: 12px; border-radius: 10px; border: 1px solid var(--border); text-align: center;">
|
|
<div style="font-size: 1.2rem; font-weight: 800; color: #818cf8;">{{ $pasteEvents }}</div>
|
|
<div style="font-size: 0.65rem; color: var(--text-muted); font-weight: 700;">Code Pastes</div>
|
|
</div>
|
|
</div>
|
|
|
|
@if(count($logs) > 0)
|
|
<table class="audit-table">
|
|
<thead>
|
|
<tr>
|
|
<th>Timestamp</th>
|
|
<th>Violation Category</th>
|
|
<th>Audit Details</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
@foreach($logs as $log)
|
|
<tr>
|
|
<td style="color: var(--text-muted);">{{ \Carbon\Carbon::parse($log['timestamp'])->format('H:i:s T') }}</td>
|
|
<td><strong>{{ strtoupper($log['type']) }}</strong></td>
|
|
<td>{{ $log['details'] ?? 'Incident flagged by proctoring engine.' }}</td>
|
|
</tr>
|
|
@endforeach
|
|
</tbody>
|
|
</table>
|
|
@else
|
|
<div style="background: rgba(16,185,129,0.1); color: #10b981; padding: 12px; border-radius: 10px; font-size: 0.8rem; font-weight: 600; margin-bottom: 28px;">
|
|
✅ Zero proctoring violations or malpractice detected during the session.
|
|
</div>
|
|
@endif
|
|
|
|
<!-- Code Solution Block -->
|
|
<div class="section-heading">
|
|
💻 Submitted Code Solution ({{ strtoupper($interview->submitted_language ?? $interview->language) }})
|
|
</div>
|
|
<div class="code-box">
|
|
{{ $interview->submitted_code ?? '// No code solution submitted by candidate.' }}
|
|
</div>
|
|
|
|
<!-- Code Output Block -->
|
|
<div class="section-heading">
|
|
🖥️ Engine Execution Stdout Output
|
|
</div>
|
|
<div class="output-box">
|
|
{{ $interview->code_output ?? 'No execution output recorded.' }}
|
|
</div>
|
|
|
|
<!-- Candidate Notes & Drawing Section -->
|
|
@if(!empty($interview->candidate_notes) || !empty($interview->candidate_drawing))
|
|
<div class="section-heading">
|
|
📝 Workspace Artifacts (Scratchpad Notes & Architecture Drawing)
|
|
</div>
|
|
<div style="background: var(--card-bg); border: 1px solid var(--border); border-radius: 12px; padding: 16px; margin-bottom: 28px;">
|
|
@if(!empty($interview->candidate_notes))
|
|
<div style="font-size: 0.75rem; font-weight: 700; color: var(--text-muted); margin-bottom: 6px;">CANDIDATE NOTES:</div>
|
|
<pre style="font-family: monospace; font-size: 0.8rem; background: white; padding: 10px; border-radius: 8px; border: 1px solid var(--border); margin-bottom: 12px;">{{ $interview->candidate_notes }}</pre>
|
|
@endif
|
|
|
|
@if(!empty($interview->candidate_drawing))
|
|
<div style="font-size: 0.75rem; font-weight: 700; color: var(--text-muted); margin-bottom: 6px;">CANDIDATE DRAWING DIAGRAM:</div>
|
|
<img src="{{ $interview->candidate_drawing }}" alt="Candidate Drawing" style="max-width: 100%; max-height: 250px; border-radius: 8px; border: 1px solid var(--border);" />
|
|
@endif
|
|
</div>
|
|
@endif
|
|
|
|
<!-- Panel Sign-Off Block -->
|
|
<div style="border-top: 2px solid var(--border); padding-top: 20px; display: flex; justify-content: space-between; align-items: center;">
|
|
<div>
|
|
<div style="font-size: 0.7rem; font-weight: 700; color: var(--text-muted); text-transform: uppercase;">
|
|
HR & Lead Panel Approval
|
|
</div>
|
|
<div style="font-weight: 700; font-size: 0.9rem; color: var(--primary); margin-top: 4px;">
|
|
SingleLogin Enterprise HR Board
|
|
</div>
|
|
</div>
|
|
|
|
<div style="text-align: right;">
|
|
<div style="font-size: 0.7rem; font-weight: 700; color: var(--text-muted); text-transform: uppercase;">
|
|
Final Recommendation
|
|
</div>
|
|
<div style="font-weight: 800; font-size: 1rem; color: {{ $integrityScore >= 80 && $codeScore >= 50 ? '#10b981' : '#ef4444' }};">
|
|
{{ $integrityScore >= 80 && $codeScore >= 50 ? 'RECOMMENDED FOR HIRE' : 'REQUIRES FURTHER REVIEW / FLAGGED' }}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
</body>
|
|
</html>
|