@revova/hydrogen 1.0.0 → 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.
package/README.md CHANGED
@@ -11,42 +11,128 @@ npm install @revova/hydrogen
11
11
  ## Requirements
12
12
 
13
13
  - React 18+
14
- - Shopify Hydrogen storefront with the Revova app installed
14
+ - Shopify Hydrogen storefront with the Revova app installed on the store
15
15
 
16
16
  ---
17
17
 
18
- ## Quick Start
18
+ ## How it works
19
+
20
+ Components and hooks call your Revova backend directly over HTTPS with a `shop` query parameter and a `Bearer` token:
19
21
 
20
- The `proxyUrl` is always `/apps/revova` — Shopify's App Proxy routes requests to your Revova backend automatically. No API keys needed in the storefront.
22
+ ```
23
+ GET https://yourapp.trycloudflare.com/api/reviews?shop=yourstore.myshopify.com&...
24
+ Authorization: Bearer <apiToken>
25
+ ```
26
+
27
+ No Shopify App Proxy. No CORS issues. No API keys exposed beyond what you pass in.
21
28
 
22
29
  ---
23
30
 
24
- ## Components
31
+ ## Setup (Hydrogen)
25
32
 
26
- ### `<ReviewWidget>`
33
+ ### 1 — Add your credentials to the environment
27
34
 
28
- Full review list with pagination, sorting, and an inline submission form.
35
+ ```env
36
+ # .env
37
+ PUBLIC_REVOVA_API_URL=https://yourapp.trycloudflare.com
38
+ PUBLIC_STORE_DOMAIN=yourstore.myshopify.com
39
+ PUBLIC_REVOVA_API_TOKEN=your_token_here
40
+ ```
41
+
42
+ Expose them through your Hydrogen loader:
43
+
44
+ ```ts
45
+ // app/root.tsx or any route loader
46
+ export async function loader({ context }: LoaderArgs) {
47
+ return {
48
+ apiUrl: context.env.PUBLIC_REVOVA_API_URL,
49
+ shop: context.env.PUBLIC_STORE_DOMAIN,
50
+ apiToken: context.env.PUBLIC_REVOVA_API_TOKEN,
51
+ };
52
+ }
53
+ ```
54
+
55
+ ### 2 — Spread credentials into any component
56
+
57
+ Every component accepts `apiUrl`, `shop`, and `apiToken`. The easiest pattern is to spread a single `creds` object:
29
58
 
30
59
  ```tsx
31
- import { ReviewWidget } from '@revova/hydrogen';
60
+ const creds = {
61
+ apiUrl: env.PUBLIC_REVOVA_API_URL,
62
+ shop: env.PUBLIC_STORE_DOMAIN,
63
+ apiToken: env.PUBLIC_REVOVA_API_TOKEN,
64
+ };
65
+
66
+ <ReviewWidget {...creds} productId={product.id} />
67
+ ```
68
+
69
+ ---
70
+
71
+ ## Quick Start
72
+
73
+ ```tsx
74
+ // app/routes/products.$handle.tsx
75
+ import { ReviewWidget, FloatingReviewButton } from '@revova/hydrogen';
76
+
77
+ export async function loader({ context, params }: LoaderArgs) {
78
+ const product = await getProduct(params.handle);
79
+ return {
80
+ product,
81
+ apiUrl: context.env.PUBLIC_REVOVA_API_URL,
82
+ shop: context.env.PUBLIC_STORE_DOMAIN,
83
+ apiToken: context.env.PUBLIC_REVOVA_API_TOKEN,
84
+ };
85
+ }
32
86
 
33
87
  export default function ProductPage() {
34
- const { product } = useLoaderData<typeof loader>();
88
+ const { product, apiUrl, shop, apiToken } = useLoaderData<typeof loader>();
89
+ const creds = { apiUrl, shop, apiToken };
35
90
 
36
91
  return (
37
- <ReviewWidget
38
- proxyUrl="/apps/revova"
39
- productId={product.id}
40
- />
92
+ <>
93
+ <h1>{product.title}</h1>
94
+ <ReviewWidget {...creds} productId={product.id} />
95
+ <FloatingReviewButton {...creds} productId={product.id} />
96
+ </>
41
97
  );
42
98
  }
43
99
  ```
44
100
 
