@okendo/shopify-hydrogen 2.3.1 → 2.3.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.
package/README.md CHANGED
@@ -55,22 +55,22 @@ https://{shop}.myshopify.com/admin/api/2024-10/graphql.json \
55
55
  -H 'X-Shopify-Access-Token: {access_token}' \
56
56
  -d '
57
57
  mutation {
58
- metafieldDefinitionCreate(
59
- definition: {
60
- name: "WidgetPreRenderStyleTags"
58
+ metafieldDefinitionCreate(
59
+ definition: {
60
+ name: "WidgetPreRenderStyleTags"
61
61
  namespace: "$app:reviews"
62
- key: "widget_pre_render_style_tags"
63
- type: "multi_line_text_field"
64
- ownerType: SHOP
65
- access: {
66
- admin: PUBLIC_READ
67
- storefront: PUBLIC_READ
68
- }
69
- }
70
- ) {
71
- createdDefinition { id name }
72
- userErrors { field message code }
73
- }
62
+ key: "widget_pre_render_style_tags"
63
+ type: "multi_line_text_field"
64
+ ownerType: SHOP
65
+ access: {
66
+ admin: PUBLIC_READ
67
+ storefront: PUBLIC_READ
68
+ }
69
+ }
70
+ ) {
71
+ createdDefinition { id name }
72
+ userErrors { field message code }
73
+ }
74
74
  }
75
75
  '
76
76
  ```
@@ -84,22 +84,22 @@ https://{shop}.myshopify.com/admin/api/2024-10/graphql.json \
84
84
  -H 'X-Shopify-Access-Token: {access_token}' \
85
85
  -d '
86
86
  mutation {
87
- metafieldDefinitionCreate(
88
- definition: {
89
- name: "WidgetPreRenderBodyStyleTags"
87
+ metafieldDefinitionCreate(
88
+ definition: {
89
+ name: "WidgetPreRenderBodyStyleTags"
90
90
  namespace: "$app:reviews"
91
- key: "widget_pre_render_body_style_tags"
92
- type: "multi_line_text_field"
93
- ownerType: SHOP
94
- access: {
95
- admin: PUBLIC_READ
96
- storefront: PUBLIC_READ
97
- }
98
- }
99
- ) {
100
- createdDefinition { id name }
101
- userErrors { field message code }
102
- }
91
+ key: "widget_pre_render_body_style_tags"
92
+ type: "multi_line_text_field"
93
+ ownerType: SHOP
94
+ access: {
95
+ admin: PUBLIC_READ
96
+ storefront: PUBLIC_READ
97
+ }
98
+ }
99
+ ) {
100
+ createdDefinition { id name }
101
+ userErrors { field message code }
102
+ }
103
103
  }
104
104
  '
105
105
  ```
@@ -113,22 +113,22 @@ https://{shop}.myshopify.com/admin/api/2024-10/graphql.json \
113
113
  -H 'X-Shopify-Access-Token: {access_token}' \
114
114
  -d '
115
115
  mutation {
116
- metafieldDefinitionCreate(
117
- definition: {
118
- name: "ReviewsWidgetSnippet"
119
- namespace: "$app:reviews"
120
- key: "reviews_widget_snippet"
121
- type: "multi_line_text_field"
122
- ownerType: PRODUCT
123
- access: {
124
- admin: PUBLIC_READ
125
- storefront: PUBLIC_READ
126
- }
127
- }
128
- ) {
129
- createdDefinition { id name }
130
- userErrors { field message code }
131
- }
116
+ metafieldDefinitionCreate(
117
+ definition: {
118
+ name: "ReviewsWidgetSnippet"
119
+ namespace: "$app:reviews"
120
+ key: "reviews_widget_snippet"
121
+ type: "multi_line_text_field"
122
+ ownerType: PRODUCT
123
+ access: {
124
+ admin: PUBLIC_READ
125
+ storefront: PUBLIC_READ
126
+ }
127
+ }
128
+ ) {
129
+ createdDefinition { id name }
130
+ userErrors { field message code }
131
+ }
132
132
  }
133
133
  '
134
134
  ```
@@ -142,22 +142,22 @@ https://{shop}.myshopify.com/admin/api/2024-10/graphql.json \
142
142
  -H 'X-Shopify-Access-Token: {access_token}' \
143
143
  -d '
144
144
  mutation {
145
- metafieldDefinitionCreate(
146
- definition: {
147
- name: "StarRatingSnippet"
148
- namespace: "$app:reviews"
149
- key: "star_rating_snippet"
150
- type: "multi_line_text_field"
151
- ownerType: PRODUCT
152
- access: {
153
- admin: PUBLIC_READ
154
- storefront: PUBLIC_READ
155
- }
156
- }
157
- ) {
158
- createdDefinition { id name }
159
- userErrors { field message code }
160
- }
145
+ metafieldDefinitionCreate(
146
+ definition: {
147
+ name: "StarRatingSnippet"
148
+ namespace: "$app:reviews"
149
+ key: "star_rating_snippet"
150
+ type: "multi_line_text_field"
151
+ ownerType: PRODUCT
152
+ access: {
153
+ admin: PUBLIC_READ
154
+ storefront: PUBLIC_READ
155
+ }
156
+ }
157
+ ) {
158
+ createdDefinition { id name }
159
+ userErrors { field message code }
160
+ }
161
161
  }
162
162
  '
163
163
  ```
@@ -171,22 +171,22 @@ https://{shop}.myshopify.com/admin/api/2024-10/graphql.json \
171
171
  -H 'X-Shopify-Access-Token: {access_token}' \
