- integrate spatie/icalendar-generator for candidate & panelist .ics invitations (RSVP & 15m alerts)
- add StoreInterviewRequest, ScheduleInterviewDto, and invitation/reminder queued actions
- add migration for job_title, round, description, and reminder_sent_at on interviews table
- style datetime-local picker indicators to pure white on dark input backgrounds
- support button loading spinners with :showLoader="true" and loadingText
- auto-open schedule drawer on validation failure with inline @error alerts and old() bindings
89 lines
3.4 KiB
PHP
89 lines
3.4 KiB
PHP
<?php
|
|
|
|
namespace App\DTOs\Interview;
|
|
|
|
use App\Http\Requests\Interview\StoreInterviewRequest;
|
|
use Carbon\Carbon;
|
|
use Illuminate\Contracts\Support\Arrayable;
|
|
use JsonSerializable;
|
|
|
|
class ScheduleInterviewDto implements Arrayable, JsonSerializable
|
|
{
|
|
/**
|
|
* @param array<int> $assignedInterviewers
|
|
*/
|
|
public function __construct(
|
|
public readonly string $candidateName,
|
|
public readonly string $candidateEmail,
|
|
public readonly string $candidatePhone,
|
|
public readonly string $jobTitle,
|
|
public readonly string $round,
|
|
public readonly ?Carbon $scheduledAt,
|
|
public readonly int $validHours,
|
|
public readonly string $language,
|
|
public readonly array $assignedInterviewers = [],
|
|
public readonly ?string $description = null,
|
|
) {}
|
|
|
|
public static function fromRequest(StoreInterviewRequest $request): self
|
|
{
|
|
$scheduledAt = $request->filled('scheduled_at')
|
|
? Carbon::parse($request->input('scheduled_at'))
|
|
: now();
|
|
|
|
return new self(
|
|
candidateName: trim($request->input('candidate_name')),
|
|
candidateEmail: strtolower(trim($request->input('candidate_email'))),
|
|
candidatePhone: trim($request->input('candidate_phone')),
|
|
jobTitle: trim($request->input('job_title', 'Software Engineer')),
|
|
round: trim($request->input('round', 'R1')) ?: 'R1',
|
|
scheduledAt: $scheduledAt,
|
|
validHours: (int) $request->input('valid_hours', 2),
|
|
language: $request->input('language', 'python'),
|
|
assignedInterviewers: array_map('intval', (array) $request->input('assigned_interviewers', [])),
|
|
description: $request->filled('description') ? trim($request->input('description')) : null,
|
|
);
|
|
}
|
|
|
|
public static function fromArray(array $data): self
|
|
{
|
|
$scheduledAt = isset($data['scheduled_at'])
|
|
? ($data['scheduled_at'] instanceof Carbon ? $data['scheduled_at'] : Carbon::parse($data['scheduled_at']))
|
|
: now();
|
|
|
|
return new self(
|
|
candidateName: trim($data['candidate_name'] ?? ''),
|
|
candidateEmail: strtolower(trim($data['candidate_email'] ?? '')),
|
|
candidatePhone: trim($data['candidate_phone'] ?? ''),
|
|
jobTitle: trim($data['job_title'] ?? 'Software Engineer'),
|
|
round: trim($data['round'] ?? 'R1') ?: 'R1',
|
|
scheduledAt: $scheduledAt,
|
|
validHours: (int) ($data['valid_hours'] ?? 2),
|
|
language: $data['language'] ?? 'python',
|
|
assignedInterviewers: array_map('intval', (array) ($data['assigned_interviewers'] ?? [])),
|
|
description: isset($data['description']) && filled($data['description']) ? trim($data['description']) : null,
|
|
);
|
|
}
|
|
|
|
public function toArray(): array
|
|
{
|
|
return [
|
|
'candidate_name' => $this->candidateName,
|
|
'candidate_email' => $this->candidateEmail,
|
|
'candidate_phone' => $this->candidatePhone,
|
|
'job_title' => $this->jobTitle,
|
|
'round' => $this->round,
|
|
'scheduled_at' => $this->scheduledAt?->toDateTimeString(),
|
|
'valid_hours' => $this->validHours,
|
|
'language' => $this->language,
|
|
'assigned_interviewers' => $this->assignedInterviewers,
|
|
'description' => $this->description,
|
|
];
|
|
}
|
|
|
|
public function jsonSerialize(): array
|
|
{
|
|
return $this->toArray();
|
|
}
|
|
}
|