@okendo/shopify-hydrogen 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. package/README.md +23 -22
  2. package/dist/esnext/components/OkendoProvider.server.d.ts +12 -0
  3. package/dist/esnext/components/OkendoProvider.server.js +49 -0
  4. package/dist/esnext/components/OkendoProvider.server.js.map +1 -0
  5. package/dist/esnext/components/OkendoReviewsWidget.server.d.ts +6 -0
  6. package/dist/esnext/components/OkendoReviewsWidget.server.js +57 -0
  7. package/dist/esnext/components/OkendoReviewsWidget.server.js.map +1 -0
  8. package/dist/esnext/components/OkendoStarRating.server.d.ts +6 -0
  9. package/dist/esnext/components/OkendoStarRating.server.js +40 -0
  10. package/dist/esnext/components/OkendoStarRating.server.js.map +1 -0
  11. package/dist/esnext/components/OkendoWidget.client.d.ts +13 -0
  12. package/dist/esnext/components/OkendoWidget.client.js +21 -0
  13. package/dist/esnext/components/OkendoWidget.client.js.map +1 -0
  14. package/dist/esnext/components/index.d.ts +3 -0
  15. package/dist/esnext/components/index.js +4 -0
  16. package/dist/esnext/components/index.js.map +1 -0
  17. package/dist/esnext/index.d.ts +1 -0
  18. package/dist/esnext/index.js +2 -0
  19. package/dist/esnext/index.js.map +1 -0
  20. package/dist/esnext/shared/productUtils.d.ts +6 -0
  21. package/dist/esnext/shared/productUtils.js +16 -0
  22. package/dist/esnext/shared/productUtils.js.map +1 -0
  23. package/dist/node/plugin/extendViteOptimizeDeps.d.ts +2 -0
  24. package/dist/node/plugin/extendViteOptimizeDeps.js +15 -0
  25. package/dist/node/plugin/extendViteOptimizeDeps.js.map +1 -0
  26. package/dist/node/plugin/index.d.ts +3 -0
  27. package/dist/node/plugin/index.js +9 -0
  28. package/dist/node/plugin/index.js.map +1 -0
  29. package/package.json +4 -3
package/README.md CHANGED
@@ -1,13 +1,16 @@
1
- # Okendo Hydrogen React Components #
1
+ # Okendo Hydrogen React Components
2
2
 
3
3
  This is the React component library to support Okendo Widget Plus Widgets in Shopify Hydrogen Projects.
4
4
 
5
5
  Currently we support server side components for 2 widgets:
6
+
6
7
  1. Reviews List
7
8
  2. Star Ratings
8
9
 
9
- This includes:
10
- ## OkendoProvider.server ##
10
+ ## Overview
11
+
12
+ ### OkendoProvider.server
13
+
11
14
  This retrieves the Widget Plus configuration from our public API.
12
15
 
13
16
  This should wrap as high up in the React component tree as possible.
@@ -15,30 +18,28 @@ This should wrap as high up in the React component tree as possible.
15
18
  In the sample Shopify Hydrogen project in `App.server.jsx` we include it as the first child of `<ShopifyProvider>`.
16
19
 
17
20
  The final server side render/output includes:
18
- * Okendo Subscriber Settings JSON
19
- * Widget Pre-Render Style Tags Metafield - This is the "Above the fold" CSS essential for rendering SSR'd Okendo Reviews Widget (first page) and Star Ratings - This ensures styled widgets before client-side hydration occurs.
20
- * Base CSS Vars
21
- * Any custom CSS specified in the Okendo Admin.
22
21
 
23
- ## OkendoStarRating.server ##
24
- This is the server-side rendered Star Rating widget - It then invokes the client side `OkendoWidget.client.tsx` component to perform client side hydration.
22
+ - Okendo Subscriber Settings JSON
23
+ - Widget Pre-Render Style Tags Metafield: This is the "Above the fold" CSS essential for rendering server-side rendered (SSR) Okendo Reviews Widget (first page) and Star Ratings. This ensures styled widgets before client-side hydration occurs.
24
+ - Base CSS Vars
25
+ - Okendo Initialisation Script: This is used to render the widgets on the page.
26
+ - Any custom CSS specified in the Okendo Admin.
27
+
28
+ ### OkendoStarRating.server
25
29
 
26
- ## OkendoReviewsWidget.server ##
27
- This is the server-side rendered Reviews List widget - It then invokes the client side `OkendoWidget.client.tsx` component to perform client side hydration.
30
+ This is the server-side rendered Star Rating widget. It then invokes the client side `OkendoWidget.client.tsx` component to perform client side hydration.
28
31
 
32
+ ### OkendoReviewsWidget.server
29
33
 
30
- ### How do I use this in my Shopify Hydrogen project? ###
31
- * Your Shopify Hydrogen app will require the following variables added to your `.env` file:
32
- ** `VITE_STORE_DOMAIN`: Your myshopify.com URL
33
- ** `VITE_SHOPIFY_STOREFRONT_TOKEN`: Your Shopify App Storefront Token - See: https://shopify.dev/api/examples/storefront-api
34
- ** `VITE_OKENDO_SUBSCRIBER_ID`: Your Okendo Subscriber ID - Issued by Okendo
35
- ** `VITE_OKENDO_API_DOMAIN`: The Okendo api domain this will override the default production domain if supplied: api.okendo.io
36
- ** `VITE_OKENDO_CDN`: The Okendo CDN domain - This will override the default production domain if supplied: cdn.okendo.io
34
+ This is the server-side rendered Reviews List widget. It then invokes the client side `OkendoWidget.client.tsx` component to perform client side hydration.
37
35
 