172
172
  -d '
173
173
  mutation {
174
- metafieldDefinitionCreate(
175
- definition: {
176
- name: "ReviewCount"
177
- namespace: "$app:reviews"
178
- key: "review_count"
179
- type: "number_integer"
180
- ownerType: PRODUCT
181
- access: {
182
- admin: PUBLIC_READ
183
- storefront: PUBLIC_READ
184
- }
185
- }
186
- ) {
187
- createdDefinition { id name }
188
- userErrors { field message code }
189
- }
174
+ metafieldDefinitionCreate(
175
+ definition: {
176
+ name: "ReviewCount"
177
+ namespace: "$app:reviews"
178
+ key: "review_count"
179
+ type: "number_integer"
180
+ ownerType: PRODUCT
181
+ access: {
182
+ admin: PUBLIC_READ
183
+ storefront: PUBLIC_READ
184
+ }
185
+ }
186
+ ) {
187
+ createdDefinition { id name }
188
+ userErrors { field message code }
189
+ }
190
190
  }
191
191
  '
192
192
  ```
@@ -200,22 +200,22 @@ https://{shop}.myshopify.com/admin/api/2024-10/graphql.json \
200
200
  -H 'X-Shopify-Access-Token: {access_token}' \
201
201
  -d '
202
202
  mutation {
203
- metafieldDefinitionCreate(
204
- definition: {
205
- name: "AverageRating"
206
- namespace: "$app:reviews"
207
- key: "average_rating"
208
- type: "rating"
209
- ownerType: PRODUCT
210
- access: {
211
- admin: PUBLIC_READ
212
- storefront: PUBLIC_READ
213
- }
214
- }
215
- ) {
216
- createdDefinition { id name }
217
- userErrors { field message code }
218
- }
203
+ metafieldDefinitionCreate(
204
+ definition: {
205
+ name: "AverageRating"
206
+ namespace: "$app:reviews"
207
+ key: "average_rating"
208
+ type: "rating"
209
+ ownerType: PRODUCT
210
+ access: {
211
+ admin: PUBLIC_READ
212
+ storefront: PUBLIC_READ
213
+ }
214
+ }
215
+ ) {
216
+ createdDefinition { id name }
217
+ userErrors { field message code }
218
+ }
219
219
  }
220
220
  '
221
221
  ```
@@ -231,26 +231,26 @@ Open your GraphQL IDE (such as Postman) and make `POST` requests with the follow
231
231
 
232
232
  ```graphql
233
233
  mutation {
234
- metafieldDefinitionCreate(
235
- definition: {
236
- name: "WidgetPreRenderStyleTags"
237
- namespace: "$app:reviews"
238
- key: "widget_pre_render_style_tags"
239
- type: "multi_line_text_field"
240
- ownerType: SHOP
234
+ metafieldDefinitionCreate(
235
+ definition: {
236
+ name: "WidgetPreRenderStyleTags"
237
+ namespace: "$app:reviews"
238
+ key: "widget_pre_render_style_tags"
239
+ type: "multi_line_text_field"
240
+ ownerType: SHOP
241
241
  access: { admin: PUBLIC_READ, storefront: PUBLIC_READ }
242
- }
243
- ) {
244
- createdDefinition {
245
- id
246
- name
247
- }
248
- userErrors {
249
- field
250
- message
251
- code
252
- }
253
- }
242
+ }
243
+ ) {
244
+ createdDefinition {
245
+ id
246
+ name
247
+ }
248
+ userErrors {
249
+ field
250
+ message
251
+ code
252
+ }
253
+ }
254
254
  }
255
255
  ```
256
256
 
