@revova/hydrogen 1.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/README.md +384 -0
- package/dist/index.cjs +1587 -0
- package/dist/index.d.cts +398 -0
- package/dist/index.d.ts +398 -0
- package/dist/index.js +1533 -0
- package/package.json +51 -0
package/README.md
ADDED
|
@@ -0,0 +1,384 @@
|
|
|
1
|
+
# @revova/hydrogen
|
|
2
|
+
|
|
3
|
+
Official Revova review widgets for Shopify Hydrogen storefronts.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @revova/hydrogen
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Requirements
|
|
12
|
+
|
|
13
|
+
- React 18+
|
|
14
|
+
- Shopify Hydrogen storefront with the Revova app installed
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Quick Start
|
|
19
|
+
|
|
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.
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Components
|
|
25
|
+
|
|
26
|
+
### `<ReviewWidget>`
|
|
27
|
+
|
|
28
|
+
Full review list with pagination, sorting, and an inline submission form.
|
|
29
|
+
|
|
30
|
+
```tsx
|
|
31
|
+
import { ReviewWidget } from '@revova/hydrogen';
|
|
32
|
+
|
|
33
|
+
export default function ProductPage() {
|
|
34
|
+
const { product } = useLoaderData<typeof loader>();
|
|
35
|
+
|
|
36
|
+
return (
|
|
37
|
+
<ReviewWidget
|
|
38
|
+
proxyUrl="/apps/revova"
|
|
39
|
+
productId={product.id}
|
|
40
|
+
/>
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
**Props**
|
|
46
|
+
|
|
47
|
+
| Prop | Type | Default | Description |
|
|
48
|
+
|---|---|---|---|
|
|
49
|
+
| `proxyUrl` | `string` | — | App proxy base URL (`/apps/revova`) |
|
|
50
|
+
| `productId` | `string` | — | Shopify product GID |
|
|
51
|
+
| `locale` | `string` | — | Locale code for translated reviews (e.g. `fr`) |
|
|
52
|
+
| `pageSize` | `number` | `10` | Reviews per page |
|
|
53
|
+
| `showForm` | `boolean` | `true` | Show the write-review button and form |
|
|
54
|
+
| `starColor` | `string` | `#f59e0b` | Star fill colour |
|
|
55
|
+
| `className` | `string` | — | CSS class on the wrapper |
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
### `<ReviewForm>`
|
|
60
|
+
|
|
61
|
+
Standalone submission form — use when you want the form separate from the list.
|
|
62
|
+
|
|
63
|
+
```tsx
|
|
64
|
+
import { ReviewForm } from '@revova/hydrogen';
|
|
65
|
+
|
|
66
|
+
// `form` comes from the ReviewsResponse returned by useReviews
|
|
67
|
+
<ReviewForm
|
|
68
|
+
proxyUrl="/apps/revova"
|
|
69
|
+
productId={product.id}
|
|
70
|
+
form={data.form}
|
|
71
|
+
onSuccess={() => console.log('submitted')}
|
|
72
|
+
/>
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
**Props:** `proxyUrl`, `productId`, `form` (required — `ResolvedForm` from loader), `onSuccess?`, `className?`
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
### `<StarRating>`
|
|
80
|
+
|
|
81
|
+
Renders star icons for any numeric rating. Supports half-stars via linear gradient fill.
|
|
82
|
+
|
|
83
|
+
```tsx
|
|
84
|
+
import { StarRating } from '@revova/hydrogen';
|
|
85
|
+
|
|
86
|
+
<StarRating rating={4.5} size={20} color="#f59e0b" />
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
**Props:** `rating` (0–5), `max?` (default 5), `size?` (px, default 16), `color?`, `className?`
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
### `<ReviewCount>`
|
|
94
|
+
|
|
95
|
+
Aggregate rating + review count badge. Fetches from `widget-globals`.
|
|
96
|
+
|
|
97
|
+
```tsx
|
|
98
|
+
import { ReviewCount } from '@revova/hydrogen';
|
|
99
|
+
|
|
100
|
+
// On a product card or PDP header
|
|
101
|
+
<ReviewCount proxyUrl="/apps/revova" starSize={14} />
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
**Props:** `proxyUrl`, `starColor?`, `starSize?`, `className?`
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
### `<ReviewCarousel>`
|
|
109
|
+
|
|
110
|
+
Auto-advancing carousel of recent reviews. Includes previous/next arrows and dot indicators.
|
|
111
|
+
|
|
112
|
+
```tsx
|
|
113
|
+
import { ReviewCarousel } from '@revova/hydrogen';
|
|
114
|
+
|
|
115
|
+
<ReviewCarousel
|
|
116
|
+
proxyUrl="/apps/revova"
|
|
117
|
+
limit={10}
|
|
118
|
+
autoPlay
|
|
119
|
+
intervalMs={4000}
|
|
120
|
+
/>
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
**Props:** `proxyUrl`, `limit?` (default 10), `autoPlay?` (default `true`), `intervalMs?` (default 4000), `starColor?`, `className?`
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
### `<ReviewGallery>`
|
|
128
|
+
|
|
129
|
+
Masonry photo grid of reviews that have images. Clicking any photo opens a lightbox with the full review.
|
|
130
|
+
|
|
131
|
+
```tsx
|
|
132
|
+
import { ReviewGallery } from '@revova/hydrogen';
|
|
133
|
+
|
|
134
|
+
<ReviewGallery
|
|
135
|
+
proxyUrl="/apps/revova"
|
|
136
|
+
columns={3}
|
|
137
|
+
limit={20}
|
|
138
|
+
/>
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
**Props:** `proxyUrl`, `limit?` (default 20), `columns?` (default 3), `starColor?`, `className?`
|
|
142
|
+
|
|
143
|
+
---
|
|
144
|
+
|
|
145
|
+
### `<QnAWidget>`
|
|
146
|
+
|
|
147
|
+
Product Q&A — lists questions with answers and includes an ask-a-question form.
|
|
148
|
+
|
|
149
|
+
```tsx
|
|
150
|
+
import { QnAWidget } from '@revova/hydrogen';
|
|
151
|
+
|
|
152
|
+
<QnAWidget
|
|
153
|
+
proxyUrl="/apps/revova"
|
|
154
|
+
productId={product.id}
|
|
155
|
+
/>
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
**Props:** `proxyUrl`, `productId`, `className?`
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
### `<TrustBadge>`
|
|
163
|
+
|
|
164
|
+
Aggregate rating badge in three styles: `pill` (default), `inline`, or `card`.
|
|
165
|
+
|
|
166
|
+
```tsx
|
|
167
|
+
import { TrustBadge } from '@revova/hydrogen';
|
|
168
|
+
|
|
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" />
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
**Props:** `proxyUrl`, `style?` (`'pill' | 'inline' | 'card'`, default `'pill'`), `starColor?`, `className?`
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
### `<ReviewTicker>`
|
|
184
|
+
|
|
185
|
+
A continuously scrolling marquee of recent review snippets — ideal for homepages and hero sections.
|
|
186
|
+
|
|
187
|
+
```tsx
|
|
188
|
+
import { ReviewTicker } from '@revova/hydrogen';
|
|
189
|
+
|
|
190
|
+
<ReviewTicker
|
|
191
|
+
proxyUrl="/apps/revova"
|
|
192
|
+
limit={20}
|
|
193
|
+
speedSeconds={30}
|
|
194
|
+
/>
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
**Props:** `proxyUrl`, `limit?` (default 20), `speedSeconds?` (default 30), `starColor?`, `className?`
|
|
198
|
+
|
|
199
|
+
---
|
|
200
|
+
|
|
201
|
+
### `<SocialProofPopup>`
|
|
202
|
+
|
|
203
|
+
A timed floating popup showing recent reviews one at a time. Appears after a short delay and cycles automatically.
|
|
204
|
+
|
|
205
|
+
```tsx
|
|
206
|
+
import { SocialProofPopup } from '@revova/hydrogen';
|
|
207
|
+
|
|
208
|
+
// Add once to your root layout
|
|
209
|
+
<SocialProofPopup
|
|
210
|
+
proxyUrl="/apps/revova"
|
|
211
|
+
position="bottom-left"
|
|
212
|
+
intervalMs={8000}
|
|
213
|
+
displayMs={5000}
|
|
214
|
+
/>
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
**Props:** `proxyUrl`, `position?` (`'bottom-left' | 'bottom-right'`, default `'bottom-left'`), `intervalMs?` (default 8000), `displayMs?` (default 5000), `starColor?`, `className?`
|
|
218
|
+
|
|
219
|
+
---
|
|
220
|
+
|
|
221
|
+
### `<FloatingReviewsTab>`
|
|
222
|
+
|
|
223
|
+
A sticky tab fixed to the left or right edge of the viewport. Clicking it slides out a panel of recent reviews.
|
|
224
|
+
|
|
225
|
+
```tsx
|
|
226
|
+
import { FloatingReviewsTab } from '@revova/hydrogen';
|
|
227
|
+
|
|
228
|
+
<FloatingReviewsTab
|
|
229
|
+
proxyUrl="/apps/revova"
|
|
230
|
+
label="Reviews"
|
|
231
|
+
position="right"
|
|
232
|
+
color="#111827"
|
|
233
|
+
/>
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
**Props:** `proxyUrl`, `label?` (default `'Reviews'`), `position?` (`'left' | 'right'`, default `'right'`), `color?`, `limit?` (default 5), `starColor?`, `className?`
|
|
237
|
+
|
|
238
|
+
---
|
|
239
|
+
|
|
240
|
+
### `<FloatingReviewButton>`
|
|
241
|
+
|
|
242
|
+
A fixed "Write a Review" button that opens a modal with the submission form.
|
|
243
|
+
|
|
244
|
+
```tsx
|
|
245
|
+
import { FloatingReviewButton } from '@revova/hydrogen';
|
|
246
|
+
|
|
247
|
+
<FloatingReviewButton
|
|
248
|
+
proxyUrl="/apps/revova"
|
|
249
|
+
productId={product.id}
|
|
250
|
+
text="Write a Review"
|
|
251
|
+
position="bottom-right"
|
|
252
|
+
color="#111827"
|
|
253
|
+
/>
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
**Props:** `proxyUrl`, `productId`, `text?` (default `'Write a Review'`), `color?`, `position?` (`'bottom-left' | 'bottom-right'`, default `'bottom-right'`), `className?`
|
|
257
|
+
|
|
258
|
+
---
|
|
259
|
+
|
|
260
|
+
## Hooks
|
|
261
|
+
|
|
262
|
+
Use hooks to build fully custom UIs while Revova handles data fetching.
|
|
263
|
+
|
|
264
|
+
### `useReviews(options)`
|
|
265
|
+
|
|
266
|
+
Paginated reviews for a product with sorting controls.
|
|
267
|
+
|
|
268
|
+
```tsx
|
|
269
|
+
import { useReviews } from '@revova/hydrogen';
|
|
270
|
+
|
|
271
|
+
const { data, loading, error, setPage, setSort, currentPage, currentSort, refetch } = useReviews({
|
|
272
|
+
proxyUrl: '/apps/revova',
|
|
273
|
+
productId: product.id,
|
|
274
|
+
limit: 5,
|
|
275
|
+
sort: 'helpful', // 'recent' | 'helpful' | 'rating_high' | 'rating_low'
|
|
276
|
+
locale: 'fr', // optional — returns translated content
|
|
277
|
+
});
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
### `useWidgetGlobals(options)`
|
|
281
|
+
|
|
282
|
+
Shop-level stats and recent reviews. Used internally by `<ReviewCount>`, `<TrustBadge>`, `<ReviewCarousel>`, `<ReviewGallery>`, `<ReviewTicker>`, `<SocialProofPopup>`, and `<FloatingReviewsTab>`.
|
|
283
|
+
|
|
284
|
+
```tsx
|
|
285
|
+
import { useWidgetGlobals } from '@revova/hydrogen';
|
|
286
|
+
|
|
287
|
+
const { data, loading, error } = useWidgetGlobals({
|
|
288
|
+
proxyUrl: '/apps/revova',
|
|
289
|
+
limit: 20,
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
// data.stats.averageRating — "4.8"
|
|
293
|
+
// data.stats.totalReviews — 142
|
|
294
|
+
// data.reviews — recent GlobalReview[]
|
|
295
|
+
// data.config — merchant widget settings
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
### `useSubmitReview(proxyUrl)`
|
|
299
|
+
|
|
300
|
+
Submit a new review programmatically.
|
|
301
|
+
|
|
302
|
+
```tsx
|
|
303
|
+
import { useSubmitReview } from '@revova/hydrogen';
|
|
304
|
+
|
|
305
|
+
const { submit, submitting, success, error, result, reset } = useSubmitReview('/apps/revova');
|
|
306
|
+
|
|
307
|
+
await submit({
|
|
308
|
+
productId: 'gid://shopify/Product/123',
|
|
309
|
+
email: 'buyer@example.com',
|
|
310
|
+
formId: 'form-id-from-loader',
|
|
311
|
+
fieldAnswers: [
|
|
312
|
+
{ fieldId: 'star-field-id', value: 5 },
|
|
313
|
+
{ fieldId: 'title-field-id', value: 'Great product!' },
|
|
314
|
+
{ fieldId: 'body-field-id', value: 'Really happy with this purchase.' },
|
|
315
|
+
],
|
|
316
|
+
});
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
### `useQnA(options)`
|
|
320
|
+
|
|
321
|
+
Fetch and submit Q&A for a product.
|
|
322
|
+
|
|
323
|
+
```tsx
|
|
324
|
+
import { useQnA } from '@revova/hydrogen';
|
|
325
|
+
|
|
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
|
|
337
|
+
await submitQuestion({
|
|
338
|
+
intent: 'question',
|
|
339
|
+
productId: product.id,
|
|
340
|
+
email: 'user@example.com',
|
|
341
|
+
body: 'Does this come in blue?',
|
|
342
|
+
});
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
### `useHelpfulVote(proxyUrl)`
|
|
346
|
+
|
|
347
|
+
Cast a helpful / not-helpful vote on a review.
|
|
348
|
+
|
|
349
|
+
```tsx
|
|
350
|
+
import { useHelpfulVote } from '@revova/hydrogen';
|
|
351
|
+
|
|
352
|
+
const { vote, loading, voted } = useHelpfulVote('/apps/revova');
|
|
353
|
+
|
|
354
|
+
<button onClick={() => vote({ reviewId: review.id, vote: 'helpful' })} disabled={voted}>
|
|
355
|
+
Helpful ({review.helpfulCount})
|
|
356
|
+
</button>
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
---
|
|
360
|
+
|
|
361
|
+
## Styling
|
|
362
|
+
|
|
363
|
+
All components are **unstyled by default** — they render semantic HTML with inline structural styles only (layout, positioning). Pass a `className` prop and override with Tailwind, CSS Modules, or any CSS-in-JS solution.
|
|
364
|
+
|
|
365
|
+
The `starColor` prop is available on every component that displays stars and defaults to `#f59e0b` (amber).
|
|
366
|
+
|
|
367
|
+
---
|
|
368
|
+
|
|
369
|
+
## Placement Guide
|
|
370
|
+
|
|
371
|
+
| Widget | Where to use |
|
|
372
|
+
|---|---|
|
|
373
|
+
| `<ReviewWidget>` | Product detail page |
|
|
374
|
+
| `<ReviewForm>` | Custom PDP, post-purchase page |
|
|
375
|
+
| `<StarRating>` | Anywhere — product cards, PDPs, search results |
|
|
376
|
+
| `<ReviewCount>` | Product cards, PDP header |
|
|
377
|
+
| `<ReviewCarousel>` | Homepage, collection pages |
|
|
378
|
+
| `<ReviewGallery>` | Homepage, dedicated reviews page |
|
|
379
|
+
| `<QnAWidget>` | Product detail page (below reviews) |
|
|
380
|
+
| `<TrustBadge>` | Homepage hero, footer, landing pages |
|
|
381
|
+
| `<ReviewTicker>` | Homepage hero, announcement bar |
|
|
382
|
+
| `<SocialProofPopup>` | Root layout (renders once site-wide) |
|
|
383
|
+
| `<FloatingReviewsTab>` | Root layout (renders once site-wide) |
|
|
384
|
+
| `<FloatingReviewButton>` | Product detail page |
|