@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 +136 -88
- package/dist/index.cjs +102 -117
- package/dist/index.d.cts +59 -58
- package/dist/index.d.ts +59 -58
- package/dist/index.js +101 -117
- package/package.json +1 -1
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
|
-
##
|
|
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
|
-
|
|
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
|
-
##
|
|
31
|
+
## Setup (Hydrogen)
|
|
25
32
|
|
|
26
|
-
###
|
|
33
|
+
### 1 — Add your credentials to the environment
|
|
27
34
|
|
|
28
|
-
|
|
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
|
-
|
|
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
|
-
|
|
38
|
-
|
|
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
|
-
|
|
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
|
-
| `
|
|
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
|
-
|
|
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:**
|
|
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.
|
|
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
|
-
|
|
101
|
-
<ReviewCount proxyUrl="/apps/revova" starSize={14} />
|
|
186
|
+
<ReviewCount {...creds} starSize={14} />
|
|
102
187
|
```
|
|
103
188
|
|
|
104
|
-
**Props:**
|
|
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:**
|
|
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:**
|
|
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:**
|
|
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
|
-
|
|
170
|
-
<TrustBadge
|
|
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:**
|
|
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:**
|
|
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.
|
|
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
|
-
|
|
273
|
+
{...creds}
|
|
211
274
|
position="bottom-left"
|
|
212
275
|
intervalMs={8000}
|
|
213
276
|
displayMs={5000}
|
|
214
277
|
/>
|
|
215
278
|
```
|
|
216
279
|
|
|
217
|
-
**Props:**
|
|
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:**
|
|
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
|
-
|
|
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:**
|
|
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
|
-
|
|
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
|
|
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(
|
|
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(
|
|
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
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
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(
|
|
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(
|
|
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})
|