From ec0dbf727bef76292517f49baa198609c5f38586 Mon Sep 17 00:00:00 2001 From: Padreug Date: Fri, 22 May 2026 12:29:08 +0200 Subject: [PATCH] feat(activities): expose fiat checkout on event create + purchase MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Both sides of the fiat-payment surface introduced by events v1.4.0: CreateEventDialog — organizer-side opt-in: - New "Accept fiat payments" switch (allow_fiat) + fiat currency picker (USD/EUR/GBP/CHF). Toggle is always shipped on create/edit so a true→false flip propagates correctly. - Hint copy notes that the host's LNbits admin needs a configured fiat provider (Stripe etc.) for the toggle to actually work at purchase time. PurchaseTicketDialog — buyer-side method selector: - Two-button selector (Lightning / Fiat) shown only when the event has `allow_fiat=true`. Hidden entirely for Lightning-only events. - Lightning path: unchanged (uses useTicketPurchase composable). - Fiat path: posts to the API with `payment_method=fiat`, then surfaces a "Open checkout" button that opens the returned fiat_payment_request URL in a new tab. Payment confirmation happens via webhook on the backend; ticket appears in My Tickets on next reload. EventsPage threads the new fiat fields through `selectedEvent` so the dialog sees them. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../components/CreateEventDialog.vue | 51 +++++++ .../components/PurchaseTicketDialog.vue | 129 ++++++++++++++++-- src/modules/activities/views/EventsPage.vue | 4 + 3 files changed, 174 insertions(+), 10 deletions(-) diff --git a/src/modules/activities/components/CreateEventDialog.vue b/src/modules/activities/components/CreateEventDialog.vue index 7f39fc0..c2c1f45 100644 --- a/src/modules/activities/components/CreateEventDialog.vue +++ b/src/modules/activities/components/CreateEventDialog.vue @@ -24,6 +24,7 @@ import { Input } from '@/components/ui/input' 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 { ScrollArea } from '@/components/ui/scroll-area' import { Select, @@ -120,6 +121,8 @@ const formSchema = toTypedSchema( event_end_time: z.string().optional().default(''), location: z.string().max(500).optional().default(''), currency: z.string().default("sat"), + allow_fiat: z.boolean().default(false), + 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), }) @@ -150,6 +153,8 @@ const form = useForm({ event_end_time: '', location: '', currency: 'sat', + allow_fiat: false, + fiat_currency: 'USD', amount_tickets: 0, price_per_ticket: 0, } @@ -213,6 +218,8 @@ async function populateFromEvent(event: TicketedEvent) { event_end_time: end.time, location: event.location ?? '', currency: event.currency ?? 'sat', + allow_fiat: event.allow_fiat ?? false, + fiat_currency: event.fiat_currency ?? 'USD', amount_tickets: event.amount_tickets ?? 0, price_per_ticket: event.price_per_ticket ?? 0, }) @@ -318,6 +325,10 @@ const onSubmit = form.handleSubmit(async (formValues) => { eventData.banner = null } if (formValues.currency) eventData.currency = formValues.currency + // allow_fiat / fiat_currency: always send so the toggle reads + // both directions on edit (a true→false flip must propagate). + eventData.allow_fiat = formValues.allow_fiat + if (formValues.fiat_currency) eventData.fiat_currency = formValues.fiat_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 @@ -591,6 +602,46 @@ const handleOpenChange = (open: boolean) => { + +
+ + +
+ Accept fiat payments + + Buyers can pay with the LNbits instance's configured fiat provider (e.g. Stripe). + +
+ + + +
+
+ + + + Fiat currency + + + + + + +
+