npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@findify/react-bundle

v0.20.0

Published

React Hook that allows you to simply integrate Findify with React app

Downloads

468

Readme

@findify/react-bundle

React hook that allows you to integrate Findify Search/Autocomplete/Smart Collections/Recommendations with any React SPA App. ​

Installation

Install dependency

yarn add @findify/react-bundle

Add script to index.html

<script type="text/javascript" src="https://assets.findify.io/%REACT_APP_FINDIFY_STORE%.min.js"></script>
​

Add variable in .env

REACT_APP_FINDIFY_STORE="YOUR_STORE_NAME"

Usage

import React from 'react'
import useFindify from '@findify/react-bundle'
​
export default () => {
  const [container, isReady, hasError, error = useFindify({ type: 'search' })
  return (
    <div ref={container} />
  )
}

​ The first element of an array is a React.createRef() that you should add as ref to the element where widget will be rendered. ​ The second element is a widget ready state: true or false. You can use this state to show and hide placeholders while findify is still rendering. ​ The third element of an array is an error state: true or false. It will return true if there are errors or if there are no items returned in response.

The fourth element of an array is an string representation of the error ​

Props

​ | Prop | Required | Default value | Description | |---|---|---|---| | type<String> | yes | ''| Type of widget. It could be search, recommendation, autocomplete, smart-collection. | | history<History> | no | undefined| Custom history instance. This prop is required if you want to have a history navigation. | | widgetKey<String> | no | random| Widget unique Id. You can provide this parameter if you would like to use Findify API in the future. | | config<Object> | no | | Custom widget configuration that will be merged with the default one. When it comes to creating Recommendation widgets, you would need to provide slot prop to the config object. | | options<Object> | no | | Additional request options | ​

For more information about Findify API and request options please visit https://developers.findify.io/docs/merchant-js-api ​ ​


Simple Jetshop example

To prevent unnecessary scroll add 'FindifyUpdate' to the ignoreForRouteTypes array in /src/components/Shop.js

<ScrollRestorationHandler
  ignoreForRouteTypes={[
    'sortOrderChange',
    'filterChange',
    'paginationChange',
    'FindifyUpdate'
  ]}
/>

Search

Go to /components/SearchPage/SearchPage.js

//...
import useFindify from '@findify/react-bundle';
import { useHistory } from 'react-router';
​
export const Container = styled(MaxWidth)`
  padding: 0 0.75rem;
`;
​
//...
const SearchPage = routeProps => {
  const track = useTracker();
  const history = useHistory();
  const { pathname, search } = routeProps.location;
  const [container, isReady] = useFindify({ type: 'search', history });
​
  useEffect(() => {
    track(trackPageEvent({ pathname: `${pathname}${search}` }));
  }, [track, pathname, search]);
​
  return (
    <Container>
      <div ref={container} />
    </Container>
  );
};

Autocomplete

Go to /components/Layout/Header/SearchBar.js

//...
import useFindify from '@findify/react-bundle';
import { useHistory } from 'react-router';
​
​
//...
const StyledSearchField = styled('div')`
  & {
    display: flex;
    height: 2rem;
    width: 100% !important;
    justify-content: center;
    input {
      border: 0;
      background: #f3f3f3;
      height: 100%;
      width: 100%;
      padding: 0 1rem;
    }
  }
`;
​
const SearchBar = ({ searchOpen, setSearchOpen }) => {
  const history = useHistory();
  const [container] = useFindify({ type: 'autocomplete', history });
  return (
    <PoseGroup flipMove={true}>
      {searchOpen && (
        <PosedSearchBarContainer key={'searchBarPosed'}>
          <InnerSearchBar>
            <StyledSearchField>
              <input ref={container} />
            </StyledSearchField>
          </InnerSearchBar>
        </PosedSearchBarContainer>
      )}
    </PoseGroup>
  )
};

Recommendation

Go to /components/StartPage/StatPage.js

//...
import useFindify from '@findify/react-bundle';
​
//...
const StartPage = ({ location: { pathname, key }, startPageId }) => {
  const [container, isReady, hasError, error] = useFindify({
    type: 'recommendation',
    config: {
      slot: 'home-findify-rec-2', // Slot is required for recommendation widgets
    }
  });
  return (
    <Fragment>
      <StartPageWrapper>
        <Container>
          <div ref={container} />
          { !isReady && !hasError && 'Widget loading...'}
          // ...

Smart Collection

Go to /components/StartPage/StatPage.js

//...
import useFindify from '@findify/react-bundle';
​
//...
​
const CategoryPage = props => {
  // ...
  const [container, isReady, hasError, error] = useFindify({ type: 'smart-collection' });
​
  if (!hasError) {
    return (
      <Container>
        <div ref={container} />
        { !isReady && 'Loading collection'}
      </Container>
    )
  }
  if (infinitePagination) {
    return <LoadableWindowedCategoryPage {...props} />;
  } else {
    return <LoadableStandardCategoryPage {...props} />;
  }
};
  //...

For Smart Collections, Findify is introducing fallback measurements by rendering the default collections, in case if the current Smart Collection is not setup in Findify. This is to prevent blank collection pages.

Content in the Search Results

//...
import useFindify from '@findify/react-bundle';
​
//...
​
const ContentPage = props => {
  // ...
  const [container, isReady, hasError, error] = useFindify({ type: 'content' });
​
  if (!hasError) {
    return (
      <Container>
        <div
          ref={container}
          data-type="shopify-collection_985"
         />
        { !isReady && 'Loading content'}
      </Container>
    )
  }
};
  //...

Unlike other widgets, content results widget get the type of content from the node where it is rendered. You must provide data-type="CONTENT_SOURCE" to the element where is will be rendered (you can get the CONTENT_SOURCE parameter from the Merchant Dashboard).

Analytics

To access Findify's analytics instance from anywhere in your app you can use the following example:

import { waitForFindify } from '@findify/react-bundle';

async () => {
  const { analytics } = await waitForFindify();
  analytics.sendEvent('event', { ...options })
}

Update cart event

Should be sent after product has been added to the cart and contain the whole cat content

 const { analytics } = await waitForFindify();
 analytics.sendEvent('update-cart', {
    line_items: [ // Array of products
      {
        item_id: "PRODUCT_ID_1",
        quantity: 1,
        unit_price: 22.35,
        variant_item_id: "VARIANT_ID_1"
      }
    ]
 });

Purchase event

Should be sent when user purchases products

 const { analytics } = await waitForFindify();
 analytics.sendEvent('purchase', {
    currency: "EUR",
    line_items: [// Array of products
      {
        item_id: "PRODUCT_ID_1",
        quantity: 1,
        unit_price: 288.28,
        variant_item_id: "VARIANT_ID_1"
      },
    ],
    order_id: "ORDER_ID",
    revenue: 288.28
 });

View page event

Should be sent every time user lands on the product page

 const { analytics } = await waitForFindify();
 analytics.sendEvent('view-page', {
  item_id: "PRODUCT_ID",
  variant_item_id: "PRODUCT_VARIANT_ID"
 })

Product click event

In case you are using your own History instance, you should update components/Cards/Product/view.tsx and change onClick event for the product card (this is done via DevTools Extension as a customization to our platfom):

const ProductCardView ({ item }) => {
  const onClick = useCallback((e) => {
    e.preventDefault();
    // Calling this method will ensure that all analytics events will be sent to Findify properly
    item.sendAnalytics();
    findify.utils.history.push(item.get('product_url'))
  }, []);

  return (
    <a onClick={onClick}>
    ...