45
- **Props**
101
+ ---
102
+
103
+ ## API Credentials (`ApiProps`)
104
+
105
+ All components and hooks require these three props. Spread them as a group for convenience.
106
+
107
+ | Prop | Type | Description |
108
+ |---|---|---|
109
+ | `apiUrl` | `string` | Revova backend base URL (e.g. `https://yourapp.trycloudflare.com`) |
110
+ | `shop` | `string` | Store myshopify.com domain (e.g. `yourstore.myshopify.com`) |
111
+ | `apiToken` | `string` | Bearer token for authorization |
112
+
113
+ ---
114
+
115
+ ## Components
116
+
117
+ ### `<ReviewWidget>`
118
+
119
+ Full review list with pagination, sorting, and an inline submission form.
120
+
121
+ ```tsx
122
+ import { ReviewWidget } from '@revova/hydrogen';
123
+
124
+ <ReviewWidget
125
+ {...creds}
126
+ productId={product.id}
127
+ pageSize={10}
128
+ showForm
129
+ locale="fr"
130
+ />
131
+ ```
46
132
 
47
133
  | Prop | Type | Default | Description |
48
134
  |---|---|---|---|
49
- | `proxyUrl` | `string` | — | App proxy base URL (`/apps/revova`) |
135
+ | `...creds` | `ApiProps` | — | `apiUrl`, `shop`, `apiToken` |
50
136
  | `productId` | `string` | — | Shopify product GID |
51
137
  | `locale` | `string` | — | Locale code for translated reviews (e.g. `fr`) |
52
138
  | `pageSize` | `number` | `10` | Reviews per page |
@@ -65,14 +151,14 @@ import { ReviewForm } from '@revova/hydrogen';
65
151
 
66
152
  // `form` comes from the ReviewsResponse returned by useReviews
67
153
  <ReviewForm
68
- proxyUrl="/apps/revova"
154
+ {...creds}
69
155
  productId={product.id}
70
156
  form={data.form}
71
157
  onSuccess={() => console.log('submitted')}
72
158
  />
73
159
  ```
74
160
 
75
- **Props:** `proxyUrl`, `productId`, `form` (required — `ResolvedForm` from loader), `onSuccess?`, `className?`
161
+ **Props:** `...creds`, `productId`, `form` (required — `ResolvedForm`), `onSuccess?`, `className?`
76
162
 
77
163
  ---
78
164
 
@@ -92,16 +178,15 @@ import { StarRating } from '@revova/hydrogen';
92
178
 
93
179
  ### `<ReviewCount>`
94
180
 
95
- Aggregate rating + review count badge. Fetches from `widget-globals`.
181
+ Aggregate rating + review count badge. Great for product cards and PDP headers.
96
182
 
97
183
  ```tsx
98
184
  import { ReviewCount } from '@revova/hydrogen';
99
185
 
100
- // On a product card or PDP header
101
- <ReviewCount proxyUrl="/apps/revova" starSize={14} />
186
+ <ReviewCount {...creds} starSize={14} />
102
187
  ```
103
188
 
104
- **Props:** `proxyUrl`, `starColor?`, `starSize?`, `className?`
189
+ **Props:** `...creds`, `starColor?`, `starSize?`, `className?`
105
190
 
106
191
  ---
107
192
 
@@ -112,15 +197,10 @@ Auto-advancing carousel of recent reviews. Includes previous/next arrows and dot
112
197
  ```tsx
113
198
  import { ReviewCarousel } from '@revova/hydrogen';
114
199
 
115
- <ReviewCarousel
116
- proxyUrl="/apps/revova"
117
- limit={10}
118
- autoPlay
119
- intervalMs={4000}
120
- />
200
+ <ReviewCarousel {...creds} limit={10} autoPlay intervalMs={4000} />
121
201
  ```
122
202
 
123
- **Props:** `proxyUrl`, `limit?` (default 10), `autoPlay?` (default `true`), `intervalMs?` (default 4000), `starColor?`, `className?`
203
+ **Props:** `...creds`, `limit?` (default 10), `autoPlay?` (default `true`), `intervalMs?` (default 4000), `starColor?`, `className?`
124
204
 
125
205
  ---
126
206
 
@@ -131,14 +211,10 @@ Masonry photo grid of reviews that have images. Clicking any photo opens a light
131
211
  ```tsx
132
212
  import { ReviewGallery } from '@revova/hydrogen';
133
213
 
134
- <ReviewGallery
135
- proxyUrl="/apps/revova"
136
- columns={3}
137
- limit={20}
138
- />
214
+ <ReviewGallery {...creds} columns={3} limit={20} />
139
215
  ```
140
216
 
141
- **Props:** `proxyUrl`, `limit?` (default 20), `columns?` (default 3), `starColor?`, `className?`
217
+ **Props:** `...creds`, `limit?` (default 20), `columns?` (default 3), `starColor?`, `className?`
142
218
 
143
219
  ---
144
220
 
@@ -149,13 +225,10 @@ Product Q&A — lists questions with answers and includes an ask-a-question form
149
225
  ```tsx
