feat: added feedback when sending feedback and saved feedback in local storage
Closes #12
This commit is contained in:
+87
-42
@@ -1,4 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, onMounted } from 'vue'
|
||||
|
||||
definePageMeta({
|
||||
middleware: 'auth',
|
||||
})
|
||||
@@ -34,6 +36,19 @@ const isFeedbackOpen = ref(false)
|
||||
const feedbackRating = ref(5)
|
||||
const feedbackComment = ref('')
|
||||
const isSubmittingFeedback = ref(false)
|
||||
const submittedFeedback = ref<{ rating: number; comment?: string } | null>(null)
|
||||
|
||||
// Carica l'eventuale feedback da local storage dopo il mount (per evitare mismatch nel SSR)
|
||||
onMounted(() => {
|
||||
try {
|
||||
const saved = localStorage.getItem(`feedback_${reportId}`)
|
||||
if (saved) {
|
||||
submittedFeedback.value = JSON.parse(saved)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Errore nel recupero del feedback da local storage:', error)
|
||||
}
|
||||
})
|
||||
|
||||
const handleSendMessage = async (messageText: string, files: File[]) => {
|
||||
isSubmittingMessage.value = true
|
||||
@@ -51,13 +66,18 @@ const handleSendMessage = async (messageText: string, files: File[]) => {
|
||||
const handleSubmitFeedback = async () => {
|
||||
isSubmittingFeedback.value = true
|
||||
try {
|
||||
await addFeedback(reportId, {
|
||||
const feedbackData = {
|
||||
rating: feedbackRating.value,
|
||||
comment: feedbackComment.value || undefined,
|
||||
})
|
||||
}
|
||||
|
||||
await addFeedback(reportId, feedbackData)
|
||||
|
||||
// Salva in local storage in mancanza di un endpoint dal backend
|
||||
localStorage.setItem(`feedback_${reportId}`, JSON.stringify(feedbackData))
|
||||
submittedFeedback.value = feedbackData
|
||||
|
||||
isFeedbackOpen.value = false
|
||||
feedbackRating.value = 5
|
||||
feedbackComment.value = ''
|
||||
await refreshReport()
|
||||
} catch (error) {
|
||||
console.error('Error submitting feedback:', error)
|
||||
@@ -251,50 +271,75 @@ const formatDate = (dateString: string): string => {
|
||||
<div v-if="canFeedback && isOwner" class="card card-bg border-0 shadow-sm mb-4">
|
||||
<div class="card-body">
|
||||
<h2 class="h6 mb-3">Valuta intervento</h2>
|
||||
<p class="text-muted small mb-3">Lascia valutazione finale quando intervento è concluso.</p>
|
||||
<button
|
||||
v-if="!isFeedbackOpen"
|
||||
type="button"
|
||||
class="btn btn-primary w-100"
|
||||
@click="isFeedbackOpen = true"
|
||||
>
|
||||
Valuta intervento
|
||||
</button>
|
||||
|
||||
<template v-else>
|
||||
<template v-if="submittedFeedback">
|
||||
<div class="alert alert-success small mb-3">
|
||||
Grazie! Il tuo feedback è stato inviato con successo.
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Valutazione</label>
|
||||
<div class="d-flex gap-2">
|
||||
<button v-for="n in 5" :key="n" type="button" class="btn btn-link p-0"
|
||||
@click="feedbackRating = n" :aria-label="`${n} stelle`">
|
||||
<BIIcon
|
||||
:name="n <= feedbackRating ? 'it-star-full' : 'it-star-outline'"
|
||||
size="lg"
|
||||
:color="n <= feedbackRating ? 'warning' : 'primary'"
|
||||
/>
|
||||
</button>
|
||||
<span class="d-block text-muted small mb-1">La tua valutazione</span>
|
||||
<div class="d-flex gap-1">
|
||||
<BIIcon
|
||||
v-for="n in 5"
|
||||
:key="n"
|
||||
:name="n <= submittedFeedback.rating ? 'it-star-full' : 'it-star-outline'"
|
||||
size="sm"
|
||||
:color="n <= submittedFeedback.rating ? 'warning' : 'primary'"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<textarea
|
||||
v-model="feedbackComment"
|
||||
class="form-control"
|
||||
placeholder="Commento opzionale"
|
||||
rows="3"
|
||||
/>
|
||||
<div v-if="submittedFeedback.comment">
|
||||
<span class="d-block text-muted small mb-1">Il tuo commento</span>
|
||||
<p class="mb-0 small text-break">{{ submittedFeedback.comment }}</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<div class="d-grid gap-2">
|
||||
<button :disabled="isSubmittingFeedback" class="btn btn-primary" type="button"
|
||||
@click="handleSubmitFeedback">
|
||||
<span v-if="isSubmittingFeedback" class="spinner-border spinner-border-sm me-2"></span>
|
||||
Invia
|
||||
</button>
|
||||
<button type="button" class="btn btn-outline-secondary" @click="isFeedbackOpen = false">
|
||||
Annulla
|
||||
</button>
|
||||
</div>
|
||||
<template v-else>
|
||||
<p class="text-muted small mb-3">Lascia valutazione finale quando intervento è concluso.</p>
|
||||
<button
|
||||
v-if="!isFeedbackOpen"
|
||||
type="button"
|
||||
class="btn btn-primary w-100"
|
||||
@click="isFeedbackOpen = true"
|
||||
>
|
||||
Valuta intervento
|
||||
</button>
|
||||
|
||||
<template v-else>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Valutazione</label>
|
||||
<div class="d-flex gap-2">
|
||||
<button v-for="n in 5" :key="n" type="button" class="btn btn-link p-0"
|
||||
@click="feedbackRating = n" :aria-label="`${n} stelle`">
|
||||
<BIIcon
|
||||
:name="n <= feedbackRating ? 'it-star-full' : 'it-star-outline'"
|
||||
size="lg"
|
||||
:color="n <= feedbackRating ? 'warning' : 'primary'"
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<textarea
|
||||
v-model="feedbackComment"
|
||||
class="form-control"
|
||||
placeholder="Commento opzionale"
|
||||
rows="3"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="d-grid gap-2">
|
||||
<button :disabled="isSubmittingFeedback" class="btn btn-primary" type="button"
|
||||
@click="handleSubmitFeedback">
|
||||
<span v-if="isSubmittingFeedback" class="spinner-border spinner-border-sm me-2"></span>
|
||||
Invia
|
||||
</button>
|
||||
<button type="button" class="btn btn-outline-secondary" @click="isFeedbackOpen = false">
|
||||
Annulla
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user