feat(chatelet): book a room and pay by Lightning (slice 2) #154

Merged
padreug merged 4 commits from feat/chatelet-booking into dev 2026-09-15 21:52:08 +00:00
Owner

Slice 2 of the chatelet guest UI (#141): book a room and pay by Lightning.

Book on the room page opens a dialog: guest count, optional contact and note, then the extension holds the dates and returns the invoice. The dialog shows the QR with copy / open-in-wallet / pay-from-LNbits-wallet and polls until it settles, then shows the confirmation. useBookingFlow mirrors events' useTicketPurchase.

Booking needs a Nostr identity (the extension DMs check-in details to the guest pubkey), so anonymous guests go through /login?redirect= and come back to the room with their dates. Both login pages now honour that param. Guest checkout without an account is a later slice.

The invoice screen polls chatelet's keyless GET /api/v1/public/bookings/{id} (aiolabs/chatelet#19) and waits for the booking to reach confirmed, so "booked" means the extension's paid listener has actually run. If the hold expires or is declined before payment the dialog shows a "Dates released" screen instead of spinning.

Tested against bohm's native LNbits with the chatelet#19 branch loaded: anonymous bounce, login, hold, wallet payment, confirmation; the extension logs the booking as confirmed.

Deploy order: chatelet#19 must be in the catalog and upgraded on aio-demo before this reaches staging, or the dialog polls a 404.

Slice 2 of the chatelet guest UI (#141): book a room and pay by Lightning. Book on the room page opens a dialog: guest count, optional contact and note, then the extension holds the dates and returns the invoice. The dialog shows the QR with copy / open-in-wallet / pay-from-LNbits-wallet and polls until it settles, then shows the confirmation. useBookingFlow mirrors events' useTicketPurchase. Booking needs a Nostr identity (the extension DMs check-in details to the guest pubkey), so anonymous guests go through /login?redirect= and come back to the room with their dates. Both login pages now honour that param. Guest checkout without an account is a later slice. The invoice screen polls chatelet's keyless GET /api/v1/public/bookings/{id} (aiolabs/chatelet#19) and waits for the booking to reach confirmed, so "booked" means the extension's paid listener has actually run. If the hold expires or is declined before payment the dialog shows a "Dates released" screen instead of spinning. Tested against bohm's native LNbits with the chatelet#19 branch loaded: anonymous bounce, login, hold, wallet payment, confirmation; the extension logs the booking as confirmed. Deploy order: chatelet#19 must be in the catalog and upgraded on aio-demo before this reaches staging, or the dialog polls a 404.
Both login pages always landed on '/'. A page that needs an identity
(chatelet's Book button) can now bounce an anonymous user through
/login?redirect=<path> and get them back. Only same-origin absolute
paths are honoured; anything else falls back to home.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Mirror the extension's BookingRequestData / Booking / BookingQuote
models and add the two calls slice 2 needs: POST /bookings (hold +
invoice) and an anonymous settlement poll on LNbits core's
GET /api/v1/payments/{hash}. Chatelet's own booking read needs a
wallet key, so the invoice is what the guest can watch until a public
booking-status endpoint lands on the extension.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Slice 2 of the guest UI. The Book button on the room page opens a
dialog that collects guest count, optional contact and a note, asks
the extension to hold the dates, then shows the bolt11 (QR, copy,
open-in-wallet, pay from the LNbits wallet) and polls settlement
until it is paid. useBookingFlow mirrors events' useTicketPurchase.

Booking needs a Nostr identity (the extension DMs check-in details to
the guest pubkey), so anonymous guests bounce through
/login?redirect= and land back on the room with their dates in the
query. Guest checkout without an account is a later slice.

Settlement is polled on LNbits core's anonymous payment status until
the extension grows a public booking-status endpoint; the paid-invoice
listener on the extension is what confirms the booking server-side.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Switch the invoice screen's poll from LNbits core's payment status to
chatelet's new keyless GET /api/v1/public/bookings/{id} (chatelet#18).
The dialog now waits for the booking to reach confirmed — meaning the
extension's paid listener has actually run — and shows a 'Dates
released' screen when the hold expires or is declined before payment
instead of spinning forever.

Needs chatelet >= the build that ships the endpoint on the target
instance (staging must be upgraded before this reaches dev).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
padreug deleted branch feat/chatelet-booking 2026-09-15 21:52:08 +00:00
Sign in to join this conversation.
No description provided.