Add organizer-only attendee list to event detail view (011)
All checks were successful
CI / backend-test (push) Successful in 59s
CI / frontend-test (push) Successful in 23s
CI / frontend-e2e (push) Successful in 1m11s
CI / build-and-publish (push) Has been skipped

New GET /events/{token}/attendees endpoint returns attendee names when
a valid organizer token is provided (403 otherwise). The frontend
conditionally renders the list below the attendee count for organizers,
silently degrading for visitors.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-08 18:34:27 +01:00
parent d7ed28e036
commit 763811fce6
24 changed files with 1307 additions and 3 deletions

View File

@@ -54,6 +54,8 @@
</div>
</dl>
<AttendeeList v-if="isOrganizer && attendeeNames !== null" :attendees="attendeeNames" />
<div v-if="event.description" class="detail__section">
<h2 class="detail__section-title">About</h2>
<p class="detail__description">{{ event.description }}</p>
@@ -111,6 +113,7 @@ import { ref, computed, onMounted } from 'vue'
import { RouterLink, useRoute } from 'vue-router'
import { api } from '@/api/client'
import { useEventStorage } from '@/composables/useEventStorage'
import AttendeeList from '@/components/AttendeeList.vue'
import BottomSheet from '@/components/BottomSheet.vue'
import RsvpBar from '@/components/RsvpBar.vue'
import type { components } from '@/api/schema'
@@ -132,6 +135,7 @@ const submitError = ref('')
const submitting = ref(false)
const rsvpName = ref<string | undefined>(undefined)
const isOrganizer = ref(false)
const attendeeNames = ref<string[] | null>(null)
const formattedDateTime = computed(() => {
if (!event.value) return ''
@@ -160,7 +164,13 @@ async function fetchEvent() {
state.value = 'loaded'
// Check if current user is the organizer
isOrganizer.value = !!getOrganizerToken(event.value.eventToken)
const orgToken = getOrganizerToken(event.value.eventToken)
isOrganizer.value = !!orgToken
// Fetch attendee list for organizer
if (orgToken) {
fetchAttendees(event.value.eventToken, orgToken)
}
// Restore RSVP status from localStorage
const stored = getRsvp(event.value.eventToken)
@@ -220,6 +230,23 @@ async function submitRsvp() {
}
}
async function fetchAttendees(eventToken: string, organizerToken: string) {
try {
const { data, error } = await api.GET('/events/{token}/attendees', {
params: {
path: { token: eventToken },
query: { organizerToken },
},
})
if (!error) {
attendeeNames.value = data!.attendees.map((a) => a.name)
}
} catch {
// Silently degrade — don't show attendee list
}
}
onMounted(fetchEvent)
</script>