Skip to content

Feature: useBraintreePayPalOneTimePaymentSession hook#889

Merged
EvanReinstein merged 10 commits into
mainfrom
feature/bt-paypal-otp-hook
Apr 21, 2026
Merged

Feature: useBraintreePayPalOneTimePaymentSession hook#889
EvanReinstein merged 10 commits into
mainfrom
feature/bt-paypal-otp-hook

Conversation

@EvanReinstein
Copy link
Copy Markdown
Contributor

Adds a new React hook for managing one-time payment sessions with Braintree PayPal.

New hook: useBraintreePayPalOneTimePaymentSession

  • Accepts payment options (amount, currency, intent, lineItems, shippingOptions, etc.) and callbacks (onApprove, onCancel, onError, onShippingAddressChange, onShippingOptionsChange)
  • Returns isPending, error, handleClick
  • Uses useProxyProps for stable callback references and useDeepCompareMemoize for object/array options to avoid unnecessary session recreation
  • Tracks failed checkout instances via failedInstanceRef to prevent retry loops

New utility: createBraintreePaymentSession (braintreeUtils.ts)

  • Extracted session creation with error handling and failed-instance tracking into a shared utility for reuse across future
    Braintree hooks

Reorganization

  • Moved useBraintreePayPal hook and test into a Braintree/ subdirectory alongside the new hook
  • Updated import path in index.ts

Type fix

  • Renamed BraintreeApprovalData fields from payerID/orderID to payerId/orderId (camelCase)

Exports

  • useBraintreePayPalOneTimePaymentSession, UseBraintreePayPalOneTimePaymentSessionProps, and UseBraintreePayPalOneTimePaymentSessionReturn are now exported from the package

@EvanReinstein EvanReinstein requested a review from a team as a code owner April 17, 2026 19:00
@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Apr 17, 2026

🦋 Changeset detected

Latest commit: 8945074

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@paypal/react-paypal-js Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

Comment thread package-lock.json
Copy link
Copy Markdown
Contributor Author

@EvanReinstein EvanReinstein Apr 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I pulled changes from main and ran npm install this updated a handful of packages to include a peer boolean.

client: BraintreeClientInstance;
}) => Promise<BraintreePayPalCheckoutInstance>;
};
[key: string]: unknown;
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added this b/c I am concerned with typing the Braintree namespace too tightly

* @param setError - Error state setter
* @returns The payment session or null if creation fails
*/
export function createBraintreePaymentSession<T>(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like this function is very similar to [createPaymentSession](https://github.com/paypal/paypal-js/blob/ffee35fcf23a510d691931ec237624edbb4762b2/packages/react-paypal-js/src/v6/utils.ts#L278) with same signature but a different error message. Can we consider reusing createPaymentSession with a configurable error message and we can remove this file.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea I went back and forth on this. Mostly b/c I thought it meant updating every usage of the new util with an error message. Let me investigate further.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We decided to take this up in a follow up, in order to keep the scope smaller.

}

export interface BraintreeTokenizePaymentOptions {
payerID?: string;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the payerID/orderID naming in BraintreeTokenizePaymentOptions intentionally preserved? I notice BraintreeApprovalData was renamed to payerId/orderId in this PR. If the Braintree SDK's tokenizePayment() method still expects the old casing, then keeping it is correct. If not, this should be updated to match. Could you confirm which casing the SDK actually expects?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea this is one of the wonky things about these values, tokenizePayment still expects the old casing. See here https://braintree.github.io/braintree-web/current/PayPalCheckoutV6.html#tokenizePayment

payerID?: string;
orderID?: string;
payerId?: string;
orderId?: string;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see in our test we still use

  const mockApprovalData = {
      payerID: "PAYER123",  
      orderID: "ORDER456",  
  };

Might be better to match this type?

  const mockApprovalData: BraintreeApprovalData = {
      payerId: "PAYER123",
      orderId: "ORDER456",
  };

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, let me update that 👍

Copy link
Copy Markdown
Contributor

@HackTheW2d HackTheW2d left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! It's really great to see so many stable ref usage with useDeepCompareMemoize, useProxyCalls. 👍

Copy link
Copy Markdown
Contributor

@nityasp nityasp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking good. Thanks for taking this up @EvanReinstein

@EvanReinstein EvanReinstein merged commit dc4957a into main Apr 21, 2026
5 checks passed
@EvanReinstein EvanReinstein deleted the feature/bt-paypal-otp-hook branch April 21, 2026 17:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants