where('is_active', true)->firstOrFail(); $program = $qrCode->program; $participant = Participant::where('uuid', $participant_uuid)->firstOrFail(); // Verify participant belongs to this program $pp = $program->programParticipants()->where('participant_id', $participant->id)->first(); abort_if(! $pp, 404); $pq = $program->questionnaire()->with('questionnaireSet.questions')->first(); if (! $pq || ! $pq->is_confirmed) { // No questionnaire — go straight to semak page return redirect()->route('public.semak.show', $qr_token); } // Check already submitted $alreadySubmitted = QuestionnaireResponse::where('program_id', $program->id) ->where('participant_id', $participant->id) ->exists(); if ($alreadySubmitted) { return view('public.questionnaire.already', compact('program', 'participant', 'qrCode')); } $questions = $pq->questionnaireSet->questions; return view('public.questionnaire.show', compact('program', 'participant', 'qrCode', 'pq', 'questions')); } public function submit(Request $request, string $qr_token, string $participant_uuid): View|RedirectResponse { $qrCode = ProgramQrCode::where('token', $qr_token)->where('is_active', true)->firstOrFail(); $program = $qrCode->program; $participant = Participant::where('uuid', $participant_uuid)->firstOrFail(); $pp = $program->programParticipants()->where('participant_id', $participant->id)->first(); abort_if(! $pp, 404); $pq = $program->questionnaire()->with('questionnaireSet.questions')->first(); abort_if(! $pq || ! $pq->is_confirmed, 404); // Prevent double-submit $existing = QuestionnaireResponse::where('program_id', $program->id) ->where('participant_id', $participant->id) ->first(); if ($existing) { return view('public.questionnaire.already', compact('program', 'participant', 'qrCode')); } $questions = $pq->questionnaireSet->questions; // Validate required questions $rules = []; foreach ($questions as $q) { if ($q->is_required) { $rules['q_' . $q->id] = 'required'; } else { $rules['q_' . $q->id] = 'nullable'; } if ($q->question_type === 'multiple_choice') { $rules['q_' . $q->id] = ($q->is_required ? 'required|' : 'nullable|') . 'array'; } } $validated = $request->validate($rules, [ 'q_*.required' => 'Soalan ini wajib dijawab.', ]); // Save response $response = QuestionnaireResponse::create([ 'program_id' => $program->id, 'participant_id' => $participant->id, 'questionnaire_set_id' => $pq->questionnaire_set_id, 'submitted_at' => now(), 'ip_address' => $request->ip(), 'user_agent' => substr($request->userAgent() ?? '', 0, 500), ]); foreach ($questions as $q) { $raw = $request->input('q_' . $q->id); if ($raw === null && ! $q->is_required) { continue; } $value = match ($q->question_type) { 'multiple_choice' => (array) $raw, 'rating' => (int) $raw, default => $raw, }; QuestionnaireAnswer::create([ 'questionnaire_response_id' => $response->id, 'questionnaire_question_id' => $q->id, 'answer_value' => $value, ]); } return view('public.questionnaire.thankyou', compact('program', 'participant', 'qrCode')); } }