sls/resources/views/components/interview/schedule-drawer.blade.php
kushal.saha 1541c8193e feat(interview): add candidate resume upload, lightbox viewer, and panelist email attachments
- Add resume file upload to schedule drawer with instant preview and validation
- Create resume lightbox modal viewer with background scroll lock and CV SVG icon
- Integrate CV tab into inspector panel with enlarge action and state 
- Attach candidate resume to panelist notification emails when 
- Fix Outlook RFC 5546 iTIP element mismatch and add table credentials copy button
2026-08-27 11:37:01 +00:00

263 lines
15 KiB
PHP

@props([
'interviewers' => [],
])
@php
$errorBag = session('errors') ?? (isset($errors) ? $errors : null) ?? new \Illuminate\Support\ViewErrorBag;
$hasInterviewErrors = $errorBag->any() && (
$errorBag->has('candidate_name') ||
$errorBag->has('candidate_email') ||
$errorBag->has('candidate_phone') ||
$errorBag->has('job_title') ||
$errorBag->has('round') ||
$errorBag->has('scheduled_at') ||
$errorBag->has('valid_hours') ||
$errorBag->has('language') ||
$errorBag->has('resume') ||
$errorBag->has('assigned_interviewers') ||
$errorBag->has('assigned_interviewers.*') ||
$errorBag->has('description')
);
@endphp
<x-drawer
id="create-interview-drawer"
title="Schedule Candidate Assessment"
description="Provision candidate temporary credentials, IDE access timeline, and assign review panelists."
width="lg"
class="{{ $hasInterviewErrors ? 'active' : '' }}"
>
<form action="{{ route('interview.store') }}" method="POST" enctype="multipart/form-data">
@csrf
@if($hasInterviewErrors)
<div class="mb-4 bg-rose-500/10 border border-rose-500/30 rounded-xl p-3.5 text-xs text-rose-300 flex items-start gap-2.5">
<i class="fa-solid fa-triangle-exclamation text-rose-400 mt-0.5 shrink-0 text-sm"></i>
<div class="flex-1">
<strong class="block font-semibold text-rose-200">Please correct the following errors:</strong>
<ul class="list-disc list-inside mt-1 space-y-0.5 text-[11px] text-rose-300">
@foreach($errorBag->all() as $errorMsg)
<li>{{ $errorMsg }}</li>
@endforeach
</ul>
</div>
</div>
@endif
<div class="space-y-4">
<div>
<x-label required>Candidate Name</x-label>
<x-input type="text" name="candidate_name" value="{{ old('candidate_name') }}" required placeholder="e.g. Jhon Doe" />
@if($errorBag->has('candidate_name'))
<p class="text-[11px] text-rose-400 mt-1 font-medium flex items-center gap-1">
<i class="fa-solid fa-circle-exclamation text-[10px]"></i> {{ $errorBag->first('candidate_name') }}
</p>
@endif
</div>
<div class="grid grid-cols-1 sm:grid-cols-2 gap-3.5">
<div>
<x-label required>Position / Job Title</x-label>
<x-input type="text" name="job_title" value="{{ old('job_title') }}" required placeholder="e.g. AIML Engineer" />
@if($errorBag->has('job_title'))
<p class="text-[11px] text-rose-400 mt-1 font-medium flex items-center gap-1">
<i class="fa-solid fa-circle-exclamation text-[10px]"></i> {{ $errorBag->first('job_title') }}
</p>
@endif
</div>
<div>
<x-label>Assessment Round</x-label>
<x-input type="text" name="round" value="{{ old('round', 'R1') }}" placeholder="e.g. R1, Technical" />
@if($errorBag->has('round'))
<p class="text-[11px] text-rose-400 mt-1 font-medium flex items-center gap-1">
<i class="fa-solid fa-circle-exclamation text-[10px]"></i> {{ $errorBag->first('round') }}
</p>
@endif
</div>
</div>
<div>
<x-label required>Candidate Email</x-label>
<x-input type="email" name="candidate_email" value="{{ old('candidate_email') }}" required placeholder="candidate@example.com" />
@if($errorBag->has('candidate_email'))
<p class="text-[11px] text-rose-400 mt-1 font-medium flex items-center gap-1">
<i class="fa-solid fa-circle-exclamation text-[10px]"></i> {{ $errorBag->first('candidate_email') }}
</p>
@endif
</div>
<div class="grid grid-cols-1 sm:grid-cols-2 gap-3.5">
<div>
<x-label required>Phone Number</x-label>
<x-input type="text" name="candidate_phone" value="{{ old('candidate_phone') }}" required placeholder="9XXXXXXXXX" />
@if($errorBag->has('candidate_phone'))
<p class="text-[11px] text-rose-400 mt-1 font-medium flex items-center gap-1">
<i class="fa-solid fa-circle-exclamation text-[10px]"></i> {{ $errorBag->first('candidate_phone') }}
</p>
@endif
</div>
<div>
<x-label required>Access Duration</x-label>
<x-select name="valid_hours" required>
<option value="1" @selected(old('valid_hours') === '1')>1 Hour</option>
<option value="2" @selected(old('valid_hours', '2') === '2')>2 Hours</option>
<option value="4" @selected(old('valid_hours') === '4')>4 Hours</option>
<option value="12" @selected(old('valid_hours') === '12')>12 Hours</option>
<option value="24" @selected(old('valid_hours') === '24')>24 Hours</option>
</x-select>
@if($errorBag->has('valid_hours'))
<p class="text-[11px] text-rose-400 mt-1 font-medium flex items-center gap-1">
<i class="fa-solid fa-circle-exclamation text-[10px]"></i> {{ $errorBag->first('valid_hours') }}
</p>
@endif
</div>
</div>
<div class="grid grid-cols-1 sm:grid-cols-2 gap-3.5">
<div>
<x-label for="scheduled_at">Start Time (Timeline)</x-label>
<x-input type="datetime-local" id="scheduled_at" name="scheduled_at" value="{{ old('scheduled_at', now()->format('Y-m-d\TH:i')) }}" class="bg-slate-900" />
@if($errorBag->has('scheduled_at'))
<p class="text-[11px] text-rose-400 mt-1 font-medium flex items-center gap-1">
<i class="fa-solid fa-circle-exclamation text-[10px]"></i> {{ $errorBag->first('scheduled_at') }}
</p>
@endif
</div>
<div>
<x-label required>Coding Language</x-label>
<x-select name="language" required>
<option value="python" @selected(old('language', 'python') === 'python')>Python 3</option>
<option value="cpp" @selected(old('language') === 'cpp')>C++ (GCC)</option>
<option value="c" @selected(old('language') === 'c')>C (GCC)</option>
<option value="java" @selected(old('language') === 'java')>Java 15</option>
<option value="php" @selected(old('language') === 'php')>PHP 8.2 / Laravel</option>
<option value="javascript" @selected(old('language') === 'javascript')>JavaScript (Node.js)</option>
</x-select>
@if($errorBag->has('language'))
<p class="text-[11px] text-rose-400 mt-1 font-medium flex items-center gap-1">
<i class="fa-solid fa-circle-exclamation text-[10px]"></i> {{ $errorBag->first('language') }}
</p>
@endif
</div>
</div>
<div>
<x-label>Candidate Resume (PDF, DOCX)</x-label>
<div class="space-y-2">
<!-- Dropzone / File Picker Container -->
<div
id="drawer-resume-dropzone"
onclick="document.getElementById('drawer_resume_input').click()"
class="border-2 border-dashed @if($errorBag->has('resume')) border-rose-500/80 bg-rose-500/5 @else border-slate-700/80 hover:border-indigo-500/50 bg-slate-900/60 hover:bg-slate-900 @endif rounded-xl p-3 text-center cursor-pointer transition-all flex flex-col items-center justify-center gap-1"
>
<div class="w-7 h-7 rounded-full bg-indigo-500/10 text-indigo-400 flex items-center justify-center text-xs">
<i class="fa-solid fa-cloud-arrow-up"></i>
</div>
<div class="text-xs text-slate-300 font-medium">
<span class="text-indigo-400 font-semibold">Click to upload</span> or drag and drop
</div>
<p class="text-[11px] text-slate-500 m-0">PDF, DOC, DOCX (Max 10MB)</p>
</div>
<input
type="file"
id="drawer_resume_input"
name="resume"
accept=".pdf,.doc,.docx,application/pdf,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document"
class="hidden"
onchange="handleDrawerResumeSelect(this)"
/>
<!-- Selected File Info & Preview Badge -->
<div
id="drawer-resume-selected"
class="hidden bg-slate-900 border border-slate-700/80 rounded-xl p-2.5 flex items-center justify-between gap-2"
>
<div class="flex items-center gap-2.5 min-w-0">
<div class="w-8 h-8 rounded-lg bg-indigo-500/20 text-indigo-400 flex items-center justify-center shrink-0">
<x-icons.cv class="w-4 h-4 text-indigo-400" />
</div>
<div class="min-w-0">
<p id="drawer-resume-filename" class="text-xs font-semibold text-white truncate m-0">resume.pdf</p>
<span id="drawer-resume-filesize" class="text-[10.5px] text-slate-400 font-mono">0 KB</span>
</div>
</div>
<div class="flex items-center gap-1 shrink-0">
<!-- Eye icon preview button -->
<button
type="button"
id="drawer-resume-preview-btn"
onclick="previewSelectedDrawerResume()"
title="Preview Resume"
class="w-7 h-7 rounded-md bg-indigo-500/20 hover:bg-indigo-500/30 text-indigo-300 hover:text-white flex items-center justify-center text-xs transition-colors cursor-pointer"
>
<i class="fa-solid fa-eye text-[11px]"></i>
</button>
<!-- Remove file button -->
<button
type="button"
onclick="clearSelectedDrawerResume()"
title="Remove file"
class="w-7 h-7 rounded-md bg-white/5 hover:bg-rose-500/20 text-slate-400 hover:text-rose-300 flex items-center justify-center text-xs transition-colors cursor-pointer"
>
<i class="fa-solid fa-trash text-[11px]"></i>
</button>
</div>
</div>
@if($errorBag->has('resume'))
<p class="text-[11px] text-rose-400 mt-1 font-medium flex items-center gap-1">
<i class="fa-solid fa-circle-exclamation text-[10px]"></i> {{ $errorBag->first('resume') }}
</p>
@endif
</div>
</div>
<div>
<x-label>Additional Instructions to candidate</x-label>
<textarea name="description" rows="2" class="w-full bg-slate-900 border @if($errorBag->has('description')) border-rose-500/80 focus:border-rose-500 @else border-slate-700/60 focus:border-indigo-500 @endif rounded-xl p-3 text-xs text-white placeholder-slate-500 focus:outline-none transition-colors" placeholder="Special requirements, interview topics, or instructions...">{{ old('description') }}</textarea>
@if($errorBag->has('description'))
<p class="text-[11px] text-rose-400 mt-1 font-medium flex items-center gap-1">
<i class="fa-solid fa-circle-exclamation text-[10px]"></i> {{ $errorBag->first('description') }}
</p>
@endif
</div>
<div>
<div class="flex justify-between items-center mb-1.5">
<x-label>Assign Internal Interviewers / Panelists</x-label>
</div>
<div class="space-y-2 max-h-35 overflow-y-auto bg-black/30 p-3 rounded-xl border @if($errorBag->has('assigned_interviewers')) border-rose-500/80 @else border-slate-700/60 @endif">
@foreach($interviewers as $usr)
<label class="flex items-center gap-2.5 text-xs text-white cursor-pointer hover:text-indigo-300 transition-colors py-0.5">
<input type="checkbox" name="assigned_interviewers[]" value="{{ $usr->id }}" @checked(in_array($usr->id, (array) old('assigned_interviewers', []))) class="accent-indigo-500 rounded w-4 h-4">
<span>{{ $usr->name }} <span class="text-slate-400 font-mono text-[11px]">({{ $usr->email }})</span></span>
</label>
@endforeach
</div>
@if($errorBag->has('assigned_interviewers'))
<p class="text-[11px] text-rose-400 mt-1 font-medium flex items-center gap-1">
<i class="fa-solid fa-circle-exclamation text-[10px]"></i> {{ $errorBag->first('assigned_interviewers') }}
</p>
@endif
@if($errorBag->has('assigned_interviewers.*'))
<p class="text-[11px] text-rose-400 mt-1 font-medium flex items-center gap-1">
<i class="fa-solid fa-circle-exclamation text-[10px]"></i> {{ $errorBag->first('assigned_interviewers.*') }}
</p>
@endif
</div>
</div>
<div class="flex justify-end gap-2.5 pt-6 mt-6 border-t border-white/10">
<x-button type="button" onclick="document.getElementById('create-interview-drawer').classList.remove('active')" variant="secondary">
Cancel
</x-button>
<x-button type="submit" variant="primary" icon="fa-solid fa-paper-plane" :showLoader="true" loadingText="Scheduling...">
Schedule
</x-button>
</div>
</form>
</x-drawer>