Keep request and appointment identities separate
Store an appointment request ID and payment request ID with a pending submission. Only a service response that matches both and includes a confirmed appointment ID may enter the confirmed state. A late result for an edited form stays ignored.
React's useState documentation explains that a state update affects the next render, not the current executing code. That is useful context for state handling, but it does not supply a payment or appointment contract.
Make uncertainty and recovery visible
The dependency-free model covers an incomplete submission, awaiting confirmation, a matching confirmation, a payment failure, an unknown confirmation outcome, and an edit that invalidates an earlier response. It refuses to replace a live pending request; reconciliation or an explicit edit must happen first:
node --test sites/reactjsx.com/evidence/P143/payment-confirmation-state.test.mjs sites/reactjsx.com/evidence/P143/booking-payment-adapter.test.mjs
The following is illustrative, unbrowser-tested JSX. It adapts the state model to a small React status component: onSubmit receives work only after both request identities exist, changing either identity dispatches an edit that invalidates a pending result, and serviceResult must match both identities for confirmed, payment-failed, or confirmation-unknown. An unknown result disables blind resubmission until the operator follows the approved recovery path or explicitly edits the request. Use an ordinary status message to report a returned state without moving focus when that fits the interaction. WAI-ARIA defines status as a live-region role; browser and assistive-technology testing still belongs to the delivered interface.
<BookingPaymentStatus appointmentRequestId={requestId} paymentRequestId={paymentId} onSubmit={submitToTrustedService} serviceResult={returnedResult} />
The text must not imply that payment is authorized or an appointment exists unless the trusted service has supplied the matching confirmation.
Let the service decide confirmation
Preserve a failed or unknown result with its request identities and approved recovery route. Do not retry automatically unless the service contract makes the request identity and idempotency behavior clear. The frontend must not decide availability, payment authorization, response provenance, or booking confirmation.
For an unknown operation outcome, see Prevent a Double Submit When an Outcome Is Unknown. For retained draft behavior during a refresh, see Preserve a React Draft During a Background Refresh. For a service-confirmed time change, see Keep Local Time Separate From a Confirmed Zoned Appointment.
Does this pattern prevent duplicate charges or bookings?
No. It makes client state honest about uncertainty. Server-side authorization, idempotency, availability, and payment-provider handling remain backend responsibilities.