150
226
  import { QnAWidget } from '@revova/hydrogen';
151
227
 
152
- <QnAWidget
153
- proxyUrl="/apps/revova"
154
- productId={product.id}
155
- />
228
+ <QnAWidget {...creds} productId={product.id} />
156
229
  ```
157
230
 
158
- **Props:** `proxyUrl`, `productId`, `className?`
231
+ **Props:** `...creds`, `productId`, `className?`
159
232
 
160
233
  ---
161
234
 
@@ -166,17 +239,12 @@ Aggregate rating badge in three styles: `pill` (default), `inline`, or `card`.
166
239
  ```tsx
167
240
  import { TrustBadge } from '@revova/hydrogen';
168
241
 
169
- // Pill great for footers, headers
170
- <TrustBadge proxyUrl="/apps/revova" style="pill" />
171
-
172
- // Card — great for landing pages
173
- <TrustBadge proxyUrl="/apps/revova" style="card" />
174
-
175
- // Inline — great inside sentences or product specs
176
- <TrustBadge proxyUrl="/apps/revova" style="inline" />
242
+ <TrustBadge {...creds} style="pill" />
243
+ <TrustBadge {...creds} style="card" />
244
+ <TrustBadge {...creds} style="inline" />
177
245
  ```
178
246
 
179
- **Props:** `proxyUrl`, `style?` (`'pill' | 'inline' | 'card'`, default `'pill'`), `starColor?`, `className?`
247
+ **Props:** `...creds`, `style?` (`'pill' | 'inline' | 'card'`, default `'pill'`), `starColor?`, `className?`
180
248
 
181
249
  ---
182
250
 
@@ -187,34 +255,29 @@ A continuously scrolling marquee of recent review snippets — ideal for homepag
187
255
  ```tsx
188
256
  import { ReviewTicker } from '@revova/hydrogen';
189
257
 
190
- <ReviewTicker
191
- proxyUrl="/apps/revova"
192
- limit={20}
193
- speedSeconds={30}
194
- />
258
+ <ReviewTicker {...creds} limit={20} speedSeconds={30} />
195
259
  ```
196
260
 
197
- **Props:** `proxyUrl`, `limit?` (default 20), `speedSeconds?` (default 30), `starColor?`, `className?`
261
+ **Props:** `...creds`, `limit?` (default 20), `speedSeconds?` (default 30), `starColor?`, `className?`
198
262
 
199
263
  ---
200
264
 
201
265
  ### `<SocialProofPopup>`
202
266
 
203
- A timed floating popup showing recent reviews one at a time. Appears after a short delay and cycles automatically.
267
+ A timed floating popup showing recent reviews one at a time. Add once to your root layout.
204
268
 
205
269
  ```tsx
206
270
  import { SocialProofPopup } from '@revova/hydrogen';
207
271
 
208
- // Add once to your root layout
209
272
  <SocialProofPopup
210
- proxyUrl="/apps/revova"
273
+ {...creds}
211
274
  position="bottom-left"
212
275
  intervalMs={8000}
213
276
  displayMs={5000}
214
277
  />
215
278
  ```
216
279
 
217
- **Props:** `proxyUrl`, `position?` (`'bottom-left' | 'bottom-right'`, default `'bottom-left'`), `intervalMs?` (default 8000), `displayMs?` (default 5000), `starColor?`, `className?`
280
+ **Props:** `...creds`, `position?` (`'bottom-left' | 'bottom-right'`, default `'bottom-left'`), `intervalMs?` (default 8000), `displayMs?` (default 5000), `starColor?`, `className?`
218
281
 
219
282
  ---
220
283
 
@@ -225,15 +288,10 @@ A sticky tab fixed to the left or right edge of the viewport. Clicking it slides
225
288
  ```tsx
226
289
  import { FloatingReviewsTab } from '@revova/hydrogen';
227
290
 
228
- <FloatingReviewsTab
229
- proxyUrl="/apps/revova"
230
- label="Reviews"
231
- position="right"
232
- color="#111827"
233
- />
291
+ <FloatingReviewsTab {...creds} label="Reviews" position="right" />
234
292
  ```
235
293
 
236
- **Props:** `proxyUrl`, `label?` (default `'Reviews'`), `position?` (`'left' | 'right'`, default `'right'`), `color?`, `limit?` (default 5), `starColor?`, `className?`
294
+ **Props:** `...creds`, `label?` (default `'Reviews'`), `position?` (`'left' | 'right'`, default `'right'`), `color?`, `limit?` (default 5), `starColor?`, `className?`
237
295
 
238
296
  ---
239
297
 
@@ -245,15 +303,14 @@ A fixed "Write a Review" button that opens a modal with the submission form.
245
303
  import { FloatingReviewButton } from '@revova/hydrogen';
246
304
 
247
305
  <FloatingReviewButton
248
- proxyUrl="/apps/revova"
306
+ {...creds}
249
307
  productId={product.id}
250
308
  text="Write a Review"
251
309
  position="bottom-right"
252
- color="#111827"
253
310
  />
254
311
  ```
