braintree / braintree-web-drop-in

Braintree Drop-in for the web
MIT License
200 stars 124 forks source link

DropUI Fails to render with ApplePay on newer iPhones #915

Closed J-Gonzalez closed 7 months ago

J-Gonzalez commented 9 months ago

General information

Issue description

With the following code snippets below, on iPhone 8 or other older devices, the drop-in widget loads fine and displays both the card and applePay options. ApplePay works as expected.

On newer devices, (iPhone 12 and 13s tested), the entire drop-in widget fails to load/render. There seem to be no errors in the logs, but the entire widget is missing (and neither card nor apple pay options appear).

Not sure what changes in iPhone versions would cause this to work in older but not newer devices.

/**
 * Creates the Braintree Drop-In UI and all supported methods.
 * @param amount number. Gets converted to correct format for Google Pay, Apple Pay, Venmo, Paypal
 * @param language Language set to translate the drop in widget
 * @param clientToken Braintree client token from new reserved order or error response
 * @param setInstance useState hook for setting the global drop-in instance
 */
const createPaymentUI = (
  amount: number,
  language: string,
  clientToken: string,
  setInstance: React.Dispatch<React.SetStateAction<dropin.Dropin | undefined>>,
  require3DSecure: boolean,
  lineItems: { name: string; price: string }[]
) => {
  let locale = 'en_US';
  if (language === 'es') {
    locale = 'es_ES';
  }

  return dropin
    .create({
      authorization: clientToken,
      container: '#dropin-container',
      threeDSecure: require3DSecure ? true : undefined, // Conditional 3DS Based on Order Rules
      dataCollector: true, // Paypal FPA
      locale,
      card: { cardholderName: { required: false } },
      applePay: {
        displayName: 'My Company',
        paymentRequest: {
          requiredBillingContactFields: ['email', 'name', 'phone', 'postalAddress'],
          countryCode: 'US',
          currencyCode: 'USD',
          supportedNetworks: ['visa', 'mastercard', 'amex', 'discover'],
          merchantCapabilities: ['supports3DS'],
          lineItems: lineItems.map((item) => ({ label: item.name, amount: item.price, type: 'final' })),
          total: { label: 'My Company', amount: amount.toFixed(2) },
        },
      },
      ...
     })
     }

React useEffect on component load

        /**
   * Using react useEffect to create Braintree drop-in UI after component has finished rendering.
   */
  React.useEffect(() => {
    let localInstance: dropin.Dropin | undefined;
    const createUI = async () => {
      if (reservedOrderFromRecoil?.order?.authorization) {
        localInstance = await createPaymentUI( grossValue, locale, authorization, setInstance, require3ds,
        // Spreading line items and fees
          [
            ..order.items.map((item) => {
              return {
                name: `${item.name} × ${item.quantity}`,
                price: (item.price * item.quantity).toFixed(2) || '0.00',
              };
            }),
            ...order.feeDisplay.map((fee) => {
              return {
                name: fee.grouping,
                price: fee.major.toFixed(2) || '0.00',
              };
            }),
          ]
        );
      }
    };
    createUI();

    // Cleanup function to remove drop-in UI from DOM
    return function cleanup() {
      localInstance?.teardown();
    };
  }, []);
hollabaq86 commented 9 months ago

Two questions:

oscarleonnogales commented 9 months ago

Hi @J-Gonzalez , to add onto what @hollabaq86 previously mentioned, could you please update to the latest version of Drop-In? (we just released a small tweak for ApplePay).

Additionally, if you're still seeing this issue, do you happen to have your integration in a test page or code sandbox that we could access? Any kind of reproducible sample would help. We haven't received any other reports from other merchants about this, so it makes me inclined to believe there's something strange going on in the React integration.

J-Gonzalez commented 7 months ago

Looks like the issue was potentially related to how the react.js setup of the widget and the ref not maintaining state correctly. I couldn't explain why newer iphones did not work while the old ones did which this React bug (that attempted to double render/mount the component) - but it did solve it.

Issue resolved as user error (which presented in a confusing way across different devices) ✅