feat(events): "send me a copy of each ticket email" toggle in the event editor

Pairs with aiolabs/events `extra.copy_to_organizer` (v1.6.1-aio.15): BCC
of every ticket email to the reply-to address (or the account email).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EYwoAkZZmXMMmaBp4WGUBo
This commit is contained in:
Padreug 2026-09-13 17:41:36 +02:00
commit 77b0bc557c
2 changed files with 18 additions and 0 deletions

View file

@ -146,6 +146,7 @@ const formSchema = toTypedSchema(
price_per_ticket: z.number().min(0).default(0), price_per_ticket: z.number().min(0).default(0),
email_notifications: z.boolean().default(false), email_notifications: z.boolean().default(false),
nostr_notifications: z.boolean().default(false), nostr_notifications: z.boolean().default(false),
copy_to_organizer: z.boolean().default(false),
notification_subject: z.string().max(200).default(''), notification_subject: z.string().max(200).default(''),
notification_body: z.string().max(2000).default(''), notification_body: z.string().max(2000).default(''),
organizer_name: z.string().trim().max(100).default(''), organizer_name: z.string().trim().max(100).default(''),
@ -201,6 +202,7 @@ const form = useForm({
price_per_ticket: 0, price_per_ticket: 0,
email_notifications: false, email_notifications: false,
nostr_notifications: false, nostr_notifications: false,
copy_to_organizer: false,
notification_subject: '', notification_subject: '',
notification_body: '', notification_body: '',
organizer_name: '', organizer_name: '',
@ -309,6 +311,7 @@ async function populateFromEvent(event: TicketedEvent) {
price_per_ticket: event.price_per_ticket ?? 0, price_per_ticket: event.price_per_ticket ?? 0,
email_notifications: event.extra?.email_notifications ?? false, email_notifications: event.extra?.email_notifications ?? false,
nostr_notifications: event.extra?.nostr_notifications ?? false, nostr_notifications: event.extra?.nostr_notifications ?? false,
copy_to_organizer: event.extra?.copy_to_organizer ?? false,
notification_subject: event.extra?.notification_subject ?? '', notification_subject: event.extra?.notification_subject ?? '',
notification_body: event.extra?.notification_body ?? '', notification_body: event.extra?.notification_body ?? '',
organizer_name: event.extra?.organizer_name ?? '', organizer_name: event.extra?.organizer_name ?? '',
@ -437,6 +440,7 @@ const onSubmit = form.handleSubmit(async (formValues) => {
payment_methods: formValues.payment_methods, payment_methods: formValues.payment_methods,
email_notifications: formValues.email_notifications, email_notifications: formValues.email_notifications,
nostr_notifications: formValues.nostr_notifications, nostr_notifications: formValues.nostr_notifications,
copy_to_organizer: formValues.copy_to_organizer,
notification_subject: formValues.notification_subject, notification_subject: formValues.notification_subject,
notification_body: formValues.notification_body, notification_body: formValues.notification_body,
organizer_name: formValues.organizer_name, organizer_name: formValues.organizer_name,
@ -842,6 +846,18 @@ const handleOpenChange = (open: boolean) => {
</FormControl> </FormControl>
</FormItem> </FormItem>
</FormField> </FormField>
<FormField v-slot="{ value, handleChange }" name="copy_to_organizer">
<FormItem class="flex flex-row items-center justify-between rounded-md border p-3 sm:col-span-2">
<div class="space-y-0.5">
<FormLabel class="text-sm">Send me a copy of each ticket email</FormLabel>
<FormDescription class="text-xs">Goes to the reply-to address below, or your account email.</FormDescription>
</div>
<FormControl>
<Switch :model-value="value as boolean" @update:model-value="handleChange" />
</FormControl>
</FormItem>
</FormField>
</div> </div>
<FormField v-slot="{ componentField }" name="notification_subject"> <FormField v-slot="{ componentField }" name="notification_subject">

View file

@ -32,6 +32,8 @@ export interface EventExtra {
/** Reply-To for ticket emails; null/absent = the organizer's LNbits /** Reply-To for ticket emails; null/absent = the organizer's LNbits
* account email. */ * account email. */
reply_to_email?: string | null reply_to_email?: string | null
/** BCC every ticket email to the reply-to address. */
copy_to_organizer?: boolean
/** Rails the organizer enabled (`lightning`, `fiat`). Empty / absent /** Rails the organizer enabled (`lightning`, `fiat`). Empty / absent
* means the legacy rule: Lightning always, fiat iff `allow_fiat`. * means the legacy rule: Lightning always, fiat iff `allow_fiat`.
* Same shape as upstream v2's `extra.payment_methods`. */ * Same shape as upstream v2's `extra.payment_methods`. */