From 1727a4cbf041f0bab2cfe5917686f37800f8ee12 Mon Sep 17 00:00:00 2001 From: Padreug Date: Wed, 20 May 2026 16:56:27 +0200 Subject: [PATCH] feat(activities): banner image upload to img.ariege.io MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the plain "Image URL" text input on the event-creation form with the shared component, single-file mode with :compress="true". Files are resized + re-encoded to WebP client-side before hitting pict-rs so phone-sized posters don't bloat the image server. The stored `banner` is the canonical pict-rs original URL — the same shape market uses — so existing display paths (thumbnail/resize URL builders, NIP-52 "image" tag publishing) need no changes. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../components/CreateEventDialog.vue | 46 +++++++++++++------ 1 file changed, 33 insertions(+), 13 deletions(-) diff --git a/src/modules/activities/components/CreateEventDialog.vue b/src/modules/activities/components/CreateEventDialog.vue index 5f3a605..2a9861a 100644 --- a/src/modules/activities/components/CreateEventDialog.vue +++ b/src/modules/activities/components/CreateEventDialog.vue @@ -41,6 +41,8 @@ import { import { Calendar, Loader2, ChevronDown, 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 type { ImageUploadService, UploadedImage } from '@/modules/base/services/ImageUploadService' import type { TicketApiService } from '../services/TicketApiService' import type { CreateEventRequest } from '../types/ticket' import { ALL_CATEGORIES } from '../types/category' @@ -66,7 +68,6 @@ const formSchema = toTypedSchema(z.object({ event_end_date: z.string().optional().default(''), event_end_time: z.string().optional().default(''), location: z.string().max(500).optional().default(''), - banner: z.string().optional().default(''), currency: z.string().default("sat"), amount_tickets: z.number().min(0).max(100000).default(0), price_per_ticket: z.number().min(0).default(0), @@ -82,13 +83,17 @@ const form = useForm({ event_end_date: '', event_end_time: '', location: '', - banner: '', currency: 'sat', amount_tickets: 0, price_per_ticket: 0, } }) +interface BannerImage extends UploadedImage { + isPrimary: boolean +} +const bannerImages = ref([]) + // Fold a date input ("YYYY-MM-DD") and an optional time input ("HH:MM") // into the events-extension wire format: date-only when no time given, // ISO 8601 datetime otherwise. The publisher switches NIP-52 kinds on @@ -100,6 +105,7 @@ function foldDateTime(date: string, time: string): string { const paymentService = injectService(SERVICE_TOKENS.PAYMENT_SERVICE) const ticketApi = injectService(SERVICE_TOKENS.TICKET_API) as TicketApiService | null +const imageService = injectService(SERVICE_TOKENS.IMAGE_UPLOAD_SERVICE) const availableCurrencies = ref(['sat']) const loadingCurrencies = ref(false) @@ -173,7 +179,9 @@ const onSubmit = form.handleSubmit(async (formValues) => { ) } if (formValues.location) eventData.location = formValues.location - if (formValues.banner) eventData.banner = formValues.banner + if (bannerImages.value.length > 0) { + eventData.banner = imageService.getImageUrl(bannerImages.value[0].alias) + } 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 @@ -183,6 +191,7 @@ const onSubmit = form.handleSubmit(async (formValues) => { toastService.success('Event submitted!') resetForm() selectedCategories.value = [] + bannerImages.value = [] emit('update:open', false) emit('event-created') } catch (error) { @@ -197,6 +206,7 @@ const handleOpenChange = (open: boolean) => { if (!open && !isLoading.value) { resetForm() selectedCategories.value = [] + bannerImages.value = [] } emit('update:open', open) } @@ -296,16 +306,26 @@ const handleOpenChange = (open: boolean) => { - - - - Image URL - - - - - - + +
+

Banner image

+

+ One poster image. Auto-resized to 1920px max edge and re-encoded as WebP. +

+ +