Line item property applied to all items

Hey team, I’m writing an app which adds properties to line items in the cart to be used later in the workflow, but I’m running into an issue when the property I want to add is hidden from the customer (using the “_“ prefix).

When adding a normal property using the “cart.bulkCartUpdate” (cart.bulkCartUpdate) and also splitting a line item it works fine, I see both items in the cart and only one of them contains the new property. But, when I do this with a hidden property (with the property name starting with “_“ like: “_hiddenProperty“, I only see one item in the cart (expected, as the property is hidden), but the property gets applied to all of the line items quantity instead of only one. Below I’ll put a simple modal.tsx so you can test the behavior too!

import React from "react";
import {
  Screen,
  ScrollView,
  Text,
  reactExtension,
  useApi,
  Button,
  useCartSubscription,
  Stack,
  Section,
  TextField,
} from "@shopify/ui-extensions-react/point-of-sale";

function generateUUID() { // Public Domain/MIT
    var d = new Date().getTime();//Timestamp
    var d2 = ((typeof performance !== 'undefined') && performance.now && (performance.now()*1000)) || 0;//Time in microseconds since page-load or 0 if unsupported
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
        var r = Math.random() * 16;//random number between 0 and 16
        if(d > 0){//Use timestamp until depleted
            r = (d + r)%16 | 0;
            d = Math.floor(d/16);
        } else {//Use microseconds since page-load if supported
            r = (d2 + r)%16 | 0;
            d2 = Math.floor(d2/16);
        }
        return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16);
    });
}

const SmartGridModal = () => {
  const api = useApi<"pos.home.modal.render">();
  const cart = useCartSubscription();
  const [propertyValues, setPropertyValues] = React.useState<{
    [key: string]: string;
  }>({});

  const handlePropertyInputChange = (uuid: string, value: string) => {
    setPropertyValues({ ...propertyValues, [uuid]: value });
  };

  const handleAddProduct = async (variantId: number | undefined, withHiddenProperty: boolean) => {
    if (!variantId) {
      console.error("No variant ID available for this line item");
      return;
    }

    try {
      // Add the same variant to the cart
      api.toast.show(`Added property to one unit of ${variantId}`);

      const lineItemsUpdated = cart.lineItems.reduce((acc, item: any) => {
        if (item.variantId === variantId) {
          if (withHiddenProperty) {
            acc.push(
              {
                ...item,
                uuid: generateUUID(),
                quantity: 1,
                properties: {
                  ...item.properties,
                  "_hey": "This is a test property",
                },
              },
              {
                ...item,
                quantity: item.quantity - 1,
              }
            );
          } else {
            acc.push(
              {
                ...item,
                uuid: generateUUID(),
                quantity: 1,
                properties: {
                  ...item.properties,
                  "hey": "This is a test property",
                },
              },
              {
                ...item,
                quantity: item.quantity - 1,
              }
            );
          }
        } else {
          acc.push(item);
        }
        return acc;
      }, [] as typeof cart.lineItems);

      api.cart.bulkCartUpdate({
        ...cart,
        lineItems: lineItemsUpdated
      })
    } catch (error) {
      console.error("Error adding product to cart:", error);
    }
  };

  return (
    <Screen name="Cart Items" title="Cart Line Items">
      <ScrollView>
        <Stack direction="vertical">
          {cart.lineItems.length === 0 ? (
            <Section>
              <Text>No items in cart</Text>
            </Section>
          ) : (
            cart.lineItems.map((item) => (
              <Section key={item.uuid}>
                <Stack direction="vertical">
                  <Text variant="headingLarge">{item.title}</Text>
                  <Text>{item.uuid}</Text>
                  <Text>Quantity: {item.quantity}</Text>
                  {item.price && <Text>Price: ${item.price.toFixed(2)}</Text>}
                  {item.sku && <Text>SKU: {item.sku}</Text>}

                  {/* Display existing properties if any */}
                  {item.properties &&
                    Object.keys(item.properties).length > 0 && (
                      <Stack direction="vertical">
                        <Text variant="headingSmall">Properties:</Text>
                        {Object.entries(item.properties).map(([key, value]) => (
                          <Text key={key}>
                            {key}: {value}
                          </Text>
                        ))}
                      </Stack>
                    )}

                  {/* Add property section */}
                  <Stack direction="vertical">
                    <TextField
                      label="Add custom note"
                      value={propertyValues[item.uuid] || ""}
                      onChange={(value) =>
                        handlePropertyInputChange(item.uuid, value)
                      }
                      placeholder="Enter a custom note"
                    />
                    <Button
                      onPress={() => handleAddProduct(item.variantId, false)}
                      title="Add hey property to one unit of this item"
                    />
                    <Button
                      onPress={() => handleAddProduct(item.variantId, true)}
                      title="Add _hey property to one unit of this item"
                    />
                  </Stack>
                </Stack>
              </Section>
            ))
          )}

          <Button onPress={() => api.navigation.dismiss()} title="Close" />
        </Stack>
      </ScrollView>
    </Screen>
  );
};

export default reactExtension("pos.home.modal.render", () => (
  <SmartGridModal />
));

Thanks,

JV