From dfc4ad7322ab7b454818e21e14370dc9a34652d4 Mon Sep 17 00:00:00 2001 From: Padreug Date: Fri, 22 May 2026 12:32:00 +0200 Subject: [PATCH] feat(activities): notification config on event create + edit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CreateEventDialog gains a collapsible "Buyer notifications" section exposing the EventExtra fields added upstream in v1.4.0 / v1.6.0: - email_notifications + nostr_notifications switches — opt buyers into email and NIP-04 Nostr DM ticket confirmations. - notification_subject + notification_body inputs — let organizers customize the message. Empty falls back to extension defaults. Submit handler builds `extra` by overlaying onto the existing event.extra so unrelated fields the LNbits admin UI sets (promo_codes, conditional, min_tickets) survive the round-trip through the webapp. Populate-from-event mirrors the same. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../components/CreateEventDialog.vue | 89 +++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/src/modules/activities/components/CreateEventDialog.vue b/src/modules/activities/components/CreateEventDialog.vue index 2752621..e42c9f2 100644 --- a/src/modules/activities/components/CreateEventDialog.vue +++ b/src/modules/activities/components/CreateEventDialog.vue @@ -25,6 +25,8 @@ import { Textarea } from '@/components/ui/textarea' import { Button } from '@/components/ui/button' import { Badge } from '@/components/ui/badge' import { Switch } from '@/components/ui/switch' +import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@/components/ui/collapsible' +import { Bell, ChevronDown } from 'lucide-vue-next' import { ScrollArea } from '@/components/ui/scroll-area' import { Select, @@ -103,6 +105,10 @@ const formSchema = toTypedSchema( fiat_currency: z.string().default("USD"), amount_tickets: z.number().min(0).max(100000).default(0), price_per_ticket: z.number().min(0).default(0), + email_notifications: z.boolean().default(false), + nostr_notifications: z.boolean().default(false), + notification_subject: z.string().max(200).default(''), + notification_body: z.string().max(2000).default(''), }) .superRefine((v, ctx) => { // End must not precede start. Compare on the folded date+time @@ -135,6 +141,10 @@ const form = useForm({ fiat_currency: 'USD', amount_tickets: 0, price_per_ticket: 0, + email_notifications: false, + nostr_notifications: false, + notification_subject: '', + notification_body: '', } }) @@ -154,6 +164,7 @@ function splitDateTime(value: string | null | undefined): { date: string; time: // 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) +const notificationsOpen = 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 @@ -197,6 +208,10 @@ async function populateFromEvent(event: TicketedEvent) { fiat_currency: event.fiat_currency ?? 'USD', amount_tickets: event.amount_tickets ?? 0, price_per_ticket: event.price_per_ticket ?? 0, + email_notifications: event.extra?.email_notifications ?? false, + nostr_notifications: event.extra?.nostr_notifications ?? false, + notification_subject: event.extra?.notification_subject ?? '', + notification_body: event.extra?.notification_body ?? '', }) selectedCategories.value = [...(event.categories ?? [])] if (event.banner) { @@ -310,6 +325,18 @@ const onSubmit = form.handleSubmit(async (formValues) => { if (formValues.price_per_ticket) eventData.price_per_ticket = formValues.price_per_ticket if (selectedCategories.value.length > 0) eventData.categories = selectedCategories.value + // Notification config goes inside the `extra` envelope. On edit + // overlay onto the existing event.extra so unrelated fields the + // LNbits admin UI sets (promo_codes, conditional, min_tickets) + // survive the round-trip. + eventData.extra = { + ...(props.event?.extra ?? {}), + email_notifications: formValues.email_notifications, + nostr_notifications: formValues.nostr_notifications, + notification_subject: formValues.notification_subject, + notification_body: formValues.notification_body, + } + if (isEditMode.value) { if (!props.onUpdateEvent || !props.event?.id) { toastService.error('Update handler missing') @@ -619,6 +646,68 @@ const handleOpenChange = (open: boolean) => { + + + + + + +
+ + + Email confirmation + + + + + + + + + Nostr DM confirmation + + + + + +
+ + + + Subject + + + + Leave blank to use the default. + + + + + + + Body + +