@okendo/shopify-hydrogen 2.3.1 → 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 +435 -346
- package/dist/cjs/index.js +1 -1
- package/dist/cjs/types/components/OkendoLoyalty/OkendoLoyaltyEmbeddedWidget.d.ts +9 -0
- package/dist/cjs/types/components/OkendoLoyalty/index.d.ts +1 -0
- package/dist/cjs/types/components/OkendoProvider/OkendoProvider.d.ts +21 -7
- package/dist/cjs/types/components/OkendoReviewsCarousel/OkendoReviewsCarousel.d.ts +13 -0
- package/dist/cjs/types/components/OkendoReviewsCarousel/index.d.ts +1 -0
- package/dist/cjs/types/components/OkendoStarRating/OkendoStarRating.d.ts +1 -1
- package/dist/cjs/types/components/index.d.ts +2 -0
- package/dist/cjs/types/fragments/fragments.d.ts +2 -2
- package/dist/cjs/types/internal/utils.d.ts +1 -0
- package/dist/esm/index.js +1 -1
- package/dist/esm/types/components/OkendoLoyalty/OkendoLoyaltyEmbeddedWidget.d.ts +9 -0
- package/dist/esm/types/components/OkendoLoyalty/index.d.ts +1 -0
- package/dist/esm/types/components/OkendoProvider/OkendoProvider.d.ts +21 -7
- package/dist/esm/types/components/OkendoReviewsCarousel/OkendoReviewsCarousel.d.ts +13 -0
- package/dist/esm/types/components/OkendoReviewsCarousel/index.d.ts +1 -0
- package/dist/esm/types/components/OkendoStarRating/OkendoStarRating.d.ts +1 -1
- package/dist/esm/types/components/index.d.ts +2 -0
- package/dist/esm/types/fragments/fragments.d.ts +2 -2
- package/dist/esm/types/internal/utils.d.ts +1 -0
- package/dist/index.d.ts +47 -12
- package/package.json +1 -1
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:
|
|
@@ -55,22 +57,22 @@ https://{shop}.myshopify.com/admin/api/2024-10/graphql.json \
|
|
|
55
57
|
-H 'X-Shopify-Access-Token: {access_token}' \
|
|
56
58
|
-d '
|
|
57
59
|
mutation {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
60
|
+
metafieldDefinitionCreate(
|
|
61
|
+
definition: {
|
|
62
|
+
name: "WidgetPreRenderStyleTags"
|
|
63
|
+
namespace: "app--1576377--reviews"
|
|
64
|
+
key: "widget_pre_render_style_tags"
|
|
65
|
+
type: "multi_line_text_field"
|
|
66
|
+
ownerType: SHOP
|
|
67
|
+
access: {
|
|
68
|
+
admin: PUBLIC_READ
|
|
69
|
+
storefront: PUBLIC_READ
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
) {
|
|
73
|
+
createdDefinition { id name }
|
|
74
|
+
userErrors { field message code }
|
|
75
|
+
}
|
|
74
76
|
}
|
|
75
77
|
'
|
|
76
78
|
```
|
|
@@ -84,22 +86,22 @@ https://{shop}.myshopify.com/admin/api/2024-10/graphql.json \
|
|
|
84
86
|
-H 'X-Shopify-Access-Token: {access_token}' \
|
|
85
87
|
-d '
|
|
86
88
|
mutation {
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
89
|
+
metafieldDefinitionCreate(
|
|
90
|
+
definition: {
|
|
91
|
+
name: "WidgetPreRenderBodyStyleTags"
|
|
92
|
+
namespace: "app--1576377--reviews"
|
|
93
|
+
key: "widget_pre_render_body_style_tags"
|
|
94
|
+
type: "multi_line_text_field"
|
|
95
|
+
ownerType: SHOP
|
|
96
|
+
access: {
|
|
97
|
+
admin: PUBLIC_READ
|
|
98
|
+
storefront: PUBLIC_READ
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
) {
|
|
102
|
+
createdDefinition { id name }
|
|
103
|
+
userErrors { field message code }
|
|
104
|
+
}
|
|
103
105
|
}
|
|
104
106
|
'
|
|
105
107
|
```
|
|
@@ -113,22 +115,22 @@ https://{shop}.myshopify.com/admin/api/2024-10/graphql.json \
|
|
|
113
115
|
-H 'X-Shopify-Access-Token: {access_token}' \
|
|
114
116
|
-d '
|
|
115
117
|
mutation {
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
118
|
+
metafieldDefinitionCreate(
|
|
119
|
+
definition: {
|
|
120
|
+
name: "ReviewsWidgetSnippet"
|
|
121
|
+
namespace: "app--1576377--reviews"
|
|
122
|
+
key: "reviews_widget_snippet"
|
|
123
|
+
type: "multi_line_text_field"
|
|
124
|
+
ownerType: PRODUCT
|
|
125
|
+
access: {
|
|
126
|
+
admin: PUBLIC_READ
|
|
127
|
+
storefront: PUBLIC_READ
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
) {
|
|
131
|
+
createdDefinition { id name }
|
|
132
|
+
userErrors { field message code }
|
|
133
|
+
}
|
|
132
134
|
}
|
|
133
135
|
'
|
|
134
136
|
```
|
|
@@ -142,22 +144,22 @@ https://{shop}.myshopify.com/admin/api/2024-10/graphql.json \
|
|
|
142
144
|
-H 'X-Shopify-Access-Token: {access_token}' \
|
|
143
145
|
-d '
|
|
144
146
|
mutation {
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
147
|
+
metafieldDefinitionCreate(
|
|
148
|
+
definition: {
|
|
149
|
+
name: "StarRatingSnippet"
|
|
150
|
+
namespace: "app--1576377--reviews"
|
|
151
|
+
key: "star_rating_snippet"
|
|
152
|
+
type: "multi_line_text_field"
|
|
153
|
+
ownerType: PRODUCT
|
|
154
|
+
access: {
|
|
155
|
+
admin: PUBLIC_READ
|
|
156
|
+
storefront: PUBLIC_READ
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
) {
|
|
160
|
+
createdDefinition { id name }
|
|
161
|
+
userErrors { field message code }
|
|
162
|
+
}
|
|
161
163
|
}
|
|
162
164
|
'
|
|
163
165
|
```
|
|
@@ -171,22 +173,22 @@ https://{shop}.myshopify.com/admin/api/2024-10/graphql.json \
|
|
|
171
173
|
-H 'X-Shopify-Access-Token: {access_token}' \
|
|
172
174
|
-d '
|
|
173
175
|
mutation {
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
176
|
+
metafieldDefinitionCreate(
|
|
177
|
+
definition: {
|
|
178
|
+
name: "ReviewCount"
|
|
179
|
+
namespace: "app--1576377--reviews"
|
|
180
|
+
key: "review_count"
|
|
181
|
+
type: "number_integer"
|
|
182
|
+
ownerType: PRODUCT
|
|
183
|
+
access: {
|
|
184
|
+
admin: PUBLIC_READ
|
|
185
|
+
storefront: PUBLIC_READ
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
) {
|
|
189
|
+
createdDefinition { id name }
|
|
190
|
+
userErrors { field message code }
|
|
191
|
+
}
|
|
190
192
|
}
|
|
191
193
|
'
|
|
192
194
|
```
|
|
@@ -200,22 +202,22 @@ https://{shop}.myshopify.com/admin/api/2024-10/graphql.json \
|
|
|
200
202
|
-H 'X-Shopify-Access-Token: {access_token}' \
|
|
201
203
|
-d '
|
|
202
204
|
mutation {
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
205
|
+
metafieldDefinitionCreate(
|
|
206
|
+
definition: {
|
|
207
|
+
name: "AverageRating"
|
|
208
|
+
namespace: "app--1576377--reviews"
|
|
209
|
+
key: "average_rating"
|
|
210
|
+
type: "rating"
|
|
211
|
+
ownerType: PRODUCT
|
|
212
|
+
access: {
|
|
213
|
+
admin: PUBLIC_READ
|
|
214
|
+
storefront: PUBLIC_READ
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
) {
|
|
218
|
+
createdDefinition { id name }
|
|
219
|
+
userErrors { field message code }
|
|
220
|
+
}
|
|
219
221
|
}
|
|
220
222
|
'
|
|
221
223
|
```
|
|
@@ -231,26 +233,29 @@ Open your GraphQL IDE (such as Postman) and make `POST` requests with the follow
|
|
|
231
233
|
|
|
232
234
|
```graphql
|
|
233
235
|
mutation {
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
236
|
+
metafieldDefinitionCreate(
|
|
237
|
+
definition: {
|
|
238
|
+
name: "WidgetPreRenderStyleTags"
|
|
239
|
+
namespace: "app--1576377--reviews"
|
|
240
|
+
key: "widget_pre_render_style_tags"
|
|
241
|
+
type: "multi_line_text_field"
|
|
242
|
+
ownerType: SHOP
|
|
243
|
+
access: {
|
|
244
|
+
admin: PUBLIC_READ,
|
|
245
|
+
storefront: PUBLIC_READ
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
) {
|
|
249
|
+
createdDefinition {
|
|
250
|
+
id
|
|
251
|
+
name
|
|
252
|
+
}
|
|
253
|
+
userErrors {
|
|
254
|
+
field
|
|
255
|
+
message
|
|
256
|
+
code
|
|
257
|
+
}
|
|
258
|
+
}
|
|
254
259
|
}
|
|
255
260
|
```
|
|
256
261
|
|
|
@@ -258,26 +263,29 @@ mutation {
|
|
|
258
263
|
|
|
259
264
|
```graphql
|
|
260
265
|
mutation {
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
266
|
+
metafieldDefinitionCreate(
|
|
267
|
+
definition: {
|
|
268
|
+
name: "WidgetPreRenderBodyStyleTags"
|
|
269
|
+
namespace: "app--1576377--reviews"
|
|
270
|
+
key: "widget_pre_render_body_style_tags"
|
|
271
|
+
type: "multi_line_text_field"
|
|
272
|
+
ownerType: SHOP
|
|
273
|
+
access: {
|
|
274
|
+
admin: PUBLIC_READ,
|
|
275
|
+
storefront: PUBLIC_READ
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
) {
|
|
279
|
+
createdDefinition {
|
|
280
|
+
id
|
|
281
|
+
name
|
|
282
|
+
}
|
|
283
|
+
userErrors {
|
|
284
|
+
field
|
|
285
|
+
message
|
|
286
|
+
code
|
|
287
|
+
}
|
|
288
|
+
}
|
|
281
289
|
}
|
|
282
290
|
```
|
|
283
291
|
|
|
@@ -285,26 +293,29 @@ mutation {
|
|
|
285
293
|
|
|
286
294
|
```graphql
|
|
287
295
|
mutation {
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
296
|
+
metafieldDefinitionCreate(
|
|
297
|
+
definition: {
|
|
298
|
+
name: "ReviewsWidgetSnippet"
|
|
299
|
+
namespace: "app--1576377--reviews"
|
|
300
|
+
key: "reviews_widget_snippet"
|
|
301
|
+
type: "multi_line_text_field"
|
|
302
|
+
ownerType: PRODUCT
|
|
303
|
+
access: {
|
|
304
|
+
admin: PUBLIC_READ,
|
|
305
|
+
storefront: PUBLIC_READ
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
) {
|
|
309
|
+
createdDefinition {
|
|
310
|
+
id
|
|
311
|
+
name
|
|
312
|
+
}
|
|
313
|
+
userErrors {
|
|
314
|
+
field
|
|
315
|
+
message
|
|
316
|
+
code
|
|
317
|
+
}
|
|
318
|
+
}
|
|
308
319
|
}
|
|
309
320
|
```
|
|
310
321
|
|
|
@@ -312,26 +323,29 @@ mutation {
|
|
|
312
323
|
|
|
313
324
|
```graphql
|
|
314
325
|
mutation {
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
326
|
+
metafieldDefinitionCreate(
|
|
327
|
+
definition: {
|
|
328
|
+
name: "StarRatingSnippet"
|
|
329
|
+
namespace: "app--1576377--reviews"
|
|
330
|
+
key: "star_rating_snippet"
|
|
331
|
+
type: "multi_line_text_field"
|
|
332
|
+
ownerType: PRODUCT
|
|
333
|
+
access: {
|
|
334
|
+
admin: PUBLIC_READ,
|
|
335
|
+
storefront: PUBLIC_READ
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
) {
|
|
339
|
+
createdDefinition {
|
|
340
|
+
id
|
|
341
|
+
name
|
|
342
|
+
}
|
|
343
|
+
userErrors {
|
|
344
|
+
field
|
|
345
|
+
message
|
|
346
|
+
code
|
|
347
|
+
}
|
|
348
|
+
}
|
|
335
349
|
}
|
|
336
350
|
```
|
|
337
351
|
|
|
@@ -339,26 +353,29 @@ mutation {
|
|
|
339
353
|
|
|
340
354
|
```graphql
|
|
341
355
|
mutation {
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
356
|
+
metafieldDefinitionCreate(
|
|
357
|
+
definition: {
|
|
358
|
+
name: "ReviewCount"
|
|
359
|
+
namespace: "app--1576377--reviews"
|
|
360
|
+
key: "review_count"
|
|
361
|
+
type: "number_integer"
|
|
362
|
+
ownerType: PRODUCT
|
|
363
|
+
access: {
|
|
364
|
+
admin: PUBLIC_READ,
|
|
365
|
+
storefront: PUBLIC_READ
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
) {
|
|
369
|
+
createdDefinition {
|
|
370
|
+
id
|
|
371
|
+
name
|
|
372
|
+
}
|
|
373
|
+
userErrors {
|
|
374
|
+
field
|
|
375
|
+
message
|
|
376
|
+
code
|
|
377
|
+
}
|
|
378
|
+
}
|
|
362
379
|
}
|
|
363
380
|
```
|
|
364
381
|
|
|
@@ -366,26 +383,29 @@ mutation {
|
|
|
366
383
|
|
|
367
384
|
```graphql
|
|
368
385
|
mutation {
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
386
|
+
metafieldDefinitionCreate(
|
|
387
|
+
definition: {
|
|
388
|
+
name: "AverageRating"
|
|
389
|
+
namespace: "app--1576377--reviews"
|
|
390
|
+
key: "average_rating"
|
|
391
|
+
type: "rating"
|
|
392
|
+
ownerType: PRODUCT
|
|
393
|
+
access: {
|
|
394
|
+
admin: PUBLIC_READ,
|
|
395
|
+
storefront: PUBLIC_READ
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
) {
|
|
399
|
+
createdDefinition {
|
|
400
|
+
id
|
|
401
|
+
name
|
|
402
|
+
}
|
|
403
|
+
userErrors {
|
|
404
|
+
field
|
|
405
|
+
message
|
|
406
|
+
code
|
|
407
|
+
}
|
|
408
|
+
}
|
|
389
409
|
}
|
|
390
410
|
```
|
|
391
411
|
|
|
@@ -444,8 +464,8 @@ Open `app/root.tsx` and add the following import:
|
|
|
444
464
|
|
|
445
465
|
```ts
|
|
446
466
|
import {
|
|
447
|
-
|
|
448
|
-
|
|
467
|
+
OkendoProvider,
|
|
468
|
+
getOkendoProviderData,
|
|
449
469
|
} from '@okendo/shopify-hydrogen';
|
|
450
470
|
```
|
|
451
471
|
|
|
@@ -458,10 +478,10 @@ return defer({
|
|
|
458
478
|
// ...
|
|
459
479
|
okendoProviderData:
|
|
460
480
|
/* place `await` here if you want server-rendered widgets */ getOkendoProviderData(
|
|
461
|
-
|
|
481
|
+
{
|
|
462
482
|
context: args.context,
|
|
463
483
|
subscriberId: '<your-okendo-subscriber-id>',
|
|
464
|
-
|
|
484
|
+
},
|
|
465
485
|
),
|
|
466
486
|
});
|
|
467
487
|
```
|
|
@@ -470,10 +490,10 @@ Locate the `Layout` component, add the `meta` tag `oke:subscriber_id` to `head`,
|
|
|
470
490
|
|
|
471
491
|
```tsx
|
|
472
492
|
<head>
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
493
|
+
<meta charSet="utf-8" />
|
|
494
|
+
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
|
495
|
+
<meta name="oke:subscriber_id" content="<your-okendo-subscriber-id>" />
|
|
496
|
+
...
|
|
477
497
|
</head>
|
|
478
498
|
```
|
|
479
499
|
|
|
@@ -487,10 +507,10 @@ Append `OkendoProvider` to `body`, and pass it the promise — or the data — r
|
|
|
487
507
|
cart={data.cart}
|
|
488
508
|
shop={data.shop}
|
|
489
509
|
consent={data.consent}
|
|
490
|
-
|
|
510
|
+
>
|
|
491
511
|
<PageLayout {...data}>{children}</PageLayout>
|
|
492
512
|
</Analytics.Provider>
|
|
493
|
-
|
|
513
|
+
</OkendoProvider>
|
|
494
514
|
) : (
|
|
495
515
|
children
|
|
496
516
|
)}
|
|
@@ -512,8 +532,8 @@ const { nonce, header, NonceProvider } = createContentSecurityPolicy({
|
|
|
512
532
|
checkoutDomain: context.env.PUBLIC_CHECKOUT_DOMAIN,
|
|
513
533
|
storeDomain: context.env.PUBLIC_STORE_DOMAIN,
|
|
514
534
|
},
|
|
515
|
-
|
|
516
|
-
|
|
535
|
+
defaultSrc: [
|
|
536
|
+
"'self'",
|
|
517
537
|
'localhost:*',
|
|
518
538
|
'https://cdn.shopify.com',
|
|
519
539
|
'https://www.google.com',
|
|
@@ -525,9 +545,9 @@ const { nonce, header, NonceProvider } = createContentSecurityPolicy({
|
|
|
525
545
|
'https://surveys.okendo.io',
|
|
526
546
|
'https://api.okendo.io',
|
|
527
547
|
'data:',
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
548
|
+
],
|
|
549
|
+
imgSrc: [
|
|
550
|
+
"'self'",
|
|
531
551
|
'https://cdn.shopify.com',
|
|
532
552
|
'data:',
|
|
533
553
|
'https://d3hw6dc1ow8pp2.cloudfront.net',
|
|
@@ -535,26 +555,26 @@ const { nonce, header, NonceProvider } = createContentSecurityPolicy({
|
|
|
535
555
|
'https://dov7r31oq5dkj.cloudfront.net',
|
|
536
556
|
'https://cdn-static.okendo.io',
|
|
537
557
|
'https://surveys.okendo.io',
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
558
|
+
],
|
|
559
|
+
mediaSrc: [
|
|
560
|
+
"'self'",
|
|
541
561
|
'https://d3hw6dc1ow8pp2.cloudfront.net',
|
|
542
562
|
'https://d3g5hqndtiniji.cloudfront.net',
|
|
543
563
|
'https://dov7r31oq5dkj.cloudfront.net',
|
|
544
564
|
'https://cdn-static.okendo.io',
|
|
545
|
-
|
|
565
|
+
],
|
|
546
566
|
styleSrc: [
|
|
547
|
-
|
|
548
|
-
|
|
567
|
+
"'self'",
|
|
568
|
+
"'unsafe-inline'",
|
|
549
569
|
'https://cdn.shopify.com',
|
|
550
570
|
'https://fonts.googleapis.com',
|
|
551
571
|
'https://fonts.gstatic.com',
|
|
552
572
|
'https://d3hw6dc1ow8pp2.cloudfront.net',
|
|
553
573
|
'https://cdn-static.okendo.io',
|
|
554
574
|
'https://surveys.okendo.io',
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
575
|
+
],
|
|
576
|
+
scriptSrc: [
|
|
577
|
+
"'self'",
|
|
558
578
|
'https://cdn.shopify.com',
|
|
559
579
|
'https://d3hw6dc1ow8pp2.cloudfront.net',
|
|
560
580
|
'https://dov7r31oq5dkj.cloudfront.net',
|
|
@@ -563,18 +583,18 @@ const { nonce, header, NonceProvider } = createContentSecurityPolicy({
|
|
|
563
583
|
'https://api.okendo.io',
|
|
564
584
|
'https://www.google.com',
|
|
565
585
|
'https://www.gstatic.com',
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
586
|
+
],
|
|
587
|
+
fontSrc: [
|
|
588
|
+
"'self'",
|
|
569
589
|
'https://fonts.gstatic.com',
|
|
570
590
|
'https://d3hw6dc1ow8pp2.cloudfront.net',
|
|
571
591
|
'https://dov7r31oq5dkj.cloudfront.net',
|
|
572
592
|
'https://cdn.shopify.com',
|
|
573
593
|
'https://cdn-static.okendo.io',
|
|
574
594
|
'https://surveys.okendo.io',
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
595
|
+
],
|
|
596
|
+
connectSrc: [
|
|
597
|
+
"'self'",
|
|
578
598
|
'https://monorail-edge.shopifysvc.com',
|
|
579
599
|
'localhost:*',
|
|
580
600
|
'ws://localhost:*',
|
|
@@ -585,7 +605,7 @@ const { nonce, header, NonceProvider } = createContentSecurityPolicy({
|
|
|
585
605
|
'https://api.raygun.com',
|
|
586
606
|
'https://www.google.com',
|
|
587
607
|
'https://www.gstatic.com',
|
|
588
|
-
|
|
608
|
+
],
|
|
589
609
|
frameSrc: ['https://www.google.com', 'https://www.gstatic.com'],
|
|
590
610
|
});
|
|
591
611
|
```
|
|
@@ -602,14 +622,14 @@ Add the following block just before the `RECOMMENDED_PRODUCTS_QUERY` GraphQL que
|
|
|
602
622
|
|
|
603
623
|
```ts
|
|
604
624
|
const OKENDO_PRODUCT_STAR_RATING_FRAGMENT = `#graphql
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
625
|
+
fragment OkendoStarRatingSnippet on Product {
|
|
626
|
+
okendoStarRatingSnippet: metafield(
|
|
627
|
+
namespace: "app--1576377--reviews"
|
|
628
|
+
key: "star_rating_snippet"
|
|
629
|
+
) {
|
|
630
|
+
value
|
|
631
|
+
}
|
|
632
|
+
}
|
|
613
633
|
` as const;
|
|
614
634
|
```
|
|
615
635
|
|
|
@@ -617,36 +637,36 @@ Then append `${OKENDO_PRODUCT_STAR_RATING_FRAGMENT}` and `...OkendoStarRatingSni
|
|
|
617
637
|
|
|
618
638
|
```ts
|
|
619
639
|
const RECOMMENDED_PRODUCTS_QUERY = `#graphql
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
640
|
+
${OKENDO_PRODUCT_STAR_RATING_FRAGMENT}
|
|
641
|
+
fragment RecommendedProduct on Product {
|
|
642
|
+
id
|
|
643
|
+
title
|
|
644
|
+
handle
|
|
645
|
+
priceRange {
|
|
646
|
+
minVariantPrice {
|
|
647
|
+
amount
|
|
648
|
+
currencyCode
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
images(first: 1) {
|
|
652
|
+
nodes {
|
|
653
|
+
id
|
|
654
|
+
url
|
|
655
|
+
altText
|
|
656
|
+
width
|
|
657
|
+
height
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
...OkendoStarRatingSnippet
|
|
661
|
+
}
|
|
662
|
+
query RecommendedProducts ($country: CountryCode, $language: LanguageCode)
|
|
663
|
+
@inContext(country: $country, language: $language) {
|
|
664
|
+
products(first: 4, sortKey: UPDATED_AT, reverse: true) {
|
|
665
|
+
nodes {
|
|
666
|
+
...RecommendedProduct
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
}
|
|
650
670
|
` as const;
|
|
651
671
|
```
|
|
652
672
|
|
|
@@ -656,17 +676,17 @@ Add `OkendoStarRating` to the `RecommendedProducts` component — for instance,
|
|
|
656
676
|
|
|
657
677
|
```tsx
|
|
658
678
|
<Image
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
679
|
+
data={product.images.nodes[0]}
|
|
680
|
+
aspectRatio="1/1"
|
|
681
|
+
sizes="(min-width: 45em) 20vw, 50vw"
|
|
662
682
|
/>
|
|
663
683
|
<h4>{product.title}</h4>
|
|
664
684
|
<OkendoStarRating
|
|
665
|
-
|
|
666
|
-
|
|
685
|
+
productId={product.id}
|
|
686
|
+
okendoStarRatingSnippet={product.okendoStarRatingSnippet}
|
|
667
687
|
/>
|
|
668
688
|
<small>
|
|
669
|
-
|
|
689
|
+
<Money data={product.priceRange.minVariantPrice} />
|
|
670
690
|
</small>
|
|
671
691
|
```
|
|
672
692
|
|
|
@@ -690,25 +710,25 @@ Add the following block just before the `PRODUCT_FRAGMENT` GraphQL query:
|
|
|
690
710
|
|
|
691
711
|
```ts
|
|
692
712
|
const OKENDO_PRODUCT_STAR_RATING_FRAGMENT = `#graphql
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
713
|
+
fragment OkendoStarRatingSnippet on Product {
|
|
714
|
+
okendoStarRatingSnippet: metafield(
|
|
715
|
+
namespace: "app--1576377--reviews"
|
|
716
|
+
key: "star_rating_snippet"
|
|
717
|
+
) {
|
|
718
|
+
value
|
|
719
|
+
}
|
|
720
|
+
}
|
|
701
721
|
` as const;
|
|
702
722
|
|
|
703
723
|
const OKENDO_PRODUCT_REVIEWS_FRAGMENT = `#graphql
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
724
|
+
fragment OkendoReviewsSnippet on Product {
|
|
725
|
+
okendoReviewsSnippet: metafield(
|
|
726
|
+
namespace: "app--1576377--reviews"
|
|
727
|
+
key: "reviews_widget_snippet"
|
|
728
|
+
) {
|
|
729
|
+
value
|
|
730
|
+
}
|
|
731
|
+
}
|
|
712
732
|
` as const;
|
|
713
733
|
```
|
|
714
734
|
|
|
@@ -716,35 +736,35 @@ Then append `${OKENDO_PRODUCT_STAR_RATING_FRAGMENT}`, `${OKENDO_PRODUCT_REVIEWS_
|
|
|
716
736
|
|
|
717
737
|
```ts
|
|
718
738
|
const PRODUCT_FRAGMENT = `#graphql
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
739
|
+
${OKENDO_PRODUCT_STAR_RATING_FRAGMENT}
|
|
740
|
+
${OKENDO_PRODUCT_REVIEWS_FRAGMENT}
|
|
741
|
+
fragment Product on Product {
|
|
742
|
+
id
|
|
743
|
+
title
|
|
744
|
+
vendor
|
|
745
|
+
handle
|
|
746
|
+
descriptionHtml
|
|
747
|
+
description
|
|
748
|
+
options {
|
|
749
|
+
name
|
|
750
|
+
values
|
|
751
|
+
}
|
|
752
|
+
selectedVariant: variantBySelectedOptions(selectedOptions: $selectedOptions) {
|
|
753
|
+
...ProductVariant
|
|
754
|
+
}
|
|
755
|
+
variants(first: 1) {
|
|
756
|
+
nodes {
|
|
757
|
+
...ProductVariant
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
seo {
|
|
761
|
+
description
|
|
762
|
+
title
|
|
763
|
+
}
|
|
764
|
+
...OkendoStarRatingSnippet
|
|
765
|
+
...OkendoReviewsSnippet
|
|
766
|
+
}
|
|
767
|
+
${PRODUCT_VARIANT_FRAGMENT}
|
|
748
768
|
` as const;
|
|
749
769
|
```
|
|
750
770
|
|
|
@@ -754,27 +774,27 @@ Add `OkendoStarRating` and `OkendoReviews` to the `Product` component:
|
|
|
754
774
|
|
|
755
775
|
```tsx
|
|
756
776
|
<>
|
|
757
|
-
|
|
758
|
-
|
|
777
|
+
<div className="product">
|
|
778
|
+
<ProductImage image={selectedVariant?.image} />
|
|
759
779
|
<div className="product-main">
|
|
760
780
|
<h1>{title}</h1>
|
|
761
781
|
<OkendoStarRating
|
|
762
782
|
productId={product.id}
|
|
763
783
|
okendoStarRatingSnippet={product.okendoStarRatingSnippet}
|
|
764
|
-
|
|
784
|
+
/>
|
|
765
785
|
<ProductPrice
|
|
766
786
|
price={selectedVariant?.price}
|
|
767
787
|
compareAtPrice={selectedVariant?.compareAtPrice}
|
|
768
788
|
/>
|
|
769
789
|
...
|
|
770
|
-
|
|
790
|
+
</div>
|
|
771
791
|
...
|
|
772
792
|
</div>
|
|
773
793
|
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
794
|
+
<OkendoReviews
|
|
795
|
+
productId={product.id}
|
|
796
|
+
okendoReviewsSnippet={product.okendoReviewsSnippet}
|
|
797
|
+
/>
|
|
778
798
|
</>
|
|
779
799
|
```
|
|
780
800
|
|
|
@@ -795,7 +815,7 @@ import { type MetaFunction } from '@remix-run/react';
|
|
|
795
815
|
import { OkendoReviews } from '@okendo/shopify-hydrogen';
|
|
796
816
|
|
|
797
817
|
export const meta: MetaFunction = () => {
|
|
798
|
-
return [{
|
|
818
|
+
return [{title: `Hydrogen | Okendo All Reviews`}];
|
|
799
819
|
};
|
|
800
820
|
|
|
801
821
|
export default function ReviewsPage() {
|
|
@@ -807,3 +827,72 @@ export default function ReviewsPage() {
|
|
|
807
827
|
);
|
|
808
828
|
}
|
|
809
829
|
```
|
|
830
|
+
|
|
831
|
+
### Okendo Reviews Carousel Widget - Client Side Only
|
|
832
|
+
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`.
|
|
833
|
+
|
|
834
|
+
Please note the all reviews widget loads on the client not the server.
|
|
835
|
+
|
|
836
|
+
```tsx
|
|
837
|
+
import { type MetaFunction } from '@remix-run/react';
|
|
838
|
+
import { OkendoReviews } from '@okendo/shopify-hydrogen';
|
|
839
|
+
|
|
840
|
+
export const meta: MetaFunction = () => {
|
|
841
|
+
return [{title: `Hydrogen | Okendo Reviews Carousel`}];
|
|
842
|
+
};
|
|
843
|
+
|
|
844
|
+
export default function AFeaturedPage() {
|
|
845
|
+
return (
|
|
846
|
+
<div className="all-reviews">
|
|
847
|
+
<h1>Reviews Carousel Widget</h1>
|
|
848
|
+
<OkendoReviewsCarousel
|
|
849
|
+
productId={product.id}
|
|
850
|
+
/>
|
|
851
|
+
</div>
|
|
852
|
+
);
|
|
853
|
+
}
|
|
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';`*
|