Repository navigation
usePaymentCheckout changes its state when a payment started elsewhere is already in flight #31
Description
Problem
After #29, only one payment can be in flight at a time. usePaymentCheckout and HybridPaymentHandler share one native PaymentHandler, and its guard (iOS paymentCompletion, Android PendingPayment) resolves an overlapping call with "A payment is already in progress". No second sheet opens.
The hook's own guard (the isPaymentInFlight ref) only covers payments started by that hook instance. If the payment in flight was started by HybridPaymentHandler.startPayment() or by another usePaymentCheckout, the hook only finds out from the native result. By then it has already:
- set
isProcessingtotrueand clearedresultanderror, - called native, which rejects the call,
- stored the in-progress result in
resultanderror, then setisProcessingback tofalse.
So a call that never started a payment still replaces the hook's previous result/error and flashes isProcessing. This is documented in docs/docs/api/use-payment-checkout.md, but the hook would be easier to use if a rejected call left its state alone.
Raised by CodeRabbit on #29: #29 (comment)
Where
package/src/hooks/usePaymentCheckout.ts(startPayment)package/src/specs/PaymentHandler.nitro.tspackage/ios/HybridPaymentHandler.swiftpackage/android/src/main/java/com/margelo/nitro/pay/HybridPaymentHandler.kt,PendingPayment.kt
Suggested fix
- Add a synchronous
isPaymentInProgress(): booleanto thePaymentHandlerspec. Back it with the existing native state:paymentCompletion != nilon iOS,PendingPaymenton Android. - In the hook, check it before touching any state. If it returns
true, return the in-progress result without callingsetIsProcessing,setResultorsetError. - Keep the native guard as the source of truth. The check only decides whether the hook updates its state.
A JS-only module-level claim is not enough. It would cover hook vs hook, but not direct HybridPaymentHandler.startPayment() calls, because that export is the raw hybrid object.
#30 (onAuthorize) also changes the spec and the Android handler, so coordinate with it.
Acceptance criteria
- With a payment in flight from
HybridPaymentHandler.startPayment(), the hook'sstartPayment()returns the in-progress result and leavesisProcessing,resultanderrorunchanged. - The same holds when the payment in flight was started by another
usePaymentCheckout. - The native guard from fix: guard concurrent startPayment calls on Android and in the hook #29 behaves as before.
-
docs/docs/api/use-payment-checkout.mddescribes the new behaviour.
Testing
- Jest: change "records the native in-progress result when a direct payment is in flight" in
package/src/__tests__/paymentHandler.test.tsto expect unchanged hook state, and add a hook-vs-hook case. - JUnit: the Android getter reflects
PendingPayment. - Manual: overlapping calls on iOS and Android.
Activity