{"id":22480145,"url":"https://github.com/findify/react-bundle","last_synced_at":"2026-04-02T02:48:16.730Z","repository":{"id":43858974,"uuid":"329692748","full_name":"findify/react-bundle","owner":"findify","description":"Findify integration with Jetshop SPA","archived":false,"fork":false,"pushed_at":"2022-10-05T09:03:21.000Z","size":157,"stargazers_count":0,"open_issues_count":0,"forks_count":2,"subscribers_count":11,"default_branch":"main","last_synced_at":"2024-11-07T20:23:38.185Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/findify.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-01-14T17:52:22.000Z","updated_at":"2021-11-18T09:41:00.000Z","dependencies_parsed_at":"2023-01-19T06:30:59.167Z","dependency_job_id":null,"html_url":"https://github.com/findify/react-bundle","commit_stats":null,"previous_names":["findify/jetshop"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/findify%2Freact-bundle","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/findify%2Freact-bundle/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/findify%2Freact-bundle/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/findify%2Freact-bundle/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/findify","download_url":"https://codeload.github.com/findify/react-bundle/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":228483524,"owners_count":17927363,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-12-06T15:19:52.858Z","updated_at":"2026-04-02T02:48:16.674Z","avatar_url":"https://github.com/findify.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# @findify/react-bundle\nReact hook that allows you to integrate Findify Search/Autocomplete/Smart Collections/Recommendations with any React SPA App.\n​\n## Installation\n​\n#### Install dependency\n```bash\nyarn add @findify/react-bundle\n```\n​\n#### Add script to `index.html`\n```html\n\u003cscript type=\"text/javascript\" src=\"https://assets.findify.io/%REACT_APP_FINDIFY_STORE%.min.js\"\u003e\u003c/script\u003e\n​\n```\n​\n#### Add variable in `.env`\n```\nREACT_APP_FINDIFY_STORE=\"YOUR_STORE_NAME\"\n```\n---\n## Usage\n```javascript\nimport React from 'react'\nimport useFindify from '@findify/react-bundle'\n​\nexport default () =\u003e {\n  const [container, isReady, hasError, error] = useFindify({ type: 'search' })\n  return (\n    \u003cdiv ref={container} /\u003e\n  )\n}\n```\n​\nThe first element of an array is a `React.createRef()` that you should add as `ref` to the element where widget will be rendered.\n​\nThe 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.\n​\nThe 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.\n\nThe fourth element of an array is an string representation of the error\n​\n### Props\n​\n| Prop | Required | Default value | Description |\n|---|---|---|---|\n| `type\u003cString\u003e` | *yes* | `''`| Type of widget. It could be `search`, `recommendation`, `autocomplete`, `smart-collection`. |\n| `history\u003cHistory\u003e` | *no* | `undefined`| Custom history instance. This prop is required if you want to have a history navigation. |\n| `widgetKey\u003cString\u003e` | *no* | `random`| Widget unique Id. You can provide this parameter if you would like to use Findify API in the future. |\n| `config\u003cObject\u003e` | *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. |\n| `options\u003cObject\u003e` | *no* | | Additional request options |\n​\n\u003e For more information about Findify API and request options please visit [https://developers.findify.io/docs/merchant-js-api](https://developers.findify.io/docs/merchant-js-api)\n​\n​\n---\n## Simple Jetshop example\n​\n\u003e To prevent unnecessary scroll add 'FindifyUpdate' to the `ignoreForRouteTypes` array in `/src/components/Shop.js`\n```javascript\n\u003cScrollRestorationHandler\n  ignoreForRouteTypes={[\n    'sortOrderChange',\n    'filterChange',\n    'paginationChange',\n    'FindifyUpdate'\n  ]}\n/\u003e\n```\n​\n### Search\nGo to `/components/SearchPage/SearchPage.js` \n```javascript\n//...\nimport useFindify from '@findify/react-bundle';\nimport { useHistory } from 'react-router';\n​\nexport const Container = styled(MaxWidth)`\n  padding: 0 0.75rem;\n`;\n​\n//...\nconst SearchPage = routeProps =\u003e {\n  const track = useTracker();\n  const history = useHistory();\n  const { pathname, search } = routeProps.location;\n  const [container, isReady, hasError, error] = useFindify({ \n    type: 'search', \n    history,\n    config: {\n      ... //you can pass extra properties to the widget\n    }\n  });\n​\n  useEffect(() =\u003e {\n    track(trackPageEvent({ pathname: `${pathname}${search}` }));\n  }, [track, pathname, search]);\n​\n  return (\n    \u003cContainer\u003e\n      \u003cdiv ref={container} /\u003e\n    \u003c/Container\u003e\n  );\n};\n```\n​\n### Autocomplete\nGo to `/components/Layout/Header/SearchBar.js`\n```javascript\n//...\nimport useFindify from '@findify/react-bundle';\nimport { useHistory } from 'react-router';\n​\n​\n//...\nconst StyledSearchField = styled('div')`\n  \u0026 {\n    display: flex;\n    height: 2rem;\n    width: 100% !important;\n    justify-content: center;\n    input {\n      border: 0;\n      background: #f3f3f3;\n      height: 100%;\n      width: 100%;\n      padding: 0 1rem;\n    }\n  }\n`;\n​\nconst SearchBar = ({ searchOpen, setSearchOpen }) =\u003e {\n  const history = useHistory();\n  const [container] = useFindify({ \n    type: 'autocomplete', \n    history,\n    config: {\n      ... //you can pass extra properties to the widget\n    }\n  });\n  return (\n    \u003cPoseGroup flipMove={true}\u003e\n      {searchOpen \u0026\u0026 (\n        \u003cPosedSearchBarContainer key={'searchBarPosed'}\u003e\n          \u003cInnerSearchBar\u003e\n            \u003cStyledSearchField\u003e\n              \u003cinput ref={container} /\u003e\n            \u003c/StyledSearchField\u003e\n          \u003c/InnerSearchBar\u003e\n        \u003c/PosedSearchBarContainer\u003e\n      )}\n    \u003c/PoseGroup\u003e\n  )\n};\n```\n​\n### Recommendation\nGo to `/components/StartPage/StatPage.js`\n```javascript\n//...\nimport useFindify from '@findify/react-bundle';\n​\n//...\nconst StartPage = ({ location: { pathname, key }, startPageId }) =\u003e {\n  const [container, isReady, hasError, error] = useFindify({\n    type: 'recommendation',\n    config: {\n      slot: 'home-findify-rec-2', // Slot is required for recommendation widgets,\n      ... //you can pass extra properties to the widget\n    },\n    options: {\n       rules: [{\n         'action': 'exclude',\n         'type': 'text',\n         'name': 'id',\n         'values': [{\n           value: ['item_id_1', 'item_id_2', ...] //can be used for Recommendation type: Frequently Purchased/Viewed Together on PDP or Cart pages\n         }]\n       }],\n       item_ids: ['item_id_1', 'item_id_2', ...] //required for Recommendation type: Frequently Purchased/Viewed Together on PDP or Cart pages\n    },\n  });\n  return (\n    \u003cFragment\u003e\n      \u003cStartPageWrapper\u003e\n        \u003cContainer\u003e\n          \u003cdiv ref={container} /\u003e\n          { !isReady \u0026\u0026 !hasError \u0026\u0026 'Widget loading...'}\n          // ...\n```\n​\n### Smart Collection\nGo to `/components/StartPage/StatPage.js`\n```javascript\n//...\nimport useFindify from '@findify/react-bundle';\n​\n//...\n​\nconst CategoryPage = props =\u003e {\n  // ...\n  const [container, isReady, hasError, error] = useFindify({ \n    type: 'smart-collection',\n    config: {\n      slot: 'some_collection_slot' //optional: you can override the smart-collections slot with custom one\n      ... //you can pass extra properties to the widget\n    }\n  });\n​\n  if (!hasError) {\n    return (\n      \u003cContainer\u003e\n        \u003cdiv ref={container} /\u003e\n        { !isReady \u0026\u0026 'Loading collection'}\n      \u003c/Container\u003e\n    )\n  }\n  if (infinitePagination) {\n    return \u003cLoadableWindowedCategoryPage {...props} /\u003e;\n  } else {\n    return \u003cLoadableStandardCategoryPage {...props} /\u003e;\n  }\n};\n  //...\n```\nFor 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.\n\n## Content in the Search Results\n```javascript\n//...\nimport useFindify from '@findify/react-bundle';\n​\n//...\n​\nconst ContentPage = props =\u003e {\n  // ...\n  const [container, isReady, hasError, error] = useFindify({ \n    type: 'content',\n    config: {\n      ... //you can pass extra properties to the widget\n    }\n  });\n​\n  if (!hasError) {\n    return (\n      \u003cContainer\u003e\n        \u003cdiv\n          ref={container}\n          data-type=\"shopify-collection_985\"\n         /\u003e\n        { !isReady \u0026\u0026 'Loading content'}\n      \u003c/Container\u003e\n    )\n  }\n};\n  //...\n```\nUnlike other widgets, content results widget get the type of content from the node where it is rendered.\nYou 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).\n\n## Analytics\nTo access Findify's analytics instance from anywhere in your app you can use the following example:\n```javascript\nimport { waitForFindify } from '@findify/react-bundle';\n\nasync () =\u003e {\n  const { analytics } = await waitForFindify();\n  analytics.sendEvent('event', { ...options })\n}\n``` \n\n### Update cart event\nShould be sent on all pages along with `view-page` event and it should have items that are currently added to the cart. If there are no products in the cart, just send an empty `line_items` array. The event must also be fired after a product has been added to the cart.\n```javascript\n const { analytics } = await waitForFindify();\n analytics.sendEvent('update-cart', {\n    line_items: [ // Array of products\n      {\n        item_id: \"PRODUCT_ID_1\",\n        quantity: 1,\n        unit_price: 22.35,\n        variant_item_id: \"VARIANT_ID_1\"\n      }\n    ]\n });\n```\n### Purchase event\nShould be sent when user purchases products\n```javascript\n const { analytics } = await waitForFindify();\n analytics.sendEvent('purchase', {\n    currency: \"EUR\",\n    line_items: [// Array of products\n      {\n        item_id: \"PRODUCT_ID_1\",\n        quantity: 1,\n        unit_price: 288.28,\n        variant_item_id: \"VARIANT_ID_1\"\n      },\n    ],\n    order_id: \"ORDER_ID\",\n    revenue: 288.28\n });\n```\n### View page event\nShould be fired on every redirect. If the user landed on the Product Page, you need to pass extra parameters: `item_id` and `variant_item_id`:\n```javascript\n const { analytics } = await waitForFindify();\n analytics.sendEvent('view-page', {\n  item_id: \"PRODUCT_ID\", //required, if the user is on the Product Page\n  variant_item_id: \"PRODUCT_VARIANT_ID\", //required, if the user is on the Product Page\n  force: true\n })\n```\n### Product click event\nIn 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 platform):\n```javascript\nconst ProductCardView ({ item }) =\u003e {\n  const onClick = useCallback((e) =\u003e {\n    e.preventDefault();\n    // Calling this method will ensure that all analytics events will be sent to Findify properly\n    item.sendAnalytics();\n    findify.utils.history.push(item.get('product_url'))\n  }, []);\n\n  return (\n    \u003ca onClick={onClick}\u003e\n    ...\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffindify%2Freact-bundle","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffindify%2Freact-bundle","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffindify%2Freact-bundle/lists"}