diff --git a/app/Http/Controllers/FormController.php b/app/Http/Controllers/FormController.php index 1e8a20e..763126d 100644 --- a/app/Http/Controllers/FormController.php +++ b/app/Http/Controllers/FormController.php @@ -1,7 +1,7 @@ has('publish')) { - $form->is_published = !$form->is_published; - $form->save(); - - return redirect()->route('forms.show', $form); +{ + try { + // Normalize the 'required' field to boolean + if ($request->has('questions')) { + $questions = $request->input('questions'); + foreach ($questions as $index => $question) { + if (isset($question['required']) && $question['required'] === 'on') { + $questions[$index]['required'] = true; + } else { + $questions[$index]['required'] = false; + } + } + $request->merge(['questions' => $questions]); } - Log::info('Incoming request data: ', $request->all()); + // Validate the request $validatedData = $request->validate([ 'title' => 'required|string|max:255', 'description' => 'nullable|string|max:255', @@ -174,50 +181,38 @@ Contact us at (123) 456-7890 or no_reply@example.com 'questions.*.text' => 'required|string|max:255', 'questions.*.options' => 'nullable|array', 'questions.*.options.*' => 'nullable|string|max:255', + 'questions.*.required' => 'boolean', ]); - Log::info('Validated data: ', $validatedData); - + // Update form $form->update([ 'title' => $validatedData['title'], 'description' => $validatedData['description'], ]); - $existingQuestionIds = []; + // Clear existing questions + $form->questions()->delete(); + + // Create or update questions foreach ($validatedData['questions'] as $questionData) { - if (isset($questionData['id'])) { - $question = Question::find($questionData['id']); - } else { - $question = new Question(); - $question->form_id = $form->id; - } - - $question->type = $questionData['type']; - $question->question_text = $questionData['text']; - $question->options = isset($questionData['options']) ? json_encode($questionData['options']) : json_encode([]); + $question = new Question([ + 'form_id' => $form->id, + 'type' => $questionData['type'], + 'question_text' => $questionData['text'], + 'options' => json_encode($questionData['options'] ?? []), + 'required' => $questionData['required'], + ]); $question->save(); - - Log::info('Saved question: ', $question->toArray()); - - $existingQuestionIds[] = $question->id; } - $form->questions()->whereNotIn('id', $existingQuestionIds)->delete(); - - Log::info('Remaining questions: ', $form->questions()->get()->toArray()); - + DB::commit(); return redirect()->route('forms.show', $form)->with('success', 'Form updated successfully.'); + } catch (\Exception $e) { + DB::rollBack(); + Log::error('Error updating form: ' . $e->getMessage()); + return back()->withErrors(['error' => 'An error occurred while updating the form. Please try again.'])->withInput(); } - - - - - - - - - - +} diff --git a/app/Http/Controllers/ResponseController.php b/app/Http/Controllers/ResponseController.php index 6f6ee4b..a3ac741 100644 --- a/app/Http/Controllers/ResponseController.php +++ b/app/Http/Controllers/ResponseController.php @@ -31,33 +31,27 @@ class ResponseController extends Controller public function viewResponse(Form $form, $responseId) { - $responses = Response::where('response_id', $responseId) ->where('form_id', $form->id) ->get(); - - $questions = Question::where('form_id', $form->id)->get()->keyBy('id'); - - - $statistics = []; - foreach ($questions as $question) { - $statistics[$question->id] = [ - 'question_text' => $question->question_text, - 'type' => $question->type, - 'options' => json_decode($question->options), - 'responses' => [] - ]; - - foreach ($responses as $response) { - $decodedAnswers = json_decode($response->answers, true); - if (isset($decodedAnswers[$question->id])) { - $statistics[$question->id]['responses'][] = $decodedAnswers[$question->id]; - } - } + if ($responses->isEmpty()) { + abort(404, 'Response not found'); } - return view('responses.viewResponse', compact('form', 'responses', 'questions', 'statistics')); + $formSnapshot = json_decode($responses->first()->form_snapshot, true); + + if (is_null($formSnapshot) || !isset($formSnapshot['questions'])) { + Log::error('Form snapshot is null or does not contain questions', [ + 'response_id' => $responseId, + 'form_snapshot' => $responses->first()->form_snapshot + ]); + abort(500, 'Form snapshot is invalid'); + } + + $questions = collect($formSnapshot['questions'])->keyBy('id'); + + return view('responses.viewResponse', compact('form', 'responses', 'questions')); } @@ -108,34 +102,39 @@ class ResponseController extends Controller public function submitForm(Request $request, Form $form) { - Log::info($request->all()); - + Log::info('Form submission started', $request->all()); $questions = $form->questions; - $requiredQuestionIds = $questions->where('required', true)->pluck('id')->toArray(); - $validatedData = $request->validate([ 'answers' => 'array', 'answers.*' => '', ]); - foreach ($requiredQuestionIds as $requiredQuestionId) { if (!isset($validatedData['answers'][$requiredQuestionId]) || empty($validatedData['answers'][$requiredQuestionId])) { - return redirect()->back() - ->withErrors(['errors' => 'Please answer all required questions.']) - ->withInput(); + return response()->json(['success' => false, 'message' => 'Please answer all required questions.']); } } - Log::info($validatedData); - + Log::info('Validation passed', $validatedData); $responseId = Uuid::uuid4()->toString(); + $formSnapshot = [ + 'title' => $form->title, + 'description' => $form->description, + 'questions' => $questions->map(function ($question) { + return [ + 'id' => $question->id, + 'question_text' => $question->question_text, + 'type' => $question->type, + 'options' => $question->options, + ]; + })->toArray(), + ]; foreach ($validatedData['answers'] as $questionId => $answer) { $response = new Response(); @@ -145,10 +144,12 @@ class ResponseController extends Controller $response->user_id = auth()->id(); $response->answers = json_encode($answer); $response->submitted_at = now(); + $response->form_snapshot = json_encode($formSnapshot); $response->save(); + + Log::info('Response saved', $response->toArray()); } - return redirect()->route('responses.showForm', $form) - ->with('success', 'Response submitted successfully.'); + return response()->json(['success' => true, 'message' => 'Response submitted successfully.']); } } diff --git a/app/Models/Question.php b/app/Models/Question.php index 14b5251..56e5d2b 100644 --- a/app/Models/Question.php +++ b/app/Models/Question.php @@ -1,25 +1,21 @@ 'array', 'options' => 'array', + 'required' => 'boolean', ]; - public function getOptionsAttribute($value) - { - return json_decode($value, true); - } - public function form() { return $this->belongsTo(Form::class); diff --git a/app/Models/Response.php b/app/Models/Response.php index 02b3e33..dd23bc0 100644 --- a/app/Models/Response.php +++ b/app/Models/Response.php @@ -8,7 +8,7 @@ use Illuminate\Database\Eloquent\Model; class Response extends Model { use HasFactory; - protected $fillable = ['form_id', 'user_id', 'answers']; + protected $fillable = ['form_id', 'user_id', 'response_id', 'question_id', 'answers', 'submitted_at', 'form_snapshot']; // Define relationships public function form() diff --git a/database/migrations/2024_07_24_174429_add_soft_deletes_to_questions_table.php b/database/migrations/2024_07_24_174429_add_soft_deletes_to_questions_table.php new file mode 100644 index 0000000..e696db3 --- /dev/null +++ b/database/migrations/2024_07_24_174429_add_soft_deletes_to_questions_table.php @@ -0,0 +1,22 @@ +softDeletes(); + }); + } + + public function down() + { + Schema::table('questions', function (Blueprint $table) { + $table->dropSoftDeletes(); + }); + } +}; diff --git a/database/migrations/2024_07_24_184851_add_form_snapshot_to_responses_table.php b/database/migrations/2024_07_24_184851_add_form_snapshot_to_responses_table.php new file mode 100644 index 0000000..f2a6be8 --- /dev/null +++ b/database/migrations/2024_07_24_184851_add_form_snapshot_to_responses_table.php @@ -0,0 +1,28 @@ +json('form_snapshot')->nullable(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('responses', function (Blueprint $table) { + $table->dropColumn('form_snapshot'); + }); + } +}; diff --git a/database/migrations/2024_07_24_185521_add_form_snapshot_to_responses_table.php b/database/migrations/2024_07_24_185521_add_form_snapshot_to_responses_table.php new file mode 100644 index 0000000..8f07a60 --- /dev/null +++ b/database/migrations/2024_07_24_185521_add_form_snapshot_to_responses_table.php @@ -0,0 +1,30 @@ +json('form_snapshot')->nullable(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('responses', function (Blueprint $table) { + if (Schema::hasColumn('responses', 'form_snapshot')) { + $table->dropColumn('form_snapshot'); + } + }); + } +}; diff --git a/resources/views/forms/edit.blade.php b/resources/views/forms/edit.blade.php index a31c7e2..1322937 100644 --- a/resources/views/forms/edit.blade.php +++ b/resources/views/forms/edit.blade.php @@ -59,6 +59,7 @@
@foreach ($questions as $index => $question)
+
- required ? 'checked' : '' }}> - +
@@ -239,16 +241,14 @@ }); updateAddButtonPosition(); + + $('#edit-form').on('submit', function(e) { + e.preventDefault(); + updateQuestionIndices(); + this.submit(); + }); }); - - - - - - - - diff --git a/resources/views/responses/showForm.blade.php b/resources/views/responses/showForm.blade.php index 1dd5604..4655392 100644 --- a/resources/views/responses/showForm.blade.php +++ b/resources/views/responses/showForm.blade.php @@ -12,7 +12,12 @@ @csrf @foreach ($questions as $question)
- + @if ($question->type == 'multiple_choice') @foreach (json_decode($question->options) as $option)
-
+ +
- +
@foreach ($responses as $response) @php - $question = $questions[$response->question_id] ?? null; + $question = $questions[$response->question_id]; $decodedAnswers = json_decode($response->answers, true); @endphp - @if ($question) -
-

