177 lines
5.8 KiB
Vue
177 lines
5.8 KiB
Vue
<script setup>
|
|
import { computed, reactive } from 'vue'
|
|
import { Head, useForm, router } from '@inertiajs/vue3'
|
|
import AppLayout from '@/Layouts/AppLayout.vue'
|
|
import AppButton from '@/Components/AppButton.vue'
|
|
import QuestionCard from '@/Components/QuestionCard.vue'
|
|
import ScoreIndicator from '@/Components/ScoreIndicator.vue'
|
|
|
|
defineOptions({ layout: AppLayout })
|
|
|
|
const props = defineProps({
|
|
session: {
|
|
type: Object,
|
|
required: true,
|
|
},
|
|
questionGroups: {
|
|
type: Array,
|
|
default: () => [],
|
|
},
|
|
answers: {
|
|
type: Object,
|
|
default: () => ({}),
|
|
},
|
|
score: {
|
|
type: Number,
|
|
default: 0,
|
|
},
|
|
})
|
|
|
|
// Answer management
|
|
const answerData = reactive({})
|
|
|
|
// Initialize answers from existing data
|
|
const initializeAnswers = () => {
|
|
props.questionGroups.forEach(group => {
|
|
group.questions.forEach(question => {
|
|
const existing = props.answers[question.id]
|
|
answerData[question.id] = {
|
|
value: existing?.value ?? null,
|
|
text_value: existing?.text_value ?? '',
|
|
}
|
|
})
|
|
})
|
|
}
|
|
initializeAnswers()
|
|
|
|
// Save a single answer with partial reload including score
|
|
let saveTimeout = null
|
|
const saveAnswer = (questionId) => {
|
|
clearTimeout(saveTimeout)
|
|
saveTimeout = setTimeout(() => {
|
|
router.put(`/sessions/${props.session.id}`, {
|
|
answers: {
|
|
[questionId]: answerData[questionId],
|
|
},
|
|
}, {
|
|
preserveScroll: true,
|
|
preserveState: true,
|
|
only: ['answers', 'score'],
|
|
})
|
|
}, 500)
|
|
}
|
|
|
|
const updateAnswer = (questionId, newValue) => {
|
|
answerData[questionId] = newValue
|
|
saveAnswer(questionId)
|
|
}
|
|
|
|
// Additional comments
|
|
const additionalComments = useForm({
|
|
additional_comments: props.session.additional_comments ?? '',
|
|
})
|
|
|
|
let commentsTimeout = null
|
|
const saveComments = () => {
|
|
clearTimeout(commentsTimeout)
|
|
commentsTimeout = setTimeout(() => {
|
|
additionalComments.put(`/sessions/${props.session.id}`, {
|
|
preserveScroll: true,
|
|
preserveState: true,
|
|
})
|
|
}, 1000)
|
|
}
|
|
|
|
// Session completion
|
|
let completing = false
|
|
const completeSession = () => {
|
|
completing = true
|
|
router.put(`/sessions/${props.session.id}`, {
|
|
complete: true,
|
|
})
|
|
}
|
|
|
|
// Check if any scored answers have been given
|
|
const hasScoredAnswers = computed(() => {
|
|
return props.score > 0
|
|
})
|
|
</script>
|
|
|
|
<template>
|
|
<Head :title="`${session.category.name} Questionnaire`" />
|
|
|
|
<div class="max-w-3xl mx-auto px-4 py-10">
|
|
<!-- Title area -->
|
|
<div class="mb-10">
|
|
<div class="flex items-center justify-between">
|
|
<h1 class="text-2xl font-bold text-white">{{ session.category.name }} Questionnaire</h1>
|
|
<ScoreIndicator :score="score" :visible="hasScoredAnswers" />
|
|
</div>
|
|
<div class="h-px bg-gradient-to-r from-primary/40 via-primary/10 to-transparent mt-4"></div>
|
|
</div>
|
|
|
|
<div class="space-y-8">
|
|
<!-- User Info Section -->
|
|
<div class="bg-white/[0.03] border border-white/[0.06] rounded-xl p-8">
|
|
<h2 class="text-lg font-semibold text-white mb-5">Basic Information</h2>
|
|
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
<div>
|
|
<span class="block text-sm font-medium text-gray-400 mb-1">Name</span>
|
|
<span class="text-white text-[15px]">{{ session.user.name }}</span>
|
|
</div>
|
|
<div>
|
|
<span class="block text-sm font-medium text-gray-400 mb-1">Email</span>
|
|
<span class="text-white text-[15px]">{{ session.user.email }}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Question Groups -->
|
|
<div
|
|
v-for="group in questionGroups"
|
|
:key="group.id"
|
|
class="bg-white/[0.03] border border-white/[0.06] rounded-xl p-8"
|
|
>
|
|
<div class="flex items-center gap-3 mb-1">
|
|
<div class="w-2 h-2 rounded-full bg-primary/60"></div>
|
|
<h2 class="text-lg font-semibold text-white">{{ group.name }}</h2>
|
|
</div>
|
|
<p v-if="group.description" class="text-gray-400 text-sm mb-2">{{ group.description }}</p>
|
|
<p v-if="group.scoring_instructions" class="text-amber-400 text-sm italic mb-4">{{ group.scoring_instructions }}</p>
|
|
|
|
<div class="divide-y divide-white/[0.06]">
|
|
<QuestionCard
|
|
v-for="question in group.questions"
|
|
:key="question.id"
|
|
:question="question"
|
|
:modelValue="answerData[question.id]"
|
|
@update:modelValue="updateAnswer(question.id, $event)"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Additional Comments -->
|
|
<div class="bg-white/[0.03] border border-white/[0.06] rounded-xl p-8">
|
|
<h2 class="text-lg font-semibold text-white mb-5">Additional Comments</h2>
|
|
<textarea
|
|
v-model="additionalComments.additional_comments"
|
|
@input="saveComments"
|
|
rows="4"
|
|
class="w-full rounded-lg border border-white/10 bg-white/5 px-4 py-3 text-white placeholder-gray-600 focus:border-primary/50 focus:ring-1 focus:ring-primary/20 transition-colors duration-200"
|
|
placeholder="Enter any additional comments to support your decision..."
|
|
></textarea>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Complete button - now enabled -->
|
|
<div class="mt-12 pt-8 border-t border-white/[0.06]">
|
|
<div class="flex justify-end">
|
|
<AppButton size="lg" @click="completeSession" data-cy="complete-session">
|
|
Complete
|
|
</AppButton>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|