feat: implement review submission with user data persistence and form state management

This commit is contained in:
Esa Kataja
2025-05-13 20:17:31 +03:00
parent 8c0b0c2211
commit 5d05175bc4
+120 -67
View File
@@ -1,81 +1,117 @@
<script setup lang="ts"> <script setup lang="ts">
import { useRuntimeConfig } from '#imports'
// Use definePageMeta to set auth middleware
definePageMeta({ definePageMeta({
middleware: 'auth' middleware: 'auth'
}) })
interface Review {
song_id: number
user_id: number
score_song: number
score_show: number
score_costume: number
review_text: string
created_at: string
updated_at: string
}
const config = useRuntimeConfig() const config = useRuntimeConfig()
const apiBase = config.public.apiBase const apiBase = config.public.apiBase
const { id } = useRoute().params const route = useRoute()
const { id } = route.params
interface Artist { // Initialize reactive data
id: number const artist = ref(null)
year: number const review = ref<Review>({})
country_fi: string
artist: string
title: string
running_order: number
lyrics_original: string
lyrics_translation_fi: string
tags: string[]
img: string
flag: string
}
const { data: artist } = await useFetch<Artist>(`/api/artist?id=${id}`)
if (!artist.value) {
throw createError({
statusCode: 404,
statusMessage: 'Artist not found'
})
}
// State for toggling lyrics visibility
const showOriginalLyrics = ref(false) const showOriginalLyrics = ref(false)
const toggleOriginalLyrics = () => { const showTranslationLyrics = ref(false)
// Form data
const song = ref(50)
const show = ref(50)
const costume = ref(50)
const textReview = ref('')
// Get user from localStorage
const user = ref(null)
// Initialize user data from localStorage on client side only
onMounted(() => {
if (process.client) {
const userData = localStorage.getItem('user')
if (userData) {
user.value = JSON.parse(userData)
}
}
})
// Functions to toggle lyrics visibility
function toggleOriginalLyrics() {
showOriginalLyrics.value = !showOriginalLyrics.value showOriginalLyrics.value = !showOriginalLyrics.value
} }
const showTranslationLyrics = ref(false) function toggleTranslationLyrics() {
const toggleTranslationLyrics = () => {
showTranslationLyrics.value = !showTranslationLyrics.value showTranslationLyrics.value = !showTranslationLyrics.value
} }
const submitReview = () => { // Form submission function
// Get slider values function submitReview() {
const songEl = document.getElementById('slider-song') as HTMLInputElement const payload = {
const showEl = document.getElementById('slider-show') as HTMLInputElement song_id: id,
const costumeEl = document.getElementById('slider-costume') as HTMLInputElement user_id: user.value?.id,
score_song: song.value,
const songRating = songEl?.value || '0' score_show: show.value,
const showRating = showEl?.value || '0' score_costume: costume.value,
const costumeRating = costumeEl?.value || '0' text_review: text_review.value
// Create review object
const review = {
artistId: id,
ratings: {
song: parseInt(songRating),
show: parseInt(showRating),
costume: parseInt(costumeRating)
},
timestamp: new Date().toISOString()
} }
console.log('Submitting review:', review) // Implement your review submission logic here
console.log('Review submitted with data:', payload)
// TODO: Send review to API const response = fetch(`${apiBase}/reviews/`, {
// await useFetch('/api/reviews', { method: 'PUT',
// method: 'POST', headers: {
// body: review 'Content-Type': 'application/json',
// }) },
body: JSON.stringify(payload),
})
} }
// Fetch artist data based on ID
onMounted(async () => {
try {
// Fetch song data
const response = await fetch(`${apiBase}/songs/${id}`)
artist.value = await response.json()
} catch (error) {
console.error('Error fetching artist data:', error)
}
// Get user from localStorage and then fetch reviews if user exists
if (process.client) {
const userData = localStorage.getItem('user')
if (userData) {
user.value = JSON.parse(userData)
// Now fetch reviews with the user ID
try {
const response = await fetch(`${apiBase}/reviews/?song_id=${id}&user_id=${user.value.id}`)
review.value = await response.json()
// If there's existing review data, populate the form
if (review.value) {
song.value = review.value.score_song || 0
show.value = review.value.score_show || 0
costume.value = review.value.score_costume || 0
textReview.value = review.value.text_review || ''
}
} catch (error) {
console.error('Error fetching review data:', error)
}
}
}
})
</script> </script>
<template> <template>
@@ -112,12 +148,30 @@ const submitReview = () => {
<ul class="flex flex-wrap justify-center list-none gap-2 p-0 m-0"> <ul class="flex flex-wrap justify-center list-none gap-2 p-0 m-0">
<li class="tag" v-for="tag in artist.tags" :key="tag">{{ tag }}</li> <li class="tag" v-for="tag in artist.tags" :key="tag">{{ tag }}</li>
</ul> </ul>
<form @submit.prevent="submitReview"> <form @submit.prevent="submitReview" class="space-y-4 flex flex-col gap-4">
<ReviewSlider id="song" category="Kappale"/> <div class="flex flex-col gap-2">
<ReviewSlider id="show" category="Lava show"/> <label for="slider-song">Kappale</label>
<ReviewSlider id="costume" category="Asuste"/> <input id="slider-song" type="range" min="1" max="100" v-model="song"/>
<label for="text_review">Arvostelu</label> <div class="flex justify-between"><p>0</p><p class="sliderSeparator">|</p><p>25</p><p class="sliderSeparator">|</p><p>50</p><p class="sliderSeparator">|</p><p>75</p><p class="sliderSeparator">|</p><p>100</p></div>
<textarea id="text_review" placeholder="Arvostelu" class="textfield" /> </div>
<div class="flex flex-col gap-2">
<label for="slider-show">Lava show</label>
<input id="slider-show" type="range" min="1" max="100" v-model="show"/>
<div class="flex justify-between"><p>0</p><p class="sliderSeparator">|</p><p>25</p><p class="sliderSeparator">|</p><p>50</p><p class="sliderSeparator">|</p><p>75</p><p class="sliderSeparator">|</p><p>100</p></div>
</div>
<div class="flex flex-col gap-2">
<label for="slider-costume">Asuste</label>
<input id="slider-costume" type="range" min="1" max="100" v-model="costume"/>
<div class="flex justify-between"><p>0</p><p class="sliderSeparator">|</p><p>25</p><p class="sliderSeparator">|</p><p>50</p><p class="sliderSeparator">|</p><p>75</p><p class="sliderSeparator">|</p><p>100</p></div>
</div>
<div class="flex flex-col gap-2">
<label for="text_review">Arvostelu (vaihtoehtoinen)</label>
<textarea id="text_review" placeholder="Arvostelu" class="textfield" v-model="textReview"/>
</div>
<button type="submit" class="btn-primary">Arvostele</button> <button type="submit" class="btn-primary">Arvostele</button>
</form> </form>
</div> </div>
@@ -145,10 +199,9 @@ const submitReview = () => {
.textfield { .textfield {
border: none; border: none;
border-bottom: 1px solid #ccc; border-bottom: 1px solid #ccc;
max-width: 80%; width: 100%; /* Changed from max-width: 80% to width: 100% */
padding: 6px; padding: 6px;
background-color: rgba(255, 255, 255, 0.2); background-color: rgba(255, 255, 255, 0.2);
border-radius: 6px; border-radius: 6px;
} }
</style> </style>