{{ $question->question_text }}

- @if ($question->type == 'dropdown') - - @elseif (in_array($question->type, ['multiple_choice', 'checkbox'])) -
- @foreach (json_decode($question->options) as $option) -
- - {{ $option }} -
- @endforeach -
- @else -

{{ is_array($decodedAnswers) ? implode(', ', $decodedAnswers) : $decodedAnswers }}

- @endif -
- @else -

Question not found for ID: {{ $response->question_id }}

- @endif +
+

+ {{ $question['question_text'] }} +

+ @if ($question['type'] == 'dropdown') + + @elseif (in_array($question['type'], ['multiple_choice', 'checkbox'])) +
+ @foreach (json_decode($question['options'] ?? '[]') as $option) +
+ + {{ $option }} +
+ @endforeach +
+ @else +

{{ is_array($decodedAnswers) ? implode(', ', $decodedAnswers) : $decodedAnswers }}

+ @endif +
@endforeach
diff --git a/resources/views/responses/viewResponses.blade.php b/resources/views/responses/viewResponses.blade.php index a8eb0c2..e1fe35b 100644 --- a/resources/views/responses/viewResponses.blade.php +++ b/resources/views/responses/viewResponses.blade.php @@ -13,6 +13,7 @@ +
diff --git a/vite.config.js b/vite.config.js index 5936321..dbbf333 100644 --- a/vite.config.js +++ b/vite.config.js @@ -11,9 +11,4 @@ export default defineConfig({ refresh: true, }), ], - server: { - // host: '192.168.29.229', - host: '192.168.2.179', - port: 5173 - }, });