Files
go-no-go/resources/js/Pages/Session/Show.vue
2026-02-03 20:18:08 +01:00

166 lines
5.0 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-4xl mx-auto px-4 py-8">
<div class="flex items-center justify-between mb-6">
<h1 class="text-3xl font-bold text-white">{{ session.category.name }} Questionnaire</h1>
<ScoreIndicator :score="score" :visible="hasScoredAnswers" />
</div>
<!-- User Info Section -->
<div class="bg-surface/50 rounded-lg p-6 mb-6">
<h2 class="text-xl font-semibold text-white mb-4">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">{{ session.user.name }}</span>
</div>
<div>
<span class="block text-sm font-medium text-gray-400 mb-1">Email</span>
<span class="text-white">{{ session.user.email }}</span>
</div>
</div>
</div>
<!-- Question Groups -->
<div
v-for="group in questionGroups"
:key="group.id"
class="bg-surface/50 rounded-lg p-6 mb-6"
>
<h2 class="text-xl font-semibold text-white mb-1">{{ group.name }}</h2>
<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-gray-700">
<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-surface/50 rounded-lg p-6 mb-6">
<h2 class="text-xl font-semibold text-white mb-4">Additional Comments</h2>
<textarea
v-model="additionalComments.additional_comments"
@input="saveComments"
rows="4"
class="w-full rounded-lg border border-gray-600 bg-surface px-3 py-2 text-white placeholder-gray-500 focus:border-primary focus:ring-1 focus:ring-primary"
placeholder="Enter any additional comments to support your decision..."
></textarea>
</div>
<!-- Complete button - now enabled -->
<div class="flex justify-end mt-8">
<AppButton size="lg" @click="completeSession" data-cy="complete-session">
Complete
</AppButton>
</div>
</div>
</template>