diff --git a/src/modules/activities/components/CreateEventDialog.vue b/src/modules/activities/components/CreateEventDialog.vue index 34477a2..dd5ab5f 100644 --- a/src/modules/activities/components/CreateEventDialog.vue +++ b/src/modules/activities/components/CreateEventDialog.vue @@ -32,45 +32,28 @@ import { SelectTrigger, SelectValue, } from '@/components/ui/select' -import { Calendar, Loader2, MapPin, AlertCircle } from 'lucide-vue-next' +import { Calendar, Loader2, MapPin } from 'lucide-vue-next' import { toastService } from '@/core/services/ToastService' import { injectService, SERVICE_TOKENS } from '@/core/di-container' import ImageUpload from '@/modules/base/components/ImageUpload.vue' import DatePicker from '@/modules/base/components/DatePicker.vue' import TimePicker from '@/modules/base/components/TimePicker.vue' -import { Alert, AlertDescription } from '@/components/ui/alert' import type { ImageUploadService, UploadedImage } from '@/modules/base/services/ImageUploadService' import type { TicketApiService } from '../services/TicketApiService' -import type { CreateEventRequest, TicketedEvent } from '../types/ticket' +import type { CreateEventRequest } from '../types/ticket' import { ALL_CATEGORIES } from '../types/category' interface Props { open: boolean - /** When set, dialog opens in edit mode for this event. */ - event?: TicketedEvent | null - /** Create handler. Required when not editing. */ - onCreateEvent?: (eventData: CreateEventRequest) => Promise - /** Update handler. Required when editing. */ - onUpdateEvent?: (eventId: string, eventData: CreateEventRequest) => Promise - /** Whether the current user is an LNbits admin. Drives the - * "edit will go back to pending approval" warning copy. */ - isAdmin?: boolean - /** Whether the events extension has auto_approve enabled. */ - autoApprove?: boolean + onCreateEvent: (eventData: CreateEventRequest) => Promise } const props = defineProps() const emit = defineEmits<{ 'update:open': [value: boolean] 'event-created': [] - 'event-updated': [] }>() -const isEditMode = computed(() => Boolean(props.event?.id)) -const willGoToPending = computed( - () => isEditMode.value && !props.isAdmin && !props.autoApprove -) - const { t } = useI18n() // Fold a date input ("YYYY-MM-DD") and an optional time input ("HH:MM") @@ -134,18 +117,6 @@ interface BannerImage extends UploadedImage { } const bannerImages = ref([]) -// Inverse of foldDateTime: split a stored "YYYY-MM-DD[THH:MM]" back -// into separate date + time pieces for the form inputs. -function splitDateTime(value: string | null | undefined): { date: string; time: string } { - if (!value) return { date: '', time: '' } - const [date, time = ''] = value.split('T') - return { date, time: time.slice(0, 5) } -} - -// When `true`, suppress the auto-mirror watcher so we don't clobber an -// edit-mode population with start-date side effects mid-setValues. -const isPopulating = ref(false) - // Auto-mirror end date to start: when the user picks a start date, // surface that same date in the end-date picker so a one-day event // requires no extra clicks. Don't overwrite an end date the user @@ -154,7 +125,6 @@ const isPopulating = ref(false) watch( () => form.values.event_start_date, (start, prev) => { - if (isPopulating.value) return if (!start) return const end = form.values.event_end_date if (!end || end < start || end === prev) { @@ -171,61 +141,18 @@ const availableCurrencies = ref(['sat']) const loadingCurrencies = ref(false) const selectedCategories = ref([]) -function populateFromEvent(event: TicketedEvent) { - isPopulating.value = true - const start = splitDateTime(event.event_start_date) - const end = splitDateTime(event.event_end_date) - form.setValues({ - name: event.name, - info: event.info ?? '', - event_start_date: start.date, - event_start_time: start.time, - event_end_date: end.date, - event_end_time: end.time, - location: event.location ?? '', - currency: event.currency ?? 'sat', - amount_tickets: event.amount_tickets ?? 0, - price_per_ticket: event.price_per_ticket ?? 0, - }) - selectedCategories.value = [...(event.categories ?? [])] - if (event.banner) { - // Mirror the URL-to-alias bridge from market's CreateProductDialog - // so the renders the existing banner via its pict-rs - // file ID. delete_token is unknown for already-uploaded images, so - // removal just clears the slot client-side. - const url = event.banner - const alias = url.includes('/image/original/') - ? url.split('/image/original/')[1] - : url - bannerImages.value = [ - { alias, isPrimary: true, delete_token: '', details: {} as any }, - ] - } else { - bannerImages.value = [] - } - // Release the watcher guard on the next tick so vee-validate's batched - // updates settle before user input can drive the auto-mirror. - setTimeout(() => { - isPopulating.value = false - }, 0) -} - watch(() => props.open, async (isOpen) => { - if (isOpen) { - if (ticketApi && !loadingCurrencies.value) { - loadingCurrencies.value = true - try { - availableCurrencies.value = await ticketApi.getCurrencies() - } catch (error) { - console.warn('Failed to load currencies:', error) - } finally { - loadingCurrencies.value = false - } + if (isOpen && ticketApi && !loadingCurrencies.value) { + loadingCurrencies.value = true + try { + availableCurrencies.value = await ticketApi.getCurrencies() + } catch (error) { + console.warn('Failed to load currencies:', error) + } finally { + loadingCurrencies.value = false } - if (props.event) { - populateFromEvent(props.event) - } - } else { + } + if (!isOpen) { selectedCategories.value = [] } }) @@ -268,11 +195,7 @@ const onSubmit = form.handleSubmit(async (formValues) => { formValues.event_start_date, formValues.event_start_time ), - } - if (!isEditMode.value) { - // Wallet binds at creation. The backend ignores the field on - // update so we leave it off the edit payload for clean wire. - eventData.wallet = preferredWallet.id + wallet: preferredWallet.id, } // Optional fields — only include if provided @@ -286,49 +209,21 @@ const onSubmit = form.handleSubmit(async (formValues) => { if (formValues.location) eventData.location = formValues.location if (bannerImages.value.length > 0) { eventData.banner = imageService.getImageUrl(bannerImages.value[0].alias) - } else if (isEditMode.value) { - // User cleared the banner during edit — propagate the null so the - // backend wipes the field instead of keeping the old image. - eventData.banner = null } if (formValues.currency) eventData.currency = formValues.currency if (formValues.amount_tickets) eventData.amount_tickets = formValues.amount_tickets if (formValues.price_per_ticket) eventData.price_per_ticket = formValues.price_per_ticket if (selectedCategories.value.length > 0) eventData.categories = selectedCategories.value - if (isEditMode.value) { - if (!props.onUpdateEvent || !props.event?.id) { - toastService.error('Update handler missing') - return - } - await props.onUpdateEvent(props.event.id, eventData) - toastService.success( - willGoToPending.value - ? 'Event updated — pending re-approval' - : 'Event updated!' - ) - emit('event-updated') - } else { - if (!props.onCreateEvent) { - toastService.error('Create handler missing') - return - } - await props.onCreateEvent(eventData) - toastService.success('Event submitted!') - emit('event-created') - } - + await props.onCreateEvent(eventData) + toastService.success('Event submitted!') resetForm() selectedCategories.value = [] bannerImages.value = [] emit('update:open', false) + emit('event-created') } catch (error) { - const errorMessage = - error instanceof Error - ? error.message - : isEditMode.value - ? 'Failed to update event' - : 'Failed to create event' + const errorMessage = error instanceof Error ? error.message : 'Failed to create event' toastService.error(errorMessage) } finally { isLoading.value = false @@ -351,27 +246,15 @@ const handleOpenChange = (open: boolean) => { - {{ isEditMode ? 'Edit Event' : 'Create Event' }} + Create Event - {{ - isEditMode - ? 'Update event details. Tickets already sold are not affected.' - : 'Only a title and start date are required.' - }} + Only a title and start date are required.
- - - - Saving will resubmit for approval. The event will be removed - from public feeds until reviewed. - - - @@ -568,11 +451,7 @@ const handleOpenChange = (open: boolean) => { diff --git a/src/modules/activities/services/TicketApiService.ts b/src/modules/activities/services/TicketApiService.ts index 432771d..a9f3975 100644 --- a/src/modules/activities/services/TicketApiService.ts +++ b/src/modules/activities/services/TicketApiService.ts @@ -148,60 +148,6 @@ export class TicketApiService { }) } - /** - * Update an existing event. Requires the event's wallet admin key. - * Status is re-derived server-side from admin/auto_approve — a non- - * admin owner editing under `auto_approve=false` lands back at - * `proposed` regardless of the current state. - */ - async updateEvent( - eventId: string, - eventData: CreateEventRequest, - adminKey: string, - ): Promise { - return this.request(`/events/api/v1/events/${eventId}`, { - method: 'PUT', - headers: { - 'Content-Type': 'application/json', - 'X-API-KEY': adminKey, - }, - body: JSON.stringify(eventData), - }) - } - - /** - * Probe whether the current user has LNbits admin privileges. The - * `/all` endpoint is `check_admin`-gated, so a 200 means "admin", - * any other response means "not admin". - */ - async isAdmin(adminKey: string): Promise { - try { - await this.request('/events/api/v1/events/all', { - method: 'GET', - headers: { 'X-API-KEY': adminKey }, - }) - return true - } catch { - return false - } - } - - /** - * Read the extension's auto_approve flag. Admin-only endpoint, so - * non-admin callers see false (the safe default for UI gating). - */ - async getAutoApprove(adminKey: string): Promise { - try { - const settings = await this.request('/events/api/v1/events/settings', { - method: 'GET', - headers: { 'X-API-KEY': adminKey }, - }) - return Boolean(settings?.auto_approve) - } catch { - return false - } - } - /** * Fetch available currencies from LNbits. */ diff --git a/src/modules/activities/views/EventsPage.vue b/src/modules/activities/views/EventsPage.vue index 2a4adac..ab4feb8 100644 --- a/src/modules/activities/views/EventsPage.vue +++ b/src/modules/activities/views/EventsPage.vue @@ -1,5 +1,5 @@ @@ -137,7 +83,7 @@ function handleEventChanged() {
- @@ -182,9 +128,9 @@ function handleEventChanged() {
- + - @@ -252,18 +189,10 @@ function handleEventChanged() {