38
- * TODO - Ideally we point to a sample hydrogen project using our widgets.
36
+ ## How do I use this in my Shopify Hydrogen project?
39
37
 
38
+ - [Okendo Shopify Hydrogen Guide](https://www.notion.so/okendo/Okendo-Shopify-Hydrogen-Guide-0054b79113c34a1fb3f9a8b661ddaac9)
39
+ - [Okendo Shopify Hydrogen Demo Project](https://bitbucket.org/okendo/okendo-shopify-hydrogen-demo/)
40
40
 
41
- ### Who do I talk to? ###
41
+ ## Who do I talk to?
42
42
 
43
- * Tom Fulcher - tom.fulcher@okendo.io, Susanne Peng - susanne.peng@okendo.io, Rowan Puckeridge - rowan.puckeridge@okendo.io
44
- * Okendo Widget Pod
43
+ - Tom Fulcher - tom.fulcher@okendo.io
44
+ - Susanne Peng - susanne.peng@okendo.io
45
+ - Rowan Puckeridge - rowan.puckeridge@okendo.io
@@ -0,0 +1,12 @@
1
+ import React from "react";
2
+ import type { ReviewWithProductPublic } from '@okendo/reviews-common';
3
+ export declare const OkendoContext: React.Context<{}>;
4
+ export declare const OkendoProvider: React.FunctionComponent<OkendoProviderProps>;
5
+ interface OkendoProviderProps {
6
+ children: React.ReactNode;
7
+ subscriberId: string;
8
+ apiDomain?: string;
9
+ cdnDomain?: string;
10
+ productUrlFormatOverride?: (product: Pick<ReviewWithProductPublic, 'productHandle' | 'productId' | 'variantId'>) => string;
11
+ }
12
+ export {};
@@ -0,0 +1,49 @@
1
+ import React from "react";
2
+ import parse from "html-react-parser";
3
+ import { Head } from "@shopify/hydrogen/client";
4
+ import { fetchSync, useShopQuery, gql } from "@shopify/hydrogen";
5
+ const kDefaultContext = {};
6
+ const kDefaultOkendoApiDomain = 'api.okendo.io/v1';
7
+ const kDefaultOkendoCdnDomain = 'd3hw6dc1ow8pp2.cloudfront.net';
8
+ export const OkendoContext = React.createContext(kDefaultContext);
9
+ export const OkendoProvider = (props) => {
10
+ var _a;
11
+ const { children, subscriberId, apiDomain, cdnDomain, productUrlFormatOverride } = props;
12
+ const url = `https://${apiDomain !== null && apiDomain !== void 0 ? apiDomain : kDefaultOkendoApiDomain}/stores/${subscriberId}/widget_plus_settings`;
13
+ const { reviewsHeaderConfig, cssVariables, customCss, starSymbols } = fetchSync(url, { preload: true }).json();
14
+ const cssVariablesNormalized = cssVariables.replace('<style id="oke-css-vars">', '').replace('</style>', '');
15
+ const customCssNormalized = customCss && customCss.replace('<style id="oke-reviews-custom-css">', '').replace('</style>', '');
16
+ const productUrlFormatter = typeof productUrlFormatOverride === 'function'
17
+ ? productUrlFormatOverride
18
+ : (product) => (product === null || product === void 0 ? void 0 : product.productHandle)
19
+ ? `/products/${product.productHandle}/${product.variantId ? '?variantId=' + product.variantId : ''}`
20
+ : undefined;
21
+ const query = gql `
22
+ query metafields {
23
+ shop {
24
+ widgetPreRenderStyleTags: metafield(namespace: "okendo", key: "WidgetPreRenderStyleTags") {
25
+ value
26
+ }
27
+ }
28
+ }
29
+ `;
30
+ const { data: { shop: { widgetPreRenderStyleTags } } } = useShopQuery({
31
+ query: query,
32
+ preload: true
33
+ });
34
+ const styles = parse((_a = widgetPreRenderStyleTags === null || widgetPreRenderStyleTags === void 0 ? void 0 : widgetPreRenderStyleTags.value) !== null && _a !== void 0 ? _a : '');
35
+ // Download contents of widget initialisation script.
36
+ const initScriptContents = fetchSync(`https://${cdnDomain !== null && cdnDomain !== void 0 ? cdnDomain : kDefaultOkendoCdnDomain}/reviews-widget-plus/js/okendo-reviews.js`).text();
37
+ return (React.createElement(React.Fragment, null,
38
+ React.createElement(Head, null,
39
+ React.createElement("script", { id: "oke-reviews-settings", type: "application/json" }, JSON.stringify(reviewsHeaderConfig)),
40
+ React.createElement("style", { id: "oke-css-vars" }, cssVariablesNormalized),
41
+ customCssNormalized && React.createElement("style", { id: "oke-reviews-custom-css" }, customCssNormalized),
42
+ React.createElement("meta", { name: "oke:subscriber_id", content: subscriberId }),
43
+ React.createElement("script", null, initScriptContents),
44
+ productUrlFormatter && React.createElement("script", { type: "text/javascript" }, `window.okeProductUrlFormatter = ${productUrlFormatter}`)),
45
+ styles,
46
+ parse(starSymbols),
47
+ children));
48
+ };
49
+ //# sourceMappingURL=OkendoProvider.server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"OkendoProvider.server.js","sourceRoot":"","sources":["../../../src/components/OkendoProvider.server.tsx"],"names":[],"mappings":"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","sourcesContent":["import React from \"react\";\nimport parse from \"html-react-parser\";\nimport { Head } from \"@shopify/hydrogen/client\";\nimport { fetchSync, useShopQuery, gql } from \"@shopify/hydrogen\";\nimport type { ReviewsAPIPublic, ReviewWithProductPublic } from '@okendo/reviews-common';\nimport type { Metafield } from \"@shopify/hydrogen/dist/esnext/storefront-api-types\";\n\nconst kDefaultContext = {};\nconst kDefaultOkendoApiDomain = 'api.okendo.io/v1';\nconst kDefaultOkendoCdnDomain = 'd3hw6dc1ow8pp2.cloudfront.net';\n\nexport const OkendoContext = React.createContext(kDefaultContext);\n\nexport const OkendoProvider: React.FunctionComponent<OkendoProviderProps> = (props): JSX.Element => {\n const { children, subscriberId, apiDomain, cdnDomain, productUrlFormatOverride } = props;\n const url = `https://${apiDomain ?? kDefaultOkendoApiDomain}/stores/${subscriberId}/widget_plus_settings`;\n const { reviewsHeaderConfig, cssVariables, customCss, starSymbols } = fetchSync(url, { preload: true }).json() as ReviewsAPIPublic.Reviews.WidgetPlusSettings.Get.Response;\n\n const cssVariablesNormalized = cssVariables.replace('<style id=\"oke-css-vars\">', '').replace('</style>', '');\n const customCssNormalized = customCss && customCss.replace('<style id=\"oke-reviews-custom-css\">', '').replace('</style>', '');\n\n const productUrlFormatter = typeof productUrlFormatOverride === 'function' \n ? productUrlFormatOverride \n : (product: Pick<ReviewWithProductPublic, 'productHandle' | 'productId' | 'variantId'>) =>\n product?.productHandle\n ? `/products/${product.productHandle}/${\n product.variantId ? '?variantId=' + product.variantId : ''\n }`\n : undefined;\n\n const query = gql`\n query metafields {\n shop {\n widgetPreRenderStyleTags: metafield(namespace: \"okendo\", key: \"WidgetPreRenderStyleTags\") {\n value\n }\n }\n }\n `;\n\n const {\n data: { shop: { widgetPreRenderStyleTags } }\n } = useShopQuery<OkendoProviderMetafields>({\n query: query,\n preload: true\n });\n\n const styles = parse(widgetPreRenderStyleTags?.value ?? '');\n\n // Download contents of widget initialisation script.\n const initScriptContents: string = fetchSync(`https://${cdnDomain ?? kDefaultOkendoCdnDomain}/reviews-widget-plus/js/okendo-reviews.js`).text();\n return (\n <>\n <Head>\n <script id=\"oke-reviews-settings\" type=\"application/json\">\n {JSON.stringify(reviewsHeaderConfig)}\n </script>\n <style id=\"oke-css-vars\">\n {cssVariablesNormalized}\n </style>\n {customCssNormalized && <style id=\"oke-reviews-custom-css\">{customCssNormalized}</style>}\n <meta name=\"oke:subscriber_id\" content={subscriberId} />\n <script>{initScriptContents}</script>\n {productUrlFormatter && <script type=\"text/javascript\">{`window.okeProductUrlFormatter = ${productUrlFormatter}`}</script>}\n </Head>\n {styles}\n {parse(starSymbols)}\n {children}\n </>\n );\n}\n\ninterface OkendoProviderProps {\n children: React.ReactNode;\n subscriberId: string;\n apiDomain?: string;\n cdnDomain?: string;\n productUrlFormatOverride?: (product: Pick<ReviewWithProductPublic, 'productHandle' | 'productId' | 'variantId'>) => string;\n}\n\ninterface OkendoProviderMetafields {\n shop: {\n widgetPreRenderStyleTags?: Pick<Metafield, 'value'>\n };\n}\n"]}
@@ -0,0 +1,6 @@
1
+ import React from 'react';
2
+ export declare const OkendoReviewsWidget: React.FunctionComponent<OkendoReviewsWidgetProps>;
3
+ interface OkendoReviewsWidgetProps {
4
+ productId?: string;
5
+ }
6
+ export default OkendoReviewsWidget;
@@ -0,0 +1,57 @@
1
+ import { useShopQuery, gql } from '@shopify/hydrogen';
2
+ import parse from 'html-react-parser';
3
+ import { OkendoWidgetClient } from './OkendoWidget.client';
4
+ import { getOkendoProductId } from '../shared/productUtils';
5
+ import React from 'react';
6
+ export const OkendoReviewsWidget = (props) => {
7
+ var _a, _b, _c, _d;
8
+ const { productId } = props;
9
+ const productQuery = productId
10
+ ? `
11
+ product(id: $productId) {
12
+ reviewsWidgetSnippet: metafield(namespace: "okendo", key: "ReviewsWidgetSnippet") {
13
+ value
14
+ }
15
+ }
16
+ `
17
+ : '';
18
+ const query = gql `
19
+ query metafields${productId ? '($productId: ID!)' : ''} {
20
+ ${productQuery}
21
+ shop {
22
+ widgetPreRenderBodyStyleTags: metafield(namespace: "okendo", key: "WidgetPreRenderBodyStyleTags") {
23
+ value
24
+ }
25
+ }
26
+ }
27
+ `;
28
+ const { data: { product, shop } } = useShopQuery({
29
+ query: query,
30
+ preload: true,
31
+ variables: {
32
+ productId: productId
33
+ }
34
+ });
35
+ if (productId && !((_a = product === null || product === void 0 ? void 0 : product.reviewsWidgetSnippet) === null || _a === void 0 ? void 0 : _a.value)) {
36
+ console.error(`--OKE-- Could not retrieve product 'reviewsWidgetSnippet' metafield.`);
37
+ return null;
38
+ }
39
+ if (!((_b = shop === null || shop === void 0 ? void 0 : shop.widgetPreRenderBodyStyleTags) === null || _b === void 0 ? void 0 : _b.value)) {
40
+ console.error(`--OKE-- Could not retrieve shop 'widgetPreRenderBodyStyleTags' metafield.`);
41
+ return null;
42
+ }
43
+ const dataAttributes = {
44
+ 'data-oke-widget': ''
45
+ };
46
+ if (productId) {
47
+ const okendoProductId = getOkendoProductId(productId);
48
+ if (okendoProductId) {
49
+ dataAttributes['data-oke-reviews-product-id'] = okendoProductId;
50
+ }
51
+ }
52
+ return (React.createElement(React.Fragment, null,
53
+ parse(shop.widgetPreRenderBodyStyleTags.value),
54
+ React.createElement(OkendoWidgetClient, { dataAttributes: dataAttributes, metafieldContent: (_d = (_c = product === null || product === void 0 ? void 0 : product.reviewsWidgetSnippet) === null || _c === void 0 ? void 0 : _c.value) !== null && _d !== void 0 ? _d : '' })));
55
+ };
56
+ export default OkendoReviewsWidget;
57
+ //# sourceMappingURL=OkendoReviewsWidget.server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"OkendoReviewsWidget.server.js","sourceRoot":"","sources":["../../../src/components/OkendoReviewsWidget.server.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,GAAG,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,KAAK,MAAM,mBAAmB,CAAC;AACtC,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAE3D,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAE5D,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,MAAM,CAAC,MAAM,mBAAmB,GAAsD,CAAC,KAAK,EAAE,EAAE;;IAC5F,MAAM,EAAE,SAAS,EAAE,GAAG,KAAK,CAAC;IAE5B,MAAM,YAAY,GAAG,SAAS;QAC1B,CAAC,CAAC;;;;;;SAMD;QACD,CAAC,CAAC,EAAE,CAAC;IAET,MAAM,KAAK,GAAG,GAAG,CAAA;0BACK,SAAS,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAC,EAAE;cAChD,YAAY;;;;;;;KAOrB,CAAC;IAEF,MAAM,EACF,IAAI,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,EAC1B,GAAG,YAAY,CAAgC;QAC5C,KAAK,EAAE,KAAK;QACZ,OAAO,EAAE,IAAI;QACb,SAAS,EAAE;YACP,SAAS,EAAE,SAAS;SACvB;KACJ,CAAC,CAAC;IAEH,IAAI,SAAS,IAAI,CAAC,CAAA,MAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,oBAAoB,0CAAE,KAAK,CAAA,EAAE;QACpD,OAAO,CAAC,KAAK,CAAC,sEAAsE,CAAC,CAAC;QACtF,OAAO,IAAI,CAAC;KACf;IAED,IAAI,CAAC,CAAA,MAAA,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAE,4BAA4B,0CAAE,KAAK,CAAA,EAAE;QAC5C,OAAO,CAAC,KAAK,CAAC,2EAA2E,CAAC,CAAC;QAC3F,OAAO,IAAI,CAAC;KACf;IAED,MAAM,cAAc,GAAQ;QACxB,iBAAiB,EAAE,EAAE;KACxB,CAAC;IAEF,IAAI,SAAS,EAAE;QACX,MAAM,eAAe,GAAG,kBAAkB,CAAC,SAAS,CAAC,CAAC;QACtD,IAAI,eAAe,EAAE;YACjB,cAAc,CAAC,6BAA6B,CAAC,GAAG,eAAe,CAAC;SACnE;KACJ;IAED,OAAO,CACH;QACK,KAAK,CAAC,IAAI,CAAC,4BAA4B,CAAC,KAAK,CAAC;QAC/C,oBAAC,kBAAkB,IAAC,cAAc,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAA,MAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,oBAAoB,0CAAE,KAAK,mCAAI,EAAE,GAAI,CACrH,CACN,CAAC;AACN,CAAC,CAAC;AAeF,eAAe,mBAAmB,CAAC","sourcesContent":["import { useShopQuery, gql } from '@shopify/hydrogen';\nimport parse from 'html-react-parser';\nimport { OkendoWidgetClient } from './OkendoWidget.client';\nimport { Metafield } from '@shopify/hydrogen/dist/esnext/storefront-api-types';\nimport { getOkendoProductId } from '../shared/productUtils';\nimport type { SKO } from '@okendo/reviews-common';\nimport React from 'react';\n\nexport const OkendoReviewsWidget: React.FunctionComponent<OkendoReviewsWidgetProps> = (props) => {\n const { productId } = props;\n\n const productQuery = productId\n ? `\n product(id: $productId) {\n reviewsWidgetSnippet: metafield(namespace: \"okendo\", key: \"ReviewsWidgetSnippet\") {\n value\n }\n }\n `\n : '';\n\n const query = gql`\n query metafields${productId ? '($productId: ID!)' : ''} {\n ${productQuery}\n shop {\n widgetPreRenderBodyStyleTags: metafield(namespace: \"okendo\", key: \"WidgetPreRenderBodyStyleTags\") {\n value\n }\n }\n }\n `;\n\n const {\n data: { product, shop }\n } = useShopQuery<OkendoReviewsWidgetMetafields>({\n query: query,\n preload: true,\n variables: {\n productId: productId\n }\n });\n\n if (productId && !product?.reviewsWidgetSnippet?.value) {\n console.error(`--OKE-- Could not retrieve product 'reviewsWidgetSnippet' metafield.`);\n return null;\n }\n\n if (!shop?.widgetPreRenderBodyStyleTags?.value) {\n console.error(`--OKE-- Could not retrieve shop 'widgetPreRenderBodyStyleTags' metafield.`);\n return null;\n }\n\n const dataAttributes: SKO = {\n 'data-oke-widget': ''\n };\n\n if (productId) {\n const okendoProductId = getOkendoProductId(productId);\n if (okendoProductId) {\n dataAttributes['data-oke-reviews-product-id'] = okendoProductId;\n }\n }\n\n return (\n <>\n {parse(shop.widgetPreRenderBodyStyleTags.value)}\n <OkendoWidgetClient dataAttributes={dataAttributes} metafieldContent={product?.reviewsWidgetSnippet?.value ?? ''} />\n </>\n );\n};\n\ninterface OkendoReviewsWidgetProps {\n productId?: string;\n}\n\ninterface OkendoReviewsWidgetMetafields {\n product: {\n reviewsWidgetSnippet?: Pick<Metafield, 'value'>;\n };\n shop: {\n widgetPreRenderBodyStyleTags?: Pick<Metafield, 'value'>;\n };\n}\n\nexport default OkendoReviewsWidget;\n"]}
@@ -0,0 +1,6 @@
1
+ import React from 'react';
2
+ export declare const OkendoStarRating: React.FunctionComponent<OkendoStarRatingProps>;
3
+ interface OkendoStarRatingProps {
4
+ productId: string;
5
+ }
6
+ export default OkendoStarRating;
@@ -0,0 +1,40 @@
1
+ import { useShopQuery, gql } from '@shopify/hydrogen';
2
+ import { OkendoWidgetClient } from './OkendoWidget.client';
3
+ import { getOkendoProductId } from '../shared/productUtils';
4
+ import React from 'react';
5
+ export const OkendoStarRating = (props) => {
6
+ const { productId } = props;
7
+ const okendoProductId = getOkendoProductId(productId);
8
+ if (!okendoProductId) {
9
+ console.warn(`--OKE-- Product does not contain id.`);
10
+ return null;
11
+ }
12
+ const query = gql `
13
+ query metafields($productId: ID!) {
14
+ product(id: $productId) {
15
+ starRatingSnippet: metafield(namespace: "okendo", key: "StarRatingSnippet") {
16
+ value
17
+ }
18
+ }
19
+ }
20
+ `;
21
+ const { data: { product: { starRatingSnippet } } } = useShopQuery({
22
+ query: query,
23
+ preload: true,
24
+ variables: {
25
+ productId: productId
26
+ }
27
+ });
28
+ if (!(starRatingSnippet === null || starRatingSnippet === void 0 ? void 0 : starRatingSnippet.value)) {
29
+ console.error(`--OKE-- Could not retrieve product 'starRatingSnippet' metafield.`);
30
+ return null;
31
+ }
32
+ const dataAttributes = {
33
+ 'data-oke-star-rating': '',
34
+ 'data-oke-reviews-product-id': okendoProductId,
35
+ 'data-oke-scroll-disabled': 'true'
36
+ };
37
+ return (React.createElement(OkendoWidgetClient, { dataAttributes: dataAttributes, metafieldContent: starRatingSnippet.value }));
38
+ };
39
+ export default OkendoStarRating;
40
+ //# sourceMappingURL=OkendoStarRating.server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"OkendoStarRating.server.js","sourceRoot":"","sources":["../../../src/components/OkendoStarRating.server.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,GAAG,EAAE,MAAM,mBAAmB,CAAC;AAGtD,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,MAAM,CAAC,MAAM,gBAAgB,GAAmD,CAAC,KAAK,EAAuB,EAAE;IAC3G,MAAM,EAAE,SAAS,EAAE,GAAG,KAAK,CAAC;IAE5B,MAAM,eAAe,GAAG,kBAAkB,CAAC,SAAS,CAAC,CAAC;IACtD,IAAI,CAAC,eAAe,EAAE;QAClB,OAAO,CAAC,IAAI,CAAC,sCAAsC,CAAC,CAAC;QACrD,OAAO,IAAI,CAAC;KACf;IAED,MAAM,KAAK,GAAG,GAAG,CAAA;;;;;;;;KAQhB,CAAC;IAEF,MAAM,EACF,IAAI,EAAE,EACF,OAAO,EAAE,EAAE,iBAAiB,EAAE,EACjC,EACJ,GAAG,YAAY,CAA6B;QACzC,KAAK,EAAE,KAAK;QACZ,OAAO,EAAE,IAAI;QACb,SAAS,EAAE;YACP,SAAS,EAAE,SAAS;SACvB;KACJ,CAAC,CAAC;IAEH,IAAI,CAAC,CAAA,iBAAiB,aAAjB,iBAAiB,uBAAjB,iBAAiB,CAAE,KAAK,CAAA,EAAE;QAC3B,OAAO,CAAC,KAAK,CAAC,mEAAmE,CAAC,CAAC;QACnF,OAAO,IAAI,CAAC;KACf;IAED,MAAM,cAAc,GAAG;QACnB,sBAAsB,EAAE,EAAE;QAC1B,6BAA6B,EAAE,eAAe;QAC9C,0BAA0B,EAAE,MAAM;KACrC,CAAC;IAEF,OAAO,CACH,oBAAC,kBAAkB,IAAC,cAAc,EAAE,cAAc,EAAE,gBAAgB,EAAE,iBAAiB,CAAC,KAAK,GAAI,CACpG,CAAC;AACN,CAAC,CAAC;AAYF,eAAe,gBAAgB,CAAC","sourcesContent":["import { useShopQuery, gql } from '@shopify/hydrogen';\nimport { Metafield } from '@shopify/hydrogen/dist/esnext/storefront-api-types';\nimport { ReactElement } from 'react';\nimport { OkendoWidgetClient } from './OkendoWidget.client';\nimport { getOkendoProductId } from '../shared/productUtils';\nimport React from 'react';\n\nexport const OkendoStarRating: React.FunctionComponent<OkendoStarRatingProps> = (props): ReactElement | null => {\n const { productId } = props;\n\n const okendoProductId = getOkendoProductId(productId);\n if (!okendoProductId) {\n console.warn(`--OKE-- Product does not contain id.`);\n return null;\n }\n\n const query = gql`\n query metafields($productId: ID!) {\n product(id: $productId) {\n starRatingSnippet: metafield(namespace: \"okendo\", key: \"StarRatingSnippet\") {\n value\n }\n }\n }\n `;\n\n const {\n data: {\n product: { starRatingSnippet }\n }\n } = useShopQuery<OkendoStarRatingMetafields>({\n query: query,\n preload: true,\n variables: {\n productId: productId\n }\n });\n\n if (!starRatingSnippet?.value) {\n console.error(`--OKE-- Could not retrieve product 'starRatingSnippet' metafield.`);\n return null;\n }\n\n const dataAttributes = {\n 'data-oke-star-rating': '',\n 'data-oke-reviews-product-id': okendoProductId,\n 'data-oke-scroll-disabled': 'true'\n };\n\n return (\n <OkendoWidgetClient dataAttributes={dataAttributes} metafieldContent={starRatingSnippet.value} />\n );\n};\n\ninterface OkendoStarRatingProps {\n productId: string;\n}\n\ninterface OkendoStarRatingMetafields {\n product: {\n starRatingSnippet?: Pick<Metafield, 'value'>;\n };\n}\n\nexport default OkendoStarRating;\n"]}
@@ -0,0 +1,13 @@
1
+ import type { SKO } from "@okendo/reviews-common";
2
+ import type { ReviewsWidgetPlus } from '@okendo/reviews-widget-plus/dist-utils/ReviewsWidgetPlus';
3
+ import React from "react";
4
+ export declare const OkendoWidgetClient: React.FunctionComponent<OkendoWidgetClientProps>;
5
+ export interface OkendoWidgetClientProps {
6
+ dataAttributes: SKO;
7
+ metafieldContent: string;
8
+ }
9
+ declare global {
10
+ interface Window {
11
+ okeWidgetApi: ReviewsWidgetPlus.WidgetWindowApi;
12
+ }
13
+ }
@@ -0,0 +1,21 @@
1
+ import React from "react";
2
+ import { useEffect, useRef } from "react";
3
+ export const OkendoWidgetClient = (props) => {
4
+ const { dataAttributes, metafieldContent } = props;
5
+ const widgetContainer = useRef(null);
6
+ const initialiseReviewsWidget = () => {
7
+ if (widgetContainer.current) {
8
+ window.okeWidgetApi.initWidget(widgetContainer.current);
9
+ }
10
+ };
11
+ useEffect(() => {
12
+ if (window.okeWidgetApi) {
13
+ initialiseReviewsWidget();
14
+ }
15
+ else {
16
+ window.addEventListener('oke-script-loaded', initialiseReviewsWidget);
17
+ }
18
+ }, []);
19
+ return (React.createElement("div", { ref: widgetContainer, ...dataAttributes, dangerouslySetInnerHTML: { __html: metafieldContent } }));
20
+ };
21
+ //# sourceMappingURL=OkendoWidget.client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"OkendoWidget.client.js","sourceRoot":"","sources":["../../../src/components/OkendoWidget.client.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AAE1C,MAAM,CAAC,MAAM,kBAAkB,GAAqD,CAAC,KAAK,EAAE,EAAE;IAC1F,MAAM,EAAE,cAAc,EAAE,gBAAgB,EAAE,GAAG,KAAK,CAAC;IACnD,MAAM,eAAe,GAAG,MAAM,CAAiB,IAAI,CAAC,CAAC;IAErD,MAAM,uBAAuB,GAAG,GAAG,EAAE;QACjC,IAAI,eAAe,CAAC,OAAO,EAAE;YACzB,MAAM,CAAC,YAAY,CAAC,UAAU,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC;SAC3D;IACL,CAAC,CAAC;IAEF,SAAS,CAAC,GAAG,EAAE;QACX,IAAI,MAAM,CAAC,YAAY,EAAE;YACrB,uBAAuB,EAAE,CAAC;SAC7B;aACI;YACD,MAAM,CAAC,gBAAgB,CAAC,mBAAmB,EAAE,uBAAuB,CAAC,CAAC;SACzE;IACL,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,OAAO,CACH,6BAAK,GAAG,EAAE,eAAe,KAAM,cAAc,EAAE,uBAAuB,EAAG,EAAE,MAAM,EAAE,gBAAgB,EAAE,GAAS,CACjH,CAAC;AACN,CAAC,CAAA","sourcesContent":["import type { SKO } from \"@okendo/reviews-common\";\nimport type { ReviewsWidgetPlus } from '@okendo/reviews-widget-plus/dist-utils/ReviewsWidgetPlus';\nimport React from \"react\";\nimport { useEffect, useRef } from \"react\";\n\nexport const OkendoWidgetClient: React.FunctionComponent<OkendoWidgetClientProps> = (props) => {\n const { dataAttributes, metafieldContent } = props;\n const widgetContainer = useRef<HTMLDivElement>(null);\n\n const initialiseReviewsWidget = () => {\n if (widgetContainer.current) {\n window.okeWidgetApi.initWidget(widgetContainer.current);\n }\n };\n\n useEffect(() => {\n if (window.okeWidgetApi) {\n initialiseReviewsWidget();\n }\n else {\n window.addEventListener('oke-script-loaded', initialiseReviewsWidget);\n }\n }, []);\n\n return (\n <div ref={widgetContainer} {...dataAttributes} dangerouslySetInnerHTML={ { __html: metafieldContent } }></div>\n );\n}\n\nexport interface OkendoWidgetClientProps {\n dataAttributes: SKO;\n metafieldContent: string;\n}\n\ndeclare global {\n interface Window {\n okeWidgetApi: ReviewsWidgetPlus.WidgetWindowApi;\n }\n}\n"]}
@@ -0,0 +1,3 @@
1
+ export * from './OkendoReviewsWidget.server';
2
+ export * from './OkendoStarRating.server';
3
+ export * from './OkendoProvider.server';
@@ -0,0 +1,4 @@
1
+ export * from './OkendoReviewsWidget.server';
2
+ export * from './OkendoStarRating.server';
3
+ export * from './OkendoProvider.server';
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/components/index.ts"],"names":[],"mappings":"AAAA,cAAc,8BAA8B,CAAC;AAC7C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,yBAAyB,CAAC","sourcesContent":["export * from './OkendoReviewsWidget.server';\nexport * from './OkendoStarRating.server';\nexport * from './OkendoProvider.server';\n"]}
@@ -0,0 +1 @@
1
+ export * from './components';
@@ -0,0 +1,2 @@
1
+ export * from './components';
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC","sourcesContent":["export * from './components';\n"]}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Gets the product ID with Okendo formatting.
3
+ * @param productId The Shopify Product ID e.g. gid://shopify/Product/10079785100.
4
+ * @returns The product ID in Okendo formatting.
5
+ */
6
+ export declare function getOkendoProductId(productId: string): string | undefined;
@@ -0,0 +1,16 @@
1
+ const kProductIdRegex = /^[0-9]*$/;
2
+ /**
3
+ * Gets the product ID with Okendo formatting.
4
+ * @param productId The Shopify Product ID e.g. gid://shopify/Product/10079785100.
5
+ * @returns The product ID in Okendo formatting.
6
+ */
7
+ export function getOkendoProductId(productId) {
8
+ if (!productId) {
9
+ return;
10
+ }
11
+ // Supports Shopify's GraphQL Id syntax e.g. gid://shopify/Product/10079785100
12
+ return `shopify-${kProductIdRegex.test(productId)
13
+ ? productId
14
+ : productId.split('/').slice(-1)[0]}`;
15
+ }
16
+ //# sourceMappingURL=productUtils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"productUtils.js","sourceRoot":"","sources":["../../../src/shared/productUtils.ts"],"names":[],"mappings":"AAAA,MAAM,eAAe,GAAG,UAAU,CAAC;AAEnC;;;;GAIG;AACH,MAAM,UAAU,kBAAkB,CAAC,SAAiB;IAChD,IAAI,CAAC,SAAS,EAAE;QACZ,OAAO;KACV;IAED,8EAA8E;IAC9E,OAAO,WAAW,eAAe,CAAC,IAAI,CAAC,SAAS,CAAC;QAC7C,CAAC,CAAC,SAAS;QACX,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAClC,EAAE,CAAC;AACX,CAAC","sourcesContent":["const kProductIdRegex = /^[0-9]*$/;\n\n/**\n * Gets the product ID with Okendo formatting.\n * @param productId The Shopify Product ID e.g. gid://shopify/Product/10079785100.\n * @returns The product ID in Okendo formatting.\n */\nexport function getOkendoProductId(productId: string): string | undefined {\n if (!productId) {\n return;\n }\n\n // Supports Shopify's GraphQL Id syntax e.g. gid://shopify/Product/10079785100\n return `shopify-${kProductIdRegex.test(productId)\n ? productId\n : productId.split('/').slice(-1)[0]\n }`;\n}\n"]}
@@ -0,0 +1,2 @@
1
+ import type { Plugin } from 'vite';
2
+ export declare const extendViteOptimizeDeps: () => Plugin;
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.extendViteOptimizeDeps = void 0;
4
+ const extendViteOptimizeDeps = () => ({
5
+ name: 'vite-plugin-okendo-extend-optimize-deps',
6
+ config: () => ({
7
+ optimizeDeps: {
8
+ include: [
9
+ '@okendo/shopify-hydrogen > html-react-parser'
10
+ ]
11
+ }
12
+ })
13
+ });
14
+ exports.extendViteOptimizeDeps = extendViteOptimizeDeps;
15
+ //# sourceMappingURL=extendViteOptimizeDeps.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extendViteOptimizeDeps.js","sourceRoot":"","sources":["../../../src/plugins/extendViteOptimizeDeps.ts"],"names":[],"mappings":";;;AAEO,MAAM,sBAAsB,GAAG,GAAW,EAAE,CAAC,CAAC;IACjD,IAAI,EAAE,yCAAyC;IAC/C,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC;QACX,YAAY,EAAE;YACV,OAAO,EAAE;gBACL,8CAA8C;aACjD;SACJ;KACJ,CAAC;CACL,CAAC,CAAC;AATU,QAAA,sBAAsB,0BAShC","sourcesContent":["import type { Plugin } from 'vite';\n\nexport const extendViteOptimizeDeps = (): Plugin => ({\n name: 'vite-plugin-okendo-extend-optimize-deps',\n config: () => ({\n optimizeDeps: {\n include: [\n '@okendo/shopify-hydrogen > html-react-parser'\n ]\n }\n })\n});\n"]}
@@ -0,0 +1,3 @@
1
+ import type { Plugin } from 'vite';
2
+ declare const _default: () => Plugin[];
3
+ export default _default;
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const extendViteOptimizeDeps_1 = require("./extendViteOptimizeDeps");
4
+ exports.default = () => {
5
+ return [
6
+ (0, extendViteOptimizeDeps_1.extendViteOptimizeDeps)()
7
+ ];
8
+ };
9
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/plugins/index.ts"],"names":[],"mappings":";;AACA,qEAAkE;AAElE,kBAAe,GAAG,EAAE;IAChB,OAAO;QACH,IAAA,+CAAsB,GAAE;KACf,CAAC;AAClB,CAAC,CAAC","sourcesContent":["import type { Plugin } from 'vite';\nimport { extendViteOptimizeDeps } from './extendViteOptimizeDeps';\n\nexport default () => {\n return [\n extendViteOptimizeDeps()\n ] as Plugin[];\n};\n"]}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@okendo/shopify-hydrogen",
3
- "version": "0.0.1",
4
- "description": "A component library containing Okendo Reviews Widget componenets.",
3
+ "version": "0.0.2",
4
+ "description": "A component library containing Okendo Reviews React components.",
5
5
  "main": "dist/esnext/index.js",
6
6
  "files": [
7
7
  "dist",
@@ -10,7 +10,8 @@
10
10
  "scripts": {
11
11
  "build": "rimraf dist/ && npm run build:plugin:cjs && npm run build:esm",
12
12
  "build:plugin:cjs": "tsc --p tsconfig.plugin.cjs.json",
13
- "build:esm": "tsc --p tsconfig.esm.json"
13
+ "build:esm": "tsc --p tsconfig.esm.json",
14
+ "prepublishOnly": "npm run build"
14
15
  },
15
16
  "author": "Okendo",
16
17
  "license": "ISC",