AuthorPanel.vue 2.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. <template>
  2. <div>
  3. <v-expansion-panel
  4. class="my-1"
  5. @update:model-value="fetchSongs"
  6. >
  7. <v-expansion-panel-title>
  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">Loading songs...</div>
  14. </v-card>
  15. <v-card v-else-if="songError" class="text-center pa-4 error--text">
  16. <v-icon color="error" large>mdi-alert-circle</v-icon>
  17. <div class="mt-2">Error loading songs: {{ songError }}</div>
  18. </v-card>
  19. <v-list v-else>
  20. <v-list-item v-for="song in songs" :key="song.id">
  21. <v-list-item-title>{{ song.title }}</v-list-item-title>
  22. </v-list-item>
  23. <v-list-item v-if="songs.length === 0">
  24. <v-list-item-title class="text-center">No songs found for this author</v-list-item-title>
  25. </v-list-item>
  26. </v-list>
  27. </v-expansion-panel-text>
  28. </v-expansion-panel>
  29. </div>
  30. </template>
  31. <script setup lang="ts">
  32. import { ref, watch } from 'vue'
  33. // Define props
  34. const props = defineProps<{
  35. author: {
  36. id: number;
  37. name: string;
  38. };
  39. }>();
  40. // Define types
  41. interface Song {
  42. id: number;
  43. title: string;
  44. author: {
  45. id: number;
  46. name: string;
  47. } | string; // Can be either an object or an IRI string
  48. }
  49. // State for songs
  50. const songs = ref<Song[]>([]);
  51. const loadingSongs = ref(false);
  52. const songError = ref<string | null>(null);
  53. // Fetch songs for the author
  54. const fetchSongs = async () => {
  55. console.log('fetchSongs', props.author.id);
  56. // Skip if already loaded
  57. if (songs.value.length > 0) {
  58. return;
  59. }
  60. loadingSongs.value = true;
  61. try {
  62. const response = await fetch(`https://local.api.snc-demo.fr/api/songs?author=${props.author.id}`);
  63. if (!response.ok) {
  64. throw new Error(`HTTP error. Status: ${response.status}`);
  65. }
  66. const data = await response.json();
  67. songs.value = data['member'] || [];
  68. } catch (err) {
  69. songError.value = err instanceof Error ? err.message : 'Unknown error';
  70. console.error(`Error fetching songs for author ${props.author.id}:`, err);
  71. } finally {
  72. loadingSongs.value = false;
  73. }
  74. };
  75. // Expose methods to parent component
  76. defineExpose({
  77. fetchSongs
  78. });
  79. </script>