checkout-sheet-kit-react-native icon indicating copy to clipboard operation
checkout-sheet-kit-react-native copied to clipboard

Issue with Cart Quantity Sync in Checkout Sheet Kit for React Native

Open vadivazhagan-vadivel opened this issue 1 year ago • 1 comments

What area is the issue related to?

Checkout Sheet Kit

What platform does the issue affect?

All platforms

What version of @shopify/checkout-sheet-kit are you using?

3.0.1

Do you have reproducible example code?

  private executeCartQuery = async (model, query, inputs: any, appConfig, appModel, _cartId?: string) => {
    try {
      let result;

      const currentCart = this.getCart(model);
      const cartId = _cartId || currentCart?.id;
      const cartPlatformId = model?.get('cartPlatform');
      const cartPlatformDSModel = appModel?.getModelValue([cartPlatformId]);
      const customerAccessToken = cartPlatformDSModel?.getIn(['loggedInUserAccessToken', 'accessToken']);

      switch (query) {
        case 'CREATE':
          result = await this.queryExecutor(
            appConfig,
            appModel,
            model,
            CartQueryRecords.CreateCart,
            Object.assign({}, {customerAccessToken}, inputs),
          );
          break;
        case 'GET_CART':
          if (cartId) {
            result = await this.queryExecutor(
              appConfig,
              appModel,
              model,
              CartQueryRecords.GetCart,
              Object.assign({}, {cartId}, inputs),
            );
          }
          break;
        case 'ADD_LINE_ITEMS':
          let lineItemsToAdd = _.get(inputs, 'lines', []).map(entry => {
            return {
              merchandiseId: entry.merchandiseId,
              sellingPlanId: entry.sellingPlanId,
              quantity: _.isNil(entry.quantity) ? 1 : entry.quantity,
              attributes: _.isEmpty(entry.attributes) ? [] : entry.attributes,
            };
          });
          result = cartId
            ? await this.queryExecutor(appConfig, appModel, model, CartQueryRecords.CartLinesAdd, {
                cartId,
                lines: lineItemsToAdd,
              })
            : await this.executeCartQuery(
                model,
                'CREATE',
                {
                  lines: lineItemsToAdd,
                },
                appConfig,
                appModel,
              );
          break;
        case 'UPDATE_LINE_ITEMS':
          const lineItemsToUpdate = _.get(inputs, 'lines', []).map(entry => {
            return {
              id: entry.id,
              merchandiseId: entry.merchandiseId,
              sellingPlanId: entry.sellingPlanId,
              quantity: entry.quantity,
              attributes: _.isEmpty(entry.attributes) ? [] : entry.attributes,
            };
          });
          result = cartId
            ? await this.queryExecutor(appConfig, appModel, model, CartQueryRecords.CartLinesUpdate, {
                cartId,
                lines: lineItemsToUpdate,
              })
            : await this.executeCartQuery(
                model,
                'CREATE',
                {
                  lines: lineItemsToUpdate,
                },
                appConfig,
                appModel,
              );
          break;
        case 'REMOVE_LINE_ITEMS':
          const linesItemsToRemove = _.get(inputs, 'lines', []).map(entry => entry?.id);
          if (cartId) {
            result = await this.queryExecutor(appConfig, appModel, model, CartQueryRecords.CartLinesRemove, {
              cartId,
              lineIds: linesItemsToRemove,
            });
          }
          break;
        case 'UPDATE_DISCOUNTS':
          if (cartId) {
            result = await this.queryExecutor(
              appConfig,
              appModel,
              model,
              CartQueryRecords.CartDiscountUpdate,
              Object.assign({}, {cartId}, inputs),
            );
          }
          break;
        case 'UPDATE_BUYER_IDENTITY':
          if (cartId) {
            result = await this.queryExecutor(
              appConfig,
              appModel,
              model,
              CartQueryRecords.CartBuyerIdentityUpdate,
              Object.assign({}, {cartId, customerAccessToken}, inputs),
            );
          }
          break;
        case 'UPDATE_ATTRIBUTES':
          if (cartId) {
            result = await this.queryExecutor(
              appConfig,
              appModel,
              model,
              CartQueryRecords.CartAttributesUpdate,
              Object.assign({}, {cartId}, inputs),
            );
          }

          break;
        case 'UPDATE_NOTE':
          if (cartId) {
            result = await this.queryExecutor(
              appConfig,
              appModel,
              model,
              CartQueryRecords.CartNoteUpdate,
              Object.assign({}, {cartId}, inputs),
            );
          }
          break;
        default:
          throw new Error(`${query} cart query is not defined`);
      }

      shopifyCheckout.preload(result.checkoutUrl) <=== preloading call
      return result;
    } catch (error) {
      console.error(`Error executing cart ${query}`, error);
    }
  };

