Compare commits
7 Commits
d391440e2a
...
2ce4691231
Author | SHA1 | Date |
---|---|---|
yash | 2ce4691231 | |
yash | c4c52ac0af | |
Yash | b6b8642496 | |
Yash | f83295fdfd | |
Yash | d4ad6e9a47 | |
Yash | 87e0486962 | |
yash | 93916d6cde |
|
@ -1,7 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use App\Models\Form;
|
use App\Models\Form;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
|
@ -104,7 +104,6 @@ Contact us at (123) 456-7890 or no_reply@example.com
|
||||||
|
|
||||||
public function store(Request $request)
|
public function store(Request $request)
|
||||||
{
|
{
|
||||||
try {
|
|
||||||
$validatedData = $request->validate([
|
$validatedData = $request->validate([
|
||||||
'title' => 'required|string|max:255',
|
'title' => 'required|string|max:255',
|
||||||
'description' => 'nullable|string',
|
'description' => 'nullable|string',
|
||||||
|
@ -112,33 +111,35 @@ Contact us at (123) 456-7890 or no_reply@example.com
|
||||||
'questions.*.type' => 'required|string|in:multiple_choice,checkbox,dropdown,text',
|
'questions.*.type' => 'required|string|in:multiple_choice,checkbox,dropdown,text',
|
||||||
'questions.*.text' => 'required|string',
|
'questions.*.text' => 'required|string',
|
||||||
'questions.*.options' => 'nullable|array',
|
'questions.*.options' => 'nullable|array',
|
||||||
'questions.*.required' => 'nullable|boolean',
|
'questions.*.required' => 'boolean',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
DB::beginTransaction();
|
||||||
|
|
||||||
$form = new Form();
|
try {
|
||||||
$form->title = $validatedData['title'];
|
$form = Form::create([
|
||||||
$form->description = $validatedData['description'];
|
'title' => $validatedData['title'],
|
||||||
$form->is_published = $request->input('is_published', false);
|
'description' => $validatedData['description'],
|
||||||
$form->user_id = Auth::id();
|
'user_id' => Auth::id(),
|
||||||
$form->save();
|
]);
|
||||||
|
|
||||||
foreach ($validatedData['questions'] as $questionData) {
|
foreach ($validatedData['questions'] as $questionData) {
|
||||||
$question = new Question();
|
$question = new Question([
|
||||||
$question->form_id = $form->id;
|
'form_id' => $form->id,
|
||||||
$question->type = $questionData['type'];
|
'type' => $questionData['type'],
|
||||||
$question->question_text = $questionData['text'];
|
'question_text' => $questionData['text'],
|
||||||
$question->options = isset($questionData['options']) ? json_encode($questionData['options']) : null;
|
'options' => json_encode($questionData['options'] ?? []),
|
||||||
$question->required = isset($questionData['required']) ? $questionData['required'] : false;
|
'required' => $questionData['required'],
|
||||||
|
]);
|
||||||
$question->save();
|
$question->save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DB::commit();
|
||||||
|
return response()->json(['success' => true, 'message' => 'Form saved successfully.']);
|
||||||
return response()->json(['success' => true, 'form_id' => $form->id]);
|
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
Log::error('Error saving form: ' . $e->getMessage(), ['exception' => $e]);
|
DB::rollBack();
|
||||||
return response()->json(['success' => false, 'message' => 'Error saving form'], 500);
|
Log::error('Error saving form: ' . $e->getMessage());
|
||||||
|
return response()->json(['success' => false, 'message' => 'Failed to save form.']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -157,14 +158,21 @@ Contact us at (123) 456-7890 or no_reply@example.com
|
||||||
|
|
||||||
public function update(Request $request, Form $form)
|
public function update(Request $request, Form $form)
|
||||||
{
|
{
|
||||||
if ($request->has('publish')) {
|
try {
|
||||||
$form->is_published = !$form->is_published;
|
// Normalize the 'required' field to boolean
|
||||||
$form->save();
|
if ($request->has('questions')) {
|
||||||
|
$questions = $request->input('questions');
|
||||||
return redirect()->route('forms.show', $form);
|
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([
|
$validatedData = $request->validate([
|
||||||
'title' => 'required|string|max:255',
|
'title' => 'required|string|max:255',
|
||||||
'description' => 'nullable|string|max:255',
|
'description' => 'nullable|string|max:255',
|
||||||
|
@ -174,50 +182,38 @@ Contact us at (123) 456-7890 or no_reply@example.com
|
||||||
'questions.*.text' => 'required|string|max:255',
|
'questions.*.text' => 'required|string|max:255',
|
||||||
'questions.*.options' => 'nullable|array',
|
'questions.*.options' => 'nullable|array',
|
||||||
'questions.*.options.*' => 'nullable|string|max:255',
|
'questions.*.options.*' => 'nullable|string|max:255',
|
||||||
|
'questions.*.required' => 'boolean',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
Log::info('Validated data: ', $validatedData);
|
// Update form
|
||||||
|
|
||||||
$form->update([
|
$form->update([
|
||||||
'title' => $validatedData['title'],
|
'title' => $validatedData['title'],
|
||||||
'description' => $validatedData['description'],
|
'description' => $validatedData['description'],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$existingQuestionIds = [];
|
// Clear existing questions
|
||||||
|
$form->questions()->delete();
|
||||||
|
|
||||||
|
// Create or update questions
|
||||||
foreach ($validatedData['questions'] as $questionData) {
|
foreach ($validatedData['questions'] as $questionData) {
|
||||||
if (isset($questionData['id'])) {
|
$question = new Question([
|
||||||
$question = Question::find($questionData['id']);
|
'form_id' => $form->id,
|
||||||
} else {
|
'type' => $questionData['type'],
|
||||||
$question = new Question();
|
'question_text' => $questionData['text'],
|
||||||
$question->form_id = $form->id;
|
'options' => json_encode($questionData['options'] ?? []),
|
||||||
}
|
'required' => $questionData['required'],
|
||||||
|
]);
|
||||||
$question->type = $questionData['type'];
|
|
||||||
$question->question_text = $questionData['text'];
|
|
||||||
$question->options = isset($questionData['options']) ? json_encode($questionData['options']) : json_encode([]);
|
|
||||||
$question->save();
|
$question->save();
|
||||||
|
|
||||||
Log::info('Saved question: ', $question->toArray());
|
|
||||||
|
|
||||||
$existingQuestionIds[] = $question->id;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$form->questions()->whereNotIn('id', $existingQuestionIds)->delete();
|
DB::commit();
|
||||||
|
|
||||||
Log::info('Remaining questions: ', $form->questions()->get()->toArray());
|
|
||||||
|
|
||||||
return redirect()->route('forms.show', $form)->with('success', 'Form updated successfully.');
|
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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -31,33 +31,27 @@ class ResponseController extends Controller
|
||||||
|
|
||||||
public function viewResponse(Form $form, $responseId)
|
public function viewResponse(Form $form, $responseId)
|
||||||
{
|
{
|
||||||
|
|
||||||
$responses = Response::where('response_id', $responseId)
|
$responses = Response::where('response_id', $responseId)
|
||||||
->where('form_id', $form->id)
|
->where('form_id', $form->id)
|
||||||
->get();
|
->get();
|
||||||
|
|
||||||
|
if ($responses->isEmpty()) {
|
||||||
$questions = Question::where('form_id', $form->id)->get()->keyBy('id');
|
abort(404, 'Response not found');
|
||||||
|
|
||||||
|
|
||||||
$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];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
public function submitForm(Request $request, Form $form)
|
||||||
{
|
{
|
||||||
Log::info($request->all());
|
Log::info('Form submission started', $request->all());
|
||||||
|
|
||||||
|
|
||||||
$questions = $form->questions;
|
$questions = $form->questions;
|
||||||
|
|
||||||
|
|
||||||
$requiredQuestionIds = $questions->where('required', true)->pluck('id')->toArray();
|
$requiredQuestionIds = $questions->where('required', true)->pluck('id')->toArray();
|
||||||
|
|
||||||
|
|
||||||
$validatedData = $request->validate([
|
$validatedData = $request->validate([
|
||||||
'answers' => 'required|array',
|
'answers' => 'array',
|
||||||
'answers.*' => 'required',
|
'answers.*' => '',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|
||||||
foreach ($requiredQuestionIds as $requiredQuestionId) {
|
foreach ($requiredQuestionIds as $requiredQuestionId) {
|
||||||
if (!isset($validatedData['answers'][$requiredQuestionId]) || empty($validatedData['answers'][$requiredQuestionId])) {
|
if (!isset($validatedData['answers'][$requiredQuestionId]) || empty($validatedData['answers'][$requiredQuestionId])) {
|
||||||
return redirect()->back()
|
return response()->json(['success' => false, 'message' => 'Please answer all required questions.']);
|
||||||
->withErrors(['errors' => 'Please answer all required questions.'])
|
|
||||||
->withInput();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Log::info($validatedData);
|
Log::info('Validation passed', $validatedData);
|
||||||
|
|
||||||
|
|
||||||
$responseId = Uuid::uuid4()->toString();
|
$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) {
|
foreach ($validatedData['answers'] as $questionId => $answer) {
|
||||||
$response = new Response();
|
$response = new Response();
|
||||||
|
@ -145,10 +144,12 @@ class ResponseController extends Controller
|
||||||
$response->user_id = auth()->id();
|
$response->user_id = auth()->id();
|
||||||
$response->answers = json_encode($answer);
|
$response->answers = json_encode($answer);
|
||||||
$response->submitted_at = now();
|
$response->submitted_at = now();
|
||||||
|
$response->form_snapshot = json_encode($formSnapshot);
|
||||||
$response->save();
|
$response->save();
|
||||||
|
|
||||||
|
Log::info('Response saved', $response->toArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
return redirect()->route('responses.showForm', $form)
|
return response()->json(['success' => true, 'message' => 'Response submitted successfully.']);
|
||||||
->with('success', 'Response submitted successfully.');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,25 +1,21 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
class Question extends Model
|
class Question extends Model
|
||||||
{
|
{
|
||||||
|
use SoftDeletes;
|
||||||
use HasFactory;
|
use HasFactory;
|
||||||
protected $fillable = ['form_id', 'user_id', 'submitted_at', 'answers'];
|
protected $fillable = ['form_id', 'type', 'question_text', 'options', 'required'];
|
||||||
|
|
||||||
protected $casts = [
|
protected $casts = [
|
||||||
'answers' => 'array',
|
|
||||||
'options' => 'array',
|
'options' => 'array',
|
||||||
|
'required' => 'boolean',
|
||||||
];
|
];
|
||||||
|
|
||||||
public function getOptionsAttribute($value)
|
|
||||||
{
|
|
||||||
return json_decode($value, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function form()
|
public function form()
|
||||||
{
|
{
|
||||||
return $this->belongsTo(Form::class);
|
return $this->belongsTo(Form::class);
|
||||||
|
|
|
@ -8,7 +8,7 @@ use Illuminate\Database\Eloquent\Model;
|
||||||
class Response extends Model
|
class Response extends Model
|
||||||
{
|
{
|
||||||
use HasFactory;
|
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
|
// Define relationships
|
||||||
public function form()
|
public function form()
|
||||||
|
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
0
database/migrations/2014_10_12_100000_create_password_reset_tokens_table.php
Executable file → Normal file
0
database/migrations/2014_10_12_100000_create_password_resets_table.php
Executable file → Normal file
0
database/migrations/2019_12_14_000001_create_personal_access_tokens_table.php
Executable file → Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
Schema::table('questions', function (Blueprint $table) {
|
||||||
|
$table->softDeletes();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::table('questions', function (Blueprint $table) {
|
||||||
|
$table->dropSoftDeletes();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,30 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::table('responses', function (Blueprint $table) {
|
||||||
|
$table->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');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
|
@ -255,3 +255,7 @@ input:focus, textarea:focus, select:focus{
|
||||||
color: black;
|
color: black;
|
||||||
height: 20px;
|
height: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.active-question {
|
||||||
|
border-left: 4px solid blue;
|
||||||
|
}
|
||||||
|
|
Before Width: | Height: | Size: 959 B After Width: | Height: | Size: 959 B |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 5.9 KiB After Width: | Height: | Size: 5.9 KiB |
Before Width: | Height: | Size: 8.5 KiB After Width: | Height: | Size: 8.5 KiB |
Before Width: | Height: | Size: 6.7 KiB After Width: | Height: | Size: 6.7 KiB |
Before Width: | Height: | Size: 6.3 KiB After Width: | Height: | Size: 6.3 KiB |
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 623 B After Width: | Height: | Size: 623 B |
Before Width: | Height: | Size: 8.5 KiB After Width: | Height: | Size: 8.5 KiB |
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
|
@ -6,7 +6,7 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||||
const optionDiv = document.createElement("div");
|
const optionDiv = document.createElement("div");
|
||||||
optionDiv.className = "option";
|
optionDiv.className = "option";
|
||||||
optionDiv.innerHTML = `
|
optionDiv.innerHTML = `
|
||||||
<input type="text" class="form-control option-input" placeholder="New Option" />
|
<input type="text" class="form-control option-input mb-1" placeholder="New Option" />
|
||||||
<span class="delete-option" onclick="deleteOption(this)">✕</span>
|
<span class="delete-option" onclick="deleteOption(this)">✕</span>
|
||||||
`;
|
`;
|
||||||
optionContainer.appendChild(optionDiv);
|
optionContainer.appendChild(optionDiv);
|
||||||
|
|