@@ -258,26 +258,26 @@ mutation {
258
258
 
259
259
  ```graphql
260
260
  mutation {
261
- metafieldDefinitionCreate(
262
- definition: {
263
- name: "WidgetPreRenderBodyStyleTags"
264
- namespace: "$app:reviews"
265
- key: "widget_pre_render_body_style_tags"
266
- type: "multi_line_text_field"
267
- ownerType: SHOP
261
+ metafieldDefinitionCreate(
262
+ definition: {
263
+ name: "WidgetPreRenderBodyStyleTags"
264
+ namespace: "$app:reviews"
265
+ key: "widget_pre_render_body_style_tags"
266
+ type: "multi_line_text_field"
267
+ ownerType: SHOP
268
268
  access: { admin: PUBLIC_READ, storefront: PUBLIC_READ }
269
- }
270
- ) {
271
- createdDefinition {
272
- id
273
- name
274
- }
275
- userErrors {
276
- field
277
- message
278
- code
279
- }
280
- }
269
+ }
270
+ ) {
271
+ createdDefinition {
272
+ id
273
+ name
274
+ }
275
+ userErrors {
276
+ field
277
+ message
278
+ code
279
+ }
280
+ }
281
281
  }
282
282
  ```
283
283
 
@@ -285,26 +285,26 @@ mutation {
285
285
 
286
286
  ```graphql
287
287
  mutation {
288
- metafieldDefinitionCreate(
289
- definition: {
290
- name: "ReviewsWidgetSnippet"
291
- namespace: "$app:reviews"
292
- key: "reviews_widget_snippet"
293
- type: "multi_line_text_field"
294
- ownerType: PRODUCT
288
+ metafieldDefinitionCreate(
289
+ definition: {
290
+ name: "ReviewsWidgetSnippet"
291
+ namespace: "$app:reviews"
292
+ key: "reviews_widget_snippet"
293
+ type: "multi_line_text_field"
294
+ ownerType: PRODUCT
295
295
  access: { admin: PUBLIC_READ, storefront: PUBLIC_READ }
296
- }
297
- ) {
298
- createdDefinition {
299
- id
300
- name
301
- }
302
- userErrors {
303
- field
304
- message
305
- code
306
- }
307
- }
296
+ }
297
+ ) {
298
+ createdDefinition {
299
+ id
300
+ name
301
+ }
302
+ userErrors {
303
+ field
304
+ message
305
+ code
306
+ }
307
+ }
308
308
  }
309
309
  ```
310
310
 
@@ -312,26 +312,26 @@ mutation {
312
312
 
313
313
  ```graphql
314
314
  mutation {
315
- metafieldDefinitionCreate(
316
- definition: {
317
- name: "StarRatingSnippet"
318
- namespace: "$app:reviews"
319
- key: "star_rating_snippet"
320
- type: "multi_line_text_field"
321
- ownerType: PRODUCT
315
+ metafieldDefinitionCreate(
316
+ definition: {
317
+ name: "StarRatingSnippet"
318
+ namespace: "$app:reviews"
319
+ key: "star_rating_snippet"
320
+ type: "multi_line_text_field"
321
+ ownerType: PRODUCT
322
322
  access: { admin: PUBLIC_READ, storefront: PUBLIC_READ }
323
- }
324
- ) {
325
- createdDefinition {
326
- id
327
- name
328
- }
329
- userErrors {
330
- field
331
- message
332
- code
333
- }
334
- }
323
+ }
324
+ ) {
325
+ createdDefinition {
326
+ id
327
+ name
328
+ }
329
+ userErrors {
330
+ field
331
+ message
332
+ code
333
+ }
334
+ }
335
335
  }
336
336
  ```
337
337
 
@@ -339,26 +339,26 @@ mutation {
339
339
 
340
340
  ```graphql
341
341
  mutation {
342
- metafieldDefinitionCreate(
343
- definition: {
344
- name: "ReviewCount"
345
- namespace: "$app:reviews"
346
- key: "review_count"
347
- type: "number_integer"
348
- ownerType: PRODUCT
342
+ metafieldDefinitionCreate(
343
+ definition: {
344
+ name: "ReviewCount"
345
+ namespace: "$app:reviews"
346
+ key: "review_count"
347
+ type: "number_integer"
348
+ ownerType: PRODUCT
349
349
  access: { admin: PUBLIC_READ, storefront: PUBLIC_READ }
350
- }
351
- ) {
352
- createdDefinition {
353
- id
354
- name
355
- }
356
- userErrors {
357
- field
358
- message
359
- code
360
- }
361
- }
350
+ }
351
+ ) {
352
+ createdDefinition {
353
+ id
354
+ name
355
+ }
356
+ userErrors {
357
+ field
358
+ message
359
+ code
360
+ }
361
+ }
362
362
  }
363
363
  ```
364
364
 
@@ -366,26 +366,26 @@ mutation {
366
366
 
367
367
  ```graphql
368
368
  mutation {
369
- metafieldDefinitionCreate(
370
- definition: {
371
- name: "AverageRating"
372
- namespace: "$app:reviews"
373
- key: "average_rating"
374
- type: "rating"
375
- ownerType: PRODUCT
369
+ metafieldDefinitionCreate(
370
+ definition: {
371
+ name: "AverageRating"
372
+ namespace: "$app:reviews"
373
+ key: "average_rating"
374
+ type: "rating"
375
+ ownerType: PRODUCT
376
376
  access: { admin: PUBLIC_READ, storefront: PUBLIC_READ }
377
- }
378
- ) {
379
- createdDefinition {
380
- id
381
- name
382
- }
383
- userErrors {
384
- field
385
- message
386
- code
387
- }
388
- }
377
+ }
378
+ ) {
379
+ createdDefinition {
380
+ id
381
+ name
382
+ }
383
+ userErrors {
384
+ field
385
+ message
386
+ code
387
+ }
388
+ }
389
389
  }
390
390
  ```
391
391
 
@@ -444,8 +444,8 @@ Open `app/root.tsx` and add the following import:
444
444
 
445
445
  ```ts
446
446
  import {
447
- OkendoProvider,
448
- getOkendoProviderData,
447
+ OkendoProvider,
448
+ getOkendoProviderData,
449
449
  } from '@okendo/shopify-hydrogen';
450
450
  ```
451
451
 
@@ -458,10 +458,10 @@ return defer({
458
458
  // ...
459
459
  okendoProviderData:
460
460
  /* place `await` here if you want server-rendered widgets */ getOkendoProviderData(
461
- {
461
+ {
462
462
  context: args.context,
463
463
  subscriberId: '<your-okendo-subscriber-id>',
464
- },
464
+ },
465
465
  ),
466
466
  });
467
467
  ```
@@ -470,10 +470,10 @@ Locate the `Layout` component, add the `meta` tag `oke:subscriber_id` to `head`,
470
470
 
471
471
  ```tsx
472
472
  <head>
473
- <meta charSet="utf-8" />
474
- <meta name="viewport" content="width=device-width,initial-scale=1" />
475
- <meta name="oke:subscriber_id" content="<your-okendo-subscriber-id>" />
476
- ...
473
+ <meta charSet="utf-8" />
474
+ <meta name="viewport" content="width=device-width,initial-scale=1" />
475
+ <meta name="oke:subscriber_id" content="<your-okendo-subscriber-id>" />
476
+ ...
477
477
  </head>
478
478
  ```
479
479
 
@@ -487,10 +487,10 @@ Append `OkendoProvider` to `body`, and pass it the promise — or the data — r
487
487
  cart={data.cart}
488
488
  shop={data.shop}
489
489
  consent={data.consent}
490
- >
490
+ >
491
491
  <PageLayout {...data}>{children}</PageLayout>
492
492
  </Analytics.Provider>
493
- </OkendoProvider>
493
+ </OkendoProvider>
494
494
  ) : (
495
495
  children
496
496
  )}
@@ -512,8 +512,8 @@ const { nonce, header, NonceProvider } = createContentSecurityPolicy({
512
512
  checkoutDomain: context.env.PUBLIC_CHECKOUT_DOMAIN,
513
513
  storeDomain: context.env.PUBLIC_STORE_DOMAIN,
514
514
  },
515
- defaultSrc: [
516
- "'self'",
515
+ defaultSrc: [
516
+ "'self'",
517
517
  'localhost:*',
518
518
  'https://cdn.shopify.com',
519
519
  'https://www.google.com',
@@ -525,9 +525,9 @@ const { nonce, header, NonceProvider } = createContentSecurityPolicy({
525
525
  'https://surveys.okendo.io',
526
526
  'https://api.okendo.io',
527
527
  'data:',
528
- ],
529
- imgSrc: [
530
- "'self'",
528
+ ],
529
+ imgSrc: [
530
+ "'self'",
531
531
  'https://cdn.shopify.com',
532
532
  'data:',
533
533
  'https://d3hw6dc1ow8pp2.cloudfront.net',
@@ -535,26 +535,26 @@ const { nonce, header, NonceProvider } = createContentSecurityPolicy({
535
535
  'https://dov7r31oq5dkj.cloudfront.net',
536
536
  'https://cdn-static.okendo.io',
537
537
  'https://surveys.okendo.io',
538
- ],
539
- mediaSrc: [
540
- "'self'",
538
+ ],
539
+ mediaSrc: [
540
+ "'self'",
541
541
  'https://d3hw6dc1ow8pp2.cloudfront.net',
542
542
  'https://d3g5hqndtiniji.cloudfront.net',
543
543
  'https://dov7r31oq5dkj.cloudfront.net',
544
544
  'https://cdn-static.okendo.io',
545
- ],
545
+ ],
546
546
  styleSrc: [
547
- "'self'",
548
- "'unsafe-inline'",
547
+ "'self'",
548
+ "'unsafe-inline'",
549
549
  'https://cdn.shopify.com',
550
550
  'https://fonts.googleapis.com',
551
551
  'https://fonts.gstatic.com',
552
552
  'https://d3hw6dc1ow8pp2.cloudfront.net',
553
553
  'https://cdn-static.okendo.io',
554
554
  'https://surveys.okendo.io',
555
- ],
556
- scriptSrc: [
557
- "'self'",
555
+ ],
556
+ scriptSrc: [
557
+ "'self'",
558
558
  'https://cdn.shopify.com',
559
559
  'https://d3hw6dc1ow8pp2.cloudfront.net',
560
560
  'https://dov7r31oq5dkj.cloudfront.net',
@@ -563,18 +563,18 @@ const { nonce, header, NonceProvider } = createContentSecurityPolicy({
563
563
  'https://api.okendo.io',
564
564
  'https://www.google.com',
565
565
  'https://www.gstatic.com',
566
- ],
567
- fontSrc: [
568
- "'self'",
566
+ ],
567
+ fontSrc: [
568
+ "'self'",
569
569
  'https://fonts.gstatic.com',
570
570
  'https://d3hw6dc1ow8pp2.cloudfront.net',
571
571
  'https://dov7r31oq5dkj.cloudfront.net',
572
572
  'https://cdn.shopify.com',
573
573
  'https://cdn-static.okendo.io',
574
574
  'https://surveys.okendo.io',
575
- ],
576
- connectSrc: [
577
- "'self'",
575
+ ],
576
+ connectSrc: [
577
+ "'self'",
578
578
  'https://monorail-edge.shopifysvc.com',
579
579
  'localhost:*',
580
580
  'ws://localhost:*',
@@ -585,7 +585,7 @@ const { nonce, header, NonceProvider } = createContentSecurityPolicy({
585
585
  'https://api.raygun.com',
586
586
  'https://www.google.com',
587
587
  'https://www.gstatic.com',
588
- ],
588
+ ],
589
589
  frameSrc: ['https://www.google.com', 'https://www.gstatic.com'],
590
590
  });
591
591
  ```
@@ -602,14 +602,14 @@ Add the following block just before the `RECOMMENDED_PRODUCTS_QUERY` GraphQL que
602
602
 
603
603
  ```ts
604
604
  const OKENDO_PRODUCT_STAR_RATING_FRAGMENT = `#graphql
605
- fragment OkendoStarRatingSnippet on Product {
606
- okendoStarRatingSnippet: metafield(
605
+ fragment OkendoStarRatingSnippet on Product {
606
+ okendoStarRatingSnippet: metafield(
607
607
  namespace: "$app:reviews"
608
608
  key: "star_rating_snippet"
609
- ) {
610
- value
611
- }
612
- }
609
+ ) {
610
+ value
611
+ }
612
+ }
613
613
  ` as const;
614
614
  ```
615
615
 
@@ -617,36 +617,36 @@ Then append `${OKENDO_PRODUCT_STAR_RATING_FRAGMENT}` and `...OkendoStarRatingSni
617
617
 
618
618
  ```ts
619
619
  const RECOMMENDED_PRODUCTS_QUERY = `#graphql
620
- ${OKENDO_PRODUCT_STAR_RATING_FRAGMENT}
621
- fragment RecommendedProduct on Product {
622
- id
623
- title
624
- handle
625
- priceRange {
626
- minVariantPrice {
627
- amount
628
- currencyCode
629
- }
630
- }
631
- images(first: 1) {
632
- nodes {
633
- id
634
- url
635
- altText
636
- width
637
- height
638
- }
639
- }
640
- ...OkendoStarRatingSnippet
641
- }
642
- query RecommendedProducts ($country: CountryCode, $language: LanguageCode)
643
- @inContext(country: $country, language: $language) {
644
- products(first: 4, sortKey: UPDATED_AT, reverse: true) {
645
- nodes {
646
- ...RecommendedProduct
647
- }
648
- }
649
- }
620
+ ${OKENDO_PRODUCT_STAR_RATING_FRAGMENT}
621
+ fragment RecommendedProduct on Product {
622
+ id
623
+ title
624
+ handle
625
+ priceRange {
626
+ minVariantPrice {
627
+ amount
628
+ currencyCode
629
+ }
630
+ }
631
+ images(first: 1) {
632
+ nodes {
633
+ id
634
+ url
635
+ altText
636
+ width
637
+ height
638
+ }
639
+ }
640
+ ...OkendoStarRatingSnippet
641
+ }
642
+ query RecommendedProducts ($country: CountryCode, $language: LanguageCode)
643
+ @inContext(country: $country, language: $language) {
644
+ products(first: 4, sortKey: UPDATED_AT, reverse: true) {
645
+ nodes {
646
+ ...RecommendedProduct
647
+ }
648
+ }
649
+ }
650
650
  ` as const;
651
651
  ```
652
652
 
@@ -656,17 +656,17 @@ Add `OkendoStarRating` to the `RecommendedProducts` component — for instance,
656
656
 
657
657
  ```tsx
658
658
  <Image
659
- data={product.images.nodes[0]}
660
- aspectRatio="1/1"
661
- sizes="(min-width: 45em) 20vw, 50vw"
659
+ data={product.images.nodes[0]}
660
+ aspectRatio="1/1"
661
+ sizes="(min-width: 45em) 20vw, 50vw"
662
662
  />
663
663
  <h4>{product.title}</h4>
664
664
  <OkendoStarRating
665
- productId={product.id}
666
- okendoStarRatingSnippet={product.okendoStarRatingSnippet}
665
+ productId={product.id}
666
+ okendoStarRatingSnippet={product.okendoStarRatingSnippet}
667
667
  />
668
668
  <small>
669
- <Money data={product.priceRange.minVariantPrice} />
669
+ <Money data={product.priceRange.minVariantPrice} />
670
670
  </small>
671
671
  ```
672
672
 
@@ -690,25 +690,25 @@ Add the following block just before the `PRODUCT_FRAGMENT` GraphQL query:
690
690
 
691
691
  ```ts
692
692
  const OKENDO_PRODUCT_STAR_RATING_FRAGMENT = `#graphql
693
- fragment OkendoStarRatingSnippet on Product {
694
- okendoStarRatingSnippet: metafield(
693
+ fragment OkendoStarRatingSnippet on Product {
694
+ okendoStarRatingSnippet: metafield(
695
695
  namespace: "$app:reviews"
696
696
  key: "star_rating_snippet"
697
- ) {
698
- value
699
- }
700
- }
697
+ ) {
698
+ value
699
+ }
700
+ }
701
701
  ` as const;
702
702
 
703
703
  const OKENDO_PRODUCT_REVIEWS_FRAGMENT = `#graphql
704
- fragment OkendoReviewsSnippet on Product {
705
- okendoReviewsSnippet: metafield(
704
+ fragment OkendoReviewsSnippet on Product {
705
+ okendoReviewsSnippet: metafield(
706
706
  namespace: "$app:reviews"
707
707
  key: "reviews_widget_snippet"
708
- ) {
709
- value
710
- }
711
- }
708
+ ) {
709
+ value
710
+ }
711
+ }
712
712
  ` as const;
713
713
  ```
714
714
 
@@ -716,35 +716,35 @@ Then append `${OKENDO_PRODUCT_STAR_RATING_FRAGMENT}`, `${OKENDO_PRODUCT_REVIEWS_
716
716
 
717
717
  ```ts
718
718
  const PRODUCT_FRAGMENT = `#graphql
719
- ${OKENDO_PRODUCT_STAR_RATING_FRAGMENT}
720
- ${OKENDO_PRODUCT_REVIEWS_FRAGMENT}
721
- fragment Product on Product {
722
- id
723
- title
724
- vendor
725
- handle
726
- descriptionHtml
727
- description
728
- options {
729
- name
730
- values
731
- }
732
- selectedVariant: variantBySelectedOptions(selectedOptions: $selectedOptions) {
733
- ...ProductVariant
734
- }
735
- variants(first: 1) {
736
- nodes {
737
- ...ProductVariant
738
- }
739
- }
740
- seo {
741
- description
742
- title
743
- }
744
- ...OkendoStarRatingSnippet
745
- ...OkendoReviewsSnippet
746
- }
747
- ${PRODUCT_VARIANT_FRAGMENT}
719
+ ${OKENDO_PRODUCT_STAR_RATING_FRAGMENT}
720
+ ${OKENDO_PRODUCT_REVIEWS_FRAGMENT}
721
+ fragment Product on Product {
722
+ id
723
+ title
724
+ vendor
725
+ handle
726
+ descriptionHtml
727
+ description
728
+ options {
729
+ name
730
+ values
731
+ }
732
+ selectedVariant: variantBySelectedOptions(selectedOptions: $selectedOptions) {
733
+ ...ProductVariant
734
+ }
735
+ variants(first: 1) {
736
+ nodes {
737
+ ...ProductVariant
738
+ }
739
+ }
740
+ seo {
741
+ description
742
+ title
743
+ }
744
+ ...OkendoStarRatingSnippet
745
+ ...OkendoReviewsSnippet
746
+ }
747
+ ${PRODUCT_VARIANT_FRAGMENT}
748
748
  ` as const;
749
749
  ```
750
750
 
@@ -754,27 +754,27 @@ Add `OkendoStarRating` and `OkendoReviews` to the `Product` component:
754
754
 
755
755
  ```tsx
756
756
  <>
757
- <div className="product">
758
- <ProductImage image={selectedVariant?.image} />
757
+ <div className="product">
758
+ <ProductImage image={selectedVariant?.image} />
759
759
  <div className="product-main">
760
760
  <h1>{title}</h1>
761
761
  <OkendoStarRating
762
762
  productId={product.id}
763
763
  okendoStarRatingSnippet={product.okendoStarRatingSnippet}
764
- />
764
+ />
765
765
  <ProductPrice
766
766
  price={selectedVariant?.price}
767
767
  compareAtPrice={selectedVariant?.compareAtPrice}
768
768
  />
769
769
  ...
770
- </div>
770
+ </div>
771
771
  ...
772
772
  </div>
773
773
 
774
- <OkendoReviews
775
- productId={product.id}
776
- okendoReviewsSnippet={product.okendoReviewsSnippet}
777
- />
774
+ <OkendoReviews
775
+ productId={product.id}
776
+ okendoReviewsSnippet={product.okendoReviewsSnippet}
777
+ />
778
778
  </>
779
779
  ```
780
780
 
@@ -795,7 +795,7 @@ import { type MetaFunction } from '@remix-run/react';
795
795
  import { OkendoReviews } from '@okendo/shopify-hydrogen';
796
796
 
797
797
  export const meta: MetaFunction = () => {
798
- return [{ title: `Hydrogen | Okendo All Reviews` }];
798
+ return [{title: `Hydrogen | Okendo All Reviews`}];
799
799
  };
800
800
 
801
801
  export default function ReviewsPage() {
@@ -807,3 +807,28 @@ export default function ReviewsPage() {
807
807
  );
808
808
  }
809
809
  ```
810
+
811
+ ### Okendo Reviews Carousel Widget - Client Side Only
812
+ If you would like to include a copy of the Okendo Reviews Carousel Widget which displays reviews by product or group for a given store (to be used on a homepage or featured page for example), please add the `OkendoReviewsCarouselWidget` with or without the the `productId` or `groupId`.
813
+
814
+ Please note the all reviews widget loads on the client not the server.
815
+
816
+ ```tsx
817
+ import { type MetaFunction } from '@remix-run/react';
818
+ import { OkendoReviews } from '@okendo/shopify-hydrogen';
819
+
820
+ export const meta: MetaFunction = () => {
821
+ return [{title: `Hydrogen | Okendo Reviews Carousel`}];
822
+ };
823
+
824
+ export default function AFeaturedPage() {
825
+ return (
826
+ <div className="all-reviews">
827
+ <h1>Reviews Carousel Widget</h1>
828
+ <OkendoReviewsCarousel
829
+ productId={product.id}
830
+ />
831
+ </div>
832
+ );
833
+ }
834
+ ```
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,o]=e.useState(!1);return e.createElement(n.Provider,{value:{okendoDataLoaded:r,setOkendoDataLoaded:o}},t)},o=()=>{const t=e.useContext(n);return void 0===t?null:t},a="cdn-static.okendo.io",s=({nonce:t="",okendoProviderData:n,productUrlFormatter:r,awaited:s,cdnDomain:i})=>{const d=o(),c=e.useRef(!1);if(e.useEffect((()=>{if(n&&d?.setOkendoDataLoaded(!0),n&&s&&!c.current){const e=document.createElement("script");e.src=`https://${i||a}/reviews-widget-plus/js/okendo-reviews.js`,document.head.appendChild(e),c.current=!0}}),[n,d,s,i]),!n)return null;const{reviewsHeaderConfig:l,cssVariables:u,customCss:p,initScriptContents:m,preRenderStyleTags:v,starSymbols:g}=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(l)}}),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"}`}}),v&&e.createElement("div",{dangerouslySetInnerHTML:{__html:v}}),g&&e.createElement("div",{dangerouslySetInnerHTML:{__html:g}}))};const i=({dataAttributes:t,metafieldContent:n=""})=>{const r=e.useRef(null),o=e.useRef(!1),a=function(t){const n=e.useRef();return e.useEffect((()=>{n.current=t})),n.current}(t),s=()=>{r.current&&(window.okeWidgetApi.initWidget(r.current),o.current=!0)};return e.useEffect((()=>{if(!a||t["data-oke-widget"]!==a["data-oke-widget"]||t["data-oke-star-rating"]!==a["data-oke-star-rating"]||t["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)}}),[t,a]),e.createElement("div",{ref:r,key:JSON.stringify(t),...t,dangerouslySetInnerHTML:n?{__html:n}:void 0})},d=/^[0-9]*$/;function c(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:o,productUrlFormatter:a,cdnDomain:i,children:d})=>e.createElement(r,null,o&&"then"in o?e.createElement(e.Suspense,null,e.createElement(t.Await,{resolve:o},(t=>e.createElement(s,{nonce:n,okendoProviderData:t,productUrlFormatter:a,cdnDomain:i,awaited:!0})))):e.createElement(s,{nonce:n,okendoProviderData:o,productUrlFormatter:a,cdnDomain:i}),d),exports.OkendoReviews=({productId:t,okendoReviewsSnippet:n,placeholder:r})=>{const a=o(),s=t?.length?c(t):null,d=t?.length?n:null,l={"data-oke-widget":"","data-oke-reviews-product-id":s};return null===a||a.okendoDataLoaded?e.createElement(i,{dataAttributes:l,metafieldContent:d?.value}):r||e.createElement("div",{style:{height:"350px"}})},exports.OkendoStarRating=({productId:t,okendoStarRatingSnippet:n,placeholder:r})=>{const a=o(),s={"data-oke-star-rating":"","data-oke-reviews-product-id":c(t)};return null===a||a.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 o=`https://${n||"api.okendo.io/v1"}/stores/${t}/widget_plus_settings`,s=await fetch(o);if(!s.ok)return console.error(`Failed to retrieve subscriber settings for subscriber ID '${t}'.`),null;const{reviewsHeaderConfig:i,cssVariables:d,customCss:c,starSymbols:l}=await s.json(),u=await fetch(`https://${r||a}/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'),v=m?.value??"";return v||console.warn("Failed to retrieve pre-rendered widget style settings."),{reviewsHeaderConfig:i,cssVariables:d,customCss:c,initScriptContents:p,preRenderStyleTags:v,starSymbols:l}};
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}};
@@ -0,0 +1,13 @@
1
+ import React from 'react';
2
+ interface OkendoReviewsCarouselProps {
3
+ productId?: string;
4
+ groupId?: string;
5
+ headerBadgeUrl?: string;
6
+ /**
7
+ * Only used if the promise returned by `getOkendoProviderData` is given to the OkendoProvider
8
+ * without being awaited; in this case, the placeholder here will be shown until the widget is ready
9
+ */
10
+ placeholder?: JSX.Element;
11
+ }
12
+ export declare const OkendoReviewsCarousel: ({ productId, groupId, headerBadgeUrl, placeholder }: OkendoReviewsCarouselProps) => React.JSX.Element;
13
+ export {};
@@ -0,0 +1 @@
1
+ export * from "./OkendoReviewsCarousel";
@@ -1,3 +1,4 @@
1
1
  export * from "./OkendoProvider";
2
2
  export * from "./OkendoReviews";
3
+ export * from "./OkendoReviewsCarousel";
3
4
  export * from "./OkendoStarRating";
package/dist/esm/index.js CHANGED
@@ -1 +1 @@
1
- import e,{createContext as t,useState as n,useContext as r,Suspense as o,useRef as a,useEffect as i}from"react";import{Await as s}from"@remix-run/react";const d=t(void 0),c=({children:t})=>{const[r,o]=n(!1);return e.createElement(d.Provider,{value:{okendoDataLoaded:r,setOkendoDataLoaded:o}},t)},l=()=>{const e=r(d);return void 0===e?null:e},u="cdn-static.okendo.io",p=async({context:e,subscriberId:t,apiDomain:n,cdnDomain:r})=>{const o=`https://${n||"api.okendo.io/v1"}/stores/${t}/widget_plus_settings`,a=await fetch(o);if(!a.ok)return console.error(`Failed to retrieve subscriber settings for subscriber ID '${t}'.`),null;const{reviewsHeaderConfig:i,cssVariables:s,customCss:d,starSymbols:c}=await a.json(),l=await fetch(`https://${r||u}/reviews-widget-plus/js/okendo-reviews.js`);if(!l.ok)return console.error("Failed to retrieve widget initialisation script."),null;const p=await l.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:s,customCss:d,initScriptContents:p,preRenderStyleTags:g,starSymbols:c}},m=({nonce:t="",okendoProviderData:n,productUrlFormatter:r,cdnDomain:a,children:i})=>e.createElement(c,null,n&&"then"in n?e.createElement(o,null,e.createElement(s,{resolve:n},(n=>e.createElement(g,{nonce:t,okendoProviderData:n,productUrlFormatter:r,cdnDomain:a,awaited:!0})))):e.createElement(g,{nonce:t,okendoProviderData:n,productUrlFormatter:r,cdnDomain:a}),i),g=({nonce:t="",okendoProviderData:n,productUrlFormatter:r,awaited:o,cdnDomain:s})=>{const d=l(),c=a(!1);if(i((()=>{if(n&&d?.setOkendoDataLoaded(!0),n&&o&&!c.current){const e=document.createElement("script");e.src=`https://${s||u}/reviews-widget-plus/js/okendo-reviews.js`,document.head.appendChild(e),c.current=!0}}),[n,d,o,s]),!n)return null;const{reviewsHeaderConfig:p,cssVariables:m,customCss:g,initScriptContents:v,preRenderStyleTags:w,starSymbols:k}=n,y=(m??"").replace('<style id="oke-css-vars">',"").replace("</style>",""),f=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}}),f&&e.createElement("style",{nonce:t,id:"oke-reviews-custom-css",dangerouslySetInnerHTML:{__html:f}}),!o&&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"}`}}),w&&e.createElement("div",{dangerouslySetInnerHTML:{__html:w}}),k&&e.createElement("div",{dangerouslySetInnerHTML:{__html:k}}))};const v=({dataAttributes:t,metafieldContent:n=""})=>{const r=a(null),o=a(!1),s=function(e){const t=a();return i((()=>{t.current=e})),t.current}(t),d=()=>{r.current&&(window.okeWidgetApi.initWidget(r.current),o.current=!0)};return i((()=>{if(!s||t["data-oke-widget"]!==s["data-oke-widget"]||t["data-oke-star-rating"]!==s["data-oke-star-rating"]||t["data-oke-reviews-product-id"]!==s["data-oke-reviews-product-id"]||!o.current)return window.okeWidgetApi&&r.current?d():document.addEventListener("oke-script-loaded",d),()=>{document.removeEventListener("oke-script-loaded",d)}}),[t,s]),e.createElement("div",{ref:r,key:JSON.stringify(t),...t,dangerouslySetInnerHTML:n?{__html:n}:void 0})},w=/^[0-9]*$/;function k(e){if(e)return`shopify-${w.test(e)?e:e.split("/").slice(-1)[0]}`}const y=({productId:t,okendoReviewsSnippet:n,placeholder:r})=>{const o=l(),a=t?.length?k(t):null,i=t?.length?n:null,s={"data-oke-widget":"","data-oke-reviews-product-id":a};return null===o||o.okendoDataLoaded?e.createElement(v,{dataAttributes:s,metafieldContent:i?.value}):r||e.createElement("div",{style:{height:"350px"}})},f=({productId:t,okendoStarRatingSnippet:n,placeholder:r})=>{const o=l(),a={"data-oke-star-rating":"","data-oke-reviews-product-id":k(t)};return null===o||o.okendoDataLoaded?e.createElement(v,{dataAttributes:a,metafieldContent:n?.value}):r||e.createElement("div",{style:{height:"20px"}})},h='#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',S='#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{S as OKENDO_PRODUCT_REVIEWS_FRAGMENT,h as OKENDO_PRODUCT_STAR_RATING_FRAGMENT,m as OkendoProvider,y as OkendoReviews,f as OkendoStarRating,p as getOkendoProviderData};
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};
@@ -0,0 +1,13 @@
1
+ import React from 'react';
2
+ interface OkendoReviewsCarouselProps {
3
+ productId?: string;
4
+ groupId?: string;
5
+ headerBadgeUrl?: string;
6
+ /**
7
+ * Only used if the promise returned by `getOkendoProviderData` is given to the OkendoProvider
8
+ * without being awaited; in this case, the placeholder here will be shown until the widget is ready
9
+ */
10
+ placeholder?: JSX.Element;
11
+ }
12
+ export declare const OkendoReviewsCarousel: ({ productId, groupId, headerBadgeUrl, placeholder }: OkendoReviewsCarouselProps) => React.JSX.Element;
13
+ export {};
@@ -0,0 +1 @@
1
+ export * from "./OkendoReviewsCarousel";
@@ -1,3 +1,4 @@
1
1
  export * from "./OkendoProvider";