Describe the issue

I am integrating @shopify/checkout-sheet-kit version 3.0.1 with my React Native application (version 0.73). The goal is to use the preload function as recommended in the documentation to ensure that the checkout stays synchronized with the cart whenever changes occur.

While the preload function generally works as expected, I am encountering a specific issue when rapidly adding multiple items to the cart. After using the addLineItem and updateLineItem GraphQL mutations to add items to the cart, I attempt to fetch the updated cart. However, if the items are added in quick succession, the cart sometimes returns incorrect quantities. For example, I might add 3 items to the cart, but the fetched cart reflects only 2 item. This discrepancy only occurs when items are added rapidly; a slight delay between additions seems to prevent the issue.

This issue is causing inconsistencies in the user experience, particularly when users quickly add multiple items to their cart and proceed to checkout. The problem does not occur if I disable the preload function, but I need to keep this feature enabled to maintain the desired functionality of my application.

Steps to Reproduce

  1. Rapidly add items to the cart using addLineItem and updateLineItem GraphQL mutations.
  2. Immediately fetch the updated cart.

Expected Behavior

The fetched cart should accurately reflect the correct quantities, matching the number of items added.

Actual Behavior

The cart sometimes returns incorrect quantities. For example, adding 3 items might result in only 2 item being shown in the cart.

Storefront domain

staging-pilgrim.myshopify.com

Screenshots/Videos/Log output

https://github.com/user-attachments/assets/aa79ca22-c7e3-4b39-9f50-5494cf860bf4

vadivazhagan-vadivel avatar Aug 02 '24 12:08 vadivazhagan-vadivel

@vadivazhagan-vadivel I've forwarded this on to the cart API team to take a look. I'll update when possible (N.B. there are public holidays in some office locations today)

kiftio avatar Aug 05 '24 15:08 kiftio

Hi @vadivazhagan-vadivel, we've identified the issue and are looking into possible solutions

In the meantime, although our sample apps tend to call preload() on each mutation of the cart, the recommendation is to only call preload when there's a strong signal the customer will enter checkout. For example if they land on the cart page. This should reduce the frequency of the issue appearing.

See the first Important Consideration here for more details

kiftio avatar Aug 23 '24 09:08 kiftio

Hi @kiftio, I tried this approach, and while it works when the customer first lands on the cart page, the issue comes back if they change the item quantity. The preload function only works as expected if it's called when the page loads and the customer doesn't make any changes afterward.

vadivazhagan-vadivel avatar Aug 23 '24 12:08 vadivazhagan-vadivel

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs in 30 days. Thank you for your contributions.

github-actions[bot] avatar Sep 23 '24 03:09 github-actions[bot]

We're still looking at this, just need to carve out some time.

kiftio avatar Sep 23 '24 08:09 kiftio

This should now be resolved

kiftio avatar Oct 08 '24 08:10 kiftio

Hello, @kiftio, the issue has returned/is still present. It behaves exactly as described by the OP. I'm using @shopify/checkout-sheet-kit v3.4.0

olgabednarczyk avatar Oct 28 '25 15:10 olgabednarczyk

@olgabednarczyk Sorry you're having issues - Could I ask you to create a fresh issue with reproduction steps - including the version of the storefront API you're using and we'll get this looked into

kieran-osgood-shopify avatar Oct 28 '25 16:10 kieran-osgood-shopify