@okendo/shopify-hydrogen 1.3.1 → 2.0.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/LICENSE.txt +1 -1
- package/README.md +376 -468
- package/dist/cjs/index.js +1 -0
- package/dist/cjs/types/components/OkendoProvider/OkendoProvider.d.ts +36 -0
- package/dist/cjs/types/components/OkendoProvider/index.d.ts +1 -0
- package/dist/cjs/types/components/OkendoReviews/OkendoReviews.d.ts +11 -0
- package/dist/cjs/types/components/OkendoReviews/index.d.ts +1 -0
- package/dist/cjs/types/components/OkendoStarRating/OkendoStarRating.d.ts +11 -0
- package/dist/cjs/types/components/OkendoStarRating/index.d.ts +1 -0
- package/dist/cjs/types/components/index.d.ts +3 -0
- package/dist/cjs/types/fragments/fragments.d.ts +2 -0
- package/dist/cjs/types/fragments/index.d.ts +1 -0
- package/dist/cjs/types/index.d.ts +2 -0
- package/dist/cjs/types/internal/OkendoWidget/OkendoWidget.d.ts +12 -0
- package/dist/cjs/types/internal/types.d.ts +3 -0
- package/dist/{esnext/shared/productUtils.d.ts → cjs/types/internal/utils.d.ts} +6 -6
- package/dist/esm/index.js +1 -0
- package/dist/esm/types/components/OkendoProvider/OkendoProvider.d.ts +36 -0
- package/dist/esm/types/components/OkendoProvider/index.d.ts +1 -0
- package/dist/esm/types/components/OkendoReviews/OkendoReviews.d.ts +11 -0
- package/dist/esm/types/components/OkendoReviews/index.d.ts +1 -0
- package/dist/esm/types/components/OkendoStarRating/OkendoStarRating.d.ts +11 -0
- package/dist/esm/types/components/OkendoStarRating/index.d.ts +1 -0
- package/dist/esm/types/components/index.d.ts +3 -0
- package/dist/esm/types/fragments/fragments.d.ts +2 -0
- package/dist/esm/types/fragments/index.d.ts +1 -0
- package/dist/esm/types/index.d.ts +2 -0
- package/dist/esm/types/internal/OkendoWidget/OkendoWidget.d.ts +12 -0
- package/dist/esm/types/internal/types.d.ts +3 -0
- package/dist/esm/types/internal/utils.d.ts +6 -0
- package/dist/index.d.ts +64 -0
- package/package.json +46 -63
- package/dist/esnext/client-components/OkendoClientStarRating.client.d.ts +0 -4
- package/dist/esnext/client-components/OkendoClientStarRating.client.js +0 -24
- package/dist/esnext/client-components/OkendoWidget.client.d.ts +0 -13
- package/dist/esnext/client-components/OkendoWidget.client.js +0 -23
- package/dist/esnext/client-components/index.d.ts +0 -1
- package/dist/esnext/client-components/index.js +0 -1
- package/dist/esnext/client.d.ts +0 -1
- package/dist/esnext/client.js +0 -1
- package/dist/esnext/components/OkendoProvider.server.d.ts +0 -15
- package/dist/esnext/components/OkendoProvider.server.js +0 -69
- package/dist/esnext/components/OkendoReviewsWidget.server.d.ts +0 -6
- package/dist/esnext/components/OkendoReviewsWidget.server.js +0 -61
- package/dist/esnext/components/OkendoStarRating.server.d.ts +0 -4
- package/dist/esnext/components/OkendoStarRating.server.js +0 -46
- package/dist/esnext/components/index.d.ts +0 -3
- package/dist/esnext/components/index.js +0 -3
- package/dist/esnext/fragments/index.d.ts +0 -1
- package/dist/esnext/fragments/index.js +0 -11
- package/dist/esnext/framework/index.d.ts +0 -0
- package/dist/esnext/framework/index.js +0 -1
- package/dist/esnext/framework/plugins/plugin.d.ts +0 -7
- package/dist/esnext/framework/plugins/plugin.js +0 -7
- package/dist/esnext/framework/plugins/suppressModuleWarning.d.ts +0 -3
- package/dist/esnext/framework/plugins/suppressModuleWarning.js +0 -18
- package/dist/esnext/index.d.ts +0 -4
- package/dist/esnext/index.js +0 -4
- package/dist/esnext/models/starRating.d.ts +0 -12
- package/dist/esnext/models/starRating.js +0 -1
- package/dist/esnext/shared/errorUtils.d.ts +0 -3
- package/dist/esnext/shared/errorUtils.js +0 -9
- package/dist/esnext/shared/logger.d.ts +0 -14
- package/dist/esnext/shared/logger.js +0 -7
- package/dist/esnext/shared/productUtils.js +0 -15
- package/dist/esnext/shared/server/requestUtils.d.ts +0 -7
- package/dist/esnext/shared/server/requestUtils.js +0 -4
- package/dist/esnext/shared/sharedTypes.d.ts +0 -5
- package/dist/esnext/shared/sharedTypes.js +0 -1
- package/dist/node/framework/index.d.ts +0 -0
- package/dist/node/framework/index.js +0 -1
- package/dist/node/framework/plugins/plugin.d.ts +0 -4
- package/dist/node/framework/plugins/plugin.js +0 -12
- package/dist/node/framework/plugins/suppressModuleWarning.d.ts +0 -3
- package/dist/node/framework/plugins/suppressModuleWarning.js +0 -20
- package/plugin.cjs +0 -1
package/README.md
CHANGED
|
@@ -1,95 +1,48 @@
|
|
|
1
|
-
|
|
1
|
+
> Note: this package is to be used on stores built with Hydrogen v2, based on Remix. If your store is built with the now deprecated Hydrogen v1, please use [version 1 of this package](https://www.npmjs.com/package/@okendo/shopify-hydrogen/v/1.3.0).
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
# Okendo Hydrogen 2 (Remix) React Components
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
This is the React component library to support Okendo Widget Plus Widgets in Shopify Hydrogen Projects.
|
|
8
|
-
|
|
9
|
-
Currently we provide the following components:
|
|
10
|
-
|
|
11
|
-
### Server Components
|
|
12
|
-
|
|
13
|
-
1. [Reviews List](#components--okendo-reviews-widget)
|
|
14
|
-
2. [Star Ratings](#components--okendo-star-rating)
|
|
15
|
-
|
|
16
|
-
### Client Components
|
|
17
|
-
|
|
18
|
-
1. [Star Ratings](#components--okendo-client-star-rating)
|
|
19
|
-
|
|
20
|
-
<br/>
|
|
21
|
-
|
|
22
|
-
# Table of contents
|
|
23
|
-
|
|
24
|
-
1. [What is Okendo Shopify Hydrogen](#introduction)
|
|
25
|
-
2. [Guided Installation](#installation)
|
|
26
|
-
- [Configure Hydrogen App](#configure-hydrogen-app-config)
|
|
27
|
-
- [Expose Shopify Metafields](#expose-shopify-metafields)
|
|
28
|
-
3. [How to Use Okendo Hydrogen Components In Your Hydrogen Apps](#how-to-use-okendo-hydrogen-components-in-your-hydrogen-app)
|
|
29
|
-
4. [Components](#components)
|
|
30
|
-
5. [GraphQL Fragments](#graphql-fragments)
|
|
31
|
-
6. [View Our Okendo Sample Hydrogen App](#view-our-okendo-sample-hydrogen-app)
|
|
32
|
-
|
|
33
|
-
<br/><br/>
|
|
34
|
-
|
|
35
|
-
# What is Okendo Shopify Hydrogen? <a id="introduction" name="introduction"></a>
|
|
36
|
-
|
|
37
|
-
Okendo Shopify Hydrogen is a React component library to be used in Shopify Hydrogen apps. This utilises [Shopify’s Hydrogen framework](https://shopify.dev/custom-storefronts/hydrogen/framework) which is used to create custom storefronts using both server-side rendered and client-side rendered React components.
|
|
38
|
-
|
|
39
|
-
The purpose of this library is for a Hydrogen-based React Shopify storefront to import this library so that the Okendo Reviews List and Okendo Star Ratings components can be rendered within their React application, providing [Okendo’s reviews display functionality](https://www.okendo.io/blog/widget-plus/).
|
|
40
|
-
|
|
41
|
-
<br/>
|
|
42
|
-
|
|
43
|
-
# Guided Installation <a id="installation" name="installation"></a>
|
|
44
|
-
|
|
45
|
-
The purpose of this documentation is to guide you on the following:
|
|
46
|
-
|
|
47
|
-
- How to configure your Shopify store ready for Okendo Shopify Hydrogen.
|
|
48
|
-
- How to install and configure Okendo Shopify Hydrogen components in your Shopify Hydrogen app.
|
|
49
|
-
|
|
50
|
-
<br/>
|
|
5
|
+
This package brings [Okendo's review widgets](https://www.okendo.io/blog/widget-plus/) to a Shopify Hydrogen store.
|
|
51
6
|
|
|
52
7
|
## Requirements
|
|
53
8
|
|
|
54
|
-
-
|
|
55
|
-
-
|
|
56
|
-
-
|
|
57
|
-
-
|
|
9
|
+
- A Shopify store with the **Okendo: Product Reviews & UCG** app installed and configured.
|
|
10
|
+
- A current Okendo subscription.
|
|
11
|
+
- A [Storefront access token](https://github.com/okendo/okendo-shopify-hydrogen-demo/wiki/Configure-Shopify-Storefront-API).
|
|
12
|
+
- A [Shopify Hydrogen](https://hydrogen.shopify.dev/) app.
|
|
58
13
|
|
|
59
|
-
|
|
14
|
+
## Demo Store
|
|
60
15
|
|
|
61
|
-
|
|
16
|
+
Our demo store, which is based on the demo store provided by Shopify, can be found [here](https://github.com/okendo/okendo-shopify-hydrogen-demo).
|
|
62
17
|
|
|
63
|
-
|
|
64
|
-
2. Make the following changes and save the file:
|
|
65
|
-
- Update `storeDomain` to specify your store's domain name.
|
|
66
|
-
- Update `storefrontToken` to specify your Storefront API access token.
|
|
18
|
+
## How it works
|
|
67
19
|
|
|
68
|
-
|
|
20
|
+
This package provides:
|
|
69
21
|
|
|
70
|
-
|
|
22
|
+
- one function: `getOkendoProviderData`
|
|
23
|
+
- three React components: `OkendoProvider`, `OkendoStarRating`, and `OkendoReviews`
|
|
71
24
|
|
|
72
|
-
|
|
25
|
+
The function `getOkendoProviderData` needs to be called in the `loader` function of the `root.tsx` file in the Hydrogen 2 store. The data is then retrieved in `App` through `useLoaderData` and provided to `OkendoProvider` which is added in the `body` of the HTML returned by `App`.
|
|
73
26
|
|
|
74
|
-
|
|
27
|
+
Then the components `OkendoStarRating` and `OkendoReviews` can be added on the store pages. There are a few more bits of configuration to do, please see below.
|
|
75
28
|
|
|
76
|
-
|
|
29
|
+
## Expose Shopify Metafields <a id="expose-shopify-metafields" name="expose-shopify-metafields"></a>
|
|
77
30
|
|
|
78
|
-
|
|
31
|
+
Okendo Reviews use Product and Shop [metafields](https://shopify.dev/api/examples/metafields). You will need to expose these metafields so that they can be retrieved by your Hydrogen app.
|
|
79
32
|
|
|
80
|
-
|
|
33
|
+
At the moment, Shopify does not have a way of exposing Shop Metafields through their admin UI, so the preferred method is to [contact Okendo Support](mailto:support@okendo.io).
|
|
81
34
|
|
|
82
35
|
<details>
|
|
83
|
-
|
|
36
|
+
<summary>For technical users, follow this method to expose metafields via the storefront API</summary>
|
|
84
37
|
|
|
85
|
-
|
|
38
|
+
### Exposing Metafields via GraphQL
|
|
86
39
|
|
|
87
|
-
|
|
40
|
+
#### Using Curl
|
|
88
41
|
|
|
89
|
-
You can also expose the required Okendo Shopify
|
|
42
|
+
You can also expose the required Okendo Shopify metafields by using GraphQL with curl.
|
|
90
43
|
|
|
91
44
|
1. Open a new terminal or PowerShell window.
|
|
92
|
-
2. Run the following command to expose the `
|
|
45
|
+
2. Run the following command to expose the `WidgetPreRenderStyleTags` shop metafield:
|
|
93
46
|
|
|
94
47
|
```bash
|
|
95
48
|
curl -X POST \
|
|
@@ -98,26 +51,26 @@ https://{shop}.myshopify.com/admin/api/2022-04/graphql.json \
|
|
|
98
51
|
-H 'X-Shopify-Access-Token: {access_token}' \
|
|
99
52
|
-d '
|
|
100
53
|
mutation {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
54
|
+
metafieldStorefrontVisibilityCreate(
|
|
55
|
+
input: {
|
|
56
|
+
namespace: "okendo"
|
|
57
|
+
key: "WidgetPreRenderStyleTags"
|
|
58
|
+
ownerType: SHOP
|
|
59
|
+
}
|
|
60
|
+
) {
|
|
61
|
+
metafieldStorefrontVisibility {
|
|
62
|
+
id
|
|
63
|
+
}
|
|
64
|
+
userErrors {
|
|
65
|
+
field
|
|
66
|
+
message
|
|
67
|
+
}
|
|
68
|
+
}
|
|
116
69
|
}
|
|
117
70
|
'
|
|
118
71
|
```
|
|
119
72
|
|
|
120
|
-
3. Run the following command to expose the `WidgetPreRenderBodyStyleTags`
|
|
73
|
+
3. Run the following command to expose the `WidgetPreRenderBodyStyleTags` shop metafield:
|
|
121
74
|
|
|
122
75
|
```bash
|
|
123
76
|
curl -X POST \
|
|
@@ -126,26 +79,26 @@ https://{shop}.myshopify.com/admin/api/2022-04/graphql.json \
|
|
|
126
79
|
-H 'X-Shopify-Access-Token: {access_token}' \
|
|
127
80
|
-d '
|
|
128
81
|
mutation {
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
82
|
+
metafieldStorefrontVisibilityCreate(
|
|
83
|
+
input: {
|
|
84
|
+
namespace: "okendo"
|
|
85
|
+
key: "WidgetPreRenderBodyStyleTags"
|
|
86
|
+
ownerType: SHOP
|
|
87
|
+
}
|
|
88
|
+
) {
|
|
89
|
+
metafieldStorefrontVisibility {
|
|
90
|
+
id
|
|
91
|
+
}
|
|
92
|
+
userErrors {
|
|
93
|
+
field
|
|
94
|
+
message
|
|
95
|
+
}
|
|
96
|
+
}
|
|
144
97
|
}
|
|
145
98
|
'
|
|
146
99
|
```
|
|
147
100
|
|
|
148
|
-
4. Run the following command to expose the `ReviewsWidgetSnippet`
|
|
101
|
+
4. Run the following command to expose the `ReviewsWidgetSnippet` product metafield:
|
|
149
102
|
|
|
150
103
|
```bash
|
|
151
104
|
curl -X POST \
|
|
@@ -154,26 +107,26 @@ https://{shop}.myshopify.com/admin/api/2022-04/graphql.json \
|
|
|
154
107
|
-H 'X-Shopify-Access-Token: {access_token}' \
|
|
155
108
|
-d '
|
|
156
109
|
mutation {
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
110
|
+
metafieldStorefrontVisibilityCreate(
|
|
111
|
+
input: {
|
|
112
|
+
namespace: "okendo"
|
|
113
|
+
key: "ReviewsWidgetSnippet"
|
|
114
|
+
ownerType: PRODUCT
|
|
115
|
+
}
|
|
116
|
+
) {
|
|
117
|
+
metafieldStorefrontVisibility {
|
|
118
|
+
id
|
|
119
|
+
}
|
|
120
|
+
userErrors {
|
|
121
|
+
field
|
|
122
|
+
message
|
|
123
|
+
}
|
|
124
|
+
}
|
|
172
125
|
}
|
|
173
126
|
'
|
|
174
127
|
```
|
|
175
128
|
|
|
176
|
-
5. Run the following command to expose the `StarRatingSnippet` the
|
|
129
|
+
5. Run the following command to expose the `StarRatingSnippet` the product metafield:
|
|
177
130
|
|
|
178
131
|
```bash
|
|
179
132
|
curl -X POST \
|
|
@@ -182,21 +135,21 @@ https://{shop}.myshopify.com/admin/api/2022-04/graphql.json \
|
|
|
182
135
|
-H 'X-Shopify-Access-Token: {access_token}' \
|
|
183
136
|
-d '
|
|
184
137
|
mutation {
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
138
|
+
metafieldStorefrontVisibilityCreate(
|
|
139
|
+
input: {
|
|
140
|
+
namespace: "okendo"
|
|
141
|
+
key: "StarRatingSnippet"
|
|
142
|
+
ownerType: PRODUCT
|
|
143
|
+
}
|
|
144
|
+
) {
|
|
145
|
+
metafieldStorefrontVisibility {
|
|
146
|
+
id
|
|
147
|
+
}
|
|
148
|
+
userErrors {
|
|
149
|
+
field
|
|
150
|
+
message
|
|
151
|
+
}
|
|
152
|
+
}
|
|
200
153
|
}
|
|
201
154
|
'
|
|
202
155
|
```
|
|
@@ -204,89 +157,91 @@ mutation {
|
|
|
204
157
|
### Using GraphQL IDE
|
|
205
158
|
|
|
206
159
|
1. Open your GraphQL IDE (such as Postman) and make a `POST` request with the following details:
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
160
|
+
|
|
161
|
+
- **URL:** https://{shop}.myshopify.com/admin/api/2022-04/graphql.json
|
|
162
|
+
- **Headers:** - X-Shopify-Access-Token: {access_token} - Content-Type: application/json
|
|
163
|
+
|
|
164
|
+
2. Execute the following request to expose the `WidgetPreRenderStyleTags` shop metafield:
|
|
210
165
|
|
|
211
166
|
```graphql
|
|
212
167
|
mutation {
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
168
|
+
metafieldStorefrontVisibilityCreate(
|
|
169
|
+
input: {
|
|
170
|
+
namespace: "okendo"
|
|
171
|
+
key: "WidgetPreRenderStyleTags"
|
|
172
|
+
ownerType: SHOP
|
|
173
|
+
}
|
|
174
|
+
) {
|
|
175
|
+
metafieldStorefrontVisibility {
|
|
176
|
+
id
|
|
177
|
+
}
|
|
178
|
+
userErrors {
|
|
179
|
+
field
|
|
180
|
+
message
|
|
181
|
+
}
|
|
182
|
+
}
|
|
228
183
|
}
|
|
229
184
|
```
|
|
230
185
|
|
|
231
|
-
3. Execute the following request to expose the `WidgetPreRenderBodyStyleTags`
|
|
186
|
+
3. Execute the following request to expose the `WidgetPreRenderBodyStyleTags` shop metafield:
|
|
232
187
|
|
|
233
188
|
```graphql
|
|
234
189
|
mutation {
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
190
|
+
metafieldStorefrontVisibilityCreate(
|
|
191
|
+
input: {
|
|
192
|
+
namespace: "okendo"
|
|
193
|
+
key: "WidgetPreRenderBodyStyleTags"
|
|
194
|
+
ownerType: SHOP
|
|
195
|
+
}
|
|
196
|
+
) {
|
|
197
|
+
metafieldStorefrontVisibility {
|
|
198
|
+
id
|
|
199
|
+
}
|
|
200
|
+
userErrors {
|
|
201
|
+
field
|
|
202
|
+
message
|
|
203
|
+
}
|
|
204
|
+
}
|
|
250
205
|
}
|
|
251
206
|
```
|
|
252
207
|
|
|
253
|
-
4. Execute the following request to expose the `ReviewsWidgetSnippet`
|
|
208
|
+
4. Execute the following request to expose the `ReviewsWidgetSnippet` product metafield:
|
|
254
209
|
|
|
255
210
|
```graphql
|
|
256
211
|
mutation {
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
212
|
+
metafieldStorefrontVisibilityCreate(
|
|
213
|
+
input: {
|
|
214
|
+
namespace: "okendo"
|
|
215
|
+
key: "ReviewsWidgetSnippet"
|
|
216
|
+
ownerType: PRODUCT
|
|
217
|
+
}
|
|
218
|
+
) {
|
|
219
|
+
metafieldStorefrontVisibility {
|
|
220
|
+
id
|
|
221
|
+
}
|
|
222
|
+
userErrors {
|
|
223
|
+
field
|
|
224
|
+
message
|
|
225
|
+
}
|
|
226
|
+
}
|
|
272
227
|
}
|
|
273
228
|
```
|
|
274
229
|
|
|
275
|
-
5. Execute the following request to expose the `StarRatingSnippet` the
|
|
230
|
+
5. Execute the following request to expose the `StarRatingSnippet` the product metafield:
|
|
276
231
|
|
|
277
232
|
```graphql
|
|
278
233
|
mutation {
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
234
|
+
metafieldStorefrontVisibilityCreate(
|
|
235
|
+
input: { namespace: "okendo", key: "StarRatingSnippet", ownerType: PRODUCT }
|
|
236
|
+
) {
|
|
237
|
+
metafieldStorefrontVisibility {
|
|
238
|
+
id
|
|
239
|
+
}
|
|
240
|
+
userErrors {
|
|
241
|
+
field
|
|
242
|
+
message
|
|
243
|
+
}
|
|
244
|
+
}
|
|
290
245
|
}
|
|
291
246
|
```
|
|
292
247
|
|
|
@@ -296,337 +251,290 @@ mutation {
|
|
|
296
251
|
- [https://shopify.dev/api/admin-graphql/2022-04/mutations/metafieldstorefrontvisibilitycreate](https://shopify.dev/api/admin-graphql/2022-04/mutations/metafieldstorefrontvisibilitycreate)
|
|
297
252
|
</details>
|
|
298
253
|
|
|
299
|
-
<br/><br/>
|
|
300
|
-
|
|
301
|
-
# How to Use Okendo Hydrogen Components In Your Hydrogen App <a id="how-to-use-okendo-hydrogen-components-in-your-hydrogen-app" name="3-how-to-use-okendo-hydrogen-components-in-your-hydrogen-app"></a>
|
|
302
|
-
|
|
303
254
|
## Installation
|
|
304
255
|
|
|
305
|
-
|
|
306
|
-
2. **Optional:** Create (or add to) your `.env` file at the top level of your project (next to **hydrogen.config.ts**) the following, where `<your_subscriber_id>` is replaced with your Okendo Subscriber ID:
|
|
307
|
-
|
|
308
|
-
```sh
|
|
309
|
-
# .env
|
|
310
|
-
VITE_OKENDO_SUBSCRIBER_ID=<your_subscriber_id>
|
|
311
|
-
```
|
|
312
|
-
|
|
313
|
-
3. Open **vite.config.ts** and add `import okendo from '@okendo/shopify-hydrogen/plugin';` to the list of imports.
|
|
314
|
-
4. Add `okendo()` to the list of `plugins`.
|
|
315
|
-
|
|
316
|
-
```tsx
|
|
317
|
-
/* vite.config.ts */
|
|
318
|
-
/// <reference types="vitest" />
|
|
319
|
-
import { defineConfig } from "vite";
|
|
320
|
-
import hydrogen from "@shopify/hydrogen/plugin";
|
|
321
|
-
import okendo from "@okendo/shopify-hydrogen/plugin";
|
|
322
|
-
|
|
323
|
-
export default defineConfig({
|
|
324
|
-
plugins: [hydrogen(), okendo()],
|
|
325
|
-
resolve: {
|
|
326
|
-
alias: [{ find: /^~\/(.*)/, replacement: "/src/$1" }],
|
|
327
|
-
},
|
|
328
|
-
optimizeDeps: {
|
|
329
|
-
include: ["@headlessui/react", "clsx", "react-use", "typographic-base"],
|
|
330
|
-
},
|
|
331
|
-
test: {
|
|
332
|
-
globals: true,
|
|
333
|
-
testTimeout: 10000,
|
|
334
|
-
hookTimeout: 10000,
|
|
335
|
-
},
|
|
336
|
-
});
|
|
337
|
-
```
|
|
338
|
-
|
|
339
|
-
5. Open **App.server.tsx** and import `OkendoProvider`.
|
|
340
|
-
6. Include the `OkendoProvider` as shown below, passing through your `subscriberId` from your Vite environment variables.
|
|
341
|
-
|
|
342
|
-
```tsx
|
|
343
|
-
/* App.server.tsx */
|
|
344
|
-
import {OkendoProvider} from '@okendo/shopify-hydrogen';
|
|
345
|
-
|
|
346
|
-
function App() {
|
|
347
|
-
return (
|
|
348
|
-
<Suspense fallback={<LoadingFallback />}>
|
|
349
|
-
<ShopifyProvider>
|
|
350
|
-
<!-- *** Include OkendoProvider HERE *** -->
|
|
351
|
-
<OkendoProvider
|
|
352
|
-
subscriberId={import.meta.env.VITE_OKENDO_SUBSCRIBER_ID}
|
|
353
|
-
/>
|
|
354
|
-
<ServerCartProvider>
|
|
355
|
-
<DefaultSeo />
|
|
356
|
-
<Router>
|
|
357
|
-
<FileRoutes />
|
|
358
|
-
<Route path="*" page={<NotFound />} />
|
|
359
|
-
</Router>
|
|
360
|
-
</ServerCartProvider>
|
|
361
|
-
<PerformanceMetrics />
|
|
362
|
-
{import.meta.env.DEV && <PerformanceMetricsDebug />}
|
|
363
|
-
</ShopifyProvider>
|
|
364
|
-
</Suspense>
|
|
365
|
-
);
|
|
366
|
-
```
|
|
367
|
-
|
|
368
|
-
If your app doesn't use Vite environment variables from a `.env` file, you could also provide your Okendo Subscriber ID through other means, i.e. directly:
|
|
369
|
-
|
|
370
|
-
```tsx
|
|
371
|
-
<OkendoProvider subscriberId={okendoSubscriberId} />
|
|
372
|
-
```
|
|
373
|
-
|
|
374
|
-
## Widget Usage
|
|
375
|
-
|
|
376
|
-
### Server Components
|
|
377
|
-
|
|
378
|
-
Import `OkendoReviewsWidget` and `OkendoStarRating` and use as JSX components. Pass in the Shopify Product ID as a prop.
|
|
379
|
-
|
|
380
|
-
The `productId` prop is optional for the `OkendoReviewsWidget`. Not providing it will mean that the widget will display reviews for all products, which is ideal for homepages or collection pages.
|
|
381
|
-
|
|
382
|
-
```tsx
|
|
383
|
-
import {
|
|
384
|
-
OkendoReviewsWidget,
|
|
385
|
-
OkendoStarRating,
|
|
386
|
-
} from '@okendo/shopify-hydrogen';
|
|
256
|
+
> The code examples provided in this section are based on the [demo store provided by Shopify](https://github.com/Shopify/hydrogen/tree/2023-01/templates/demo-store). You will find the following steps already done in [our demo store](https://github.com/okendo/okendo-shopify-hydrogen-demo).
|
|
387
257
|
|
|
388
|
-
|
|
258
|
+
Run:
|
|
389
259
|
|
|
390
|
-
|
|
391
|
-
|
|
260
|
+
```bash
|
|
261
|
+
npm i @okendo/shopify-hydrogen
|
|
392
262
|
```
|
|
393
263
|
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
<br />
|
|
397
|
-
|
|
398
|
-
### Client Components
|
|
399
|
-
|
|
400
|
-
#### Star Rating Widget Usage in Client Components
|
|
401
|
-
|
|
402
|
-
We also include an `OkendoClientStarRating` component for use within client-side (e.g.`<your component>.client.tsx`) components.
|
|
264
|
+
### `app/root.tsx`
|
|
403
265
|
|
|
404
|
-
|
|
266
|
+
Open `app/root.tsx` and add the following import:
|
|
405
267
|
|
|
406
|
-
```
|
|
407
|
-
import {
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
const okendoClientStarRating = <OkendoClientStarRating productId={product.id} />;
|
|
268
|
+
```ts
|
|
269
|
+
import {
|
|
270
|
+
OkendoProvider,
|
|
271
|
+
getOkendoProviderData,
|
|
272
|
+
} from "@okendo/shopify-hydrogen";
|
|
412
273
|
```
|
|
413
274
|
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
<br />
|
|
417
|
-
|
|
418
|
-
# Components <a id="components" name="components"></a>
|
|
419
|
-
|
|
420
|
-
### OkendoProvider
|
|
421
|
-
|
|
422
|
-
Top level component for enabling Okendo Widgets.
|
|
423
|
-
|
|
424
|
-
We recommend using it directly inside the `<ShopifyProvider>` as its first child in **App.server.tsx**.
|
|
425
|
-
|
|
426
|
-
It will provide:
|
|
275
|
+
Locate the `meta` function, and append the property `oke:subscriber_id` containing your Okendo subscriber ID:
|
|
427
276
|
|
|
428
|
-
|
|
429
|
-
-
|
|
430
|
-
|
|
431
|
-
- Custom CSS specified in the Okendo Admin (if applicable)
|
|
432
|
-
- "Above the fold" CSS essential for Server-Side Rendered (SSR) widgets. This ensures styled widgets prior to client-side hydration.
|
|
433
|
-
- Okendo widget initialisation script
|
|
434
|
-
- Used to render/hydrate widgets on the page
|
|
435
|
-
|
|
436
|
-
| Name | Type | Description | Required |
|
|
437
|
-
| ------------------------------------- | ----------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
|
|
438
|
-
| <code>subscriberId</code> | <code>string</code> | The Okendo subscriber ID. | yes |
|
|
439
|
-
| <code>apiDomain</code> | <code>string</code> | To override the default Okendo API Domain. (Default: <code>api.okendo.io/v1</code>) | no |
|
|
440
|
-
| <code>cdnDomain</code> | <code>string</code> | To override the default Okendo CDN domain. (Default: <code>cdn-static.okendo.io</code>) | no |
|
|
441
|
-
| <code>productUrlFormatOverride</code> | <code>(product: ReviewProduct) => string</code> | By default, we use Hydrogen's out of the box product routing.<br />**Advanced Usage Only:** Function hook which allows the custom configuration of the Shopify product URLs from the Okendo Reviews Widget. | no |
|
|
442
|
-
|
|
443
|
-
### OkendoReviewsWidget<a id="components--okendo-reviews-widget" name="components--okendo-reviews-widget"></a>
|
|
444
|
-
|
|
445
|
-
The Okendo Reviews List widget.
|
|
446
|
-
|
|
447
|
-
| Name | Type | Description | Required |
|
|
448
|
-
| ---------------------- | ------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
|
|
449
|
-
| <code>productId</code> | <code>string</code> | The Shopify Product ID. If provided, the Reviews Widget will be configured to display reviews specific to that product. Otherwise, the Reviews Widget will display reviews for all products. | no |
|
|
450
|
-
|
|
451
|
-
### OkendoStarRating<a id="components--okendo-star-rating" name="components--okendo-star-rating"></a>
|
|
452
|
-
|
|
453
|
-
The Okendo Star Rating widget - **For use in _server_ components**.
|
|
454
|
-
|
|
455
|
-
| Name | Type | Description | Required |
|
|
456
|
-
| ---------------------- | ------------------- | ----------------------- | -------- |
|
|
457
|
-
| <code>productId</code> | <code>string</code> | The Shopify Product ID. | yes |
|
|
277
|
+
```ts
|
|
278
|
+
'oke:subscriber_id': '<your-okendo-subscriber-id>',
|
|
279
|
+
```
|
|
458
280
|
|
|
459
|
-
|
|
281
|
+
The `meta` function should now look like the following:
|
|
460
282
|
|
|
461
|
-
|
|
283
|
+
```ts
|
|
284
|
+
export const meta: MetaFunction = () => ({
|
|
285
|
+
charset: "utf-8",
|
|
286
|
+
viewport: "width=device-width,initial-scale=1",
|
|
287
|
+
"oke:subscriber_id": "<your-okendo-subscriber-id>",
|
|
288
|
+
});
|
|
289
|
+
```
|
|
462
290
|
|
|
463
|
-
|
|
291
|
+
Locate the `loader` function and append the `okendoProviderData` property to the returned data:
|
|
464
292
|
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
293
|
+
```ts
|
|
294
|
+
okendoProviderData: await getOkendoProviderData({
|
|
295
|
+
context,
|
|
296
|
+
subscriberId: '<your-okendo-subscriber-id>',
|
|
297
|
+
}),
|
|
298
|
+
```
|
|
469
299
|
|
|
470
|
-
|
|
300
|
+
The `loader` function returned data should now look like the following:
|
|
301
|
+
|
|
302
|
+
```ts
|
|
303
|
+
return defer({
|
|
304
|
+
isLoggedIn: Boolean(customerAccessToken),
|
|
305
|
+
layout,
|
|
306
|
+
selectedLocale: context.storefront.i18n,
|
|
307
|
+
cart: cartId ? getCart(context, cartId) : undefined,
|
|
308
|
+
analytics: {
|
|
309
|
+
shopifySalesChannel: ShopifySalesChannel.hydrogen,
|
|
310
|
+
shopId: layout.shop.id,
|
|
311
|
+
},
|
|
312
|
+
seo,
|
|
313
|
+
okendoProviderData: await getOkendoProviderData({
|
|
314
|
+
context,
|
|
315
|
+
subscriberId: "<your-okendo-subscriber-id>",
|
|
316
|
+
}),
|
|
317
|
+
});
|
|
318
|
+
```
|
|
471
319
|
|
|
472
|
-
|
|
320
|
+
Locate the `App` function, append `OkendoProvider` to `body`, and provide it with the data returned by `getOkendoProviderData`:
|
|
473
321
|
|
|
474
|
-
|
|
322
|
+
```tsx
|
|
323
|
+
...
|
|
324
|
+
<body>
|
|
325
|
+
<OkendoProvider okendoProviderData={data.okendoProviderData} />
|
|
326
|
+
...
|
|
327
|
+
</body>
|
|
328
|
+
...
|
|
329
|
+
```
|
|
475
330
|
|
|
476
|
-
|
|
331
|
+
### `app/data/fragments.ts`
|
|
477
332
|
|
|
478
|
-
|
|
333
|
+
Open `app/data/fragments.ts` and add the following import:
|
|
479
334
|
|
|
480
|
-
|
|
335
|
+
```ts
|
|
336
|
+
import { OKENDO_PRODUCT_STAR_RATING_FRAGMENT } from "@okendo/shopify-hydrogen";
|
|
337
|
+
```
|
|
481
338
|
|
|
482
|
-
|
|
339
|
+
Then add `${OKENDO_PRODUCT_STAR_RATING_FRAGMENT}` and `...OkendoStarRatingSnippet` to `PRODUCT_CARD_FRAGMENT`:
|
|
340
|
+
|
|
341
|
+
```ts
|
|
342
|
+
export const PRODUCT_CARD_FRAGMENT = `#graphql
|
|
343
|
+
${OKENDO_PRODUCT_STAR_RATING_FRAGMENT}
|
|
344
|
+
fragment ProductCard on Product {
|
|
345
|
+
id
|
|
346
|
+
title
|
|
347
|
+
publishedAt
|
|
348
|
+
handle
|
|
349
|
+
...OkendoStarRatingSnippet
|
|
350
|
+
variants(first: 1) {
|
|
351
|
+
...
|
|
352
|
+
```
|
|
483
353
|
|
|
484
|
-
|
|
354
|
+
### `app/components/ProductCard.tsx`
|
|
485
355
|
|
|
486
|
-
|
|
356
|
+
Open `app/components/ProductCard.tsx` and add the following import:
|
|
487
357
|
|
|
488
|
-
|
|
358
|
+
```ts
|
|
359
|
+
import {
|
|
360
|
+
OkendoStarRating,
|
|
361
|
+
WithOkendoStarRatingSnippet,
|
|
362
|
+
} from "@okendo/shopify-hydrogen";
|
|
363
|
+
```
|
|
489
364
|
|
|
490
|
-
|
|
365
|
+
Tweak the type of the `product` prop to be:
|
|
491
366
|
|
|
492
|
-
|
|
367
|
+
```ts
|
|
368
|
+
product: SerializeFrom<Product & WithOkendoStarRatingSnippet>;
|
|
369
|
+
```
|
|
493
370
|
|
|
494
|
-
|
|
371
|
+
`ProductCard` should now look like this:
|
|
495
372
|
|
|
496
|
-
|
|
373
|
+
```ts
|
|
374
|
+
export function ProductCard({
|
|
375
|
+
product,
|
|
376
|
+
label,
|
|
377
|
+
className,
|
|
378
|
+
loading,
|
|
379
|
+
onClick,
|
|
380
|
+
quickAdd,
|
|
381
|
+
}: {
|
|
382
|
+
product: SerializeFrom<Product & WithOkendoStarRatingSnippet>;
|
|
383
|
+
label?: string;
|
|
384
|
+
className?: string;
|
|
385
|
+
loading?: HTMLImageElement['loading'];
|
|
386
|
+
onClick?: () => void;
|
|
387
|
+
quickAdd?: boolean;
|
|
388
|
+
}) {
|
|
389
|
+
```
|
|
497
390
|
|
|
498
|
-
|
|
391
|
+
Add the `OkendoStarRating` component:
|
|
499
392
|
|
|
500
393
|
```tsx
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
publishedAt
|
|
506
|
-
handle
|
|
507
|
-
variants(first: 1) {
|
|
508
|
-
nodes {
|
|
509
|
-
id
|
|
510
|
-
image {
|
|
511
|
-
url
|
|
512
|
-
altText
|
|
513
|
-
width
|
|
514
|
-
height
|
|
515
|
-
}
|
|
516
|
-
priceV2 {
|
|
517
|
-
amount
|
|
518
|
-
currencyCode
|
|
519
|
-
}
|
|
520
|
-
compareAtPriceV2 {
|
|
521
|
-
amount
|
|
522
|
-
currencyCode
|
|
523
|
-
}
|
|
524
|
-
}
|
|
525
|
-
}
|
|
526
|
-
}
|
|
527
|
-
`;
|
|
394
|
+
<OkendoStarRating
|
|
395
|
+
productId={product.id}
|
|
396
|
+
okendoStarRatingSnippet={product.okendoStarRatingSnippet}
|
|
397
|
+
/>
|
|
528
398
|
```
|
|
529
399
|
|
|
530
|
-
|
|
400
|
+
For instance, you can add it below the product title, like this:
|
|
531
401
|
|
|
532
402
|
```tsx
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
id
|
|
544
|
-
image {
|
|
545
|
-
url
|
|
546
|
-
altText
|
|
547
|
-
width
|
|
548
|
-
height
|
|
549
|
-
}
|
|
550
|
-
priceV2 {
|
|
551
|
-
amount
|
|
552
|
-
currencyCode
|
|
553
|
-
}
|
|
554
|
-
compareAtPriceV2 {
|
|
555
|
-
amount
|
|
556
|
-
currencyCode
|
|
557
|
-
}
|
|
558
|
-
}
|
|
559
|
-
}
|
|
560
|
-
}
|
|
561
|
-
`;
|
|
403
|
+
<Text
|
|
404
|
+
className="w-full overflow-hidden whitespace-nowrap text-ellipsis "
|
|
405
|
+
as="h3"
|
|
406
|
+
>
|
|
407
|
+
{product.title}
|
|
408
|
+
</Text>
|
|
409
|
+
<OkendoStarRating
|
|
410
|
+
productId={product.id}
|
|
411
|
+
okendoStarRatingSnippet={product.okendoStarRatingSnippet}
|
|
412
|
+
/>
|
|
562
413
|
```
|
|
563
414
|
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
The `okendoStarRatingSnippet` is a server-side rendered version of the output of your star rating contents. This is supplied to your `Product`/`Collection` queries using the `OKENDO_PRODUCT_STAR_RATING_FRAGMENT` to fetch a metafield containg the markup.
|
|
415
|
+
### `app/routes/($lang)/products/$productHandle.tsx`
|
|
567
416
|
|
|
568
|
-
|
|
417
|
+
Open `app/routes/($lang)/products/$productHandle.tsx` and add the following imports:
|
|
569
418
|
|
|
570
|
-
|
|
419
|
+
```ts
|
|
420
|
+
import {
|
|
421
|
+
OkendoReviews,
|
|
422
|
+
OkendoStarRating,
|
|
423
|
+
WithOkendoStarRatingSnippet,
|
|
424
|
+
WithOkendoReviewsSnippet,
|
|
425
|
+
OKENDO_PRODUCT_STAR_RATING_FRAGMENT,
|
|
426
|
+
OKENDO_PRODUCT_REVIEWS_FRAGMENT,
|
|
427
|
+
} from "@okendo/shopify-hydrogen";
|
|
428
|
+
```
|
|
571
429
|
|
|
572
|
-
|
|
430
|
+
In the storefront query, tweak the type of `product` to be:
|
|
573
431
|
|
|
574
|
-
|
|
432
|
+
```ts
|
|
433
|
+
product: ProductType & {
|
|
434
|
+
selectedVariant?: ProductVariant;
|
|
435
|
+
} & WithOkendoStarRatingSnippet &
|
|
436
|
+
WithOkendoReviewsSnippet;
|
|
437
|
+
```
|
|
575
438
|
|
|
576
|
-
|
|
577
|
-
|
|
439
|
+
The storefront query should now look like this:
|
|
440
|
+
|
|
441
|
+
```ts
|
|
442
|
+
const { shop, product } = await context.storefront.query<{
|
|
443
|
+
product: ProductType & {
|
|
444
|
+
selectedVariant?: ProductVariant;
|
|
445
|
+
} & WithOkendoStarRatingSnippet &
|
|
446
|
+
WithOkendoReviewsSnippet;
|
|
447
|
+
shop: Shop;
|
|
448
|
+
}>(PRODUCT_QUERY, {
|
|
449
|
+
variables: {
|
|
450
|
+
handle: productHandle,
|
|
451
|
+
selectedOptions,
|
|
452
|
+
country: context.storefront.i18n.country,
|
|
453
|
+
language: context.storefront.i18n.language,
|
|
454
|
+
},
|
|
455
|
+
});
|
|
578
456
|
```
|
|
579
457
|
|
|
580
|
-
|
|
458
|
+
Add the `OkendoStarRating` component:
|
|
581
459
|
|
|
582
460
|
```tsx
|
|
583
|
-
|
|
584
|
-
|
|
461
|
+
<OkendoStarRating
|
|
462
|
+
productId={product.id}
|
|
463
|
+
okendoStarRatingSnippet={product.okendoStarRatingSnippet}
|
|
464
|
+
/>
|
|
585
465
|
```
|
|
586
466
|
|
|
587
|
-
|
|
467
|
+
For instance, you can add it between the product title and the store name, like this:
|
|
588
468
|
|
|
589
469
|
```tsx
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
loading?: HTMLImageElement['loading'];
|
|
601
|
-
onClick?: () => void;
|
|
602
|
-
}) {
|
|
603
|
-
...
|
|
604
|
-
}
|
|
470
|
+
<Heading as="h1" className="whitespace-normal">
|
|
471
|
+
{title}
|
|
472
|
+
</Heading>
|
|
473
|
+
<OkendoStarRating
|
|
474
|
+
productId={product.id}
|
|
475
|
+
okendoStarRatingSnippet={product.okendoStarRatingSnippet}
|
|
476
|
+
/>
|
|
477
|
+
{vendor && (
|
|
478
|
+
<Text className={'opacity-50 font-medium'}>{vendor}</Text>
|
|
479
|
+
)}
|
|
605
480
|
```
|
|
606
481
|
|
|
607
|
-
|
|
482
|
+
Add the `OkendoReviews` component:
|
|
608
483
|
|
|
609
484
|
```tsx
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
okendoStarRatingSnippet={product.okendoStarRatingSnippet}
|
|
615
|
-
/>
|
|
616
|
-
) : null;
|
|
617
|
-
}
|
|
485
|
+
<OkendoReviews
|
|
486
|
+
productId={product.id}
|
|
487
|
+
okendoReviewsSnippet={product.okendoReviewsSnippet}
|
|
488
|
+
/>
|
|
618
489
|
```
|
|
619
490
|
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
- [GraphQL Fragments](https://www.apollographql.com/docs/react/data/fragments/)
|
|
491
|
+
For instance, you can add it below the product section:
|
|
623
492
|
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
493
|
+
```tsx
|
|
494
|
+
...
|
|
495
|
+
</Section>
|
|
496
|
+
<OkendoReviews
|
|
497
|
+
productId={product.id}
|
|
498
|
+
okendoReviewsSnippet={product.okendoReviewsSnippet}
|
|
499
|
+
/>
|
|
500
|
+
<Suspense fallback={<Skeleton className="h-32" />}>
|
|
501
|
+
...
|
|
502
|
+
```
|
|
627
503
|
|
|
628
|
-
|
|
504
|
+
Locate `PRODUCT_QUERY` and add the following to it:
|
|
629
505
|
|
|
630
|
-
|
|
506
|
+
```ts
|
|
507
|
+
...
|
|
508
|
+
${OKENDO_PRODUCT_STAR_RATING_FRAGMENT}
|
|
509
|
+
${OKENDO_PRODUCT_REVIEWS_FRAGMENT}
|
|
510
|
+
...
|
|
511
|
+
...OkendoStarRatingSnippet
|
|
512
|
+
...OkendoReviewsSnippet
|
|
513
|
+
```
|
|
631
514
|
|
|
632
|
-
|
|
515
|
+
It should now look like this:
|
|
516
|
+
|
|
517
|
+
```ts
|
|
518
|
+
const PRODUCT_QUERY = `#graphql
|
|
519
|
+
${MEDIA_FRAGMENT}
|
|
520
|
+
${PRODUCT_VARIANT_FRAGMENT}
|
|
521
|
+
${OKENDO_PRODUCT_STAR_RATING_FRAGMENT}
|
|
522
|
+
${OKENDO_PRODUCT_REVIEWS_FRAGMENT}
|
|
523
|
+
query Product(
|
|
524
|
+
$country: CountryCode
|
|
525
|
+
$language: LanguageCode
|
|
526
|
+
$handle: String!
|
|
527
|
+
$selectedOptions: [SelectedOptionInput!]!
|
|
528
|
+
) @inContext(country: $country, language: $language) {
|
|
529
|
+
product(handle: $handle) {
|
|
530
|
+
id
|
|
531
|
+
title
|
|
532
|
+
vendor
|
|
533
|
+
handle
|
|
534
|
+
descriptionHtml
|
|
535
|
+
description
|
|
536
|
+
...OkendoStarRatingSnippet
|
|
537
|
+
...OkendoReviewsSnippet
|
|
538
|
+
options {
|
|
539
|
+
...
|
|
540
|
+
```
|