- Update API: events, users, policies, routes, resources, migrations - Remove deprecated models/resources (customers, setlists, invitations, etc.) - Refresh admin app and docs; remove apps/band Made-with: Cursor
193 lines
5.0 KiB
Vue
193 lines
5.0 KiB
Vue
<script setup lang="ts">
|
|
import { useEvents } from '@/composables/useEvents'
|
|
import { useRoute, useRouter } from 'vue-router'
|
|
import type { EventCrewEventStatus, 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: string; value: EventCrewEventStatus }[] = [
|
|
{ title: 'Draft', value: 'draft' },
|
|
{ title: 'Published', value: 'published' },
|
|
{ title: 'Registration open', value: 'registration_open' },
|
|
{ title: 'Build-up', value: 'buildup' },
|
|
{ title: 'Show day', value: 'showday' },
|
|
{ title: 'Teardown', value: 'teardown' },
|
|
{ title: 'Closed', value: 'closed' },
|
|
]
|
|
|
|
const errors = ref<Record<string, string>>({})
|
|
|
|
watch(() => eventId.value, async () => {
|
|
if (!eventId.value) {
|
|
return
|
|
}
|
|
await fetchEvent(eventId.value)
|
|
if (currentEvent.value) {
|
|
const e = currentEvent.value
|
|
formData.value = {
|
|
name: e.name,
|
|
slug: e.slug,
|
|
start_date: e.start_date,
|
|
end_date: e.end_date,
|
|
timezone: e.timezone,
|
|
status: e.status,
|
|
}
|
|
}
|
|
}, { immediate: true })
|
|
|
|
function flattenValidationErrors(raw: Record<string, string[] | string>): Record<string, string> {
|
|
const out: Record<string, string> = {}
|
|
for (const [key, val] of Object.entries(raw)) {
|
|
out[key] = Array.isArray(val) ? val[0]! : val
|
|
}
|
|
return out
|
|
}
|
|
|
|
async function handleSubmit() {
|
|
errors.value = {}
|
|
try {
|
|
await updateEvent(eventId.value, formData.value)
|
|
await router.push(`/events/${eventId.value}`)
|
|
}
|
|
catch (err: unknown) {
|
|
const ax = err as { response?: { data?: { errors?: Record<string, string[] | string>; message?: string } } }
|
|
if (ax.response?.data?.errors) {
|
|
errors.value = flattenValidationErrors(ax.response.data.errors)
|
|
}
|
|
else {
|
|
errors.value._general = ax.response?.data?.message ?? (err instanceof Error ? 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.name"
|
|
label="Name"
|
|
:error-messages="errors.name"
|
|
required
|
|
/>
|
|
</VCol>
|
|
|
|
<VCol cols="12">
|
|
<AppTextField
|
|
v-model="formData.slug"
|
|
label="Slug"
|
|
:error-messages="errors.slug"
|
|
required
|
|
/>
|
|
</VCol>
|
|
|
|
<VCol
|
|
cols="12"
|
|
md="6"
|
|
>
|
|
<AppTextField
|
|
v-model="formData.start_date"
|
|
label="Start date"
|
|
type="date"
|
|
:error-messages="errors.start_date"
|
|
/>
|
|
</VCol>
|
|
|
|
<VCol
|
|
cols="12"
|
|
md="6"
|
|
>
|
|
<AppTextField
|
|
v-model="formData.end_date"
|
|
label="End date"
|
|
type="date"
|
|
:error-messages="errors.end_date"
|
|
/>
|
|
</VCol>
|
|
|
|
<VCol cols="12">
|
|
<AppTextField
|
|
v-model="formData.timezone"
|
|
label="Timezone"
|
|
:error-messages="errors.timezone"
|
|
/>
|
|
</VCol>
|
|
|
|
<VCol cols="12">
|
|
<AppSelect
|
|
v-model="formData.status"
|
|
label="Status"
|
|
:items="statusOptions"
|
|
:error-messages="errors.status"
|
|
/>
|
|
</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"
|
|
>
|
|
Save
|
|
</VBtn>
|
|
<VBtn
|
|
variant="tonal"
|
|
:to="`/events/${eventId}`"
|
|
>
|
|
Cancel
|
|
</VBtn>
|
|
</div>
|
|
</VCol>
|
|
</VRow>
|
|
</VForm>
|
|
</VCardText>
|
|
</VCard>
|
|
|
|
<VCard v-else-if="isLoading">
|
|
<VCardText class="text-center py-12">
|
|
<VProgressCircular
|
|
indeterminate
|
|
color="primary"
|
|
/>
|
|
</VCardText>
|
|
</VCard>
|
|
</div>
|
|
</template>
|