improvements

This commit is contained in:
2026-02-19 14:32:42 +01:00
parent 78c51d55b5
commit f1824ff752
16 changed files with 1244 additions and 31 deletions

View File

@@ -8,12 +8,14 @@
use App\Models\Session;
use App\Services\ActivityLogger;
use App\Services\ScoringService;
use Barryvdh\DomPDF\Facade\Pdf;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Arr;
use Illuminate\Validation\ValidationException;
use Inertia\Inertia;
use Inertia\Response;
use Inertia\Response as InertiaResponse;
final class SessionController extends Controller
{
@@ -37,7 +39,7 @@ public function store(Request $request): RedirectResponse
/**
* Display the session questionnaire with category, question groups, questions, and existing answers.
*/
public function show(Session $session): Response
public function show(Session $session): InertiaResponse
{
$session->load('category', 'user');
@@ -51,14 +53,10 @@ public function show(Session $session): Response
$answers = $session->answers()->get()->keyBy('question_id');
$scoringService = new ScoringService;
$score = $scoringService->calculateScore($session);
return Inertia::render('Session/Show', [
'session' => $session,
'questionGroups' => $questionGroups,
'answers' => $answers,
'score' => $score,
]);
}
@@ -201,7 +199,7 @@ private function validateDetailsAnswer($question, $answer, array &$errors): void
/**
* Display the final session result.
*/
public function result(Session $session): Response
public function result(Session $session): InertiaResponse
{
$session->load('category');
@@ -212,4 +210,30 @@ public function result(Session $session): Response
'categoryName' => $session->category->name,
]);
}
/**
* Generate and download a PDF export of the completed session result.
*/
public function pdf(Session $session): Response
{
abort_unless($session->user_id === auth()->id(), 403);
abort_unless($session->status === 'completed', 403);
$session->load(['user', 'category', 'answers.question']);
$questionGroups = $session->category
->questionGroups()
->with(['questions' => fn ($q) => $q->orderBy('sort_order')])
->orderBy('sort_order')
->get();
ActivityLogger::log('session_pdf_downloaded', $session->user_id, sessionId: $session->id, categoryId: $session->category_id);
$pdf = Pdf::loadView('pdf.session-result', [
'session' => $session,
'questionGroups' => $questionGroups,
]);
return $pdf->download("go-no-go-{$session->id}.pdf");
}
}

View File

@@ -0,0 +1,40 @@
<?php
declare(strict_types=1);
namespace App\Jobs;
use App\Models\Session;
use App\Services\ActivityLogger;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Queue\Queueable;
final class CloseSessionsJob implements ShouldQueue
{
use Queueable;
/**
* Find all in-progress sessions idle for more than 12 hours and mark them as
* 'unfinished' status, logging each closure individually via ActivityLogger.
*/
public function handle(): void
{
Session::query()
->where('status', 'in_progress')
->where('created_at', '<', now()->subHours(12))
->each(function (Session $session): void {
$session->update([
'status' => 'unfinished',
'completed_at' => now(),
]);
ActivityLogger::log(
'session_auto_closed',
$session->user_id,
sessionId: $session->id,
categoryId: $session->category_id,
metadata: ['reason' => 'idle_12h'],
);
});
}
}

View File

@@ -4,10 +4,10 @@
namespace App\Nova;
use App\Nova\Actions\DownloadExcel;
use Illuminate\Support\Str;
use Laravel\Nova\Fields\BelongsTo;
use Laravel\Nova\Fields\Boolean;
use Laravel\Nova\Fields\DateTime;
use Laravel\Nova\Fields\HasMany;
use Laravel\Nova\Fields\ID;
use Laravel\Nova\Fields\Number;
@@ -15,7 +15,6 @@
use Laravel\Nova\Fields\Text;
use Laravel\Nova\Fields\Textarea;
use Laravel\Nova\Http\Requests\NovaRequest;
use App\Nova\Actions\DownloadExcel;
final class QuestionResource extends Resource
{
@@ -90,8 +89,6 @@ public function fields(NovaRequest $request): array
->filterable()
->help('The group this question belongs to. Questions are shown together by group in the questionnaire.'),
Textarea::make('Text')
->rules('required')
->updateRules('required')

View File

@@ -4,6 +4,7 @@
namespace App\Nova;
use App\Nova\Actions\DownloadExcel;
use Laravel\Nova\Fields\BelongsTo;
use Laravel\Nova\Fields\DateTime;
use Laravel\Nova\Fields\HasMany;
@@ -12,7 +13,6 @@
use Laravel\Nova\Fields\Select;
use Laravel\Nova\Fields\Textarea;
use Laravel\Nova\Http\Requests\NovaRequest;
use App\Nova\Actions\DownloadExcel;
final class SessionResource extends Resource
{
@@ -107,12 +107,13 @@ public function fields(NovaRequest $request): array
->options([
'in_progress' => 'In Progress',
'completed' => 'Completed',
'unfinished' => 'Unfinished',
'abandoned' => 'Abandoned',
])
->displayUsingLabels()
->sortable()
->filterable()
->help('The current state of this session. "In Progress" means the user has not yet submitted, "Completed" means submitted, "Abandoned" means the user left without finishing.'),
->help('The current state of this session. "In Progress" means the user has not yet submitted, "Completed" means submitted, "Unfinished" means the session was auto-closed after inactivity, "Abandoned" means the user left without finishing.'),
Number::make('Score')
->sortable()