121 lines
3.4 KiB
PHP
121 lines
3.4 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Http\Controllers;
|
|
|
|
use App\Http\Requests\Screening\UpdateScreeningRequest;
|
|
use App\Models\Category;
|
|
use App\Models\Screening;
|
|
use App\Services\ActivityLogger;
|
|
use Illuminate\Http\RedirectResponse;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Arr;
|
|
use Inertia\Inertia;
|
|
use Inertia\Response;
|
|
|
|
final class ScreeningController extends Controller
|
|
{
|
|
/**
|
|
* Create a new screening session for the authenticated user.
|
|
*/
|
|
public function store(Request $request): RedirectResponse
|
|
{
|
|
$screening = Screening::create([
|
|
'user_id' => auth()->id(),
|
|
]);
|
|
|
|
ActivityLogger::log('screening_started', auth()->id());
|
|
|
|
return redirect()->route('screening.show', $screening);
|
|
}
|
|
|
|
/**
|
|
* Display the screening questionnaire.
|
|
*/
|
|
public function show(Screening $screening): Response
|
|
{
|
|
return Inertia::render('Screening/Show', [
|
|
'screening' => $screening,
|
|
'questions' => array_values(config('screening.questions')),
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Save screening answers and redirect to result.
|
|
*/
|
|
public function update(UpdateScreeningRequest $request, Screening $screening): RedirectResponse
|
|
{
|
|
$validated = $request->validated();
|
|
|
|
$this->saveAnswers($screening, Arr::get($validated, 'answers'));
|
|
$this->calculateAndUpdateScore($screening, Arr::get($validated, 'answers'));
|
|
|
|
ActivityLogger::log('screening_completed', auth()->id(), metadata: ['score' => $screening->score, 'passed' => $screening->passed]);
|
|
|
|
return redirect()->route('screening.result', $screening);
|
|
}
|
|
|
|
/**
|
|
* Display the screening result with available categories.
|
|
*/
|
|
public function result(Screening $screening): Response
|
|
{
|
|
return Inertia::render('Screening/Result', [
|
|
'screening' => $screening,
|
|
'passed' => $screening->passed,
|
|
'score' => $screening->score,
|
|
'totalQuestions' => count(config('screening.questions')),
|
|
'categories' => $screening->passed ? Category::orderBy('sort_order')->get(['id', 'name']) : [],
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Save screening answers to the database using upsert pattern.
|
|
*/
|
|
private function saveAnswers(Screening $screening, array $answers): void
|
|
{
|
|
foreach ($answers as $questionNumber => $value) {
|
|
$screening->answers()->updateOrCreate(
|
|
[
|
|
'screening_id' => $screening->id,
|
|
'question_number' => (int) $questionNumber,
|
|
],
|
|
[
|
|
'value' => $value,
|
|
]
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Calculate the score and update the screening record.
|
|
*/
|
|
private function calculateAndUpdateScore(Screening $screening, array $answers): void
|
|
{
|
|
$score = $this->calculateScore($answers);
|
|
$passed = $score >= config('screening.passing_score', 5);
|
|
|
|
$screening->update([
|
|
'score' => $score,
|
|
'passed' => $passed,
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Calculate the total score from the answers.
|
|
*/
|
|
private function calculateScore(array $answers): int
|
|
{
|
|
$score = 0;
|
|
|
|
foreach ($answers as $value) {
|
|
if ($value === 'yes') {
|
|
$score++;
|
|
}
|
|
}
|
|
|
|
return $score;
|
|
}
|
|
}
|