2
2
  export * from "./OkendoReviews";
3
+ export * from "./OkendoReviewsCarousel";
3
4
  export * from "./OkendoStarRating";
package/dist/index.d.ts CHANGED
@@ -61,6 +61,18 @@ interface OkendoReviewsProps {
61
61
  }
62
62
  declare const OkendoReviews: ({ productId, okendoReviewsSnippet, placeholder }: OkendoReviewsProps) => React.JSX.Element;
63
63
 
64
+ interface OkendoReviewsCarouselProps {
65
+ productId?: string;
66
+ groupId?: string;
67
+ headerBadgeUrl?: string;
68
+ /**
69
+ * Only used if the promise returned by `getOkendoProviderData` is given to the OkendoProvider
70
+ * without being awaited; in this case, the placeholder here will be shown until the widget is ready
71
+ */
72
+ placeholder?: JSX.Element;
73
+ }
74
+ declare const OkendoReviewsCarousel: ({ productId, groupId, headerBadgeUrl, placeholder }: OkendoReviewsCarouselProps) => React.JSX.Element;
75
+
64
76
  interface WithOkendoStarRatingSnippet {
65
77
  okendoStarRatingSnippet?: MetafieldValue | null;
66
78
  }
@@ -78,4 +90,4 @@ declare const OkendoStarRating: ({ productId, okendoStarRatingSnippet, placehold
78
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";
79
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";
80
92
 
81
- export { OKENDO_PRODUCT_REVIEWS_FRAGMENT, OKENDO_PRODUCT_STAR_RATING_FRAGMENT, OkendoProvider, OkendoReviews, OkendoStarRating, type WithOkendoReviewsSnippet, type WithOkendoStarRatingSnippet, getOkendoProviderData };
93
+ export { OKENDO_PRODUCT_REVIEWS_FRAGMENT, OKENDO_PRODUCT_STAR_RATING_FRAGMENT, 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.1",
3
+ "version": "2.3.2",
4
4
  "description": "Okendo React components for Shopify Hydrogen 2 (Remix)",
5
5
  "author": "Okendo",
6
6
  "license": "SEE LICENSE IN LICENSE.txt",