has('options')) { $request->merge(['options' => array_values(array_filter($request->input('options', [])))]); } $data = $request->validate([ 'question_text' => 'required|string|max:1000', 'question_type' => 'required|in:tajuk,rating,single_choice,multiple_choice,short_text,long_text', 'is_required' => 'boolean', 'parent_id' => 'nullable|integer|exists:questionnaire_questions,id', 'options' => 'nullable|array', 'options.*' => 'required|string|max:255', 'rating_labels' => 'nullable|array', 'rating_labels.*' => 'nullable|string|max:100', ]); if ($data['question_type'] === 'rating') { if (empty($data['parent_id'])) { return back()->withErrors(['parent_id' => 'Soalan rating mesti diletakkan di bawah tajuk.'])->withInput(); } $parent = QuestionnaireQuestion::find($data['parent_id']); if (! $parent || $parent->question_type !== 'tajuk') { return back()->withErrors(['parent_id' => 'Parent mesti jenis Tajuk.'])->withInput(); } } $needsOptions = in_array($data['question_type'], ['single_choice', 'multiple_choice']); if ($needsOptions && empty($data['options'])) { return back()->withErrors(['options' => 'Pilihan jawapan diperlukan untuk jenis soalan ini.'])->withInput(); } $parentId = $data['question_type'] === 'rating' ? ($data['parent_id'] ?? null) : null; $maxOrder = $set->questions() ->when($parentId, fn($q) => $q->where('parent_id', $parentId), fn($q) => $q->whereNull('parent_id') ) ->max('sort_order') ?? 0; $ratingLabels = null; if ($data['question_type'] === 'tajuk') { $filtered = array_filter($data['rating_labels'] ?? [], fn($v) => $v !== null && $v !== ''); $ratingLabels = ! empty($filtered) ? $filtered : null; } $set->questions()->create([ 'question_text' => $data['question_text'], 'question_type' => $data['question_type'], 'parent_id' => $parentId, 'is_required' => $data['question_type'] === 'tajuk' ? false : ($data['is_required'] ?? true), 'options_json' => $needsOptions ? array_values(array_filter($data['options'] ?? [])) : null, 'rating_labels' => $ratingLabels, 'sort_order' => $maxOrder + 1, ]); return redirect()->route('admin.questionnaires.show', $set) ->with('success', 'Soalan berjaya ditambah.'); } public function update(Request $request, QuestionnaireQuestion $question): RedirectResponse { if ($request->has('options')) { $request->merge(['options' => array_values(array_filter($request->input('options', [])))]); } $data = $request->validate([ 'question_text' => 'required|string|max:1000', 'question_type' => 'required|in:tajuk,rating,single_choice,multiple_choice,short_text,long_text', 'is_required' => 'boolean', 'parent_id' => 'nullable|integer|exists:questionnaire_questions,id', 'options' => 'nullable|array', 'options.*' => 'required|string|max:255', 'rating_labels' => 'nullable|array', 'rating_labels.*' => 'nullable|string|max:100', ]); if ($data['question_type'] === 'rating') { if (empty($data['parent_id'])) { return back()->withErrors(['parent_id' => 'Soalan rating mesti diletakkan di bawah tajuk.'])->withInput(); } $parent = QuestionnaireQuestion::find($data['parent_id']); if (! $parent || $parent->question_type !== 'tajuk') { return back()->withErrors(['parent_id' => 'Parent mesti jenis Tajuk.'])->withInput(); } } $needsOptions = in_array($data['question_type'], ['single_choice', 'multiple_choice']); $parentId = $data['question_type'] === 'rating' ? ($data['parent_id'] ?? null) : null; $ratingLabels = null; if ($data['question_type'] === 'tajuk') { $filtered = array_filter($data['rating_labels'] ?? [], fn($v) => $v !== null && $v !== ''); $ratingLabels = ! empty($filtered) ? $filtered : null; } $question->update([ 'question_text' => $data['question_text'], 'question_type' => $data['question_type'], 'parent_id' => $parentId, 'is_required' => $data['question_type'] === 'tajuk' ? false : ($data['is_required'] ?? true), 'options_json' => $needsOptions ? array_values(array_filter($data['options'] ?? [])) : null, 'rating_labels' => $ratingLabels, ]); return redirect()->route('admin.questionnaires.show', $question->questionnaire_set_id) ->with('success', 'Soalan berjaya dikemaskini.'); } public function destroy(QuestionnaireQuestion $question): RedirectResponse { $setId = $question->questionnaire_set_id; // Cascade-delete children if this is a tajuk (DB cascade handles it too, but be explicit) if ($question->question_type === 'tajuk') { $question->children()->delete(); } $question->delete(); return redirect()->route('admin.questionnaires.show', $setId) ->with('success', 'Soalan berjaya dipadam.'); } public function reorder(Request $request): JsonResponse { $data = $request->validate([ 'order' => 'required|array', 'order.*' => 'integer|exists:questionnaire_questions,id', 'parent_id' => 'nullable|integer|exists:questionnaire_questions,id', ]); foreach ($data['order'] as $sortOrder => $questionId) { QuestionnaireQuestion::where('id', $questionId) ->update(['sort_order' => $sortOrder + 1]); } return response()->json(['ok' => true]); } }