Shopify / shopify-app-bridge

https://shopify.dev/docs/api/app-bridge
85 stars 9 forks source link

Resource picker issue with Product and Collection resourceType in the same component #186

Open karthik-skr opened 1 year ago

karthik-skr commented 1 year ago

Hi team,

I am using the product and collection type resource picker on the same page. Depending on the radio button selection, either product or collection resource type state, opening that specific resource type picker.

If we first open the collection resource picker, then there is no issue. The issue is when we open the product resource picker first. Then if we switch to the collection resource picker, the onselection payload selection comes as an empty array when we select collections.

Is anyone facing this issue?

henrytao-me commented 1 year ago

Can you provide more info about your setup? Ex: app-bridge version, vanilla javascript or react, Web or Shopify Mobile?

karthik-skr commented 1 year ago

@henrytao-me , I am using app-bridge resource picker in shopify app admin screen.

import { ResourcePicker } from "@shopify/app-bridge-react"; import { RadioButton } from "@shopify/polaris";

"@shopify/app-bridge-react": "^3.7.2",

joeyfreund commented 1 year ago

@karthik-skr , any chance you can share your code here? (if you don't feel comfortable sharing your actual code, then perhaps a similar code snippet that reproduces the problem)

I would like to understand whether this is a bug in the library, or something that needs to be clarified in our docs.

Waynenabors commented 1 year ago

I'm having a similar issue and can reproduce with this

"@shopify/app-bridge": "^3.7.4",
"@shopify/app-bridge-react": "^3.7.4",
import { ResourcePicker } from "@shopify/app-bridge-react";
<ResourcePicker
            resourceType="Collection"
            open
            onSelection={payload => {
              console.log("payload", payload);
            }}
          />
payload {id: '2a3fba1c...', selection: Array(0)}

Only happens when coming from an external url to the page (Admin > Discounts in this instance); if I hit refresh it works the second time. Also using some components from "@shopify/discount-app-components". On web google chrome

pie2211 commented 1 year ago

Same issue for us where we're importing multiple resource pickers onto a page, in our case each picker resides in a separately imported section component.

<Page>
      <Layout>
        <Layout.Section>
              <LinkedProductSection />
        </Layout.Section>
        <Layout.Section>
              <GatedProductsSection />
        </Layout.Section>
        <Layout.Section>
              <GatedDiscountSection />
        </Layout.Section>
      </Layout>
</Page >

The collection picker was functioning as intended with any number and combination of product/collection picker interactions, at some point it then started to exhibit the issue outlined.

A roll back to an earlier commit followed by placing the pickers directly into a stripped down test page did not resolve the issue.

Also tried a couple of additional tests:

  1. passing a props object to a single component implementation and updating the item type
  2. render a picker only when open state true (mount/unmount)
  3. apply unique component key ids.

In all combinations and cases the exact same issue was observed:

The product pickers always return a payload selection whereas the collection picker only returns data if opened before a product picker or on a second opening following a product picker open/close. All pickers fetch and return a list of resources.

    "@reduxjs/toolkit": "^1.9.3",
    "@sentry/react": "^7.42.0",
    "@sentry/tracing": "^7.42.0",

    "@shopify/app-bridge": "^3.7.4",
    "@shopify/app-bridge-react": "^3.7.4",

    "@shopify/app-bridge-utils": "^3.5.1",
    "@shopify/polaris": "^10.38.0",
    "@shopify/react-form": "^2.5.1",
    "@vitejs/plugin-react": "3.1.0",
    "i18next": "^22.4.11",
    "i18next-browser-languagedetector": "^7.0.1",
    "i18next-http-backend": "^2.1.1",
    "react": "^18.1.0",
    "react-dom": "^18.1.0",
    "react-i18next": "^12.2.0",
    "react-query": "^3.39.3",
    "react-redux": "^8.0.5",
    "react-router-dom": "^6.9.0",
    "redux-thunk": "^2.4.2",
    "vite": "^4.1.4"
daviareias commented 8 months ago

It seems that I've found the cause.

The problem occurs when you mix two types "gid" in the array that you pass "selectionIds"

This code will reproduce the error after you click save

shopify.resourcePicker({
 // this seems to still work if you choose type "product", 
 // if you choose "variant" it will also reproduce the error
  type: "collection",
  selectionIds: [
    { id: "gid://shopify/Collection/397487309036" },
    { id: "gid://shopify/Product/397487309036" }
  ],
});

In the example above, Shopify expects a collection gid, but we passed a product gid as well, if you pass a non existant collection it seems to be able to handle it.

Solution in React

The easiest way that I found to fix it is just to clear the array if you change the type of resource you're passing.

function MyComponent({ resourceType }: { resourceType: "product" | "collection"|"variant" }) {
    type T = {
        id: string;
        variants?: { id: string }[];
    };

    const [selected, setSelected] = useState([] as T[]);

    useEffect(() => {
        // This resets the state when the resource type changes
        setSelected([]);
    }, [resourceType]);

    shopify.resourcePicker({
        type: resourceType,
        selectionIds: selected
    });

    // ...rest of the code
}

In this component, the useEffect hook is used to reset the selected state whenever the resourceType changes. This ensures that when the resource picker is invoked, it receives the correct type of resource ids.

I wish Shopify would give us a way to close the resourcePicker instead of making it hang for ever.