feat(chatelet): let a guest resume a held-but-unpaid booking #160

Merged
padreug merged 1 commit from feat/chatelet-resume-pending-invoice into dev 2026-09-21 17:58:25 +00:00
Owner

Closing the invoice dialog left the guest stranded: the hold blocks the
room until it expires, and the public booking read-back has no bolt11, so
there was no way back to the invoice — they had to wait out the hold to try
the room again.

Persist each hold's invoice on the device when it is created
(usePendingBooking, localStorage keyed by room, one per room, pruned on
expiry). On the room page, if a live hold exists for it (verified via the
public booking endpoint), show a "Resume payment" banner that reopens the
invoice from the saved bolt11 and resumes the settlement poll. The saved
entry is cleared when the booking confirms, the hold lapses, or it expires.
Works without an account — the store is the browser's, not the server's.

Verified headlessly against a real hold: the banner shows for a live hold
and resumes to the invoice (QR + amount); an expired hold shows nothing and
is pruned. vue-tsc build passes.

Note: there is no guest-cancel endpoint, so a guest who changes their mind
still waits out the hold; a backend cancel is a natural follow-up.

Closing the invoice dialog left the guest stranded: the hold blocks the room until it expires, and the public booking read-back has no bolt11, so there was no way back to the invoice — they had to wait out the hold to try the room again. Persist each hold's invoice on the device when it is created (`usePendingBooking`, localStorage keyed by room, one per room, pruned on expiry). On the room page, if a live hold exists for it (verified via the public booking endpoint), show a "Resume payment" banner that reopens the invoice from the saved bolt11 and resumes the settlement poll. The saved entry is cleared when the booking confirms, the hold lapses, or it expires. Works without an account — the store is the browser's, not the server's. Verified headlessly against a real hold: the banner shows for a live hold and resumes to the invoice (QR + amount); an expired hold shows nothing and is pruned. vue-tsc build passes. Note: there is no guest-cancel endpoint, so a guest who changes their mind still waits out the hold; a backend cancel is a natural follow-up.
Closing the invoice dialog left the guest stranded: the hold blocks the
room until it expires, and the public booking read-back has no bolt11, so
there was no way back to the invoice — they had to wait out the hold to try
the room again.

Persist each hold's invoice on the device when it is created
(usePendingBooking, localStorage keyed by room, one per room, pruned on
expiry). On the room page, if a live hold exists for it (verified via the
public booking endpoint), show a 'Resume payment' banner that reopens the
invoice from the saved bolt11 and resumes the settlement poll. The saved
entry is cleared when the booking confirms, the hold lapses, or it expires.
Works without an account — the store is the browser's, not the server's.

Verified headlessly against a real hold: the banner shows for a live hold
and resumes to the invoice (QR + amount); an expired hold shows nothing and
is pruned. vue-tsc build passes.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
padreug deleted branch feat/chatelet-resume-pending-invoice 2026-09-21 17:58:25 +00:00
Sign in to join this conversation.
No description provided.