Skip to content

Commit dd9b73f

Browse files
committed
Implement saving survey answers
1 parent 4f147c2 commit dd9b73f

File tree

7 files changed

+128
-14
lines changed

7 files changed

+128
-14
lines changed

app/Http/Controllers/SurveyController.php

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,14 @@
22

33
namespace App\Http\Controllers;
44

5+
use App\Http\Requests\StoreSurveyAnswerRequest;
56
use App\Http\Resources\SurveyResource;
67
use App\Models\Survey;
78
use App\Http\Requests\StoreSurveyRequest;
89
use App\Http\Requests\UpdateSurveyRequest;
10+
use App\Models\SurveyAnswer;
911
use App\Models\SurveyQuestion;
12+
use App\Models\SurveyQuestionAnswer;
1013
use Illuminate\Http\Request;
1114
use Illuminate\Support\Arr;
1215
use Illuminate\Support\Facades\File;
@@ -152,6 +155,36 @@ public function destroy(Survey $survey, Request $request)
152155
return response('', 204);
153156
}
154157

158+
public function storeAnswer(StoreSurveyAnswerRequest $request, Survey $survey)
159+
{
160+
$validated = $request->validated();
161+
// var_dump($validated, $survey);
162+
163+
$surveyAnswer = SurveyAnswer::create([
164+
'survey_id' => $survey->id,
165+
'start_date' => date('Y-m-d H:i:s'),
166+
'end_date' => date('Y-m-d H:i:s'),
167+
]);
168+
169+
foreach ($validated['answers'] as $questionId => $answer) {
170+
$question = SurveyQuestion::where(['id' => $questionId, 'survey_id' => $survey->id])->get();
171+
if (!$question) {
172+
return response("Invalid question ID: \"$questionId\"", 400);
173+
}
174+
175+
$data = [
176+
'survey_question_id' => $questionId,
177+
'survey_answer_id' => $surveyAnswer->id,
178+
'answer' => is_array($answer) ? json_encode($answer) : $answer
179+
];
180+
181+
$questionAnswer = SurveyQuestionAnswer::create($data);
182+
}
183+
184+
return response("", 201);
185+
186+
}
187+
155188
/**
156189
* Create a question and return
157190
*
@@ -254,4 +287,11 @@ private function saveImage($image)
254287

255288
return $relativePath;
256289
}
290+
291+
public function createQuestionAnswer($data)
292+
{
293+
if (is_array($data['answer'])) {
294+
$data['answer'] = json_encode($data['answer']);
295+
}
296+
}
257297
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
3+
namespace App\Http\Requests;
4+
5+
use Illuminate\Foundation\Http\FormRequest;
6+
7+
class StoreSurveyAnswerRequest extends FormRequest
8+
{
9+
/**
10+
* Determine if the user is authorized to make this request.
11+
*
12+
* @return bool
13+
*/
14+
public function authorize()
15+
{
16+
return true;
17+
}
18+
19+
/**
20+
* Get the validation rules that apply to the request.
21+
*
22+
* @return array
23+
*/
24+
public function rules()
25+
{
26+
return [
27+
'answers' => 'required|array'
28+
];
29+
}
30+
}

app/Models/SurveyAnswer.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,9 @@
88
class SurveyAnswer extends Model
99
{
1010
use HasFactory;
11+
12+
public const CREATED_AT = null;
13+
public const UPDATED_AT = null;
14+
15+
protected $fillable = ['survey_id', 'start_date', 'end_date'];
1116
}

app/Models/SurveyQuestionAnswer.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,6 @@
88
class SurveyQuestionAnswer extends Model
99
{
1010
use HasFactory;
11+
12+
protected $fillable = ['survey_question_id', 'survey_answer_id', 'answer'];
1113
}

routes/api.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
Route::get('/survey-by-slug/{survey:slug}', [\App\Http\Controllers\SurveyController::class, 'show']);
2525
});
2626

27+
Route::post('/survey/{survey}/answer', [\App\Http\Controllers\SurveyController::class, 'storeAnswer']);
28+
2729
Route::post('/register', [AuthController::class, 'register']);
2830
Route::post('/login', [AuthController::class, 'login']);
2931

vue/src/store/index.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,9 @@ const store = createStore({
107107
return res;
108108
});
109109
},
110+
saveSurveyAnswer({commit}, {surveyId, answers}) {
111+
return axiosClient.post(`/survey/${surveyId}/answer`, {answers});
112+
}
110113
},
111114
mutations: {
112115
logout: (state) => {

vue/src/views/SurveyPublicView.vue

Lines changed: 46 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,40 @@
11
<template>
22
<div class="py-5 px-8">
33
<div v-if="loading" class="flex justify-center">Loading...</div>
4-
<form @submit.prevent="submitSurvey" v-else>
5-
<div class="grid grid-cols-4">
4+
<form @submit.prevent="submitSurvey" v-else class="container mx-auto">
5+
<div class="grid grid-cols-6 items-center">
66
<div class="mr-4">
77
<img :src="survey.image_url" alt="" />
88
</div>
9-
<div class="col-span-3">
10-
<h1 class="text-3xl">{{ survey.title }}</h1>
9+
<div class="col-span-5">
10+
<h1 class="text-3xl mb-3">{{ survey.title }}</h1>
11+
<p class="text-gray-500 text-sm" v-html="survey.description"></p>
1112
</div>
1213
</div>
13-
<div v-for="(question, ind) of survey.questions" :key="question.id">
14-
<QuestionViewer v-model="questions[question.id]" :question="question" :index="ind" />
14+
15+
<div v-if="surveyFinished" class="py-8 px-6 bg-emerald-400 text-white w-[600px] mx-auto">
16+
<div class="text-xl mb-3 font-semibold ">Thank you for participating in this survey.</div>
17+
<button @click="submitAnotherResponse" type="button" class="inline-flex justify-center py-2 px-4 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
18+
Submit another response
19+
</button>
1520
</div>
21+
<div v-else>
22+
<hr class="my-3">
23+
<div v-for="(question, ind) of survey.questions" :key="question.id">
24+
<QuestionViewer
25+
v-model="answers[question.id]"
26+
:question="question"
27+
:index="ind"
28+
/>
29+
</div>
1630

17-
<button
18-
type="submit"
19-
class="inline-flex justify-center py-2 px-4 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
20-
>
21-
Submit
22-
</button>
31+
<button
32+
type="submit"
33+
class="inline-flex justify-center py-2 px-4 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
34+
>
35+
Submit
36+
</button>
37+
</div>
2338
</form>
2439
</div>
2540
</template>
@@ -35,12 +50,29 @@ const store = useStore();
3550
const loading = computed(() => store.state.currentSurvey.loading);
3651
const survey = computed(() => store.state.currentSurvey.data);
3752
38-
const questions = ref({});
53+
const surveyFinished = ref(false);
54+
55+
const answers = ref({});
3956
4057
store.dispatch("getSurveyBySlug", route.params.slug);
4158
4259
function submitSurvey() {
43-
console.log(JSON.stringify(questions.value, undefined, 2));
60+
console.log(JSON.stringify(answers.value, undefined, 2));
61+
store
62+
.dispatch("saveSurveyAnswer", {
63+
surveyId: survey.value.id,
64+
answers: answers.value,
65+
})
66+
.then((response) => {
67+
if (response.status === 201) {
68+
surveyFinished.value = true;
69+
}
70+
});
71+
}
72+
73+
function submitAnotherResponse() {
74+
answers.value = {};
75+
surveyFinished.value = false;
4476
}
4577
</script>
4678

0 commit comments

Comments
 (0)