@okendo/shopify-hydrogen 2.3.2 → 2.4.0

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.
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  # Okendo Hydrogen 2 (Remix) React Components
4
4
 
5
- This package brings [Okendo's review widgets](https://www.okendo.io/blog/widget-plus/) to a Shopify Hydrogen store.
5
+ This package brings [Okendo's review widgets](https://www.okendo.io/blog/widget-plus/) and [Loyalty widgets](https://okendo.io/loyalty/) to a Shopify Hydrogen store.
6
6
 
7
7
  ## Requirements
8
8
 
@@ -44,6 +44,8 @@ Follow the instructions on [this page](https://help.shopify.com/en/manual/apps/a
44
44
 
45
45
  #### Using Curl
46
46
 
47
+ > Note: The settings metafields exist within the Okendo App's Reserved Namespace. To access these metafields we need to include the Okendo App ID (`app--1576377`) as a prefix in the `namespace` field.
48
+
47
49
  Open a new terminal or PowerShell window, then:
48
50
 
49
51
  1. Run the following command to expose the `widget_pre_render_style_tags` shop metafield:
@@ -58,7 +60,7 @@ mutation {
58
60
  metafieldDefinitionCreate(
59
61
  definition: {
60
62
  name: "WidgetPreRenderStyleTags"
61
- namespace: "$app:reviews"
63
+ namespace: "app--1576377--reviews"
62
64
  key: "widget_pre_render_style_tags"
63
65
  type: "multi_line_text_field"
64
66
  ownerType: SHOP
@@ -87,7 +89,7 @@ mutation {
87
89
  metafieldDefinitionCreate(
88
90
  definition: {
89
91
  name: "WidgetPreRenderBodyStyleTags"
90
- namespace: "$app:reviews"
92
+ namespace: "app--1576377--reviews"
91
93
  key: "widget_pre_render_body_style_tags"
92
94
  type: "multi_line_text_field"
93
95
  ownerType: SHOP
@@ -116,7 +118,7 @@ mutation {
116
118
  metafieldDefinitionCreate(
117
119
  definition: {
118
120
  name: "ReviewsWidgetSnippet"
119
- namespace: "$app:reviews"
121
+ namespace: "app--1576377--reviews"
120
122
  key: "reviews_widget_snippet"
121
123
  type: "multi_line_text_field"
122
124
  ownerType: PRODUCT
@@ -145,7 +147,7 @@ mutation {
145
147
  metafieldDefinitionCreate(
146
148
  definition: {
147
149
  name: "StarRatingSnippet"
148
- namespace: "$app:reviews"
150
+ namespace: "app--1576377--reviews"
149
151
  key: "star_rating_snippet"
150
152
  type: "multi_line_text_field"
151
153
  ownerType: PRODUCT
@@ -174,7 +176,7 @@ mutation {
174
176
  metafieldDefinitionCreate(
175
177
  definition: {
176
178
  name: "ReviewCount"
177
- namespace: "$app:reviews"
179
+ namespace: "app--1576377--reviews"
178
180
  key: "review_count"
179
181
  type: "number_integer"
180
182
  ownerType: PRODUCT
@@ -203,7 +205,7 @@ mutation {
203
205
  metafieldDefinitionCreate(
204
206
  definition: {
205
207
  name: "AverageRating"
206
- namespace: "$app:reviews"
208
+ namespace: "app--1576377--reviews"
207
209
  key: "average_rating"
208
210
  type: "rating"
209
211
  ownerType: PRODUCT
@@ -234,12 +236,15 @@ mutation {
234
236
  metafieldDefinitionCreate(
235
237
  definition: {
236
238
  name: "WidgetPreRenderStyleTags"
237
- namespace: "$app:reviews"
239
+ namespace: "app--1576377--reviews"
238
240
  key: "widget_pre_render_style_tags"
239
241
  type: "multi_line_text_field"
240
242
  ownerType: SHOP
241
- access: { admin: PUBLIC_READ, storefront: PUBLIC_READ }
242
- }
243
+ access: {
244
+ admin: PUBLIC_READ,
245
+ storefront: PUBLIC_READ
246
+ }
247
+ }
243
248
  ) {
244
249
  createdDefinition {
245
250
  id
@@ -261,12 +266,15 @@ mutation {
261
266
  metafieldDefinitionCreate(
262
267
  definition: {
263
268
  name: "WidgetPreRenderBodyStyleTags"
264
- namespace: "$app:reviews"
269
+ namespace: "app--1576377--reviews"
265
270
  key: "widget_pre_render_body_style_tags"
266
271
  type: "multi_line_text_field"
267
272
  ownerType: SHOP
268
- access: { admin: PUBLIC_READ, storefront: PUBLIC_READ }
269
- }
273
+ access: {
274
+ admin: PUBLIC_READ,
275
+ storefront: PUBLIC_READ
276
+ }
277
+ }
270
278
  ) {
271
279
  createdDefinition {
272
280
  id
@@ -288,12 +296,15 @@ mutation {
288
296
  metafieldDefinitionCreate(
289
297
  definition: {
290
298
  name: "ReviewsWidgetSnippet"
291
- namespace: "$app:reviews"
299
+ namespace: "app--1576377--reviews"
292
300
  key: "reviews_widget_snippet"
293
301
  type: "multi_line_text_field"
294
302
  ownerType: PRODUCT
295
- access: { admin: PUBLIC_READ, storefront: PUBLIC_READ }
296
- }
303
+ access: {
304
+ admin: PUBLIC_READ,
305
+ storefront: PUBLIC_READ
306
+ }
307
+ }
297
308
  ) {
298
309
  createdDefinition {
299
310
  id
@@ -315,12 +326,15 @@ mutation {
315
326
  metafieldDefinitionCreate(
316
327
  definition: {
317
328
  name: "StarRatingSnippet"
318
- namespace: "$app:reviews"
329
+ namespace: "app--1576377--reviews"
319
330
  key: "star_rating_snippet"
320
331
  type: "multi_line_text_field"
321
332
  ownerType: PRODUCT
322
- access: { admin: PUBLIC_READ, storefront: PUBLIC_READ }
323
- }
333
+ access: {
334
+ admin: PUBLIC_READ,
335
+ storefront: PUBLIC_READ
336
+ }
337
+ }
324
338
  ) {
325
339
  createdDefinition {
326
340
  id
@@ -342,12 +356,15 @@ mutation {
342
356
  metafieldDefinitionCreate(
343
357
  definition: {
344
358
  name: "ReviewCount"
345
- namespace: "$app:reviews"
359
+ namespace: "app--1576377--reviews"
346
360
  key: "review_count"
347
361
  type: "number_integer"
348
362
  ownerType: PRODUCT
349
- access: { admin: PUBLIC_READ, storefront: PUBLIC_READ }
350
- }
363
+ access: {
364
+ admin: PUBLIC_READ,
365
+ storefront: PUBLIC_READ
366
+ }
367
+ }
351
368
  ) {
352
369
  createdDefinition {
353
370
  id
@@ -369,12 +386,15 @@ mutation {
369
386
  metafieldDefinitionCreate(
370
387
  definition: {
371
388
  name: "AverageRating"
372
- namespace: "$app:reviews"
389
+ namespace: "app--1576377--reviews"
373
390
  key: "average_rating"
374
391
  type: "rating"
375
392
  ownerType: PRODUCT
376
- access: { admin: PUBLIC_READ, storefront: PUBLIC_READ }
377
- }
393
+ access: {
394
+ admin: PUBLIC_READ,
395
+ storefront: PUBLIC_READ
396
+ }
397
+ }
378
398
  ) {
379
399
  createdDefinition {
380
400
  id
@@ -604,8 +624,8 @@ Add the following block just before the `RECOMMENDED_PRODUCTS_QUERY` GraphQL que
604
624
  const OKENDO_PRODUCT_STAR_RATING_FRAGMENT = `#graphql
605
625
  fragment OkendoStarRatingSnippet on Product {
606
626
  okendoStarRatingSnippet: metafield(
607
- namespace: "$app:reviews"
608
- key: "star_rating_snippet"
627
+ namespace: "app--1576377--reviews"
628
+ key: "star_rating_snippet"
609
629
  ) {
610
630
  value
611
631
  }
@@ -692,8 +712,8 @@ Add the following block just before the `PRODUCT_FRAGMENT` GraphQL query:
692
712
  const OKENDO_PRODUCT_STAR_RATING_FRAGMENT = `#graphql
693
713
  fragment OkendoStarRatingSnippet on Product {
694
714
  okendoStarRatingSnippet: metafield(
695
- namespace: "$app:reviews"
696
- key: "star_rating_snippet"
715
+ namespace: "app--1576377--reviews"
716
+ key: "star_rating_snippet"
697
717
  ) {
698
718
  value
699
719
  }
@@ -703,8 +723,8 @@ const OKENDO_PRODUCT_STAR_RATING_FRAGMENT = `#graphql
703
723
  const OKENDO_PRODUCT_REVIEWS_FRAGMENT = `#graphql
704
724
  fragment OkendoReviewsSnippet on Product {
705
725
  okendoReviewsSnippet: metafield(
706
- namespace: "$app:reviews"
707
- key: "reviews_widget_snippet"
726
+ namespace: "app--1576377--reviews"
727
+ key: "reviews_widget_snippet"
708
728
  ) {
709
729
  value
710
730
  }
@@ -831,4 +851,48 @@ export default function AFeaturedPage() {
831
851
  </div>
832
852
  );
833
853
  }
834
- ```
854
+ ```
855
+
856
+ # Loyalty Widgets
857
+ ## Installation
858
+ To include Loyalty Widgets in your Shopify Hydrogen store, you will need to make the following changes:
859
+
860
+ 1. Add `customerAccessToken: await args.context.customerAccount.getAccessToken(),` to your `loader` function, this will be used to log your customer into the Loyalty App.
861
+
862
+ 2. Add `okendoProducts: ['reviews', 'loyalty'],` as a property to `getOkendoProviderData` in your `loader` function, alongside the existing `context` and `subscriberId` arguments.
863
+
864
+ > Note: If you only wish to use the Loyalty product and not reviews then simply leave out the `'reviews'` from the array like so: `okendoProducts: ['loyalty'],`.
865
+
866
+ The relevant section should now look something like this:
867
+ ```ts
868
+ return defer({
869
+ // ...
870
+ customerAccessToken: await args.context.customerAccount.getAccessToken(),
871
+ okendoProviderData:
872
+ getOkendoProviderData(
873
+ {
874
+ context: args.context,
875
+ subscriberId: '<your-okendo-subscriber-id>',
876
+ okendoProducts: ['reviews', 'loyalty'],
877
+ },
878
+ ),
879
+ });
880
+ ```
881
+
882
+ 3. Add `customerAccessToken={data.customerAccessToken}` to the `OkendoProvider` component, it should now look like:
883
+ ```ts
884
+ <OkendoProvider
885
+ nonce={nonce}
886
+ okendoProviderData={data.okendoProviderData}
887
+ customerAccessToken={data.customerAccessToken}
888
+ >
889
+ ...
890
+ </OkendoProvider>
891
+ ```
892
+
893
+ If your Okendo Loyalty Settings are [correctly set up](https://support.okendo.io/en/collections/8270193-okendo-loyalty) and your program has launched, the Loyalty Floating Widget will now appear on your store.
894
+
895
+ ## Dedicated Loyalty Page
896
+ Add `<OkendoLoyaltyEmbeddedWidget />` to any components/pages where you wish to have the Dedicated Loyalty Page appear.
897
+
898
+ *Make sure you are importing the component from the `okendo-shopify-hydrogen` package: `import {OkendoLoyaltyEmbeddedWidget} from '@okendo/shopify-hydrogen';`*
package/dist/cjs/index.js CHANGED
@@ -1 +1 @@
1
- "use strict";var e=require("react"),t=require("@remix-run/react");const n=e.createContext(void 0),r=({children:t})=>{const[r,a]=e.useState(!1);return e.createElement(n.Provider,{value:{okendoDataLoaded:r,setOkendoDataLoaded:a}},t)},a=()=>{const t=e.useContext(n);return void 0===t?null:t},o="cdn-static.okendo.io",s=({nonce:t="",okendoProviderData:n,productUrlFormatter:r,awaited:s,cdnDomain:i})=>{const d=a(),l=e.useRef(!1);if(e.useEffect((()=>{if(n&&d?.setOkendoDataLoaded(!0),n&&s&&!l.current){const e=document.createElement("script");e.src=`https://${i||o}/reviews-widget-plus/js/okendo-reviews.js`,document.head.appendChild(e),l.current=!0}}),[n,d,s,i]),!n)return null;const{reviewsHeaderConfig:c,cssVariables:u,customCss:p,initScriptContents:m,preRenderStyleTags:g,starSymbols:v}=n,k=(u??"").replace('<style id="oke-css-vars">',"").replace("</style>",""),w=p?p.replace('<style id="oke-reviews-custom-css">',"").replace("</style>",""):"";return e.createElement(e.Fragment,null,e.createElement("script",{nonce:t,id:"oke-reviews-settings",type:"application/json",dangerouslySetInnerHTML:{__html:JSON.stringify(c)}}),e.createElement("style",{nonce:t,id:"oke-css-vars",dangerouslySetInnerHTML:{__html:k}}),w&&e.createElement("style",{nonce:t,id:"oke-reviews-custom-css",dangerouslySetInnerHTML:{__html:w}}),!s&&m&&e.createElement("script",{nonce:t,dangerouslySetInnerHTML:{__html:m}}),e.createElement("script",{nonce:t,type:"text/javascript",dangerouslySetInnerHTML:{__html:`window.okeProductUrlFormatter = ${"function"==typeof r?r.toString():"string"==typeof r?r:"(product) =>\n product && product.productHandle\n ? \"/products/\" + product.productHandle + \"/\" + (product.variantId ? '?variantId=' + product.variantId : '')\n : undefined"}`}}),g&&e.createElement("div",{dangerouslySetInnerHTML:{__html:g}}),v&&e.createElement("div",{dangerouslySetInnerHTML:{__html:v}}))};const i=({dataAttributes:t,metafieldContent:n=""})=>{const r=e.useRef(null),a=e.useRef(!1),o=function(t){const n=e.useRef();return e.useEffect((()=>{n.current=t})),n.current}(t),s=()=>{r.current&&(window.okeWidgetApi.initWidget(r.current),a.current=!0)};return e.useEffect((()=>{if(!o||t["data-oke-widget"]!==o["data-oke-widget"]||t["data-oke-star-rating"]!==o["data-oke-star-rating"]||t["data-oke-reviews-product-id"]!==o["data-oke-reviews-product-id"]||!a.current)return window.okeWidgetApi&&r.current?s():document.addEventListener("oke-script-loaded",s),()=>{document.removeEventListener("oke-script-loaded",s)}}),[t,o]),e.createElement("div",{ref:r,key:JSON.stringify(t),...t,dangerouslySetInnerHTML:n?{__html:n}:void 0})},d=/^[0-9]*$/;function l(e){if(e)return`shopify-${d.test(e)?e:e.split("/").slice(-1)[0]}`}exports.OKENDO_PRODUCT_REVIEWS_FRAGMENT='#graphql\n\tfragment OkendoReviewsSnippet on Product {\n\t\tokendoReviewsSnippet: metafield(\n\t\t\tnamespace: "$app:reviews"\n\t\t\tkey: "reviews_widget_snippet"\n\t\t) {\n\t\t\tvalue\n\t\t}\n\t}\n',exports.OKENDO_PRODUCT_STAR_RATING_FRAGMENT='#graphql\n\tfragment OkendoStarRatingSnippet on Product {\n\t\tokendoStarRatingSnippet: metafield(\n\t\t\tnamespace: "$app:reviews"\n\t\t\tkey: "star_rating_snippet"\n\t\t) {\n\t\t\tvalue\n\t\t}\n\t}\n',exports.OkendoProvider=({nonce:n="",okendoProviderData:a,productUrlFormatter:o,cdnDomain:i,children:d})=>e.createElement(r,null,a&&"then"in a?e.createElement(e.Suspense,null,e.createElement(t.Await,{resolve:a},(t=>e.createElement(s,{nonce:n,okendoProviderData:t,productUrlFormatter:o,cdnDomain:i,awaited:!0})))):e.createElement(s,{nonce:n,okendoProviderData:a,productUrlFormatter:o,cdnDomain:i}),d),exports.OkendoReviews=({productId:t,okendoReviewsSnippet:n,placeholder:r})=>{const o=a(),s=t?.length?l(t):null,d=t?.length?n:null,c={"data-oke-widget":"","data-oke-reviews-product-id":s};return null===o||o.okendoDataLoaded?e.createElement(i,{dataAttributes:c,metafieldContent:d?.value}):r||e.createElement("div",{style:{height:"350px"}})},exports.OkendoReviewsCarousel=({productId:t,groupId:n,headerBadgeUrl:r,placeholder:o})=>{const s=a(),d={"data-oke-carousel":"","data-oke-reviews-product-id":t?.length?l(t):null,"data-oke-reviews-group-id":n?.length?n:null,"data-oke-header-badge-url":r};return null===s||s.okendoDataLoaded?e.createElement(i,{dataAttributes:d}):o||e.createElement("div",{style:{height:"350px"}})},exports.OkendoStarRating=({productId:t,okendoStarRatingSnippet:n,placeholder:r})=>{const o=a(),s={"data-oke-star-rating":"","data-oke-reviews-product-id":l(t)};return null===o||o.okendoDataLoaded?e.createElement(i,{dataAttributes:s,metafieldContent:n?.value}):r||e.createElement("div",{style:{height:"20px"}})},exports.getOkendoProviderData=async({context:e,subscriberId:t,apiDomain:n,cdnDomain:r})=>{const a=`https://${n||"api.okendo.io/v1"}/stores/${t}/widget_plus_settings`,s=await fetch(a);if(!s.ok)return console.error(`Failed to retrieve subscriber settings for subscriber ID '${t}'.`),null;const{reviewsHeaderConfig:i,cssVariables:d,customCss:l,starSymbols:c}=await s.json(),u=await fetch(`https://${r||o}/reviews-widget-plus/js/okendo-reviews.js`);if(!u.ok)return console.error("Failed to retrieve widget initialisation script."),null;const p=await u.text(),{shop:{widgetPreRenderStyleTags:m}}=await e.storefront.query('#graphql\n\t\tquery metafields {\n\t\t\tshop {\n\t\t\t\twidgetPreRenderStyleTags: metafield(\n\t\t\t\t\tnamespace: "$app:reviews"\n\t\t\t\t\tkey: "widget_pre_render_style_tags"\n\t\t\t\t) {\n\t\t\t\t\tvalue\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t'),g=m?.value??"";return g||console.warn("Failed to retrieve pre-rendered widget style settings."),{reviewsHeaderConfig:i,cssVariables:d,customCss:l,initScriptContents:p,preRenderStyleTags:g,starSymbols:c}};
1
+ "use strict";var e=require("@remix-run/react"),t=require("react");const n=t.createContext(void 0),r=({children:e})=>{const[r,o]=t.useState(!1);return t.createElement(n.Provider,{value:{okendoDataLoaded:r,setOkendoDataLoaded:o}},e)},o=()=>{const e=t.useContext(n);return void 0===e?null:e},a=/^[0-9]*$/,s="app--1576377";function i(e){if(e)return`shopify-${a.test(e)?e:e.split("/").slice(-1)[0]}`}const d="cdn-static.okendo.io",l=({nonce:e="",okendoProviderData:n,productUrlFormatter:r,awaited:a,cdnDomain:s})=>{const i=o(),l=t.useRef(!1),c=t.useRef(!1);if(t.useEffect((()=>{if(n&&n.loyaltySettings&&!1===l.current){const e=document.createElement("script");e.src=`https://${s||d}/loyalty/js/init-onsite.js`,document.head.appendChild(e);const t=document.createElement("script");t.type="application/json",t.id="oke-loyalty-settings";const r=n.loyaltySettings?n.loyaltySettings.replace('<script type="application/json" id="oke-loyalty-settings">',"").replace('<\/script><script src="https://rhys-cdn.okendo.dev/loyalty/js/init-onsite.js" defer><\/script>',""):"";t.innerHTML=r,document.head.appendChild(t),l.current=!0}}),[n,s]),t.useEffect((()=>{if(n&&i?.setOkendoDataLoaded(!0),n&&a&&!c.current){const e=document.createElement("script");e.src=`https://${s||d}/reviews-widget-plus/js/okendo-reviews.js`,document.head.appendChild(e),c.current=!0}}),[n,i,a,s]),!n)return null;const{reviewsHeaderConfig:u,cssVariables:p,customCss:m,initScriptContents:y,preRenderStyleTags:g,starSymbols:v}=n,k=(p??"").replace('<style id="oke-css-vars">',"").replace("</style>",""),w=m?m.replace('<style id="oke-reviews-custom-css">',"").replace("</style>",""):"";return t.createElement(t.Fragment,null,t.createElement("script",{nonce:e,id:"oke-reviews-settings",type:"application/json",dangerouslySetInnerHTML:{__html:JSON.stringify(u)}}),t.createElement("style",{nonce:e,id:"oke-css-vars",dangerouslySetInnerHTML:{__html:k}}),w&&t.createElement("style",{nonce:e,id:"oke-reviews-custom-css",dangerouslySetInnerHTML:{__html:w}}),!a&&y&&t.createElement("script",{nonce:e,dangerouslySetInnerHTML:{__html:y}}),t.createElement("script",{nonce:e,type:"text/javascript",dangerouslySetInnerHTML:{__html:`window.okeProductUrlFormatter = ${"function"==typeof r?r.toString():"string"==typeof r?r:"(product) =>\n product && product.productHandle\n ? \"/products/\" + product.productHandle + \"/\" + (product.variantId ? '?variantId=' + product.variantId : '')\n : undefined"}`}}),g&&t.createElement("div",{dangerouslySetInnerHTML:{__html:g}}),v&&t.createElement("div",{dangerouslySetInnerHTML:{__html:v}}))};const c=({dataAttributes:e,metafieldContent:n=""})=>{const r=t.useRef(null),o=t.useRef(!1),a=function(e){const n=t.useRef();return t.useEffect((()=>{n.current=e})),n.current}(e),s=()=>{r.current&&(window.okeWidgetApi.initWidget(r.current),o.current=!0)};return t.useEffect((()=>{if(!a||e["data-oke-widget"]!==a["data-oke-widget"]||e["data-oke-star-rating"]!==a["data-oke-star-rating"]||e["data-oke-reviews-product-id"]!==a["data-oke-reviews-product-id"]||!o.current)return window.okeWidgetApi&&r.current?s():document.addEventListener("oke-script-loaded",s),()=>{document.removeEventListener("oke-script-loaded",s)}}),[e,a]),t.createElement("div",{ref:r,key:JSON.stringify(e),...e,dangerouslySetInnerHTML:n?{__html:n}:void 0})},u=`#graphql\n\tfragment OkendoStarRatingSnippet on Product {\n\t\tokendoStarRatingSnippet: metafield(\n\t\t\tnamespace: "${s}--reviews"\n\t\t\tkey: "star_rating_snippet"\n\t\t) {\n\t\t\tvalue\n\t\t}\n\t}\n`,p=`#graphql\n\tfragment OkendoReviewsSnippet on Product {\n\t\tokendoReviewsSnippet: metafield(\n\t\t\tnamespace: "${s}--reviews"\n\t\t\tkey: "reviews_widget_snippet"\n\t\t) {\n\t\t\tvalue\n\t\t}\n\t}\n`;exports.OKENDO_PRODUCT_REVIEWS_FRAGMENT=p,exports.OKENDO_PRODUCT_STAR_RATING_FRAGMENT=u,exports.OkendoLoyaltyEmbeddedWidget=function(){const n=e.useLocation();return t.useEffect((()=>{window?.okeLoyaltyApi?.initialiseWidgets()}),[n.pathname]),t.createElement("div",{"data-oke-loyalty-embedded-widget":""})},exports.OkendoProvider=({nonce:n="",okendoProviderData:o,customerAccessToken:a,productUrlFormatter:s,cdnDomain:i,children:d})=>t.createElement(r,null,o&&"then"in o?t.createElement(t.Suspense,null,t.createElement(e.Await,{resolve:o},(e=>t.createElement(l,{nonce:n,okendoProviderData:e,productUrlFormatter:s,cdnDomain:i,awaited:!0})))):t.createElement(l,{nonce:n,okendoProviderData:o,productUrlFormatter:s,cdnDomain:i}),a&&t.createElement("script",{nonce:n,id:"oke-loyalty-customer-access-token",type:"application/json",dangerouslySetInnerHTML:{__html:JSON.stringify({customerAccessToken:a})}}),d),exports.OkendoReviews=({productId:e,okendoReviewsSnippet:n,placeholder:r})=>{const a=o(),s=e?.length?i(e):null,d=e?.length?n:null,l={"data-oke-widget":"","data-oke-reviews-product-id":s};return null===a||a.okendoDataLoaded?t.createElement(c,{dataAttributes:l,metafieldContent:d?.value}):r||t.createElement("div",{style:{height:"350px"}})},exports.OkendoReviewsCarousel=({productId:e,groupId:n,headerBadgeUrl:r,placeholder:a})=>{const s=o(),d={"data-oke-carousel":"","data-oke-reviews-product-id":e?.length?i(e):null,"data-oke-reviews-group-id":n?.length?n:null,"data-oke-header-badge-url":r};return null===s||s.okendoDataLoaded?t.createElement(c,{dataAttributes:d}):a||t.createElement("div",{style:{height:"350px"}})},exports.OkendoStarRating=({productId:e,okendoStarRatingSnippet:n,placeholder:r})=>{const a=o(),s={"data-oke-star-rating":"","data-oke-reviews-product-id":i(e)};return null===a||a.okendoDataLoaded?t.createElement(c,{dataAttributes:s,metafieldContent:n?.value}):r||t.createElement("div",{style:{height:"20px"}})},exports.getOkendoProviderData=async({context:e,subscriberId:t,apiDomain:n,cdnDomain:r,okendoProducts:o=["reviews"],appNamespace:a})=>{if(!o.length)return null;const i=`loyaltySettings: metafield(\n namespace: "${a??s}--loyalty",\n key: "loyalty_settings"\n ) {\n value\n }`,l=`widgetPreRenderStyleTags: metafield(\n namespace: "${a??s}--reviews",\n key: "widget_pre_render_style_tags"\n ) {\n value\n }`,c=`#graphql\n query metafields {\n shop {\n ${o.includes("loyalty")?i:""}\n ${o.includes("reviews")?l:""}\n }\n }\n `,{shop:{loyaltySettings:u,widgetPreRenderStyleTags:p}}=await e.storefront.query(c);let m=null;if(o.includes("loyalty")&&(m={...m??{},loyaltySettings:u?.value??""}),o.includes("reviews")){const e=`https://${n||"api.okendo.io/v1"}/stores/${t}/widget_plus_settings`,o=await fetch(e);if(!o.ok)return console.error(`Failed to retrieve subscriber settings for subscriber ID '${t}'.`),m;const{reviewsHeaderConfig:a,cssVariables:s,customCss:i,starSymbols:l}=await o.json(),c=await fetch(`https://${r||d}/reviews-widget-plus/js/okendo-reviews.js`);if(!c.ok)return console.error("Failed to retrieve widget initialisation script."),m;const u=await c.text(),y=p?.value??"";y||console.warn("Failed to retrieve pre-rendered widget style settings."),m={...m??{},reviewsHeaderConfig:a,cssVariables:s,customCss:i,initScriptContents:u,preRenderStyleTags:y,starSymbols:l}}return m};
@@ -0,0 +1,9 @@
1
+ import React from 'react';
2
+ declare global {
3
+ interface Window {
4
+ okeLoyaltyApi?: {
5
+ initialiseWidgets: () => void;
6
+ };
7
+ }
8
+ }
9
+ export declare function OkendoLoyaltyEmbeddedWidget(): React.JSX.Element;
@@ -0,0 +1 @@
1
+ export * from './OkendoLoyaltyEmbeddedWidget';
@@ -1,7 +1,9 @@
1
1
  import type { WidgetPlus } from '@okendo/reviews-common';
2
- import type { Storefront } from '@shopify/hydrogen';
2
+ import type { CustomerAccount, Storefront } from '@shopify/hydrogen';
3
3
  import React, { type PropsWithChildren } from 'react';
4
- interface OkendoProviderData {
4
+ type OkendoProviderData = Partial<OkendoReviewsProviderData & OkendoLoyaltyProviderData>;
5
+ type OkendoProduct = 'reviews' | 'loyalty';
6
+ interface OkendoReviewsProviderData {
5
7
  reviewsHeaderConfig: WidgetPlus.ReviewsHeaderConfig;
6
8
  cssVariables: string;
7
9
  customCss?: string;
@@ -9,14 +11,21 @@ interface OkendoProviderData {
9
11
  preRenderStyleTags: string;
10
12
  starSymbols: string;
11
13
  }
12
- export declare const getOkendoProviderData: ({ context, subscriberId, apiDomain, cdnDomain, }: {
13
- context: {
14
- storefront: Storefront;
15
- };
14
+ interface OkendoLoyaltyProviderData {
15
+ loyaltySettings: string;
16
+ }
17
+ export declare const getOkendoProviderData: ({ context, subscriberId, apiDomain, cdnDomain, okendoProducts, appNamespace, }: {
18
+ context: StorefrontContext;
16
19
  subscriberId: string;
17
20
  apiDomain?: string;
18
21
  cdnDomain?: string;
22
+ okendoProducts?: OkendoProduct[];
23
+ appNamespace?: string;
19
24
  }) => Promise<OkendoProviderData | null>;
25
+ interface StorefrontContext {
26
+ customerAccount: CustomerAccount;
27
+ storefront: Storefront;
28
+ }
20
29
  interface ReviewProduct {
21
30
  productHandle?: string;
22
31
  productId: string;
@@ -36,9 +45,14 @@ interface OkendoProviderProps {
36
45
  * show slightly after page load, but it have the advantage of not increasing the page load time.
37
46
  */
38
47
  okendoProviderData: Partial<OkendoProviderData> | null | Promise<Partial<OkendoProviderData> | null>;
48
+ /**
49
+ * Used by the loyalty widget to verify the user's identity via the Storefront API.
50
+ * Can be retrieved via `await context.customerAccount.getAccessToken()` in the loader function.
51
+ */
52
+ customerAccessToken?: string;
39
53
  /** An optional product URL formatter */
40
54
  productUrlFormatter?: (product: ReviewProduct) => string;
41
55
  cdnDomain?: string;
42
56
  }
43
- export declare const OkendoProvider: ({ nonce, okendoProviderData, productUrlFormatter, cdnDomain, children, }: OkendoProviderProps & PropsWithChildren) => React.JSX.Element;
57
+ export declare const OkendoProvider: ({ nonce, okendoProviderData, customerAccessToken, productUrlFormatter, cdnDomain, children, }: OkendoProviderProps & PropsWithChildren) => React.JSX.Element;
44
58
  export {};
@@ -12,5 +12,5 @@ interface OkendoStarRatingProps {
12
12
  */
13
13
  placeholder?: ReactNode;
14
14
  }
15
- export declare const OkendoStarRating: ({ productId, okendoStarRatingSnippet, placeholder }: OkendoStarRatingProps) => string | number | true | Iterable<React.ReactNode> | React.JSX.Element;
15
+ export declare const OkendoStarRating: ({ productId, okendoStarRatingSnippet, placeholder }: OkendoStarRatingProps) => string | number | true | React.JSX.Element | Iterable<React.ReactNode>;
16
16
  export {};
@@ -1,3 +1,4 @@
1
+ export * from "./OkendoLoyalty";
1
2
  export * from "./OkendoProvider";
2
3
  export * from "./OkendoReviews";
3
4
  export * from "./OkendoReviewsCarousel";
@@ -1,2 +1,2 @@
1
- export declare const OKENDO_PRODUCT_STAR_RATING_FRAGMENT: "#graphql\n\tfragment OkendoStarRatingSnippet on Product {\n\t\tokendoStarRatingSnippet: metafield(\n\t\t\tnamespace: \"$app:reviews\"\n\t\t\tkey: \"star_rating_snippet\"\n\t\t) {\n\t\t\tvalue\n\t\t}\n\t}\n";
2
- export declare const OKENDO_PRODUCT_REVIEWS_FRAGMENT: "#graphql\n\tfragment OkendoReviewsSnippet on Product {\n\t\tokendoReviewsSnippet: metafield(\n\t\t\tnamespace: \"$app:reviews\"\n\t\t\tkey: \"reviews_widget_snippet\"\n\t\t) {\n\t\t\tvalue\n\t\t}\n\t}\n";
1
+ export declare const OKENDO_PRODUCT_STAR_RATING_FRAGMENT: "#graphql\n\tfragment OkendoStarRatingSnippet on Product {\n\t\tokendoStarRatingSnippet: metafield(\n\t\t\tnamespace: \"app--1576377--reviews\"\n\t\t\tkey: \"star_rating_snippet\"\n\t\t) {\n\t\t\tvalue\n\t\t}\n\t}\n";
2
+ export declare const OKENDO_PRODUCT_REVIEWS_FRAGMENT: "#graphql\n\tfragment OkendoReviewsSnippet on Product {\n\t\tokendoReviewsSnippet: metafield(\n\t\t\tnamespace: \"app--1576377--reviews\"\n\t\t\tkey: \"reviews_widget_snippet\"\n\t\t) {\n\t\t\tvalue\n\t\t}\n\t}\n";
@@ -1,3 +1,4 @@
1
+ export declare const OKENDO_APP_NAMESPACE = "app--1576377";
1
2
  /**
2
3
  * Gets the product ID with Okendo formatting.
3
4
  * @param productId The Shopify Product ID e.g. gid://shopify/Product/10079785100.
package/dist/esm/index.js CHANGED
@@ -1 +1 @@
1
- import e,{createContext as t,useState as n,useContext as r,Suspense as a,useRef as o,useEffect as i}from"react";import{Await as d}from"@remix-run/react";const s=t(void 0),l=({children:t})=>{const[r,a]=n(!1);return e.createElement(s.Provider,{value:{okendoDataLoaded:r,setOkendoDataLoaded:a}},t)},c=()=>{const e=r(s);return void 0===e?null:e},u="cdn-static.okendo.io",p=async({context:e,subscriberId:t,apiDomain:n,cdnDomain:r})=>{const a=`https://${n||"api.okendo.io/v1"}/stores/${t}/widget_plus_settings`,o=await fetch(a);if(!o.ok)return console.error(`Failed to retrieve subscriber settings for subscriber ID '${t}'.`),null;const{reviewsHeaderConfig:i,cssVariables:d,customCss:s,starSymbols:l}=await o.json(),c=await fetch(`https://${r||u}/reviews-widget-plus/js/okendo-reviews.js`);if(!c.ok)return console.error("Failed to retrieve widget initialisation script."),null;const p=await c.text(),{shop:{widgetPreRenderStyleTags:m}}=await e.storefront.query('#graphql\n\t\tquery metafields {\n\t\t\tshop {\n\t\t\t\twidgetPreRenderStyleTags: metafield(\n\t\t\t\t\tnamespace: "$app:reviews"\n\t\t\t\t\tkey: "widget_pre_render_style_tags"\n\t\t\t\t) {\n\t\t\t\t\tvalue\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t'),g=m?.value??"";return g||console.warn("Failed to retrieve pre-rendered widget style settings."),{reviewsHeaderConfig:i,cssVariables:d,customCss:s,initScriptContents:p,preRenderStyleTags:g,starSymbols:l}},m=({nonce:t="",okendoProviderData:n,productUrlFormatter:r,cdnDomain:o,children:i})=>e.createElement(l,null,n&&"then"in n?e.createElement(a,null,e.createElement(d,{resolve:n},(n=>e.createElement(g,{nonce:t,okendoProviderData:n,productUrlFormatter:r,cdnDomain:o,awaited:!0})))):e.createElement(g,{nonce:t,okendoProviderData:n,productUrlFormatter:r,cdnDomain:o}),i),g=({nonce:t="",okendoProviderData:n,productUrlFormatter:r,awaited:a,cdnDomain:d})=>{const s=c(),l=o(!1);if(i((()=>{if(n&&s?.setOkendoDataLoaded(!0),n&&a&&!l.current){const e=document.createElement("script");e.src=`https://${d||u}/reviews-widget-plus/js/okendo-reviews.js`,document.head.appendChild(e),l.current=!0}}),[n,s,a,d]),!n)return null;const{reviewsHeaderConfig:p,cssVariables:m,customCss:g,initScriptContents:v,preRenderStyleTags:k,starSymbols:w}=n,y=(m??"").replace('<style id="oke-css-vars">',"").replace("</style>",""),h=g?g.replace('<style id="oke-reviews-custom-css">',"").replace("</style>",""):"";return e.createElement(e.Fragment,null,e.createElement("script",{nonce:t,id:"oke-reviews-settings",type:"application/json",dangerouslySetInnerHTML:{__html:JSON.stringify(p)}}),e.createElement("style",{nonce:t,id:"oke-css-vars",dangerouslySetInnerHTML:{__html:y}}),h&&e.createElement("style",{nonce:t,id:"oke-reviews-custom-css",dangerouslySetInnerHTML:{__html:h}}),!a&&v&&e.createElement("script",{nonce:t,dangerouslySetInnerHTML:{__html:v}}),e.createElement("script",{nonce:t,type:"text/javascript",dangerouslySetInnerHTML:{__html:`window.okeProductUrlFormatter = ${"function"==typeof r?r.toString():"string"==typeof r?r:"(product) =>\n product && product.productHandle\n ? \"/products/\" + product.productHandle + \"/\" + (product.variantId ? '?variantId=' + product.variantId : '')\n : undefined"}`}}),k&&e.createElement("div",{dangerouslySetInnerHTML:{__html:k}}),w&&e.createElement("div",{dangerouslySetInnerHTML:{__html:w}}))};const v=({dataAttributes:t,metafieldContent:n=""})=>{const r=o(null),a=o(!1),d=function(e){const t=o();return i((()=>{t.current=e})),t.current}(t),s=()=>{r.current&&(window.okeWidgetApi.initWidget(r.current),a.current=!0)};return i((()=>{if(!d||t["data-oke-widget"]!==d["data-oke-widget"]||t["data-oke-star-rating"]!==d["data-oke-star-rating"]||t["data-oke-reviews-product-id"]!==d["data-oke-reviews-product-id"]||!a.current)return window.okeWidgetApi&&r.current?s():document.addEventListener("oke-script-loaded",s),()=>{document.removeEventListener("oke-script-loaded",s)}}),[t,d]),e.createElement("div",{ref:r,key:JSON.stringify(t),...t,dangerouslySetInnerHTML:n?{__html:n}:void 0})},k=/^[0-9]*$/;function w(e){if(e)return`shopify-${k.test(e)?e:e.split("/").slice(-1)[0]}`}const y=({productId:t,okendoReviewsSnippet:n,placeholder:r})=>{const a=c(),o=t?.length?w(t):null,i=t?.length?n:null,d={"data-oke-widget":"","data-oke-reviews-product-id":o};return null===a||a.okendoDataLoaded?e.createElement(v,{dataAttributes:d,metafieldContent:i?.value}):r||e.createElement("div",{style:{height:"350px"}})},h=({productId:t,groupId:n,headerBadgeUrl:r,placeholder:a})=>{const o=c(),i={"data-oke-carousel":"","data-oke-reviews-product-id":t?.length?w(t):null,"data-oke-reviews-group-id":n?.length?n:null,"data-oke-header-badge-url":r};return null===o||o.okendoDataLoaded?e.createElement(v,{dataAttributes:i}):a||e.createElement("div",{style:{height:"350px"}})},f=({productId:t,okendoStarRatingSnippet:n,placeholder:r})=>{const a=c(),o={"data-oke-star-rating":"","data-oke-reviews-product-id":w(t)};return null===a||a.okendoDataLoaded?e.createElement(v,{dataAttributes:o,metafieldContent:n?.value}):r||e.createElement("div",{style:{height:"20px"}})},S='#graphql\n\tfragment OkendoStarRatingSnippet on Product {\n\t\tokendoStarRatingSnippet: metafield(\n\t\t\tnamespace: "$app:reviews"\n\t\t\tkey: "star_rating_snippet"\n\t\t) {\n\t\t\tvalue\n\t\t}\n\t}\n',_='#graphql\n\tfragment OkendoReviewsSnippet on Product {\n\t\tokendoReviewsSnippet: metafield(\n\t\t\tnamespace: "$app:reviews"\n\t\t\tkey: "reviews_widget_snippet"\n\t\t) {\n\t\t\tvalue\n\t\t}\n\t}\n';export{_ as OKENDO_PRODUCT_REVIEWS_FRAGMENT,S as OKENDO_PRODUCT_STAR_RATING_FRAGMENT,m as OkendoProvider,y as OkendoReviews,h as OkendoReviewsCarousel,f as OkendoStarRating,p as getOkendoProviderData};
1
+ import{useLocation as e,Await as t}from"@remix-run/react";import n,{useEffect as r,createContext as o,useState as a,useContext as i,Suspense as s,useRef as d}from"react";function l(){const t=e();return r((()=>{window?.okeLoyaltyApi?.initialiseWidgets()}),[t.pathname]),n.createElement("div",{"data-oke-loyalty-embedded-widget":""})}const c=o(void 0),u=({children:e})=>{const[t,r]=a(!1);return n.createElement(c.Provider,{value:{okendoDataLoaded:t,setOkendoDataLoaded:r}},e)},p=()=>{const e=i(c);return void 0===e?null:e},m=/^[0-9]*$/,y="app--1576377";function g(e){if(e)return`shopify-${m.test(e)?e:e.split("/").slice(-1)[0]}`}const v="cdn-static.okendo.io",k=async({context:e,subscriberId:t,apiDomain:n,cdnDomain:r,okendoProducts:o=["reviews"],appNamespace:a})=>{if(!o.length)return null;const i=`loyaltySettings: metafield(\n namespace: "${a??y}--loyalty",\n key: "loyalty_settings"\n ) {\n value\n }`,s=`widgetPreRenderStyleTags: metafield(\n namespace: "${a??y}--reviews",\n key: "widget_pre_render_style_tags"\n ) {\n value\n }`,d=`#graphql\n query metafields {\n shop {\n ${o.includes("loyalty")?i:""}\n ${o.includes("reviews")?s:""}\n }\n }\n `,{shop:{loyaltySettings:l,widgetPreRenderStyleTags:c}}=await e.storefront.query(d);let u=null;if(o.includes("loyalty")&&(u={...u??{},loyaltySettings:l?.value??""}),o.includes("reviews")){const e=`https://${n||"api.okendo.io/v1"}/stores/${t}/widget_plus_settings`,o=await fetch(e);if(!o.ok)return console.error(`Failed to retrieve subscriber settings for subscriber ID '${t}'.`),u;const{reviewsHeaderConfig:a,cssVariables:i,customCss:s,starSymbols:d}=await o.json(),l=await fetch(`https://${r||v}/reviews-widget-plus/js/okendo-reviews.js`);if(!l.ok)return console.error("Failed to retrieve widget initialisation script."),u;const p=await l.text(),m=c?.value??"";m||console.warn("Failed to retrieve pre-rendered widget style settings."),u={...u??{},reviewsHeaderConfig:a,cssVariables:i,customCss:s,initScriptContents:p,preRenderStyleTags:m,starSymbols:d}}return u},w=({nonce:e="",okendoProviderData:r,customerAccessToken:o,productUrlFormatter:a,cdnDomain:i,children:d})=>n.createElement(u,null,r&&"then"in r?n.createElement(s,null,n.createElement(t,{resolve:r},(t=>n.createElement(h,{nonce:e,okendoProviderData:t,productUrlFormatter:a,cdnDomain:i,awaited:!0})))):n.createElement(h,{nonce:e,okendoProviderData:r,productUrlFormatter:a,cdnDomain:i}),o&&n.createElement("script",{nonce:e,id:"oke-loyalty-customer-access-token",type:"application/json",dangerouslySetInnerHTML:{__html:JSON.stringify({customerAccessToken:o})}}),d),h=({nonce:e="",okendoProviderData:t,productUrlFormatter:o,awaited:a,cdnDomain:i})=>{const s=p(),l=d(!1),c=d(!1);if(r((()=>{if(t&&t.loyaltySettings&&!1===l.current){const e=document.createElement("script");e.src=`https://${i||v}/loyalty/js/init-onsite.js`,document.head.appendChild(e);const n=document.createElement("script");n.type="application/json",n.id="oke-loyalty-settings";const r=t.loyaltySettings?t.loyaltySettings.replace('<script type="application/json" id="oke-loyalty-settings">',"").replace('<\/script><script src="https://rhys-cdn.okendo.dev/loyalty/js/init-onsite.js" defer><\/script>',""):"";n.innerHTML=r,document.head.appendChild(n),l.current=!0}}),[t,i]),r((()=>{if(t&&s?.setOkendoDataLoaded(!0),t&&a&&!c.current){const e=document.createElement("script");e.src=`https://${i||v}/reviews-widget-plus/js/okendo-reviews.js`,document.head.appendChild(e),c.current=!0}}),[t,s,a,i]),!t)return null;const{reviewsHeaderConfig:u,cssVariables:m,customCss:y,initScriptContents:g,preRenderStyleTags:k,starSymbols:w}=t,h=(m??"").replace('<style id="oke-css-vars">',"").replace("</style>",""),f=y?y.replace('<style id="oke-reviews-custom-css">',"").replace("</style>",""):"";return n.createElement(n.Fragment,null,n.createElement("script",{nonce:e,id:"oke-reviews-settings",type:"application/json",dangerouslySetInnerHTML:{__html:JSON.stringify(u)}}),n.createElement("style",{nonce:e,id:"oke-css-vars",dangerouslySetInnerHTML:{__html:h}}),f&&n.createElement("style",{nonce:e,id:"oke-reviews-custom-css",dangerouslySetInnerHTML:{__html:f}}),!a&&g&&n.createElement("script",{nonce:e,dangerouslySetInnerHTML:{__html:g}}),n.createElement("script",{nonce:e,type:"text/javascript",dangerouslySetInnerHTML:{__html:`window.okeProductUrlFormatter = ${"function"==typeof o?o.toString():"string"==typeof o?o:"(product) =>\n product && product.productHandle\n ? \"/products/\" + product.productHandle + \"/\" + (product.variantId ? '?variantId=' + product.variantId : '')\n : undefined"}`}}),k&&n.createElement("div",{dangerouslySetInnerHTML:{__html:k}}),w&&n.createElement("div",{dangerouslySetInnerHTML:{__html:w}}))};const f=({dataAttributes:e,metafieldContent:t=""})=>{const o=d(null),a=d(!1),i=function(e){const t=d();return r((()=>{t.current=e})),t.current}(e),s=()=>{o.current&&(window.okeWidgetApi.initWidget(o.current),a.current=!0)};return r((()=>{if(!i||e["data-oke-widget"]!==i["data-oke-widget"]||e["data-oke-star-rating"]!==i["data-oke-star-rating"]||e["data-oke-reviews-product-id"]!==i["data-oke-reviews-product-id"]||!a.current)return window.okeWidgetApi&&o.current?s():document.addEventListener("oke-script-loaded",s),()=>{document.removeEventListener("oke-script-loaded",s)}}),[e,i]),n.createElement("div",{ref:o,key:JSON.stringify(e),...e,dangerouslySetInnerHTML:t?{__html:t}:void 0})},S=({productId:e,okendoReviewsSnippet:t,placeholder:r})=>{const o=p(),a=e?.length?g(e):null,i=e?.length?t:null,s={"data-oke-widget":"","data-oke-reviews-product-id":a};return null===o||o.okendoDataLoaded?n.createElement(f,{dataAttributes:s,metafieldContent:i?.value}):r||n.createElement("div",{style:{height:"350px"}})},_=({productId:e,groupId:t,headerBadgeUrl:r,placeholder:o})=>{const a=p(),i={"data-oke-carousel":"","data-oke-reviews-product-id":e?.length?g(e):null,"data-oke-reviews-group-id":t?.length?t:null,"data-oke-header-badge-url":r};return null===a||a.okendoDataLoaded?n.createElement(f,{dataAttributes:i}):o||n.createElement("div",{style:{height:"350px"}})},E=({productId:e,okendoStarRatingSnippet:t,placeholder:r})=>{const o=p(),a={"data-oke-star-rating":"","data-oke-reviews-product-id":g(e)};return null===o||o.okendoDataLoaded?n.createElement(f,{dataAttributes:a,metafieldContent:t?.value}):r||n.createElement("div",{style:{height:"20px"}})},L=`#graphql\n\tfragment OkendoStarRatingSnippet on Product {\n\t\tokendoStarRatingSnippet: metafield(\n\t\t\tnamespace: "${y}--reviews"\n\t\t\tkey: "star_rating_snippet"\n\t\t) {\n\t\t\tvalue\n\t\t}\n\t}\n`,b=`#graphql\n\tfragment OkendoReviewsSnippet on Product {\n\t\tokendoReviewsSnippet: metafield(\n\t\t\tnamespace: "${y}--reviews"\n\t\t\tkey: "reviews_widget_snippet"\n\t\t) {\n\t\t\tvalue\n\t\t}\n\t}\n`;export{b as OKENDO_PRODUCT_REVIEWS_FRAGMENT,L as OKENDO_PRODUCT_STAR_RATING_FRAGMENT,l as OkendoLoyaltyEmbeddedWidget,w as OkendoProvider,S as OkendoReviews,_ as OkendoReviewsCarousel,E as OkendoStarRating,k as getOkendoProviderData};
@@ -0,0 +1,9 @@
1
+ import React from 'react';
2
+ declare global {
3
+ interface Window {
4
+ okeLoyaltyApi?: {
5
+ initialiseWidgets: () => void;
6
+ };
7
+ }
8
+ }
9
+ export declare function OkendoLoyaltyEmbeddedWidget(): React.JSX.Element;
@@ -0,0 +1 @@
1
+ export * from './OkendoLoyaltyEmbeddedWidget';
@@ -1,7 +1,9 @@
1
1
  import type { WidgetPlus } from '@okendo/reviews-common';
2
- import type { Storefront } from '@shopify/hydrogen';
2
+ import type { CustomerAccount, Storefront } from '@shopify/hydrogen';
3
3
  import React, { type PropsWithChildren } from 'react';
4
- interface OkendoProviderData {
4
+ type OkendoProviderData = Partial<OkendoReviewsProviderData & OkendoLoyaltyProviderData>;
5
+ type OkendoProduct = 'reviews' | 'loyalty';
6
+ interface OkendoReviewsProviderData {
5
7
  reviewsHeaderConfig: WidgetPlus.ReviewsHeaderConfig;
6
8
  cssVariables: string;
7
9
  customCss?: string;
@@ -9,14 +11,21 @@ interface OkendoProviderData {
9
11
  preRenderStyleTags: string;
10
12
  starSymbols: string;
11
13
  }
12
- export declare const getOkendoProviderData: ({ context, subscriberId, apiDomain, cdnDomain, }: {
13
- context: {
14
- storefront: Storefront;
15
- };
14
+ interface OkendoLoyaltyProviderData {
15
+ loyaltySettings: string;
16
+ }
17
+ export declare const getOkendoProviderData: ({ context, subscriberId, apiDomain, cdnDomain, okendoProducts, appNamespace, }: {
18
+ context: StorefrontContext;
16
19
  subscriberId: string;
17
20
  apiDomain?: string;
18
21
  cdnDomain?: string;
22
+ okendoProducts?: OkendoProduct[];
23
+ appNamespace?: string;
19
24
  }) => Promise<OkendoProviderData | null>;
25
+ interface StorefrontContext {
26
+ customerAccount: CustomerAccount;
27
+ storefront: Storefront;
28
+ }
20
29
  interface ReviewProduct {
21
30
  productHandle?: string;
22
31
  productId: string;
@@ -36,9 +45,14 @@ interface OkendoProviderProps {
36
45
  * show slightly after page load, but it have the advantage of not increasing the page load time.
37
46
  */
38
47
  okendoProviderData: Partial<OkendoProviderData> | null | Promise<Partial<OkendoProviderData> | null>;
48
+ /**
49
+ * Used by the loyalty widget to verify the user's identity via the Storefront API.
50
+ * Can be retrieved via `await context.customerAccount.getAccessToken()` in the loader function.
51
+ */
52
+ customerAccessToken?: string;
39
53
  /** An optional product URL formatter */
40
54
  productUrlFormatter?: (product: ReviewProduct) => string;
41
55
  cdnDomain?: string;
42
56
  }
43
- export declare const OkendoProvider: ({ nonce, okendoProviderData, productUrlFormatter, cdnDomain, children, }: OkendoProviderProps & PropsWithChildren) => React.JSX.Element;
57
+ export declare const OkendoProvider: ({ nonce, okendoProviderData, customerAccessToken, productUrlFormatter, cdnDomain, children, }: OkendoProviderProps & PropsWithChildren) => React.JSX.Element;
44
58
  export {};
@@ -12,5 +12,5 @@ interface OkendoStarRatingProps {
12
12
  */
13
13
  placeholder?: ReactNode;
14
14
  }
15
- export declare const OkendoStarRating: ({ productId, okendoStarRatingSnippet, placeholder }: OkendoStarRatingProps) => string | number | true | Iterable<React.ReactNode> | React.JSX.Element;
15
+ export declare const OkendoStarRating: ({ productId, okendoStarRatingSnippet, placeholder }: OkendoStarRatingProps) => string | number | true | React.JSX.Element | Iterable<React.ReactNode>;
16
16
  export {};
@@ -1,3 +1,4 @@
1
+ export * from "./OkendoLoyalty";
1
2
  export * from "./OkendoProvider";
2
3
  export * from "./OkendoReviews";
3
4
  export * from "./OkendoReviewsCarousel";
@@ -1,2 +1,2 @@
1
- export declare const OKENDO_PRODUCT_STAR_RATING_FRAGMENT: "#graphql\n\tfragment OkendoStarRatingSnippet on Product {\n\t\tokendoStarRatingSnippet: metafield(\n\t\t\tnamespace: \"$app:reviews\"\n\t\t\tkey: \"star_rating_snippet\"\n\t\t) {\n\t\t\tvalue\n\t\t}\n\t}\n";
2
- export declare const OKENDO_PRODUCT_REVIEWS_FRAGMENT: "#graphql\n\tfragment OkendoReviewsSnippet on Product {\n\t\tokendoReviewsSnippet: metafield(\n\t\t\tnamespace: \"$app:reviews\"\n\t\t\tkey: \"reviews_widget_snippet\"\n\t\t) {\n\t\t\tvalue\n\t\t}\n\t}\n";
1
+ export declare const OKENDO_PRODUCT_STAR_RATING_FRAGMENT: "#graphql\n\tfragment OkendoStarRatingSnippet on Product {\n\t\tokendoStarRatingSnippet: metafield(\n\t\t\tnamespace: \"app--1576377--reviews\"\n\t\t\tkey: \"star_rating_snippet\"\n\t\t) {\n\t\t\tvalue\n\t\t}\n\t}\n";
2
+ export declare const OKENDO_PRODUCT_REVIEWS_FRAGMENT: "#graphql\n\tfragment OkendoReviewsSnippet on Product {\n\t\tokendoReviewsSnippet: metafield(\n\t\t\tnamespace: \"app--1576377--reviews\"\n\t\t\tkey: \"reviews_widget_snippet\"\n\t\t) {\n\t\t\tvalue\n\t\t}\n\t}\n";
@@ -1,3 +1,4 @@
1
+ export declare const OKENDO_APP_NAMESPACE = "app--1576377";
1
2
  /**
2
3
  * Gets the product ID with Okendo formatting.
3
4
  * @param productId The Shopify Product ID e.g. gid://shopify/Product/10079785100.
package/dist/index.d.ts CHANGED
@@ -1,8 +1,19 @@
1
- import { WidgetPlus } from '@okendo/reviews-common';
2
- import { Storefront } from '@shopify/hydrogen';
3
1
  import React, { PropsWithChildren, ReactNode } from 'react';
2
+ import { WidgetPlus } from '@okendo/reviews-common';
3
+ import { CustomerAccount, Storefront } from '@shopify/hydrogen';
4
+
5
+ declare global {
6
+ interface Window {
7
+ okeLoyaltyApi?: {
8
+ initialiseWidgets: () => void;
9
+ };
10
+ }
11
+ }
12
+ declare function OkendoLoyaltyEmbeddedWidget(): React.JSX.Element;
4
13
 
5
- interface OkendoProviderData {
14
+ type OkendoProviderData = Partial<OkendoReviewsProviderData & OkendoLoyaltyProviderData>;
15
+ type OkendoProduct = 'reviews' | 'loyalty';
16
+ interface OkendoReviewsProviderData {
6
17
  reviewsHeaderConfig: WidgetPlus.ReviewsHeaderConfig;
7
18
  cssVariables: string;
8
19
  customCss?: string;
@@ -10,14 +21,21 @@ interface OkendoProviderData {
10
21
  preRenderStyleTags: string;
11
22
  starSymbols: string;
12
23
  }
13
- declare const getOkendoProviderData: ({ context, subscriberId, apiDomain, cdnDomain, }: {
14
- context: {
15
- storefront: Storefront;
16
- };
24
+ interface OkendoLoyaltyProviderData {
25
+ loyaltySettings: string;
26
+ }
27
+ declare const getOkendoProviderData: ({ context, subscriberId, apiDomain, cdnDomain, okendoProducts, appNamespace, }: {
28
+ context: StorefrontContext;
17
29
  subscriberId: string;
18
30
  apiDomain?: string;
19
31
  cdnDomain?: string;
32
+ okendoProducts?: OkendoProduct[];
33
+ appNamespace?: string;
20
34
  }) => Promise<OkendoProviderData | null>;
35
+ interface StorefrontContext {
36
+ customerAccount: CustomerAccount;
37
+ storefront: Storefront;
38
+ }
21
39
  interface ReviewProduct {
22
40
  productHandle?: string;
23
41
  productId: string;
@@ -37,11 +55,16 @@ interface OkendoProviderProps {
37
55
  * show slightly after page load, but it have the advantage of not increasing the page load time.
38
56
  */
39
57
  okendoProviderData: Partial<OkendoProviderData> | null | Promise<Partial<OkendoProviderData> | null>;
58
+ /**
59
+ * Used by the loyalty widget to verify the user's identity via the Storefront API.
60
+ * Can be retrieved via `await context.customerAccount.getAccessToken()` in the loader function.
61
+ */
62
+ customerAccessToken?: string;
40
63
  /** An optional product URL formatter */
41
64
  productUrlFormatter?: (product: ReviewProduct) => string;
42
65
  cdnDomain?: string;
43
66
  }
44
- declare const OkendoProvider: ({ nonce, okendoProviderData, productUrlFormatter, cdnDomain, children, }: OkendoProviderProps & PropsWithChildren) => React.JSX.Element;
67
+ declare const OkendoProvider: ({ nonce, okendoProviderData, customerAccessToken, productUrlFormatter, cdnDomain, children, }: OkendoProviderProps & PropsWithChildren) => React.JSX.Element;
45
68
 
46
69
  interface MetafieldValue {
47
70
  value: string;
@@ -85,9 +108,9 @@ interface OkendoStarRatingProps {
85
108
  */
86
109
  placeholder?: ReactNode;
87
110
  }
88
- declare const OkendoStarRating: ({ productId, okendoStarRatingSnippet, placeholder }: OkendoStarRatingProps) => string | number | true | Iterable<React.ReactNode> | React.JSX.Element;
111
+ declare const OkendoStarRating: ({ productId, okendoStarRatingSnippet, placeholder }: OkendoStarRatingProps) => string | number | true | React.JSX.Element | Iterable<React.ReactNode>;
89
112
 
90
- declare const OKENDO_PRODUCT_STAR_RATING_FRAGMENT: "#graphql\n\tfragment OkendoStarRatingSnippet on Product {\n\t\tokendoStarRatingSnippet: metafield(\n\t\t\tnamespace: \"$app:reviews\"\n\t\t\tkey: \"star_rating_snippet\"\n\t\t) {\n\t\t\tvalue\n\t\t}\n\t}\n";
91
- declare const OKENDO_PRODUCT_REVIEWS_FRAGMENT: "#graphql\n\tfragment OkendoReviewsSnippet on Product {\n\t\tokendoReviewsSnippet: metafield(\n\t\t\tnamespace: \"$app:reviews\"\n\t\t\tkey: \"reviews_widget_snippet\"\n\t\t) {\n\t\t\tvalue\n\t\t}\n\t}\n";
113
+ declare const OKENDO_PRODUCT_STAR_RATING_FRAGMENT: "#graphql\n\tfragment OkendoStarRatingSnippet on Product {\n\t\tokendoStarRatingSnippet: metafield(\n\t\t\tnamespace: \"app--1576377--reviews\"\n\t\t\tkey: \"star_rating_snippet\"\n\t\t) {\n\t\t\tvalue\n\t\t}\n\t}\n";
114
+ declare const OKENDO_PRODUCT_REVIEWS_FRAGMENT: "#graphql\n\tfragment OkendoReviewsSnippet on Product {\n\t\tokendoReviewsSnippet: metafield(\n\t\t\tnamespace: \"app--1576377--reviews\"\n\t\t\tkey: \"reviews_widget_snippet\"\n\t\t) {\n\t\t\tvalue\n\t\t}\n\t}\n";
92
115
 
93
- export { OKENDO_PRODUCT_REVIEWS_FRAGMENT, OKENDO_PRODUCT_STAR_RATING_FRAGMENT, OkendoProvider, OkendoReviews, OkendoReviewsCarousel, OkendoStarRating, type WithOkendoReviewsSnippet, type WithOkendoStarRatingSnippet, getOkendoProviderData };
116
+ export { OKENDO_PRODUCT_REVIEWS_FRAGMENT, OKENDO_PRODUCT_STAR_RATING_FRAGMENT, OkendoLoyaltyEmbeddedWidget, OkendoProvider, OkendoReviews, OkendoReviewsCarousel, OkendoStarRating, type WithOkendoReviewsSnippet, type WithOkendoStarRatingSnippet, getOkendoProviderData };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@okendo/shopify-hydrogen",
3
- "version": "2.3.2",
3
+ "version": "2.4.0",
4
4
  "description": "Okendo React components for Shopify Hydrogen 2 (Remix)",
5
5
  "author": "Okendo",
6
6
  "license": "SEE LICENSE IN LICENSE.txt",