How to filter items in a ResourceList

Viewed 144

I am trying to filter ResourceItems in my ResourceList by their tag. For exmaple, if a user searches for the tag "Sports", all items with the this tag should be returned.

I have been utilising this example to produce this, but it doesn't actually have any functionality when the user enters a tag to filter by.

This is my code so far, in which I don't get any items back:

const GetProductList = () => {
  
  // State setup
  const [taggedWith, setTaggedWith] = useState(null);
  const [queryValue, setQueryValue] = useState(null);

  // Handled TaggedWith filter
  const handleTaggedChange = useCallback(
    (value) => setTaggedWith(value),
    [],
  );

  const handleTaggedRemove = useCallback(() => setTaggedWith(null), []);
  const handleQueryRemove = useCallback(() => setQueryValue(null), []);
  const handleFilterClear = useCallback(() => {
    handleTaggedRemove();
    handleQueryRemove();
  }, [handleQueryRemove, handleTaggedRemove]);

  const filters = [
    {
      key:'taggedWith',
      label:'Tagged With',
      filter: (
        <TextField 
          label="Tagged With"
          value={taggedWith}
          onChange={handleTaggedChange}
          labelHidden
        />
      ),
      shortcut: true,
    }
  ];

  const appliedFilters = !isEmpty(taggedWith)
    ? [
        {
          key: 'taggedWith',
          label: disambiguateLabel('taggedWith', taggedWith),
          onRemove: handleTaggedRemove,
        },
      ]
    : [];

  const filterControl = (
    <Filters
      queryValue={queryValue}
      filters={filters}
      appliedFilters={appliedFilters}
      onQueryChange={setQueryValue}
      onQueryClear={handleQueryRemove}
      onClearAll={handleFilterClear}
      children={() => {
        <div>Hello World</div>
      }}
    >
      <div>
        <Button onClick={() => console.log('New Filter Saved')}>Save</Button>
      </div>
    </Filters>
  )

  // Execute GET_PRODUCTS GQL Query
  const { loading, error, data } = useQuery(GET_PRODUCTS);

  if (loading) return "Loading products...";
  if (error) return `Error = ${error}`;

  // Return dropdown menu of all products
  return (
    <Frame>
      <Page>
        <Layout>

          <Layout.Section>
            <DisplayText size="large">WeBuy Valuation Tool</DisplayText>
          </Layout.Section>

          <Layout.Section>
            <Card>
              <Card.Section>
                <div>
                  <Card>
                    <ResourceList
                      resourceName={{singular: 'product', plural: 'products'}}
                      items={data ? data.products.edges : ""}
                      renderItem={renderItem}
                      filterControl={filterControl}
                    >
                    </ResourceList>
                  </Card>
                </div>
              </Card.Section>
            </Card>
          </Layout.Section>
        </Layout>
      </Page>
    </Frame>
  )

  function renderItem(item) {
    const { id, title, images, tags } = item.node;
    const media = (
      <Thumbnail
        source={ images.edges[0] ? images.edges[0].node.originalSrc : '' }
        alt={ images.edges[0] ? images.edges[0].node.altText : '' }
      />
    );
    const resourceItem = (
      <ResourceItem 
        id={id} 
        accessibilityLabel={`View details for ${title}`}
        media={media}
      >
        <Stack>
          <Stack.Item fill>
            <h3><TextStyle variation="strong">{title}</TextStyle></h3>
            <h2>{tags}</h2>
          </Stack.Item>
          <Stack.Item>
            <AddMetafield id={id} />
            <DeleteMetafield id={id} />
          </Stack.Item>
        </Stack>
      </ResourceItem>
    );

    tags ? tags.forEach(tag => {
      if (tag == "Sports") {
        console.log("has tag")
        return resourceItem
      }
    }) : console.log("Return") 
  }

  function disambiguateLabel (key, value) {
    switch(key) {
      case 'taggedWith' :
        return `Tagged with ${value}`;
      default:
        return value;
    }
  }

  function isEmpty(value) {
    if (Array.isArray(value)) {
      return value.length === 0;
    } else {
      return value === '' || value == null;
    }
  }

}

1 Answers

I Couldn't find any documentation on how to implement this, and I expected it to be built-in, but I ended up doing something like this:

//add "filter.apply" function to the filter object
const filters = [{...apply:(c:Item)=>...},isApplied=...]   
const appliedFilters = filters.filter(f=>f.isApplied);

let filteredItems = pageData.Items;
for (const filter of appliedFilters){
    filteredItems = filteredItems.filter(filter.apply)
}
if(queryValue && queryValue.length > 0){
    filteredItems = filteredItems.filter((c:FBComment)=>c.text.includes(queryValue))
}

Related