judgeme-hydrogen-fixed 1.0.0 → 1.0.1
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/CHANGELOG.md +34 -0
- package/README.md +105 -103
- package/dist/index.d.mts +63 -11
- package/dist/index.d.ts +63 -11
- package/dist/index.js +100 -36
- package/dist/index.mjs +101 -37
- package/package.json +14 -3
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [1.0.1] - 2026-01-06
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
- Updated documentation and GitHub repository links
|
|
12
|
+
|
|
13
|
+
## [1.0.0] - 2026-01-06
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
- Initial release
|
|
17
|
+
- `useJudgeme` hook with proper dependency arrays (fixing the infinite render loop bug from the original package)
|
|
18
|
+
- All Judge.me widget components:
|
|
19
|
+
- `JudgemePreviewBadge` - Star rating badge for product cards
|
|
20
|
+
- `JudgemeReviewWidget` - Full review widget for product pages
|
|
21
|
+
- `JudgemeCarousel` - Review carousel widget
|
|
22
|
+
- `JudgemeReviewsTab` - Reviews tab widget
|
|
23
|
+
- `JudgemeAllReviewsRating` - Overall rating display
|
|
24
|
+
- `JudgemeVerifiedBadge` - Verified badge widget
|
|
25
|
+
- `JudgemeAllReviewsCount` - Total reviews count
|
|
26
|
+
- `JudgemeMedals` - Medals/badges widget
|
|
27
|
+
- Full TypeScript support
|
|
28
|
+
- Proper cleanup of timeouts to prevent memory leaks
|
|
29
|
+
|
|
30
|
+
### Fixed
|
|
31
|
+
|
|
32
|
+
- Fixed infinite render loop caused by `useEffect` with no dependency array in original `@judgeme/shopify-hydrogen` package
|
|
33
|
+
- Fixed infinite refresh loops caused by `installed.js` when deployed to Shopify Oxygen
|
|
34
|
+
- Widgets now initialize by calling `jdgm_preloader()` directly instead of relying on problematic bootstrap script
|
package/README.md
CHANGED
|
@@ -1,21 +1,15 @@
|
|
|
1
1
|
# judgeme-hydrogen-fixed
|
|
2
2
|
|
|
3
|
-
A fixed version of
|
|
3
|
+
A fixed version of `@judgeme/shopify-hydrogen` for Shopify Hydrogen/Oxygen that eliminates infinite refresh loops and improper React hook usage.
|
|
4
4
|
|
|
5
|
-
## Why
|
|
5
|
+
## Why This Package?
|
|
6
6
|
|
|
7
|
-
The official `@judgeme/shopify-hydrogen` package has
|
|
7
|
+
The official `@judgeme/shopify-hydrogen` package has critical bugs that make it unusable in production:
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
-
|
|
11
|
-
- Memory leaks from uncleaned timeouts
|
|
9
|
+
1. **Infinite render loop** - `useEffect` with no dependency array runs on every render
|
|
10
|
+
2. **Refresh loop on Oxygen** - `installed.js` causes page refreshes in production deployments
|
|
12
11
|
|
|
13
|
-
This package
|
|
14
|
-
|
|
15
|
-
- ✅ Loads Judge.me scripts only once on mount
|
|
16
|
-
- ✅ Re-renders widgets only on route changes (not every render)
|
|
17
|
-
- ✅ Properly cleans up timeouts to prevent memory leaks
|
|
18
|
-
- ✅ Includes proper TypeScript types
|
|
12
|
+
This package fixes both issues while maintaining full compatibility with Judge.me widgets.
|
|
19
13
|
|
|
20
14
|
## Installation
|
|
21
15
|
|
|
@@ -25,130 +19,138 @@ npm install judgeme-hydrogen-fixed
|
|
|
25
19
|
|
|
26
20
|
## Usage
|
|
27
21
|
|
|
28
|
-
### 1.
|
|
22
|
+
### 1. Add the Hook to Your Root Component
|
|
23
|
+
|
|
24
|
+
Add `useJudgeme` to your root layout or App component:
|
|
29
25
|
|
|
30
26
|
```tsx
|
|
31
27
|
// app/root.tsx
|
|
32
|
-
import { useJudgeme } from
|
|
28
|
+
import { useJudgeme } from 'judgeme-hydrogen-fixed';
|
|
33
29
|
|
|
34
30
|
export default function App() {
|
|
35
31
|
useJudgeme({
|
|
36
|
-
shopDomain:
|
|
37
|
-
publicToken:
|
|
38
|
-
cdnHost:
|
|
32
|
+
shopDomain: 'your-store.myshopify.com',
|
|
33
|
+
publicToken: 'your-judge-me-public-token',
|
|
34
|
+
cdnHost: 'https://cdn.judge.me',
|
|
39
35
|
delay: 500, // optional, defaults to 500ms
|
|
40
36
|
});
|
|
41
37
|
|
|
42
|
-
return
|
|
38
|
+
return (
|
|
39
|
+
<html>
|
|
40
|
+
{/* ... */}
|
|
41
|
+
</html>
|
|
42
|
+
);
|
|
43
43
|
}
|
|
44
44
|
```
|
|
45
45
|
|
|
46
|
-
### 2. Add
|
|
46
|
+
### 2. Add Widget Components
|
|
47
47
|
|
|
48
|
-
|
|
49
|
-
// app/routes/products.$handle.tsx
|
|
50
|
-
import {
|
|
51
|
-
JudgemePreviewBadge,
|
|
52
|
-
JudgemeReviewWidget,
|
|
53
|
-
} from "judgeme-hydrogen-fixed";
|
|
48
|
+
#### Preview Badge (Star Rating)
|
|
54
49
|
|
|
55
|
-
|
|
56
|
-
|
|
50
|
+
Display star ratings on product cards or near product titles:
|
|
51
|
+
|
|
52
|
+
```tsx
|
|
53
|
+
import { JudgemePreviewBadge } from 'judgeme-hydrogen-fixed';
|
|
57
54
|
|
|
55
|
+
function ProductCard({ product }) {
|
|
58
56
|
return (
|
|
59
57
|
<div>
|
|
60
|
-
<
|
|
58
|
+
<h2>{product.title}</h2>
|
|
59
|
+
<JudgemePreviewBadge
|
|
60
|
+
id={product.id}
|
|
61
|
+
productTitle={product.title}
|
|
62
|
+
productHandle={product.handle}
|
|
63
|
+
/>
|
|
64
|
+
</div>
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
#### Review Widget (Full Reviews Section)
|
|
61
70
|
|
|
62
|
-
|
|
63
|
-
<JudgemePreviewBadge id={productId} template="product" />
|
|
71
|
+
Display the complete reviews section on product pages:
|
|
64
72
|
|
|
65
|
-
|
|
73
|
+
```tsx
|
|
74
|
+
import { JudgemeReviewWidget } from 'judgeme-hydrogen-fixed';
|
|
66
75
|
|
|
67
|
-
|
|
68
|
-
|
|
76
|
+
function ProductPage({ product }) {
|
|
77
|
+
return (
|
|
78
|
+
<div>
|
|
79
|
+
{/* Product content */}
|
|
80
|
+
|
|
81
|
+
<JudgemeReviewWidget
|
|
82
|
+
id={product.id}
|
|
83
|
+
productTitle={product.title}
|
|
84
|
+
productHandle={product.handle}
|
|
85
|
+
productImageUrl={product.featuredImage?.url}
|
|
86
|
+
productDescription={product.description}
|
|
87
|
+
/>
|
|
69
88
|
</div>
|
|
70
89
|
);
|
|
71
90
|
}
|
|
72
91
|
```
|
|
73
92
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
| Component | Description |
|
|
77
|
-
| ------------------------- | ---------------------------------------- |
|
|
78
|
-
| `JudgemePreviewBadge` | Star rating badge for product pages |
|
|
79
|
-
| `JudgemeReviewWidget` | Full reviews list with write review form |
|
|
80
|
-
| `JudgemeCarousel` | Carousel of recent reviews |
|
|
81
|
-
| `JudgemeReviewsTab` | Reviews tab for tabbed layouts |
|
|
82
|
-
| `JudgemeAllReviewsRating` | Overall store rating |
|
|
83
|
-
| `JudgemeVerifiedBadge` | Verified store badge |
|
|
84
|
-
| `JudgemeAllReviewsCount` | Total review count |
|
|
85
|
-
| `JudgemeMedals` | Store medals/achievements |
|
|
86
|
-
|
|
87
|
-
## Configuration
|
|
88
|
-
|
|
89
|
-
### useJudgeme Options
|
|
90
|
-
|
|
91
|
-
| Option | Type | Required | Default | Description |
|
|
92
|
-
| ------------- | -------- | -------- | ------- | -------------------------------------------------- |
|
|
93
|
-
| `shopDomain` | `string` | Yes | - | Your Shopify store domain |
|
|
94
|
-
| `publicToken` | `string` | Yes | - | Your Judge.me public token |
|
|
95
|
-
| `cdnHost` | `string` | Yes | - | Judge.me CDN host (usually `https://cdn.judge.me`) |
|
|
96
|
-
| `delay` | `number` | No | `500` | Delay before re-rendering widgets on route change |
|
|
97
|
-
|
|
98
|
-
## CSP Configuration
|
|
99
|
-
|
|
100
|
-
If you're using Content Security Policy, add these domains:
|
|
101
|
-
|
|
102
|
-
```typescript
|
|
103
|
-
// entry.server.tsx
|
|
104
|
-
const scriptSrc = [
|
|
105
|
-
// ... other sources
|
|
106
|
-
"https://cdn.judge.me",
|
|
107
|
-
"https://cdnwidget.judge.me",
|
|
108
|
-
"https://*.judge.me",
|
|
109
|
-
];
|
|
110
|
-
|
|
111
|
-
const connectSrc = [
|
|
112
|
-
// ... other sources
|
|
113
|
-
"https://cdn.judge.me",
|
|
114
|
-
"https://*.judge.me",
|
|
115
|
-
];
|
|
116
|
-
|
|
117
|
-
const styleSrc = [
|
|
118
|
-
// ... other sources
|
|
119
|
-
"https://*.judge.me",
|
|
120
|
-
];
|
|
121
|
-
|
|
122
|
-
const imgSrc = [
|
|
123
|
-
// ... other sources
|
|
124
|
-
"https://*.judge.me",
|
|
125
|
-
];
|
|
126
|
-
```
|
|
93
|
+
### Available Components
|
|
127
94
|
|
|
128
|
-
|
|
95
|
+
| Component | Description |
|
|
96
|
+
|-----------|-------------|
|
|
97
|
+
| `JudgemePreviewBadge` | Star rating badge for product cards |
|
|
98
|
+
| `JudgemeReviewWidget` | Full review widget with reviews list and write review form |
|
|
99
|
+
| `JudgemeCarousel` | Review carousel widget |
|
|
100
|
+
| `JudgemeReviewsTab` | Reviews tab widget |
|
|
101
|
+
| `JudgemeAllReviewsRating` | Overall rating display across all products |
|
|
102
|
+
| `JudgemeVerifiedBadge` | Verified badge for social proof |
|
|
103
|
+
| `JudgemeAllReviewsCount` | Total reviews count across all products |
|
|
104
|
+
| `JudgemeMedals` | Store medals/badges widget |
|
|
129
105
|
|
|
130
|
-
|
|
106
|
+
## How It Works
|
|
131
107
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
```
|
|
108
|
+
### The Problem with installed.js
|
|
109
|
+
|
|
110
|
+
The official Judge.me package loads `installed.js` which performs automatic initialization. On Shopify Oxygen (and other edge deployments), this script causes infinite page refresh loops.
|
|
111
|
+
|
|
112
|
+
### Our Solution
|
|
138
113
|
|
|
139
|
-
|
|
114
|
+
1. **No installed.js** - We don't load the problematic bootstrap script
|
|
115
|
+
2. **Direct preloader call** - Widgets are initialized by calling `jdgm_preloader()` directly
|
|
116
|
+
3. **Smart retry mechanism** - Waits for widget elements to appear in DOM before initializing
|
|
117
|
+
4. **Proper React hooks** - Correct dependency arrays prevent infinite render loops
|
|
118
|
+
5. **Route change handling** - Widgets re-initialize on client-side navigation
|
|
140
119
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
120
|
+
## Configuration Options
|
|
121
|
+
|
|
122
|
+
| Option | Type | Required | Default | Description |
|
|
123
|
+
|--------|------|----------|---------|-------------|
|
|
124
|
+
| `shopDomain` | `string` | Yes | - | Your Shopify store domain |
|
|
125
|
+
| `publicToken` | `string` | Yes | - | Your Judge.me public token |
|
|
126
|
+
| `cdnHost` | `string` | Yes | - | Judge.me CDN host (usually `https://cdn.judge.me`) |
|
|
127
|
+
| `delay` | `number` | No | `500` | Delay (ms) before re-rendering widgets on route change |
|
|
128
|
+
|
|
129
|
+
## TypeScript Support
|
|
130
|
+
|
|
131
|
+
Full TypeScript support is included. All components and the hook are fully typed.
|
|
132
|
+
|
|
133
|
+
```tsx
|
|
134
|
+
import type {
|
|
135
|
+
UseJudgemeConfig,
|
|
136
|
+
JudgemePreviewBadgeProps,
|
|
137
|
+
JudgemeReviewWidgetProps,
|
|
138
|
+
} from 'judgeme-hydrogen-fixed';
|
|
146
139
|
```
|
|
147
140
|
|
|
141
|
+
## Finding Your Judge.me Credentials
|
|
142
|
+
|
|
143
|
+
1. Log in to your [Judge.me dashboard](https://judge.me/dashboard)
|
|
144
|
+
2. Go to **Settings** > **Technical**
|
|
145
|
+
3. Find your **Public Token** and **Shop Domain**
|
|
146
|
+
4. The CDN host is typically `https://cdn.judge.me`
|
|
147
|
+
|
|
148
148
|
## License
|
|
149
149
|
|
|
150
|
-
MIT
|
|
150
|
+
MIT © Ben Goodman
|
|
151
151
|
|
|
152
|
-
##
|
|
152
|
+
## Links
|
|
153
153
|
|
|
154
|
-
|
|
154
|
+
- [GitHub Repository](https://github.com/ben-goodman-uk/judgeme-hydrogen-fixed)
|
|
155
|
+
- [Report Issues](https://github.com/ben-goodman-uk/judgeme-hydrogen-fixed/issues)
|
|
156
|
+
- [npm Package](https://www.npmjs.com/package/judgeme-hydrogen-fixed)
|
package/dist/index.d.mts
CHANGED
|
@@ -6,13 +6,26 @@ declare global {
|
|
|
6
6
|
SHOP_DOMAIN?: string;
|
|
7
7
|
PLATFORM?: string;
|
|
8
8
|
PUBLIC_TOKEN?: string;
|
|
9
|
-
productData?:
|
|
9
|
+
productData?: {
|
|
10
|
+
id: string;
|
|
11
|
+
title: string;
|
|
12
|
+
handle: string;
|
|
13
|
+
description?: string;
|
|
14
|
+
image?: string;
|
|
15
|
+
};
|
|
10
16
|
};
|
|
11
17
|
jdgm_preloader?: () => void;
|
|
12
18
|
jdgmCacheServer?: {
|
|
13
19
|
reloadAll: () => void;
|
|
14
20
|
};
|
|
15
21
|
jdgm_rerender?: ReturnType<typeof setTimeout>;
|
|
22
|
+
JDGM_PRODUCT?: {
|
|
23
|
+
id: string;
|
|
24
|
+
title: string;
|
|
25
|
+
handle: string;
|
|
26
|
+
description?: string;
|
|
27
|
+
url?: string;
|
|
28
|
+
};
|
|
16
29
|
}
|
|
17
30
|
}
|
|
18
31
|
interface UseJudgemeConfig {
|
|
@@ -44,12 +57,40 @@ interface JudgemePreviewBadgeProps {
|
|
|
44
57
|
* @default 'product'
|
|
45
58
|
*/
|
|
46
59
|
template?: 'product' | 'collection';
|
|
60
|
+
/**
|
|
61
|
+
* Product title - needed for the review modal
|
|
62
|
+
*/
|
|
63
|
+
productTitle?: string;
|
|
64
|
+
/**
|
|
65
|
+
* Product handle/slug
|
|
66
|
+
*/
|
|
67
|
+
productHandle?: string;
|
|
68
|
+
/**
|
|
69
|
+
* Product image URL
|
|
70
|
+
*/
|
|
71
|
+
productImageUrl?: string;
|
|
47
72
|
}
|
|
48
73
|
interface JudgemeReviewWidgetProps {
|
|
49
74
|
/**
|
|
50
75
|
* Shopify product ID (numeric ID only, not the full GID)
|
|
51
76
|
*/
|
|
52
77
|
id: string;
|
|
78
|
+
/**
|
|
79
|
+
* Product title - needed for the review modal
|
|
80
|
+
*/
|
|
81
|
+
productTitle?: string;
|
|
82
|
+
/**
|
|
83
|
+
* Product handle/slug
|
|
84
|
+
*/
|
|
85
|
+
productHandle?: string;
|
|
86
|
+
/**
|
|
87
|
+
* Product image URL
|
|
88
|
+
*/
|
|
89
|
+
productImageUrl?: string;
|
|
90
|
+
/**
|
|
91
|
+
* Product description
|
|
92
|
+
*/
|
|
93
|
+
productDescription?: string;
|
|
53
94
|
}
|
|
54
95
|
interface JudgemeCarouselProps {
|
|
55
96
|
}
|
|
@@ -65,20 +106,25 @@ interface JudgemeMedalsProps {
|
|
|
65
106
|
}
|
|
66
107
|
|
|
67
108
|
/**
|
|
68
|
-
* Fixed version of useJudgeme
|
|
109
|
+
* Fixed version of useJudgeme for Shopify Hydrogen/Oxygen.
|
|
110
|
+
*
|
|
111
|
+
* ## Problems with the official @judgeme/shopify-hydrogen package:
|
|
69
112
|
*
|
|
70
|
-
*
|
|
71
|
-
*
|
|
113
|
+
* 1. **Infinite render loop**: useEffect with no dependency array runs on every render
|
|
114
|
+
* 2. **Refresh loop on Oxygen**: installed.js causes page refreshes in production
|
|
72
115
|
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
*
|
|
116
|
+
* ## How this version fixes it:
|
|
117
|
+
*
|
|
118
|
+
* 1. **No installed.js** - Does not load installed.js which causes refresh loops on Oxygen
|
|
119
|
+
* 2. **Direct preloader call** - Calls jdgm_preloader() directly to initialize widgets
|
|
120
|
+
* 3. **Proper dependencies** - Re-renders widgets only on actual route changes
|
|
121
|
+
* 4. **Global deduplication** - Prevents double-loading across component remounts
|
|
122
|
+
* 5. **Proper cleanup** - Cleans up timeouts to prevent memory leaks
|
|
77
123
|
*
|
|
78
124
|
* @example
|
|
79
125
|
* ```tsx
|
|
80
126
|
* // In your root.tsx or App component
|
|
81
|
-
* import { useJudgeme } from '
|
|
127
|
+
* import { useJudgeme } from 'judgeme-hydrogen-fixed';
|
|
82
128
|
*
|
|
83
129
|
* function App() {
|
|
84
130
|
* useJudgeme({
|
|
@@ -91,6 +137,12 @@ interface JudgemeMedalsProps {
|
|
|
91
137
|
* return <Outlet />;
|
|
92
138
|
* }
|
|
93
139
|
* ```
|
|
140
|
+
*
|
|
141
|
+
* @param config - Configuration options
|
|
142
|
+
* @param config.shopDomain - Your Shopify store domain (e.g., 'your-store.myshopify.com')
|
|
143
|
+
* @param config.publicToken - Your Judge.me public token
|
|
144
|
+
* @param config.cdnHost - Judge.me CDN host (usually 'https://cdn.judge.me')
|
|
145
|
+
* @param config.delay - Delay before re-rendering widgets on route change (default: 500ms)
|
|
94
146
|
*/
|
|
95
147
|
declare function useJudgeme({ shopDomain, publicToken, cdnHost, delay, }: UseJudgemeConfig): void;
|
|
96
148
|
|
|
@@ -98,12 +150,12 @@ declare function useJudgeme({ shopDomain, publicToken, cdnHost, delay, }: UseJud
|
|
|
98
150
|
* Preview badge showing star rating for a product
|
|
99
151
|
* Place this near the product title on product pages
|
|
100
152
|
*/
|
|
101
|
-
declare function JudgemePreviewBadge({ id, template, }: JudgemePreviewBadgeProps): React.ReactElement;
|
|
153
|
+
declare function JudgemePreviewBadge({ id, template, productTitle, productHandle, productImageUrl, }: JudgemePreviewBadgeProps): React.ReactElement;
|
|
102
154
|
/**
|
|
103
155
|
* Full review widget with reviews list and write review form
|
|
104
156
|
* Place this at the bottom of product pages
|
|
105
157
|
*/
|
|
106
|
-
declare function JudgemeReviewWidget({ id, }: JudgemeReviewWidgetProps): React.ReactElement;
|
|
158
|
+
declare function JudgemeReviewWidget({ id, productTitle, productHandle, productImageUrl, productDescription, }: JudgemeReviewWidgetProps): React.ReactElement;
|
|
107
159
|
/**
|
|
108
160
|
* Carousel showing recent reviews across all products
|
|
109
161
|
*/
|
package/dist/index.d.ts
CHANGED
|
@@ -6,13 +6,26 @@ declare global {
|
|
|
6
6
|
SHOP_DOMAIN?: string;
|
|
7
7
|
PLATFORM?: string;
|
|
8
8
|
PUBLIC_TOKEN?: string;
|
|
9
|
-
productData?:
|
|
9
|
+
productData?: {
|
|
10
|
+
id: string;
|
|
11
|
+
title: string;
|
|
12
|
+
handle: string;
|
|
13
|
+
description?: string;
|
|
14
|
+
image?: string;
|
|
15
|
+
};
|
|
10
16
|
};
|
|
11
17
|
jdgm_preloader?: () => void;
|
|
12
18
|
jdgmCacheServer?: {
|
|
13
19
|
reloadAll: () => void;
|
|
14
20
|
};
|
|
15
21
|
jdgm_rerender?: ReturnType<typeof setTimeout>;
|
|
22
|
+
JDGM_PRODUCT?: {
|
|
23
|
+
id: string;
|
|
24
|
+
title: string;
|
|
25
|
+
handle: string;
|
|
26
|
+
description?: string;
|
|
27
|
+
url?: string;
|
|
28
|
+
};
|
|
16
29
|
}
|
|
17
30
|
}
|
|
18
31
|
interface UseJudgemeConfig {
|
|
@@ -44,12 +57,40 @@ interface JudgemePreviewBadgeProps {
|
|
|
44
57
|
* @default 'product'
|
|
45
58
|
*/
|
|
46
59
|
template?: 'product' | 'collection';
|
|
60
|
+
/**
|
|
61
|
+
* Product title - needed for the review modal
|
|
62
|
+
*/
|
|
63
|
+
productTitle?: string;
|
|
64
|
+
/**
|
|
65
|
+
* Product handle/slug
|
|
66
|
+
*/
|
|
67
|
+
productHandle?: string;
|
|
68
|
+
/**
|
|
69
|
+
* Product image URL
|
|
70
|
+
*/
|
|
71
|
+
productImageUrl?: string;
|
|
47
72
|
}
|
|
48
73
|
interface JudgemeReviewWidgetProps {
|
|
49
74
|
/**
|
|
50
75
|
* Shopify product ID (numeric ID only, not the full GID)
|
|
51
76
|
*/
|
|
52
77
|
id: string;
|
|
78
|
+
/**
|
|
79
|
+
* Product title - needed for the review modal
|
|
80
|
+
*/
|
|
81
|
+
productTitle?: string;
|
|
82
|
+
/**
|
|
83
|
+
* Product handle/slug
|
|
84
|
+
*/
|
|
85
|
+
productHandle?: string;
|
|
86
|
+
/**
|
|
87
|
+
* Product image URL
|
|
88
|
+
*/
|
|
89
|
+
productImageUrl?: string;
|
|
90
|
+
/**
|
|
91
|
+
* Product description
|
|
92
|
+
*/
|
|
93
|
+
productDescription?: string;
|
|
53
94
|
}
|
|
54
95
|
interface JudgemeCarouselProps {
|
|
55
96
|
}
|
|
@@ -65,20 +106,25 @@ interface JudgemeMedalsProps {
|
|
|
65
106
|
}
|
|
66
107
|
|
|
67
108
|
/**
|
|
68
|
-
* Fixed version of useJudgeme
|
|
109
|
+
* Fixed version of useJudgeme for Shopify Hydrogen/Oxygen.
|
|
110
|
+
*
|
|
111
|
+
* ## Problems with the official @judgeme/shopify-hydrogen package:
|
|
69
112
|
*
|
|
70
|
-
*
|
|
71
|
-
*
|
|
113
|
+
* 1. **Infinite render loop**: useEffect with no dependency array runs on every render
|
|
114
|
+
* 2. **Refresh loop on Oxygen**: installed.js causes page refreshes in production
|
|
72
115
|
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
*
|
|
116
|
+
* ## How this version fixes it:
|
|
117
|
+
*
|
|
118
|
+
* 1. **No installed.js** - Does not load installed.js which causes refresh loops on Oxygen
|
|
119
|
+
* 2. **Direct preloader call** - Calls jdgm_preloader() directly to initialize widgets
|
|
120
|
+
* 3. **Proper dependencies** - Re-renders widgets only on actual route changes
|
|
121
|
+
* 4. **Global deduplication** - Prevents double-loading across component remounts
|
|
122
|
+
* 5. **Proper cleanup** - Cleans up timeouts to prevent memory leaks
|
|
77
123
|
*
|
|
78
124
|
* @example
|
|
79
125
|
* ```tsx
|
|
80
126
|
* // In your root.tsx or App component
|
|
81
|
-
* import { useJudgeme } from '
|
|
127
|
+
* import { useJudgeme } from 'judgeme-hydrogen-fixed';
|
|
82
128
|
*
|
|
83
129
|
* function App() {
|
|
84
130
|
* useJudgeme({
|
|
@@ -91,6 +137,12 @@ interface JudgemeMedalsProps {
|
|
|
91
137
|
* return <Outlet />;
|
|
92
138
|
* }
|
|
93
139
|
* ```
|
|
140
|
+
*
|
|
141
|
+
* @param config - Configuration options
|
|
142
|
+
* @param config.shopDomain - Your Shopify store domain (e.g., 'your-store.myshopify.com')
|
|
143
|
+
* @param config.publicToken - Your Judge.me public token
|
|
144
|
+
* @param config.cdnHost - Judge.me CDN host (usually 'https://cdn.judge.me')
|
|
145
|
+
* @param config.delay - Delay before re-rendering widgets on route change (default: 500ms)
|
|
94
146
|
*/
|
|
95
147
|
declare function useJudgeme({ shopDomain, publicToken, cdnHost, delay, }: UseJudgemeConfig): void;
|
|
96
148
|
|
|
@@ -98,12 +150,12 @@ declare function useJudgeme({ shopDomain, publicToken, cdnHost, delay, }: UseJud
|
|
|
98
150
|
* Preview badge showing star rating for a product
|
|
99
151
|
* Place this near the product title on product pages
|
|
100
152
|
*/
|
|
101
|
-
declare function JudgemePreviewBadge({ id, template, }: JudgemePreviewBadgeProps): React.ReactElement;
|
|
153
|
+
declare function JudgemePreviewBadge({ id, template, productTitle, productHandle, productImageUrl, }: JudgemePreviewBadgeProps): React.ReactElement;
|
|
102
154
|
/**
|
|
103
155
|
* Full review widget with reviews list and write review form
|
|
104
156
|
* Place this at the bottom of product pages
|
|
105
157
|
*/
|
|
106
|
-
declare function JudgemeReviewWidget({ id, }: JudgemeReviewWidgetProps): React.ReactElement;
|
|
158
|
+
declare function JudgemeReviewWidget({ id, productTitle, productHandle, productImageUrl, productDescription, }: JudgemeReviewWidgetProps): React.ReactElement;
|
|
107
159
|
/**
|
|
108
160
|
* Carousel showing recent reviews across all products
|
|
109
161
|
*/
|
package/dist/index.js
CHANGED
|
@@ -35,6 +35,7 @@ module.exports = __toCommonJS(index_exports);
|
|
|
35
35
|
// src/useJudgeme.ts
|
|
36
36
|
var import_react = require("react");
|
|
37
37
|
var import_react2 = require("@remix-run/react");
|
|
38
|
+
var globalScriptsLoaded = false;
|
|
38
39
|
function useJudgeme({
|
|
39
40
|
shopDomain,
|
|
40
41
|
publicToken,
|
|
@@ -42,75 +43,92 @@ function useJudgeme({
|
|
|
42
43
|
delay = 500
|
|
43
44
|
}) {
|
|
44
45
|
const location = (0, import_react2.useLocation)();
|
|
45
|
-
const
|
|
46
|
+
const lastPathnameRef = (0, import_react.useRef)("");
|
|
46
47
|
const rerenderTimeoutRef = (0, import_react.useRef)(null);
|
|
48
|
+
const isInitializedRef = (0, import_react.useRef)(false);
|
|
49
|
+
const refreshWidgets = (0, import_react.useCallback)(() => {
|
|
50
|
+
if (typeof window === "undefined") return;
|
|
51
|
+
const attemptRefresh = (retriesLeft) => {
|
|
52
|
+
const widgets = document.querySelectorAll(".jdgm-widget");
|
|
53
|
+
if (widgets.length === 0 && retriesLeft > 0) {
|
|
54
|
+
setTimeout(() => attemptRefresh(retriesLeft - 1), 200);
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
try {
|
|
58
|
+
if (typeof window.jdgm_preloader === "function" && !window.jdgmCacheServer) {
|
|
59
|
+
window.jdgm_preloader();
|
|
60
|
+
} else if (window.jdgmCacheServer) {
|
|
61
|
+
window.jdgmCacheServer.reloadAll();
|
|
62
|
+
}
|
|
63
|
+
} catch (e) {
|
|
64
|
+
console.warn("Judge.me: Error refreshing widgets", e);
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
attemptRefresh(10);
|
|
68
|
+
}, []);
|
|
47
69
|
(0, import_react.useEffect)(() => {
|
|
48
|
-
if (
|
|
70
|
+
if (typeof window === "undefined") return;
|
|
71
|
+
if (globalScriptsLoaded || isInitializedRef.current) return;
|
|
49
72
|
if (!shopDomain || !publicToken || !cdnHost) {
|
|
50
73
|
console.warn(
|
|
51
74
|
"Judge.me: Missing config values for store domain, store public token, or cdn host"
|
|
52
75
|
);
|
|
53
76
|
return;
|
|
54
77
|
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
}
|
|
62
|
-
`;
|
|
78
|
+
globalScriptsLoaded = true;
|
|
79
|
+
isInitializedRef.current = true;
|
|
80
|
+
window.jdgm = window.jdgm || {};
|
|
81
|
+
window.jdgm.SHOP_DOMAIN = shopDomain;
|
|
82
|
+
window.jdgm.PLATFORM = "shopify";
|
|
83
|
+
window.jdgm.PUBLIC_TOKEN = publicToken;
|
|
63
84
|
fetch(`${cdnHost}/widget_preloader.js`).then((res) => {
|
|
64
85
|
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
65
86
|
return res.text();
|
|
66
87
|
}).then((text) => {
|
|
67
|
-
const preloaderFunction = `function jdgm_preloader(){${text}}`;
|
|
68
|
-
const shopCredentialsScript = document.createElement("script");
|
|
69
88
|
const preloaderScript = document.createElement("script");
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
document.head.append(
|
|
75
|
-
shopCredentialsScript,
|
|
76
|
-
preloaderScript,
|
|
77
|
-
installedScript
|
|
78
|
-
);
|
|
79
|
-
isLoadedRef.current = true;
|
|
80
|
-
console.log("Judge.me scripts loaded");
|
|
89
|
+
preloaderScript.innerText = `function jdgm_preloader(){${text}}`;
|
|
90
|
+
document.head.appendChild(preloaderScript);
|
|
91
|
+
console.log("Judge.me preloader script loaded, initializing widgets...");
|
|
92
|
+
refreshWidgets();
|
|
81
93
|
}).catch((error) => {
|
|
82
94
|
console.error("Judge.me: Failed to load scripts", error);
|
|
95
|
+
globalScriptsLoaded = false;
|
|
96
|
+
isInitializedRef.current = false;
|
|
83
97
|
});
|
|
84
98
|
return () => {
|
|
85
99
|
if (rerenderTimeoutRef.current) {
|
|
86
100
|
clearTimeout(rerenderTimeoutRef.current);
|
|
87
101
|
}
|
|
88
102
|
};
|
|
89
|
-
}, [shopDomain, publicToken, cdnHost]);
|
|
103
|
+
}, [shopDomain, publicToken, cdnHost, refreshWidgets]);
|
|
90
104
|
(0, import_react.useEffect)(() => {
|
|
105
|
+
if (typeof window === "undefined") return;
|
|
106
|
+
const normalizedPathname = location.pathname.replace(/\/$/, "") || "/";
|
|
107
|
+
if (lastPathnameRef.current === normalizedPathname) {
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
lastPathnameRef.current = normalizedPathname;
|
|
91
111
|
if (rerenderTimeoutRef.current) {
|
|
92
112
|
clearTimeout(rerenderTimeoutRef.current);
|
|
93
113
|
}
|
|
94
|
-
rerenderTimeoutRef.current = setTimeout(
|
|
95
|
-
if (window.jdgm_preloader && !window.jdgmCacheServer) {
|
|
96
|
-
window.jdgm_preloader();
|
|
97
|
-
} else if (window.jdgmCacheServer) {
|
|
98
|
-
window.jdgmCacheServer.reloadAll();
|
|
99
|
-
}
|
|
100
|
-
}, delay);
|
|
114
|
+
rerenderTimeoutRef.current = setTimeout(refreshWidgets, delay);
|
|
101
115
|
return () => {
|
|
102
116
|
if (rerenderTimeoutRef.current) {
|
|
103
117
|
clearTimeout(rerenderTimeoutRef.current);
|
|
104
118
|
}
|
|
105
119
|
};
|
|
106
|
-
}, [location.pathname,
|
|
120
|
+
}, [location.pathname, delay, refreshWidgets]);
|
|
107
121
|
}
|
|
108
122
|
|
|
109
123
|
// src/components.tsx
|
|
124
|
+
var import_react3 = require("react");
|
|
110
125
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
111
126
|
function JudgemePreviewBadge({
|
|
112
127
|
id,
|
|
113
|
-
template = "product"
|
|
128
|
+
template = "product",
|
|
129
|
+
productTitle,
|
|
130
|
+
productHandle,
|
|
131
|
+
productImageUrl
|
|
114
132
|
}) {
|
|
115
133
|
const shopifyId = id ? id.replace("gid://shopify/Product/", "") : "";
|
|
116
134
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
@@ -119,15 +137,61 @@ function JudgemePreviewBadge({
|
|
|
119
137
|
className: "jdgm-widget jdgm-preview-badge",
|
|
120
138
|
"data-id": shopifyId,
|
|
121
139
|
"data-template": template,
|
|
122
|
-
"data-auto-install": "false"
|
|
140
|
+
"data-auto-install": "false",
|
|
141
|
+
...productTitle && { "data-product-title": productTitle },
|
|
142
|
+
...productHandle && { "data-product-handle": productHandle },
|
|
143
|
+
...productImageUrl && { "data-product-url": productImageUrl }
|
|
123
144
|
}
|
|
124
145
|
);
|
|
125
146
|
}
|
|
126
147
|
function JudgemeReviewWidget({
|
|
127
|
-
id
|
|
148
|
+
id,
|
|
149
|
+
productTitle,
|
|
150
|
+
productHandle,
|
|
151
|
+
productImageUrl,
|
|
152
|
+
productDescription
|
|
128
153
|
}) {
|
|
129
154
|
const shopifyId = id ? id.replace("gid://shopify/Product/", "") : "";
|
|
130
|
-
|
|
155
|
+
(0, import_react3.useEffect)(() => {
|
|
156
|
+
if (typeof window !== "undefined" && productTitle) {
|
|
157
|
+
if (!window.jdgm) {
|
|
158
|
+
window.jdgm = {};
|
|
159
|
+
}
|
|
160
|
+
window.jdgm.productData = {
|
|
161
|
+
id: shopifyId,
|
|
162
|
+
title: productTitle,
|
|
163
|
+
handle: productHandle || "",
|
|
164
|
+
description: productDescription || "",
|
|
165
|
+
image: productImageUrl || ""
|
|
166
|
+
};
|
|
167
|
+
window.JDGM_PRODUCT = {
|
|
168
|
+
id: shopifyId,
|
|
169
|
+
title: productTitle,
|
|
170
|
+
handle: productHandle || "",
|
|
171
|
+
description: productDescription || "",
|
|
172
|
+
url: productImageUrl || ""
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
}, [
|
|
176
|
+
shopifyId,
|
|
177
|
+
productTitle,
|
|
178
|
+
productHandle,
|
|
179
|
+
productImageUrl,
|
|
180
|
+
productDescription
|
|
181
|
+
]);
|
|
182
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
183
|
+
"div",
|
|
184
|
+
{
|
|
185
|
+
className: "jdgm-widget jdgm-review-widget",
|
|
186
|
+
"data-id": shopifyId,
|
|
187
|
+
...productTitle && { "data-product-title": productTitle },
|
|
188
|
+
...productHandle && { "data-product-handle": productHandle },
|
|
189
|
+
...productImageUrl && { "data-product-url": productImageUrl },
|
|
190
|
+
...productDescription && {
|
|
191
|
+
"data-product-description": productDescription
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
);
|
|
131
195
|
}
|
|
132
196
|
function JudgemeCarousel() {
|
|
133
197
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "jdgm-widget jdgm-carousel-widget" });
|
package/dist/index.mjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// src/useJudgeme.ts
|
|
2
|
-
import { useEffect, useRef } from "react";
|
|
2
|
+
import { useEffect, useRef, useCallback } from "react";
|
|
3
3
|
import { useLocation } from "@remix-run/react";
|
|
4
|
+
var globalScriptsLoaded = false;
|
|
4
5
|
function useJudgeme({
|
|
5
6
|
shopDomain,
|
|
6
7
|
publicToken,
|
|
@@ -8,75 +9,92 @@ function useJudgeme({
|
|
|
8
9
|
delay = 500
|
|
9
10
|
}) {
|
|
10
11
|
const location = useLocation();
|
|
11
|
-
const
|
|
12
|
+
const lastPathnameRef = useRef("");
|
|
12
13
|
const rerenderTimeoutRef = useRef(null);
|
|
14
|
+
const isInitializedRef = useRef(false);
|
|
15
|
+
const refreshWidgets = useCallback(() => {
|
|
16
|
+
if (typeof window === "undefined") return;
|
|
17
|
+
const attemptRefresh = (retriesLeft) => {
|
|
18
|
+
const widgets = document.querySelectorAll(".jdgm-widget");
|
|
19
|
+
if (widgets.length === 0 && retriesLeft > 0) {
|
|
20
|
+
setTimeout(() => attemptRefresh(retriesLeft - 1), 200);
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
try {
|
|
24
|
+
if (typeof window.jdgm_preloader === "function" && !window.jdgmCacheServer) {
|
|
25
|
+
window.jdgm_preloader();
|
|
26
|
+
} else if (window.jdgmCacheServer) {
|
|
27
|
+
window.jdgmCacheServer.reloadAll();
|
|
28
|
+
}
|
|
29
|
+
} catch (e) {
|
|
30
|
+
console.warn("Judge.me: Error refreshing widgets", e);
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
attemptRefresh(10);
|
|
34
|
+
}, []);
|
|
13
35
|
useEffect(() => {
|
|
14
|
-
if (
|
|
36
|
+
if (typeof window === "undefined") return;
|
|
37
|
+
if (globalScriptsLoaded || isInitializedRef.current) return;
|
|
15
38
|
if (!shopDomain || !publicToken || !cdnHost) {
|
|
16
39
|
console.warn(
|
|
17
40
|
"Judge.me: Missing config values for store domain, store public token, or cdn host"
|
|
18
41
|
);
|
|
19
42
|
return;
|
|
20
43
|
}
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
}
|
|
28
|
-
`;
|
|
44
|
+
globalScriptsLoaded = true;
|
|
45
|
+
isInitializedRef.current = true;
|
|
46
|
+
window.jdgm = window.jdgm || {};
|
|
47
|
+
window.jdgm.SHOP_DOMAIN = shopDomain;
|
|
48
|
+
window.jdgm.PLATFORM = "shopify";
|
|
49
|
+
window.jdgm.PUBLIC_TOKEN = publicToken;
|
|
29
50
|
fetch(`${cdnHost}/widget_preloader.js`).then((res) => {
|
|
30
51
|
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
31
52
|
return res.text();
|
|
32
53
|
}).then((text) => {
|
|
33
|
-
const preloaderFunction = `function jdgm_preloader(){${text}}`;
|
|
34
|
-
const shopCredentialsScript = document.createElement("script");
|
|
35
54
|
const preloaderScript = document.createElement("script");
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
document.head.append(
|
|
41
|
-
shopCredentialsScript,
|
|
42
|
-
preloaderScript,
|
|
43
|
-
installedScript
|
|
44
|
-
);
|
|
45
|
-
isLoadedRef.current = true;
|
|
46
|
-
console.log("Judge.me scripts loaded");
|
|
55
|
+
preloaderScript.innerText = `function jdgm_preloader(){${text}}`;
|
|
56
|
+
document.head.appendChild(preloaderScript);
|
|
57
|
+
console.log("Judge.me preloader script loaded, initializing widgets...");
|
|
58
|
+
refreshWidgets();
|
|
47
59
|
}).catch((error) => {
|
|
48
60
|
console.error("Judge.me: Failed to load scripts", error);
|
|
61
|
+
globalScriptsLoaded = false;
|
|
62
|
+
isInitializedRef.current = false;
|
|
49
63
|
});
|
|
50
64
|
return () => {
|
|
51
65
|
if (rerenderTimeoutRef.current) {
|
|
52
66
|
clearTimeout(rerenderTimeoutRef.current);
|
|
53
67
|
}
|
|
54
68
|
};
|
|
55
|
-
}, [shopDomain, publicToken, cdnHost]);
|
|
69
|
+
}, [shopDomain, publicToken, cdnHost, refreshWidgets]);
|
|
56
70
|
useEffect(() => {
|
|
71
|
+
if (typeof window === "undefined") return;
|
|
72
|
+
const normalizedPathname = location.pathname.replace(/\/$/, "") || "/";
|
|
73
|
+
if (lastPathnameRef.current === normalizedPathname) {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
lastPathnameRef.current = normalizedPathname;
|
|
57
77
|
if (rerenderTimeoutRef.current) {
|
|
58
78
|
clearTimeout(rerenderTimeoutRef.current);
|
|
59
79
|
}
|
|
60
|
-
rerenderTimeoutRef.current = setTimeout(
|
|
61
|
-
if (window.jdgm_preloader && !window.jdgmCacheServer) {
|
|
62
|
-
window.jdgm_preloader();
|
|
63
|
-
} else if (window.jdgmCacheServer) {
|
|
64
|
-
window.jdgmCacheServer.reloadAll();
|
|
65
|
-
}
|
|
66
|
-
}, delay);
|
|
80
|
+
rerenderTimeoutRef.current = setTimeout(refreshWidgets, delay);
|
|
67
81
|
return () => {
|
|
68
82
|
if (rerenderTimeoutRef.current) {
|
|
69
83
|
clearTimeout(rerenderTimeoutRef.current);
|
|
70
84
|
}
|
|
71
85
|
};
|
|
72
|
-
}, [location.pathname,
|
|
86
|
+
}, [location.pathname, delay, refreshWidgets]);
|
|
73
87
|
}
|
|
74
88
|
|
|
75
89
|
// src/components.tsx
|
|
90
|
+
import { useEffect as useEffect2 } from "react";
|
|
76
91
|
import { jsx } from "react/jsx-runtime";
|
|
77
92
|
function JudgemePreviewBadge({
|
|
78
93
|
id,
|
|
79
|
-
template = "product"
|
|
94
|
+
template = "product",
|
|
95
|
+
productTitle,
|
|
96
|
+
productHandle,
|
|
97
|
+
productImageUrl
|
|
80
98
|
}) {
|
|
81
99
|
const shopifyId = id ? id.replace("gid://shopify/Product/", "") : "";
|
|
82
100
|
return /* @__PURE__ */ jsx(
|
|
@@ -85,15 +103,61 @@ function JudgemePreviewBadge({
|
|
|
85
103
|
className: "jdgm-widget jdgm-preview-badge",
|
|
86
104
|
"data-id": shopifyId,
|
|
87
105
|
"data-template": template,
|
|
88
|
-
"data-auto-install": "false"
|
|
106
|
+
"data-auto-install": "false",
|
|
107
|
+
...productTitle && { "data-product-title": productTitle },
|
|
108
|
+
...productHandle && { "data-product-handle": productHandle },
|
|
109
|
+
...productImageUrl && { "data-product-url": productImageUrl }
|
|
89
110
|
}
|
|
90
111
|
);
|
|
91
112
|
}
|
|
92
113
|
function JudgemeReviewWidget({
|
|
93
|
-
id
|
|
114
|
+
id,
|
|
115
|
+
productTitle,
|
|
116
|
+
productHandle,
|
|
117
|
+
productImageUrl,
|
|
118
|
+
productDescription
|
|
94
119
|
}) {
|
|
95
120
|
const shopifyId = id ? id.replace("gid://shopify/Product/", "") : "";
|
|
96
|
-
|
|
121
|
+
useEffect2(() => {
|
|
122
|
+
if (typeof window !== "undefined" && productTitle) {
|
|
123
|
+
if (!window.jdgm) {
|
|
124
|
+
window.jdgm = {};
|
|
125
|
+
}
|
|
126
|
+
window.jdgm.productData = {
|
|
127
|
+
id: shopifyId,
|
|
128
|
+
title: productTitle,
|
|
129
|
+
handle: productHandle || "",
|
|
130
|
+
description: productDescription || "",
|
|
131
|
+
image: productImageUrl || ""
|
|
132
|
+
};
|
|
133
|
+
window.JDGM_PRODUCT = {
|
|
134
|
+
id: shopifyId,
|
|
135
|
+
title: productTitle,
|
|
136
|
+
handle: productHandle || "",
|
|
137
|
+
description: productDescription || "",
|
|
138
|
+
url: productImageUrl || ""
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
}, [
|
|
142
|
+
shopifyId,
|
|
143
|
+
productTitle,
|
|
144
|
+
productHandle,
|
|
145
|
+
productImageUrl,
|
|
146
|
+
productDescription
|
|
147
|
+
]);
|
|
148
|
+
return /* @__PURE__ */ jsx(
|
|
149
|
+
"div",
|
|
150
|
+
{
|
|
151
|
+
className: "jdgm-widget jdgm-review-widget",
|
|
152
|
+
"data-id": shopifyId,
|
|
153
|
+
...productTitle && { "data-product-title": productTitle },
|
|
154
|
+
...productHandle && { "data-product-handle": productHandle },
|
|
155
|
+
...productImageUrl && { "data-product-url": productImageUrl },
|
|
156
|
+
...productDescription && {
|
|
157
|
+
"data-product-description": productDescription
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
);
|
|
97
161
|
}
|
|
98
162
|
function JudgemeCarousel() {
|
|
99
163
|
return /* @__PURE__ */ jsx("div", { className: "jdgm-widget jdgm-carousel-widget" });
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "judgeme-hydrogen-fixed",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "Fixed version of @judgeme/shopify-hydrogen
|
|
3
|
+
"version": "1.0.1",
|
|
4
|
+
"description": "Fixed version of @judgeme/shopify-hydrogen for Hydrogen/Oxygen. Fixes infinite refresh loops caused by installed.js and improper React hooks.",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
7
7
|
"types": "./dist/index.d.ts",
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
"files": [
|
|
16
16
|
"dist",
|
|
17
17
|
"README.md",
|
|
18
|
+
"CHANGELOG.md",
|
|
18
19
|
"LICENSE"
|
|
19
20
|
],
|
|
20
21
|
"scripts": {
|
|
@@ -27,13 +28,23 @@
|
|
|
27
28
|
"judge.me",
|
|
28
29
|
"shopify",
|
|
29
30
|
"hydrogen",
|
|
31
|
+
"oxygen",
|
|
30
32
|
"react",
|
|
31
33
|
"reviews",
|
|
32
34
|
"remix",
|
|
33
|
-
"bug-fix"
|
|
35
|
+
"bug-fix",
|
|
36
|
+
"refresh-loop-fix"
|
|
34
37
|
],
|
|
35
38
|
"author": "Ben Goodman",
|
|
36
39
|
"license": "MIT",
|
|
40
|
+
"repository": {
|
|
41
|
+
"type": "git",
|
|
42
|
+
"url": "https://github.com/ben-goodman-uk/judgeme-hydrogen-fixed"
|
|
43
|
+
},
|
|
44
|
+
"bugs": {
|
|
45
|
+
"url": "https://github.com/ben-goodman-uk/judgeme-hydrogen-fixed/issues"
|
|
46
|
+
},
|
|
47
|
+
"homepage": "https://github.com/ben-goodman-uk/judgeme-hydrogen-fixed#readme",
|
|
37
48
|
"peerDependencies": {
|
|
38
49
|
"react": ">=18.0.0",
|
|
39
50
|
"@remix-run/react": ">=2.0.0"
|