@okendo/shopify-hydrogen 1.0.1 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (27) hide show
  1. package/README.md +333 -146
  2. package/dist/esnext/client-components/OkendoClientStarRating.client.d.ts +4 -0
  3. package/dist/esnext/client-components/OkendoClientStarRating.client.js +25 -0
  4. package/dist/esnext/{components → client-components}/OkendoWidget.client.d.ts +1 -1
  5. package/dist/esnext/{components → client-components}/OkendoWidget.client.js +0 -0
  6. package/dist/esnext/client-components/index.d.ts +1 -0
  7. package/dist/esnext/client-components/index.js +1 -0
  8. package/dist/esnext/client.d.ts +1 -0
  9. package/dist/esnext/client.js +1 -0
  10. package/dist/esnext/components/OkendoProvider.server.js +2 -1
  11. package/dist/esnext/components/OkendoReviewsWidget.server.js +4 -2
  12. package/dist/esnext/components/OkendoStarRating.server.d.ts +1 -3
  13. package/dist/esnext/components/OkendoStarRating.server.js +4 -2
  14. package/dist/esnext/components/index.d.ts +1 -1
  15. package/dist/esnext/components/index.js +1 -1
  16. package/dist/esnext/fragments/index.d.ts +1 -0
  17. package/dist/esnext/fragments/index.js +11 -0
  18. package/dist/esnext/index.d.ts +3 -1
  19. package/dist/esnext/index.js +3 -1
  20. package/dist/esnext/models/starRating.d.ts +12 -0
  21. package/dist/esnext/models/starRating.js +1 -0
  22. package/dist/esnext/shared/{requestUtils.d.ts → server/requestUtils.d.ts} +1 -1
  23. package/dist/esnext/shared/{requestUtils.js → server/requestUtils.js} +0 -0
  24. package/dist/esnext/shared/sharedTypes.d.ts +4 -0
  25. package/package.json +13 -2
  26. package/dist/esnext/shared/index.d.ts +0 -4
  27. package/dist/esnext/shared/index.js +0 -4
package/README.md CHANGED
@@ -2,11 +2,17 @@
2
2
 
3
3
  This is the React component library to support Okendo Widget Plus Widgets in Shopify Hydrogen Projects.
4
4
 
5
- Currently we provide server side components for 2 widgets:
5
+ Currently we provide the following components:
6
+
7
+ ### Server Components
6
8
 
