AuthorPanel.vue 2.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. <template>
  2. <div>
  3. <v-expansion-panel
  4. class="my-1"
  5. @group:selected="fetchSongs"
  6. >
  7. <v-expansion-panel-title class="font-weight-bold">
  8. {{ author.name }}
  9. </v-expansion-panel-title>
  10. <v-expansion-panel-text>
  11. <v-card v-if="loadingSongs" class="text-center pa-4">
  12. <v-progress-circular :indeterminate="true" />
  13. <div class="mt-2">
  14. Loading songs...
  15. </div>
  16. </v-card>
  17. <v-card v-else-if="songError" class="text-center pa-4 error--text">
  18. <v-icon color="error" large>mdi-alert-circle</v-icon>
  19. <div class="mt-2">
  20. Error loading songs: {{ songError }}
  21. </div>
  22. </v-card>
  23. <v-list v-else>
  24. <v-list-item v-for="song in songs" :key="song.id">
  25. <v-list-item-title>
  26. - {{ song.title }}
  27. </v-list-item-title>
  28. </v-list-item>
  29. <v-list-item v-if="songs.length === 0">
  30. <v-list-item-title class="text-center">No songs found for this author</v-list-item-title>
  31. </v-list-item>
  32. </v-list>
  33. </v-expansion-panel-text>
  34. </v-expansion-panel>
  35. </div>
  36. </template>
  37. <script setup lang="ts">
  38. import { ref, PropType } from 'vue'
  39. import type Author from '~/types/interfaces'
  40. // Define props
  41. const props = defineProps({
  42. author: {
  43. type: Object as PropType<Author>,
  44. required: true
  45. }
  46. })
  47. const runtimeConfig = useRuntimeConfig()
  48. const apiBaseUrl = runtimeConfig.apiBaseUrl ?? runtimeConfig.public.apiBaseUrl
  49. const songs = ref<Song[]>([]);
  50. const loadingSongs = ref(false);
  51. const songError = ref<string | null>(null);
  52. // Fetch songs for the author
  53. const fetchSongs = async () => {
  54. console.log('fetchSongs', props.author.id)
  55. // Skip if already loaded
  56. if (songs.value.length > 0) {
  57. return
  58. }
  59. loadingSongs.value = true
  60. try {
  61. const response = await fetch( apiBaseUrl + `/api/songs?author=${props.author.id}`)
  62. if (!response.ok) {
  63. throw new Error(`HTTP error. Status: ${response.status}`)
  64. }
  65. const data = await response.json()
  66. songs.value = data.member || []
  67. } catch (err) {
  68. songError.value = err instanceof Error ? err.message : 'Unknown error';
  69. console.error(`Error fetching songs for author ${props.author.id}:`, err)
  70. } finally {
  71. loadingSongs.value = false
  72. }
  73. }
  74. // Expose methods to parent component
  75. defineExpose({
  76. fetchSongs
  77. })
  78. </script>