feat: initial commit - Band Management application

This commit is contained in:
2026-01-06 03:11:46 +01:00
commit 34e12e00b3
24543 changed files with 3991790 additions and 0 deletions

View File

@@ -0,0 +1,300 @@
<script setup lang="ts">
import { useEvents } from '@/composables/useEvents'
import { useRoute, useRouter } from 'vue-router'
import type { UpdateEventData } from '@/types/events'
definePage({
meta: {
navActiveLink: 'events',
},
})
const route = useRoute()
const router = useRouter()
const { currentEvent, fetchEvent, updateEvent, isLoading } = useEvents()
const eventId = computed(() => route.params.id as string)
const formData = ref<UpdateEventData>({})
const statusOptions = [
{ title: 'Draft', value: 'draft' },
{ title: 'Pending', value: 'pending' },
{ title: 'Confirmed', value: 'confirmed' },
{ title: 'Completed', value: 'completed' },
{ title: 'Cancelled', value: 'cancelled' },
]
const visibilityOptions = [
{ title: 'Private', value: 'private' },
{ title: 'Members', value: 'members' },
{ title: 'Public', value: 'public' },
]
const errors = ref<Record<string, string>>({})
// Load event data
watch(() => eventId.value, async () => {
if (eventId.value) {
await fetchEvent(eventId.value)
if (currentEvent.value) {
formData.value = {
title: currentEvent.value.title,
description: currentEvent.value.description || '',
event_date: currentEvent.value.event_date,
start_time: currentEvent.value.start_time,
end_time: currentEvent.value.end_time || '',
load_in_time: currentEvent.value.load_in_time || '',
soundcheck_time: currentEvent.value.soundcheck_time || '',
location_id: currentEvent.value.location?.id || '',
customer_id: currentEvent.value.customer?.id || '',
setlist_id: currentEvent.value.setlist?.id || '',
fee: currentEvent.value.fee || undefined,
currency: currentEvent.value.currency,
status: currentEvent.value.status,
visibility: currentEvent.value.visibility,
rsvp_deadline: currentEvent.value.rsvp_deadline || '',
notes: currentEvent.value.notes || '',
internal_notes: currentEvent.value.internal_notes || '',
is_public_setlist: currentEvent.value.is_public_setlist,
}
}
}
}, { immediate: true })
async function handleSubmit() {
errors.value = {}
try {
await updateEvent(eventId.value, formData.value)
router.push(`/events/${eventId.value}`)
} catch (err: any) {
if (err.response?.data?.errors) {
errors.value = err.response.data.errors
} else {
errors.value._general = err.message || 'Failed to update event'
}
}
}
</script>
<template>
<div>
<VCard v-if="currentEvent">
<VCardTitle class="d-flex align-center gap-2">
<VIcon icon="tabler-arrow-left" />
<RouterLink
:to="`/events/${eventId}`"
class="text-decoration-none"
>
Back to Event
</RouterLink>
</VCardTitle>
<VDivider />
<VCardText>
<VForm @submit.prevent="handleSubmit">
<VRow>
<VCol cols="12">
<AppTextField
v-model="formData.title"
label="Title"
placeholder="Event Title"
:error-messages="errors.title"
required
/>
</VCol>
<VCol cols="12">
<AppTextarea
v-model="formData.description"
label="Description"
placeholder="Event Description"
rows="3"
/>
</VCol>
<VCol
cols="12"
md="6"
>
<AppTextField
v-model="formData.event_date"
label="Event Date"
type="date"
:error-messages="errors.event_date"
required
/>
</VCol>
<VCol
cols="12"
md="6"
>
<AppTextField
v-model="formData.start_time"
label="Start Time"
type="time"
:error-messages="errors.start_time"
required
/>
</VCol>
<VCol
cols="12"
md="6"
>
<AppTextField
v-model="formData.end_time"
label="End Time"
type="time"
/>
</VCol>
<VCol
cols="12"
md="6"
>
<AppTextField
v-model="formData.load_in_time"
label="Load-in Time"
type="time"
/>
</VCol>
<VCol
cols="12"
md="6"
>
<AppTextField
v-model="formData.soundcheck_time"
label="Soundcheck Time"
type="time"
/>
</VCol>
<VCol
cols="12"
md="6"
>
<AppTextField
v-model="formData.rsvp_deadline"
label="RSVP Deadline"
type="datetime-local"
/>
</VCol>
<VCol
cols="12"
md="6"
>
<AppTextField
v-model.number="formData.fee"
label="Fee"
type="number"
step="0.01"
prefix="€"
/>
</VCol>
<VCol
cols="12"
md="6"
>
<AppSelect
v-model="formData.currency"
label="Currency"
:items="[{ title: 'EUR', value: 'EUR' }, { title: 'USD', value: 'USD' }]"
/>
</VCol>
<VCol
cols="12"
md="6"
>
<AppSelect
v-model="formData.status"
label="Status"
:items="statusOptions"
/>
</VCol>
<VCol
cols="12"
md="6"
>
<AppSelect
v-model="formData.visibility"
label="Visibility"
:items="visibilityOptions"
/>
</VCol>
<VCol cols="12">
<AppTextarea
v-model="formData.notes"
label="Notes"
placeholder="Public notes"
rows="3"
/>
</VCol>
<VCol cols="12">
<AppTextarea
v-model="formData.internal_notes"
label="Internal Notes"
placeholder="Private notes (only visible to admins)"
rows="3"
/>
</VCol>
<VCol cols="12">
<VCheckbox
v-model="formData.is_public_setlist"
label="Public Setlist"
/>
</VCol>
<VCol cols="12">
<VAlert
v-if="errors._general"
type="error"
class="mb-4"
>
{{ errors._general }}
</VAlert>
<div class="d-flex gap-4">
<VBtn
type="submit"
color="primary"
:loading="isLoading"
>
Update Event
</VBtn>
<VBtn
variant="tonal"
color="secondary"
:to="`/events/${eventId}`"
>
Cancel
</VBtn>
</div>
</VCol>
</VRow>
</VForm>
</VCardText>
</VCard>
<VCard v-else>
<VCardText class="text-center py-12">
<VProgressCircular
indeterminate
color="primary"
/>
</VCardText>
</VCard>
</div>
</template>