255
312
 
256
- **Props:** `proxyUrl`, `productId`, `text?` (default `'Write a Review'`), `color?`, `position?` (`'bottom-left' | 'bottom-right'`, default `'bottom-right'`), `className?`
313
+ **Props:** `...creds`, `productId`, `text?` (default `'Write a Review'`), `color?`, `position?` (`'bottom-left' | 'bottom-right'`, default `'bottom-right'`), `className?`
257
314
 
258
315
  ---
259
316
 
@@ -269,7 +326,7 @@ Paginated reviews for a product with sorting controls.
269
326
  import { useReviews } from '@revova/hydrogen';
270
327
 
271
328
  const { data, loading, error, setPage, setSort, currentPage, currentSort, refetch } = useReviews({
272
- proxyUrl: '/apps/revova',
329
+ ...creds,
273
330
  productId: product.id,
274
331
  limit: 5,
275
332
  sort: 'helpful', // 'recent' | 'helpful' | 'rating_high' | 'rating_low'
@@ -279,15 +336,12 @@ const { data, loading, error, setPage, setSort, currentPage, currentSort, refetc
279
336
 
280
337
  ### `useWidgetGlobals(options)`
281
338
 
282
- Shop-level stats and recent reviews. Used internally by `<ReviewCount>`, `<TrustBadge>`, `<ReviewCarousel>`, `<ReviewGallery>`, `<ReviewTicker>`, `<SocialProofPopup>`, and `<FloatingReviewsTab>`.
339
+ Shop-level stats and recent reviews. Used internally by most global widgets.
283
340
 
284
341
  ```tsx
285
342
  import { useWidgetGlobals } from '@revova/hydrogen';
286
343
 
287
- const { data, loading, error } = useWidgetGlobals({
288
- proxyUrl: '/apps/revova',
289
- limit: 20,
290
- });
344
+ const { data, loading, error } = useWidgetGlobals({ ...creds, limit: 20 });
291
345
 
292
346
  // data.stats.averageRating — "4.8"
293
347
  // data.stats.totalReviews — 142
@@ -295,14 +349,14 @@ const { data, loading, error } = useWidgetGlobals({
295
349
  // data.config — merchant widget settings
296
350
  ```
297
351
 
298
- ### `useSubmitReview(proxyUrl)`
352
+ ### `useSubmitReview(creds)`
299
353
 
300
354
  Submit a new review programmatically.
301
355
 
302
356
  ```tsx
303
357
  import { useSubmitReview } from '@revova/hydrogen';
304
358
 
305
- const { submit, submitting, success, error, result, reset } = useSubmitReview('/apps/revova');
359
+ const { submit, submitting, success, error, result, reset } = useSubmitReview(creds);
306
360
 
307
361
  await submit({
308
362
  productId: 'gid://shopify/Product/123',
@@ -323,17 +377,11 @@ Fetch and submit Q&A for a product.
323
377
  ```tsx
324
378
  import { useQnA } from '@revova/hydrogen';
325
379
 
326
- const {
327
- data,
328
- loading,
329
- setPage,
330
- submitQuestion,
331
- submitAnswer,
332
- submitState,
333
- resetSubmit,
334
- } = useQnA({ proxyUrl: '/apps/revova', productId: product.id });
335
-
336
- // Submit a question
380
+ const { data, loading, setPage, submitQuestion, submitAnswer, submitState, resetSubmit } = useQnA({
381
+ ...creds,
382
+ productId: product.id,
383
+ });
384
+
337
385
  await submitQuestion({
338
386
  intent: 'question',
339
387
  productId: product.id,
@@ -342,14 +390,14 @@ await submitQuestion({
342
390
  });
343
391
  ```
344
392
 
345
- ### `useHelpfulVote(proxyUrl)`
393
+ ### `useHelpfulVote(creds)`
346
394
 
347
395
  Cast a helpful / not-helpful vote on a review.
348
396
 
349
397
  ```tsx
350
398
  import { useHelpfulVote } from '@revova/hydrogen';
351
399
 
352
- const { vote, loading, voted } = useHelpfulVote('/apps/revova');
400
+ const { vote, loading, voted } = useHelpfulVote(creds);
353
401
 
354
402
  <button onClick={() => vote({ reviewId: review.id, vote: 'helpful' })} disabled={voted}>
355
403
  Helpful ({review.helpfulCount})