7
9
  1. [Reviews List](#components--okendo-reviews-widget)
8
10
  2. [Star Ratings](#components--okendo-star-rating)
9
11
 
12
+ ### Client Components
13
+
14
+ 1. [Star Ratings](#components--okendo-client-star-rating)
15
+
10
16
  <br/>
11
17
 
12
18
  # Table of contents
@@ -17,7 +23,8 @@ Currently we provide server side components for 2 widgets:
17
23
  - [Expose Shopify Metafields](#expose-shopify-metafields)
18
24
  3. [How to Use Okendo Hydrogen Components In Your Hydrogen Apps](#how-to-use-okendo-hydrogen-components-in-your-hydrogen-app)
19
25
  4. [Components](#components)
20
- 5. [View Our Okendo Sample Hydrogen App](#view-our-okendo-sample-hydrogen-app)
26
+ 5. [GraphQL Fragments](#graphql-fragments)
27
+ 6. [View Our Okendo Sample Hydrogen App](#view-our-okendo-sample-hydrogen-app)
21
28
 
22
29
  <br/><br/>
23
30
 
@@ -43,7 +50,7 @@ The purpose of this documentation is to guide you on the following:
43
50
  - You have an existing Shopify store.
44
51
  - You have an existing Hydrogen app. ([Learn how to create a Hydrogen app](https://shopify.dev/custom-storefronts/hydrogen/getting-started/create))
45
52
  - You have a current Okendo Reviews subscription and have the **Okendo: Product Reviews & UCG** app installed and configured.
46
- - You have an existing Shopify custom app with Storefront access token. ([Learn how to configure Shopify Storefront](https://www.notion.so/Configure-Shopify-Storefront-9e78e31bb4d94546aa1d037367c6a0b8))
53
+ - You have an existing Shopify custom app with Storefront access token. ([Learn how to configure Shopify Storefront](https://github.com/okendo/okendo-shopify-hydrogen-demo/wiki/Configure-Shopify-Storefront-API))
47
54
 
48
55
  <br/>
49
56
 
@@ -73,7 +80,6 @@ The preferred method to expose Metafields is to [contact Okendo Support](mailto:
73
80
 
74
81
  ## Exposing Metafields via GraphQL
75
82
 
76
-
77
83
  ### Using Curl
78
84
 
79
85
  You can also expose the required Okendo Shopify Metafields by using GraphQL with curl.
@@ -194,100 +200,97 @@ mutation {
194
200
  ### Using GraphQL IDE
195
201
 
196
202
  1. Open your GraphQL IDE (such as Postman) and make a `POST` request with the following details:
197
- - **URL:** https://{shop}.myshopify.com/admin/api/2022-04/graphql.json
198
- - **Headers:** - X-Shopify-Access-Token: {access_token} - Content-Type: application/json 2. Execute the following request to expose the `WidgetPreRenderStyleTag` Shop Metafield.
199
-
200
- ```graphql
201
- mutation {
202
- metafieldStorefrontVisibilityCreate(
203
- input: {
204
- namespace: "okendo"
205
- key: "WidgetPreRenderStyleTags"
206
- ownerType: SHOP
207
- }
208
- ) {
209
- metafieldStorefrontVisibility {
210
- id
211
- }
212
- userErrors {
213
- field
214
- message
215
- }
203
+ - **URL:** https://{shop}.myshopify.com/admin/api/2022-04/graphql.json
204
+ - **Headers:** - X-Shopify-Access-Token: {access_token} - Content-Type: application/json
205
+ 2. Execute the following request to expose the `WidgetPreRenderStyleTag` Shop Metafield.
206
+
207
+ ```graphql
208
+ mutation {
209
+ metafieldStorefrontVisibilityCreate(
210
+ input: {
211
+ namespace: "okendo"
212
+ key: "WidgetPreRenderStyleTags"
213
+ ownerType: SHOP
214
+ }
215
+ ) {
216
+ metafieldStorefrontVisibility {
217
+ id
218
+ }
219
+ userErrors {
220
+ field
221
+ message
216
222
  }
217
223
  }
218
- ```
224
+ }
225
+ ```
219
226
 
220
- 3. Execute the following request to expose the `WidgetPreRenderBodyStyleTags` Shop Metafield.
227
+ 3. Execute the following request to expose the `WidgetPreRenderBodyStyleTags` Shop Metafield.
221
228
 
222
- ```graphql
223
- mutation {
224
- metafieldStorefrontVisibilityCreate(
225
- input: {
226
- namespace: "okendo"
227
- key: "WidgetPreRenderBodyStyleTags"
228
- ownerType: SHOP
229
- }
230
- ) {
231
- metafieldStorefrontVisibility {
232
- id
233
- }
234
- userErrors {
235
- field
236
- message
237
- }
229
+ ```graphql
230
+ mutation {
231
+ metafieldStorefrontVisibilityCreate(
232
+ input: {
233
+ namespace: "okendo"
234
+ key: "WidgetPreRenderBodyStyleTags"
235
+ ownerType: SHOP
236
+ }
237
+ ) {
238
+ metafieldStorefrontVisibility {
239
+ id
240
+ }
241
+ userErrors {
242
+ field
243
+ message
238
244
  }
239
245
  }
240
- ```
246
+ }
247
+ ```
241
248
 
242
- 4. Execute the following request to expose the `ReviewsWidgetSnippet` Product Metafield.
249
+ 4. Execute the following request to expose the `ReviewsWidgetSnippet` Product Metafield.
243
250
 
244
- ```graphql
245
- mutation {
246
- metafieldStorefrontVisibilityCreate(
247
- input: {
248
- namespace: "okendo"
249
- key: "ReviewsWidgetSnippet"
250
- ownerType: PRODUCT
251
- }
252
- ) {
253
- metafieldStorefrontVisibility {
254
- id
255
- }
256
- userErrors {
257
- field
258
- message
259
- }
251
+ ```graphql
252
+ mutation {
253
+ metafieldStorefrontVisibilityCreate(
254
+ input: {
255
+ namespace: "okendo"
256
+ key: "ReviewsWidgetSnippet"
257
+ ownerType: PRODUCT
258
+ }
259
+ ) {
260
+ metafieldStorefrontVisibility {
261
+ id
262
+ }
263
+ userErrors {
264
+ field
265
+ message
260
266
  }
261
267
  }
262
- ```
268
+ }
269
+ ```
263
270
 
264
- 5. Execute the following request to expose the `StarRatingSnippet` the Product Metafield.
271
+ 5. Execute the following request to expose the `StarRatingSnippet` the Product Metafield.
265
272
 
266
- ```graphql
267
- mutation {
268
- metafieldStorefrontVisibilityCreate(
269
- input: {
270
- namespace: "okendo"
271
- key: "StarRatingSnippet"
272
- ownerType: PRODUCT
273
- }
274
- ) {
275
- metafieldStorefrontVisibility {
276
- id
277
- }
278
- userErrors {
279
- field
280
- message
281
- }
273
+ ```graphql
274
+ mutation {
275
+ metafieldStorefrontVisibilityCreate(
276
+ input: { namespace: "okendo", key: "StarRatingSnippet", ownerType: PRODUCT }
277
+ ) {
278
+ metafieldStorefrontVisibility {
279
+ id
280
+ }
281
+ userErrors {
282
+ field
283
+ message
282
284
  }
283
285
  }
284
- ```
286
+ }
287
+ ```
285
288
 
286
- **References**
289
+ **References**
287
290
 
288
- - [https://shopify.dev/api/examples/metafields#step-1-expose-metafields](https://shopify.dev/api/examples/metafields#step-1-expose-metafields)
289
- - [https://shopify.dev/api/admin-graphql/2022-04/mutations/metafieldstorefrontvisibilitycreate](https://shopify.dev/api/admin-graphql/2022-04/mutations/metafieldstorefrontvisibilitycreate)
290
- </details>
291
+ - [https://shopify.dev/api/examples/metafields#step-1-expose-metafields](https://shopify.dev/api/examples/metafields#step-1-expose-metafields)
292
+ - [https://shopify.dev/api/admin-graphql/2022-04/mutations/metafieldstorefrontvisibilitycreate](https://shopify.dev/api/admin-graphql/2022-04/mutations/metafieldstorefrontvisibilitycreate)
293
+ </details>
291
294
 
292
295
  <br/><br/>
293
296
 
@@ -298,77 +301,76 @@ mutation {
298
301
  1. In your Hydrogen app directory, run `npm install @okendo/shopify-hydrogen` inside a terminal or PowerShell window.
299
302
  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:
300
303
 
301
- ```sh
302
- # .env
303
- VITE_OKENDO_SUBSCRIBER_ID=<your_subscriber_id>
304
- ```
304
+ ```sh
305
+ # .env
306
+ VITE_OKENDO_SUBSCRIBER_ID=<your_subscriber_id>
307
+ ```
305
308
 
306
309
  3. Open **vite.config.ts** and add `import okendo from '@okendo/shopify-hydrogen/plugin';` to the list of imports.
307
310
  4. Add `okendo()` to the list of `plugins`.
308
311
 
309
- ```tsx
310
- /* vite.config.ts */
311
- /// <reference types="vitest" />
312
- import {defineConfig} from 'vite';
313
- import hydrogen from '@shopify/hydrogen/plugin';
314
- import okendo from '@okendo/shopify-hydrogen/plugin';
315
-
316
- export default defineConfig({
317
- plugins: [hydrogen(), okendo()],
318
- resolve: {
319
- alias: [{find: /^~\/(.*)/, replacement: '/src/$1'}],
320
- },
321
- optimizeDeps: {
322
- include: ['@headlessui/react', 'clsx', 'react-use', 'typographic-base'],
323
- },
324
- test: {
325
- globals: true,
326
- testTimeout: 10000,
327
- hookTimeout: 10000,
328
- },
329
- });
330
-
331
- ```
312
+ ```tsx
313
+ /* vite.config.ts */
314
+ /// <reference types="vitest" />
315
+ import { defineConfig } from "vite";
316
+ import hydrogen from "@shopify/hydrogen/plugin";
317
+ import okendo from "@okendo/shopify-hydrogen/plugin";
318
+
319
+ export default defineConfig({
320
+ plugins: [hydrogen(), okendo()],
321
+ resolve: {
322
+ alias: [{ find: /^~\/(.*)/, replacement: "/src/$1" }],
323
+ },
324
+ optimizeDeps: {
325
+ include: ["@headlessui/react", "clsx", "react-use", "typographic-base"],
326
+ },
327
+ test: {
328
+ globals: true,
329
+ testTimeout: 10000,
330
+ hookTimeout: 10000,
331
+ },
332
+ });
333
+ ```
332
334
 
333
335
  5. Open **App.server.tsx** and import `OkendoProvider`.
334
336
  6. Include the `OkendoProvider` as shown below, passing through your `subscriberId` from your Vite environment variables.
335
337
 
336
- ```tsx
337
- /* App.server.tsx */
338
- import {OkendoProvider} from '@okendo/shopify-hydrogen';
339
-
340
- function App() {
341
- return (
342
- <Suspense fallback={<LoadingFallback />}>
343
- <ShopifyProvider>
344
- <!-- *** Include OkendoProvider HERE *** -->
345
- <OkendoProvider
346
- subscriberId={import.meta.env.VITE_OKENDO_SUBSCRIBER_ID}
347
- />
348
- <ServerCartProvider>
349
- <DefaultSeo />
350
- <Router>
351
- <FileRoutes />
352
- <Route path="*" page={<NotFound />} />
353
- </Router>
354
- </ServerCartProvider>
355
- <PerformanceMetrics />
356
- {import.meta.env.DEV && <PerformanceMetricsDebug />}
357
- </ShopifyProvider>
358
- </Suspense>
359
- );
360
- ```
361
-
362
- 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:
363
-
364
- ``` tsx
365
- <OkendoProvider
366
- subscriberId={okendoSubscriberId}
367
- />
368
- ```
338
+ ```tsx
339
+ /* App.server.tsx */
340
+ import {OkendoProvider} from '@okendo/shopify-hydrogen';
341
+
342
+ function App() {
343
+ return (
344
+ <Suspense fallback={<LoadingFallback />}>
345
+ <ShopifyProvider>
346
+ <!-- *** Include OkendoProvider HERE *** -->
347
+ <OkendoProvider
348
+ subscriberId={import.meta.env.VITE_OKENDO_SUBSCRIBER_ID}
349
+ />
350
+ <ServerCartProvider>
351
+ <DefaultSeo />
352
+ <Router>
353
+ <FileRoutes />
354
+ <Route path="*" page={<NotFound />} />
355
+ </Router>
356
+ </ServerCartProvider>
357
+ <PerformanceMetrics />
358
+ {import.meta.env.DEV && <PerformanceMetricsDebug />}
359
+ </ShopifyProvider>
360
+ </Suspense>
361
+ );
362
+ ```
363
+
364
+ 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:
365
+
366
+ ```tsx
367
+ <OkendoProvider subscriberId={okendoSubscriberId} />
368
+ ```
369
369
 
370
370
  ## Widget Usage
371
371
 
372
+ ### Server Components
373
+
372
374
  Import `OkendoReviewsWidget` and `OkendoStarRating` and use as TSX components. Pass in the Shopify Product ID as a prop.
373
375
 
374
376
  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.
@@ -385,7 +387,27 @@ const okendoReviewsWidget = <OkendoReviewsWidget productId={product.id} />;
385
387
  const okendoStarRating = <OkendoStarRating productId={product.id} />;
386
388
  ```
387
389
 
388
- > ℹ️ &nbsp;Okendo widgets are server components. If you want to use them within a client component, you must pass the widget components as props to your client component. Widget components can be used directly in a server component. [Learn more here](https://shopify.dev/api/hydrogen/components#customizing-hydrogen-components).
390
+ > ℹ️ &nbsp;Okendo `OkendoReviewsWidget` and `OkendoStarRating` widgets are server components. If you want to use them within a client component, you must pass the widget components as props to your client component. Widget components can be used directly in a server component. [Learn more here](#graphql-fragments).
391
+
392
+ <br />
393
+
394
+ ### Client Components
395
+
396
+ #### Star Rating Widget Usage in Client Components
397
+
398
+ We also include an `OkendoClientStarRating` component for use within client-side (e.g.`<your component>.client.tsx`) components.
399
+
400
+ Import the `OkendoClientStarRating` component inside a client component and use as a TSX component as seen below:
401
+
402
+ ```tsx
403
+ import { OkendoClientStarRating } from '@okendo/shopify-hydrogen';
404
+
405
+ ...
406
+
407
+ const okendoClientStarRating = <OkendoClientStarRating productId={product.id} />;
408
+ ```
409
+
410
+ > ℹ️ &nbsp;OPTIONAL: You can render the `OkendoClientStarRating` component without making any client-side network requests by using an optional prop `okendoStarRatingSnippet`. This can be achieved using a GraphQL Fragment. [Learn more here](#graphql-fragments).
389
411
 
390
412
  <br />
391
413
 
@@ -418,18 +440,183 @@ It will provide:
418
440
 
419
441
  The Okendo Reviews List widget.
420
442
 
421
- | Name | Type | Description | Required |
422
- | --------- | ------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
443
+ | Name | Type | Description | Required |
444
+ | ---------------------- | ------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
423
445
  | <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 |
424
446
 
425
447
  ### OkendoStarRating<a id="components--okendo-star-rating" name="components--okendo-star-rating"></a>
426
- The Okendo Star Rating widget.
448
+
449
+ The Okendo Star Rating widget - **For use in _server_ components**.
427
450
 
428
451
  | Name | Type | Description | Required |
429
452
  | ---------------------- | ------------------- | ----------------------- | -------- |
430
453
  | <code>productId</code> | <code>string</code> | The Shopify Product ID. | yes |
454
+
455
+ <br/>
456
+
457
+ ### OkendoClientStarRating<a id="components--okendo-client-star-rating" name="components--okendo-client-star-rating"></a>
458
+
459
+ The Okendo Star Rating widget - **For use in _client_ components**.
460
+
461
+ | Name | Type | Description | Required |
462
+ | ------------------------------------ | -------------------------------------------------- | --------------------------------------------------------------- | -------- |
463
+ | <code>productId</code> | <code>string</code> | The Shopify Product ID. | yes |
464
+ | <code>okendoStarRatingSnippet</code> | <code>Pick<Metafield, "value"> \| undefined</code> | The server-side pre-rendered markup representing a star snippet | no |
465
+
466
+ <br/>
467
+
468
+ ---
469
+
470
+ # GraphQL Fragments <a id="graphql-fragments" name="graphql-fragments"></a>
471
+
472
+ A GraphQL fragment is a piece of logic that can be shared between multiple queries and mutations.
473
+
474
+ We offer performance benefits even when using our client Star Rating Widget by exposing an `OKENDO_PRODUCT_STAR_RATING_FRAGMENT` GraphQL Fragment for use in your server components.
475
+
476
+ This allows you to fetch pre-rendered markup in a **server component** for use within the client component (usually passed down as a property from the server component to the client).
477
+
478
+ If the pre-rendered mark-up is present, the star rating widget initialization does not occur in the client, offering performance benefits.
479
+
431
480
  <br/>
432
481
 
482
+ ## Example: Using GraphQL Framgment with OkendoClientStarRating
483
+
484
+ > ℹ️ &nbsp;NOTE: The following example usage is based on our Okendo Hydrogen Demo Store. Refer to the [Github repo](https://github.com/okendo/okendo-shopify-hydrogen-demo) to see a working example.
485
+
486
+ <br/>
487
+
488
+ In the sample [Okendo Hydrogen Demo Store](https://github.com/okendo/okendo-shopify-hydrogen-demo) we extend the `PRODUCT_CARD_FRAGMENT` with our `OKENDO_PRODUCT_STAR_RATING_FRAGMENT`.
489
+
490
+ Open `ProductGrid.client.tsx` and make the changes to the `PRODUCT_CARD_FRAGMENT` as seen below:
491
+
492
+ <br/>
493
+
494
+ **Before**
495
+
496
+ ```tsx
497
+ export const PRODUCT_CARD_FRAGMENT = gql`
498
+ fragment ProductCard on Product {
499
+ id
500
+ title
501
+ publishedAt
502
+ handle
503
+ variants(first: 1) {
504
+ nodes {
505
+ id
506
+ image {
507
+ url
508
+ altText
509
+ width
510
+ height
511
+ }
512
+ priceV2 {
513
+ amount
514
+ currencyCode
515
+ }
516
+ compareAtPriceV2 {
517
+ amount
518
+ currencyCode
519
+ }
520
+ }
521
+ }
522
+ }
523
+ `;
524
+ ```
525
+
526
+ **After**
527
+
528
+ ```tsx
529
+ export const PRODUCT_CARD_FRAGMENT = gql`
530
+ ${OKENDO_PRODUCT_STAR_RATING_FRAGMENT}
531
+ fragment ProductCard on Product {
532
+ id
533
+ title
534
+ publishedAt
535
+ handle
536
+ ...OkendoStarRatingSnippet
537
+ variants(first: 1) {
538
+ nodes {
539
+ id
540
+ image {
541
+ url
542
+ altText
543
+ width
544
+ height
545
+ }
546
+ priceV2 {
547
+ amount
548
+ currencyCode
549
+ }
550
+ compareAtPriceV2 {
551
+ amount
552
+ currencyCode
553
+ }
554
+ }
555
+ }
556
+ }
557
+ `;
558
+ ```
559
+
560
+ Adding the `OKENDO_PRODUCT_STAR_RATING_FRAGMENT` GraphQL Fragment allows you to access and include an `okendoStarRatingSnippet` in your `Product` query.
561
+
562
+ 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.
563
+
564
+ To help with typing we have exposed an `OkendoProductFragment` type which can be used as a union type with an existing Hydrogen `Product` type.
565
+
566
+ For this example we have used `ProductCard.client.tsx` from our Okendo Hydrogen Demo App.
567
+
568
+ The `ProductCard.client.tsx` component has the result of a server-side `useShopQuery` passed down as props to it.
569
+
570
+ Because we have implemented our `OKENDO_PRODUCT_STAR_RATING_FRAGMENT` we can express the resulting type as a union:
571
+
572
+ ```tsx
573
+ Product & OkendoProductFragment;
574
+ ```
575
+
576
+ In the `ProductCard.client.tsx` import the `OkendoProductFragment` type and the `OkendoClientStarRating` component:
577
+
578
+ ```tsx
579
+ import type { OkendoProductFragment } from "@okendo/shopify-hydrogen";
580
+ import { OkendoClientStarRating } from "@okendo/shopify-hydrogen/client";
581
+ ```
582
+
583
+ The constructor of the `ProductCard.client.tsx` component can then be modified to use a union-type for the `Product` being passed in to the constructor:
584
+
585
+ ```tsx
586
+ export function ProductCard({
587
+ product,
588
+ label,
589
+ className,
590
+ loading,
591
+ onClick,
592
+ }: {
593
+ product: Product & OkendoProductFragment;
594
+ label?: string;
595
+ className?: string;
596
+ loading?: HTMLImageElement['loading'];
597
+ onClick?: () => void;
598
+ }) {
599
+ ...
600
+ }
601
+ ```
602
+
603
+ Import the `OkendoClientStarRating` component inside the client component and use as seen below. Pass in `product.okendoStarRatingSnippet` as the value for the optional prop `okendoStarRatingSnippet`. This will use the pre-rendered value of the star rating markup without having to make any client-side network requests.
604
+
605
+ ```tsx
606
+ {
607
+ product.okendoStarRatingSnippet?.value ? (
608
+ <OkendoClientStarRating
609
+ productId={product.id}
610
+ okendoStarRatingSnippet={product.okendoStarRatingSnippet}
611
+ />
612
+ ) : null;
613
+ }
614
+ ```
615
+
616
+ **References**
617
+
618
+ - [GraphQL Fragments](https://www.apollographql.com/docs/react/data/fragments/)
619
+
433
620
  ---
434
621
 
435
622
  <br/>
@@ -0,0 +1,4 @@
1
+ import React from 'react';
2
+ import type { OkendoClientStarRatingProps } from '../models/starRating';
3
+ export declare const OkendoClientStarRating: React.FunctionComponent<OkendoClientStarRatingProps>;
4
+ export default OkendoClientStarRating;
@@ -0,0 +1,25 @@
1
+ import React from 'react';
2
+ import { OkendoWidgetClient } from './OkendoWidget.client';
3
+ import { getOkendoProductId } from '../shared/productUtils';
4
+ import { widgetConfigurationError, widgetMetafieldError } from '../shared/errorUtils';
5
+ export const OkendoClientStarRating = (props) => {
6
+ const { productId, okendoStarRatingSnippet } = props;
7
+ const okendoProductId = getOkendoProductId(productId);
8
+ if (!okendoProductId) {
9
+ console.error(widgetConfigurationError('OkendoClientStarRating', 'productId was not provided'));
10
+ return null;
11
+ }
12
+ if (!okendoStarRatingSnippet?.value) {
13
+ console.warn(widgetMetafieldError('OkendoStarRating', 'StarRatingSnippet'));
14
+ }
15
+ const dataAttributes = {
16
+ 'data-oke-star-rating': '',
17
+ 'data-oke-reviews-product-id': okendoProductId,
18
+ 'data-oke-scroll-disabled': 'true'
19
+ };
20
+ if (okendoStarRatingSnippet?.value) {
21
+ dataAttributes['data-oke-rendered'] = okendoStarRatingSnippet.value;
22
+ }
23
+ return (React.createElement(OkendoWidgetClient, { dataAttributes: dataAttributes, metafieldContent: okendoStarRatingSnippet?.value }));
24
+ };
25
+ export default OkendoClientStarRating;
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
  import type { ReviewsWidgetPlus } from '@okendo/reviews-widget-plus/dist-utils/ReviewsWidgetPlus';
3
- import type { SKO } from '../shared';
3
+ import type { SKO } from '../shared/sharedTypes';
4
4
  export declare const OkendoWidgetClient: React.FunctionComponent<OkendoWidgetClientProps>;
5
5
  export interface OkendoWidgetClientProps {
6
6
  dataAttributes: SKO;
@@ -0,0 +1 @@
1
+ export * from './OkendoClientStarRating.client';
@@ -0,0 +1 @@
1
+ export * from './OkendoClientStarRating.client';
@@ -0,0 +1 @@
1
+ export * from './client-components';
@@ -0,0 +1 @@
1
+ export * from './client-components';
@@ -2,7 +2,8 @@ import React from 'react';
2
2
  import parse from 'html-react-parser';
3
3
  import { fetchSync, useShopQuery, gql, CacheShort } from '@shopify/hydrogen';
4
4
  import { Head } from '@shopify/hydrogen';
5
- import { okendoError, setInOkendoRequestContext } from '../shared';
5
+ import { okendoError } from '../shared/errorUtils';
6
+ import { setInOkendoRequestContext } from '../shared/server/requestUtils';
6
7
  const kDefaultOkendoApiDomain = 'api.okendo.io/v1';
7
8
  const kDefaultOkendoCdnDomain = 'cdn-static.okendo.io';
8
9
  export const OkendoProvider = (props) => {
@@ -1,8 +1,10 @@
1
1
  import React from 'react';
2
2
  import parse from 'html-react-parser';
3
3
  import { useShopQuery, gql } from '@shopify/hydrogen';
4
- import { OkendoWidgetClient } from './OkendoWidget.client';
5
- import { getOkendoProductId, useOkendoRequestContext, widgetMetafieldError } from '../shared';
4
+ import { OkendoWidgetClient } from '../client-components/OkendoWidget.client';
5
+ import { widgetMetafieldError } from '../shared/errorUtils';
6
+ import { getOkendoProductId } from '../shared/productUtils';
7
+ import { useOkendoRequestContext } from '../shared/server/requestUtils';
6
8
  export const OkendoReviewsWidget = (props) => {
7
9
  const { setupFailed } = useOkendoRequestContext();
8
10
  if (setupFailed) {
@@ -1,6 +1,4 @@
1
1
  import React from 'react';
2
+ import type { OkendoStarRatingProps } from '../models/starRating';
2
3
  export declare const OkendoStarRating: React.FunctionComponent<OkendoStarRatingProps>;
3
- interface OkendoStarRatingProps {
4
- productId: string;
5
- }
6
4
  export default OkendoStarRating;
@@ -1,7 +1,9 @@
1
1
  import React from 'react';
2
2
  import { useShopQuery, gql } from '@shopify/hydrogen';
3
- import { OkendoWidgetClient } from './OkendoWidget.client';
4
- import { getOkendoProductId, useOkendoRequestContext, widgetConfigurationError, widgetMetafieldError } from '../shared';
3
+ import { OkendoWidgetClient } from '../client-components/OkendoWidget.client';
4
+ import { widgetConfigurationError, widgetMetafieldError } from '../shared/errorUtils';
5
+ import { getOkendoProductId } from '../shared/productUtils';
6
+ import { useOkendoRequestContext } from '../shared/server/requestUtils';
5
7
  export const OkendoStarRating = (props) => {
6
8
  const { setupFailed } = useOkendoRequestContext();
7
9
  if (setupFailed) {
@@ -1,3 +1,3 @@
1
+ export * from './OkendoProvider.server';
1
2
  export * from './OkendoReviewsWidget.server';
2
3
  export * from './OkendoStarRating.server';
3
- export * from './OkendoProvider.server';
@@ -1,3 +1,3 @@
1
+ export * from './OkendoProvider.server';
1
2
  export * from './OkendoReviewsWidget.server';
2
3
  export * from './OkendoStarRating.server';
3
- export * from './OkendoProvider.server';
@@ -0,0 +1 @@
1
+ export declare const OKENDO_PRODUCT_STAR_RATING_FRAGMENT: string;
@@ -0,0 +1,11 @@
1
+ import { gql } from '@shopify/hydrogen';
2
+ export const OKENDO_PRODUCT_STAR_RATING_FRAGMENT = gql `
3
+ fragment OkendoStarRatingSnippet on Product {
4
+ okendoStarRatingSnippet: metafield(
5
+ namespace: "okendo"
6
+ key: "StarRatingSnippet"
7
+ ) {
8
+ value
9
+ }
10
+ }
11
+ `;
@@ -1,2 +1,4 @@
1
1
  export * from './components';
2
- export * from './shared';
2
+ export * from './fragments';
3
+ export * from './shared/server/requestUtils';
4
+ export * from './shared/sharedTypes';
@@ -1,2 +1,4 @@
1
1
  export * from './components';
2
- export * from './shared';
2
+ export * from './fragments';
3
+ export * from './shared/server/requestUtils';
4
+ export * from './shared/sharedTypes';
@@ -0,0 +1,12 @@
1
+ import type { Metafield } from '@shopify/hydrogen/dist/esnext/storefront-api-types';
2
+ export interface OkendoClientStarRatingProps extends OkendoStarRatingProps {
3
+ okendoStarRatingSnippet?: Pick<Metafield, 'value'>;
4
+ }
5
+ export interface OkendoStarRatingProps {
6
+ productId: string;
7
+ }
8
+ export interface OkendoStarRatingMetafields {
9
+ product: {
10
+ starRatingSnippet?: Pick<Metafield, 'value'>;
11
+ };
12
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -1,4 +1,4 @@
1
- import { SKO } from './sharedTypes';
1
+ import type { SKO } from '../sharedTypes';
2
2
  export declare function setInOkendoRequestContext(key: keyof OkendoRequestContextKeys, value: RequestContextSafeType | RequestContextSafeType[]): void;
3
3
  export declare function useOkendoRequestContext(): OkendoRequestContext;
4
4
  interface OkendoRequestContextKeys {
@@ -1 +1,5 @@
1
+ import type { Metafield } from '@shopify/hydrogen/dist/esnext/storefront-api-types';
1
2
  export declare type SKO = Record<string, unknown>;
3
+ export declare type OkendoProductFragment = {
4
+ okendoStarRatingSnippet?: Pick<Metafield, 'value'>;
5
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@okendo/shopify-hydrogen",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "description": "A component library containing Okendo Reviews React components.",
5
5
  "main": "dist/esnext/index.js",
6
6
  "engines": {
@@ -12,6 +12,16 @@
12
12
  "import": "./dist/esnext/framework/plugins/plugin.js",
13
13
  "require": "./dist/node/framework/plugins/plugin.js"
14
14
  },
15
+ "./client": {
16
+ "import": {
17
+ "types": "./dist/esnext/client.d.ts",
18
+ "default": "./dist/esnext/client.js"
19
+ },
20
+ "node": {
21
+ "types": "./dist/esnext/client.d.ts",
22
+ "default": "./dist/esnext/client.js"
23
+ }
24
+ },
15
25
  "./plugin.cjs": "./plugin.cjs",
16
26
  "./package.json": "./package.json",
17
27
  "./*": "./dist/esnext/*.js"
@@ -40,8 +50,9 @@
40
50
  "@types/react": "^18.0.14",
41
51
  "@types/react-dom": "^18.0.5",
42
52
  "dotenv": "^16.0.1",
53
+ "ncp": "^2.0.0",
43
54
  "rimraf": "^3.0.2",
44
- "typescript": "^4.7.2",
55
+ "typescript": "^4.7.4",
45
56
  "vite": "^2.9.0"
46
57
  },
47
58
  "peerDependencies": {
@@ -1,4 +0,0 @@
1
- export * from './errorUtils';
2
- export * from './productUtils';
3
- export * from './requestUtils';
4
- export * from './sharedTypes';
@@ -1,4 +0,0 @@
1
- export * from './errorUtils';
2
- export * from './productUtils';
3
- export * from './requestUtils';
4
- export * from './sharedTypes';