judgeme-hydrogen-fixed 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/LICENSE +21 -0
- package/README.md +154 -0
- package/dist/index.d.mts +132 -0
- package/dist/index.d.ts +132 -0
- package/dist/index.js +161 -0
- package/dist/index.mjs +126 -0
- package/package.json +48 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Ben Goodman
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
# judgeme-hydrogen-fixed
|
|
2
|
+
|
|
3
|
+
A fixed version of the official `@judgeme/shopify-hydrogen` package for integrating Judge.me reviews into Shopify Hydrogen stores.
|
|
4
|
+
|
|
5
|
+
## Why this package?
|
|
6
|
+
|
|
7
|
+
The official `@judgeme/shopify-hydrogen` package has a bug in its `useJudgeme` hook - it contains a `useEffect` with **no dependency array**, which causes it to run on every render. This can lead to:
|
|
8
|
+
|
|
9
|
+
- Infinite refresh loops
|
|
10
|
+
- Performance issues
|
|
11
|
+
- Memory leaks from uncleaned timeouts
|
|
12
|
+
|
|
13
|
+
This package provides a properly implemented version that:
|
|
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
|
|
19
|
+
|
|
20
|
+
## Installation
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npm install judgeme-hydrogen-fixed
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Usage
|
|
27
|
+
|
|
28
|
+
### 1. Initialize Judge.me in your root component
|
|
29
|
+
|
|
30
|
+
```tsx
|
|
31
|
+
// app/root.tsx
|
|
32
|
+
import { useJudgeme } from "judgeme-hydrogen-fixed";
|
|
33
|
+
|
|
34
|
+
export default function App() {
|
|
35
|
+
useJudgeme({
|
|
36
|
+
shopDomain: "your-store.myshopify.com",
|
|
37
|
+
publicToken: "your-judge-me-public-token",
|
|
38
|
+
cdnHost: "https://cdn.judge.me",
|
|
39
|
+
delay: 500, // optional, defaults to 500ms
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
return <Outlet />;
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### 2. Add widgets to your product pages
|
|
47
|
+
|
|
48
|
+
```tsx
|
|
49
|
+
// app/routes/products.$handle.tsx
|
|
50
|
+
import {
|
|
51
|
+
JudgemePreviewBadge,
|
|
52
|
+
JudgemeReviewWidget,
|
|
53
|
+
} from "judgeme-hydrogen-fixed";
|
|
54
|
+
|
|
55
|
+
function ProductPage({ product }) {
|
|
56
|
+
const productId = product.id.replace("gid://shopify/Product/", "");
|
|
57
|
+
|
|
58
|
+
return (
|
|
59
|
+
<div>
|
|
60
|
+
<h1>{product.title}</h1>
|
|
61
|
+
|
|
62
|
+
{/* Star rating badge - place near title */}
|
|
63
|
+
<JudgemePreviewBadge id={productId} template="product" />
|
|
64
|
+
|
|
65
|
+
{/* Product details... */}
|
|
66
|
+
|
|
67
|
+
{/* Full review widget - place at bottom */}
|
|
68
|
+
<JudgemeReviewWidget id={productId} />
|
|
69
|
+
</div>
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Available Components
|
|
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
|
+
```
|
|
127
|
+
|
|
128
|
+
## The Bug Fix Explained
|
|
129
|
+
|
|
130
|
+
The original package has this code:
|
|
131
|
+
|
|
132
|
+
```javascript
|
|
133
|
+
// ❌ Original (buggy) - runs on EVERY render
|
|
134
|
+
useEffect(() => {
|
|
135
|
+
// Widget re-render logic...
|
|
136
|
+
}); // No dependency array!
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
This package fixes it:
|
|
140
|
+
|
|
141
|
+
```javascript
|
|
142
|
+
// ✅ Fixed - runs only on route changes
|
|
143
|
+
useEffect(() => {
|
|
144
|
+
// Widget re-render logic...
|
|
145
|
+
}, [location.pathname, location.search, delay]);
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## License
|
|
149
|
+
|
|
150
|
+
MIT
|
|
151
|
+
|
|
152
|
+
## Contributing
|
|
153
|
+
|
|
154
|
+
Issues and PRs welcome! If Judge.me fixes the official package, this one will be deprecated.
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
declare global {
|
|
4
|
+
interface Window {
|
|
5
|
+
jdgm?: {
|
|
6
|
+
SHOP_DOMAIN?: string;
|
|
7
|
+
PLATFORM?: string;
|
|
8
|
+
PUBLIC_TOKEN?: string;
|
|
9
|
+
productData?: unknown;
|
|
10
|
+
};
|
|
11
|
+
jdgm_preloader?: () => void;
|
|
12
|
+
jdgmCacheServer?: {
|
|
13
|
+
reloadAll: () => void;
|
|
14
|
+
};
|
|
15
|
+
jdgm_rerender?: ReturnType<typeof setTimeout>;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
interface UseJudgemeConfig {
|
|
19
|
+
/**
|
|
20
|
+
* Your Shopify store domain (e.g., 'your-store.myshopify.com')
|
|
21
|
+
*/
|
|
22
|
+
shopDomain: string;
|
|
23
|
+
/**
|
|
24
|
+
* Your Judge.me public token
|
|
25
|
+
*/
|
|
26
|
+
publicToken: string;
|
|
27
|
+
/**
|
|
28
|
+
* Judge.me CDN host (usually 'https://cdn.judge.me')
|
|
29
|
+
*/
|
|
30
|
+
cdnHost: string;
|
|
31
|
+
/**
|
|
32
|
+
* Delay in milliseconds before re-rendering widgets on route change
|
|
33
|
+
* @default 500
|
|
34
|
+
*/
|
|
35
|
+
delay?: number;
|
|
36
|
+
}
|
|
37
|
+
interface JudgemePreviewBadgeProps {
|
|
38
|
+
/**
|
|
39
|
+
* Shopify product ID (numeric ID only, not the full GID)
|
|
40
|
+
*/
|
|
41
|
+
id: string;
|
|
42
|
+
/**
|
|
43
|
+
* Template type
|
|
44
|
+
* @default 'product'
|
|
45
|
+
*/
|
|
46
|
+
template?: 'product' | 'collection';
|
|
47
|
+
}
|
|
48
|
+
interface JudgemeReviewWidgetProps {
|
|
49
|
+
/**
|
|
50
|
+
* Shopify product ID (numeric ID only, not the full GID)
|
|
51
|
+
*/
|
|
52
|
+
id: string;
|
|
53
|
+
}
|
|
54
|
+
interface JudgemeCarouselProps {
|
|
55
|
+
}
|
|
56
|
+
interface JudgemeReviewsTabProps {
|
|
57
|
+
}
|
|
58
|
+
interface JudgemeAllReviewsRatingProps {
|
|
59
|
+
}
|
|
60
|
+
interface JudgemeVerifiedBadgeProps {
|
|
61
|
+
}
|
|
62
|
+
interface JudgemeAllReviewsCountProps {
|
|
63
|
+
}
|
|
64
|
+
interface JudgemeMedalsProps {
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Fixed version of useJudgeme that properly handles React's render cycle.
|
|
69
|
+
*
|
|
70
|
+
* The original @judgeme/shopify-hydrogen package has a useEffect with no
|
|
71
|
+
* dependency array that runs on every render, causing infinite refresh loops.
|
|
72
|
+
*
|
|
73
|
+
* This fixed version:
|
|
74
|
+
* 1. Loads Judge.me scripts only once on mount
|
|
75
|
+
* 2. Re-renders widgets only on route changes (not every render)
|
|
76
|
+
* 3. Properly cleans up timeouts to prevent memory leaks
|
|
77
|
+
*
|
|
78
|
+
* @example
|
|
79
|
+
* ```tsx
|
|
80
|
+
* // In your root.tsx or App component
|
|
81
|
+
* import { useJudgeme } from '@judgeme/hydrogen-fixed';
|
|
82
|
+
*
|
|
83
|
+
* function App() {
|
|
84
|
+
* useJudgeme({
|
|
85
|
+
* shopDomain: 'your-store.myshopify.com',
|
|
86
|
+
* publicToken: 'your-public-token',
|
|
87
|
+
* cdnHost: 'https://cdn.judge.me',
|
|
88
|
+
* delay: 500, // optional, defaults to 500ms
|
|
89
|
+
* });
|
|
90
|
+
*
|
|
91
|
+
* return <Outlet />;
|
|
92
|
+
* }
|
|
93
|
+
* ```
|
|
94
|
+
*/
|
|
95
|
+
declare function useJudgeme({ shopDomain, publicToken, cdnHost, delay, }: UseJudgemeConfig): void;
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Preview badge showing star rating for a product
|
|
99
|
+
* Place this near the product title on product pages
|
|
100
|
+
*/
|
|
101
|
+
declare function JudgemePreviewBadge({ id, template, }: JudgemePreviewBadgeProps): React.ReactElement;
|
|
102
|
+
/**
|
|
103
|
+
* Full review widget with reviews list and write review form
|
|
104
|
+
* Place this at the bottom of product pages
|
|
105
|
+
*/
|
|
106
|
+
declare function JudgemeReviewWidget({ id, }: JudgemeReviewWidgetProps): React.ReactElement;
|
|
107
|
+
/**
|
|
108
|
+
* Carousel showing recent reviews across all products
|
|
109
|
+
*/
|
|
110
|
+
declare function JudgemeCarousel(): React.ReactElement;
|
|
111
|
+
/**
|
|
112
|
+
* Tab showing all reviews (typically used in a tabbed layout)
|
|
113
|
+
*/
|
|
114
|
+
declare function JudgemeReviewsTab(): React.ReactElement;
|
|
115
|
+
/**
|
|
116
|
+
* Shows the overall rating across all products
|
|
117
|
+
*/
|
|
118
|
+
declare function JudgemeAllReviewsRating(): React.ReactElement;
|
|
119
|
+
/**
|
|
120
|
+
* Verified badge for social proof
|
|
121
|
+
*/
|
|
122
|
+
declare function JudgemeVerifiedBadge(): React.ReactElement;
|
|
123
|
+
/**
|
|
124
|
+
* Shows the total review count across all products
|
|
125
|
+
*/
|
|
126
|
+
declare function JudgemeAllReviewsCount(): React.ReactElement;
|
|
127
|
+
/**
|
|
128
|
+
* Displays Judge.me medals/badges earned by the store
|
|
129
|
+
*/
|
|
130
|
+
declare function JudgemeMedals(): React.ReactElement;
|
|
131
|
+
|
|
132
|
+
export { JudgemeAllReviewsCount, type JudgemeAllReviewsCountProps, JudgemeAllReviewsRating, type JudgemeAllReviewsRatingProps, JudgemeCarousel, type JudgemeCarouselProps, JudgemeMedals, type JudgemeMedalsProps, JudgemePreviewBadge, type JudgemePreviewBadgeProps, JudgemeReviewWidget, type JudgemeReviewWidgetProps, JudgemeReviewsTab, type JudgemeReviewsTabProps, JudgemeVerifiedBadge, type JudgemeVerifiedBadgeProps, type UseJudgemeConfig, useJudgeme };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
declare global {
|
|
4
|
+
interface Window {
|
|
5
|
+
jdgm?: {
|
|
6
|
+
SHOP_DOMAIN?: string;
|
|
7
|
+
PLATFORM?: string;
|
|
8
|
+
PUBLIC_TOKEN?: string;
|
|
9
|
+
productData?: unknown;
|
|
10
|
+
};
|
|
11
|
+
jdgm_preloader?: () => void;
|
|
12
|
+
jdgmCacheServer?: {
|
|
13
|
+
reloadAll: () => void;
|
|
14
|
+
};
|
|
15
|
+
jdgm_rerender?: ReturnType<typeof setTimeout>;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
interface UseJudgemeConfig {
|
|
19
|
+
/**
|
|
20
|
+
* Your Shopify store domain (e.g., 'your-store.myshopify.com')
|
|
21
|
+
*/
|
|
22
|
+
shopDomain: string;
|
|
23
|
+
/**
|
|
24
|
+
* Your Judge.me public token
|
|
25
|
+
*/
|
|
26
|
+
publicToken: string;
|
|
27
|
+
/**
|
|
28
|
+
* Judge.me CDN host (usually 'https://cdn.judge.me')
|
|
29
|
+
*/
|
|
30
|
+
cdnHost: string;
|
|
31
|
+
/**
|
|
32
|
+
* Delay in milliseconds before re-rendering widgets on route change
|
|
33
|
+
* @default 500
|
|
34
|
+
*/
|
|
35
|
+
delay?: number;
|
|
36
|
+
}
|
|
37
|
+
interface JudgemePreviewBadgeProps {
|
|
38
|
+
/**
|
|
39
|
+
* Shopify product ID (numeric ID only, not the full GID)
|
|
40
|
+
*/
|
|
41
|
+
id: string;
|
|
42
|
+
/**
|
|
43
|
+
* Template type
|
|
44
|
+
* @default 'product'
|
|
45
|
+
*/
|
|
46
|
+
template?: 'product' | 'collection';
|
|
47
|
+
}
|
|
48
|
+
interface JudgemeReviewWidgetProps {
|
|
49
|
+
/**
|
|
50
|
+
* Shopify product ID (numeric ID only, not the full GID)
|
|
51
|
+
*/
|
|
52
|
+
id: string;
|
|
53
|
+
}
|
|
54
|
+
interface JudgemeCarouselProps {
|
|
55
|
+
}
|
|
56
|
+
interface JudgemeReviewsTabProps {
|
|
57
|
+
}
|
|
58
|
+
interface JudgemeAllReviewsRatingProps {
|
|
59
|
+
}
|
|
60
|
+
interface JudgemeVerifiedBadgeProps {
|
|
61
|
+
}
|
|
62
|
+
interface JudgemeAllReviewsCountProps {
|
|
63
|
+
}
|
|
64
|
+
interface JudgemeMedalsProps {
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Fixed version of useJudgeme that properly handles React's render cycle.
|
|
69
|
+
*
|
|
70
|
+
* The original @judgeme/shopify-hydrogen package has a useEffect with no
|
|
71
|
+
* dependency array that runs on every render, causing infinite refresh loops.
|
|
72
|
+
*
|
|
73
|
+
* This fixed version:
|
|
74
|
+
* 1. Loads Judge.me scripts only once on mount
|
|
75
|
+
* 2. Re-renders widgets only on route changes (not every render)
|
|
76
|
+
* 3. Properly cleans up timeouts to prevent memory leaks
|
|
77
|
+
*
|
|
78
|
+
* @example
|
|
79
|
+
* ```tsx
|
|
80
|
+
* // In your root.tsx or App component
|
|
81
|
+
* import { useJudgeme } from '@judgeme/hydrogen-fixed';
|
|
82
|
+
*
|
|
83
|
+
* function App() {
|
|
84
|
+
* useJudgeme({
|
|
85
|
+
* shopDomain: 'your-store.myshopify.com',
|
|
86
|
+
* publicToken: 'your-public-token',
|
|
87
|
+
* cdnHost: 'https://cdn.judge.me',
|
|
88
|
+
* delay: 500, // optional, defaults to 500ms
|
|
89
|
+
* });
|
|
90
|
+
*
|
|
91
|
+
* return <Outlet />;
|
|
92
|
+
* }
|
|
93
|
+
* ```
|
|
94
|
+
*/
|
|
95
|
+
declare function useJudgeme({ shopDomain, publicToken, cdnHost, delay, }: UseJudgemeConfig): void;
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Preview badge showing star rating for a product
|
|
99
|
+
* Place this near the product title on product pages
|
|
100
|
+
*/
|
|
101
|
+
declare function JudgemePreviewBadge({ id, template, }: JudgemePreviewBadgeProps): React.ReactElement;
|
|
102
|
+
/**
|
|
103
|
+
* Full review widget with reviews list and write review form
|
|
104
|
+
* Place this at the bottom of product pages
|
|
105
|
+
*/
|
|
106
|
+
declare function JudgemeReviewWidget({ id, }: JudgemeReviewWidgetProps): React.ReactElement;
|
|
107
|
+
/**
|
|
108
|
+
* Carousel showing recent reviews across all products
|
|
109
|
+
*/
|
|
110
|
+
declare function JudgemeCarousel(): React.ReactElement;
|
|
111
|
+
/**
|
|
112
|
+
* Tab showing all reviews (typically used in a tabbed layout)
|
|
113
|
+
*/
|
|
114
|
+
declare function JudgemeReviewsTab(): React.ReactElement;
|
|
115
|
+
/**
|
|
116
|
+
* Shows the overall rating across all products
|
|
117
|
+
*/
|
|
118
|
+
declare function JudgemeAllReviewsRating(): React.ReactElement;
|
|
119
|
+
/**
|
|
120
|
+
* Verified badge for social proof
|
|
121
|
+
*/
|
|
122
|
+
declare function JudgemeVerifiedBadge(): React.ReactElement;
|
|
123
|
+
/**
|
|
124
|
+
* Shows the total review count across all products
|
|
125
|
+
*/
|
|
126
|
+
declare function JudgemeAllReviewsCount(): React.ReactElement;
|
|
127
|
+
/**
|
|
128
|
+
* Displays Judge.me medals/badges earned by the store
|
|
129
|
+
*/
|
|
130
|
+
declare function JudgemeMedals(): React.ReactElement;
|
|
131
|
+
|
|
132
|
+
export { JudgemeAllReviewsCount, type JudgemeAllReviewsCountProps, JudgemeAllReviewsRating, type JudgemeAllReviewsRatingProps, JudgemeCarousel, type JudgemeCarouselProps, JudgemeMedals, type JudgemeMedalsProps, JudgemePreviewBadge, type JudgemePreviewBadgeProps, JudgemeReviewWidget, type JudgemeReviewWidgetProps, JudgemeReviewsTab, type JudgemeReviewsTabProps, JudgemeVerifiedBadge, type JudgemeVerifiedBadgeProps, type UseJudgemeConfig, useJudgeme };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
JudgemeAllReviewsCount: () => JudgemeAllReviewsCount,
|
|
24
|
+
JudgemeAllReviewsRating: () => JudgemeAllReviewsRating,
|
|
25
|
+
JudgemeCarousel: () => JudgemeCarousel,
|
|
26
|
+
JudgemeMedals: () => JudgemeMedals,
|
|
27
|
+
JudgemePreviewBadge: () => JudgemePreviewBadge,
|
|
28
|
+
JudgemeReviewWidget: () => JudgemeReviewWidget,
|
|
29
|
+
JudgemeReviewsTab: () => JudgemeReviewsTab,
|
|
30
|
+
JudgemeVerifiedBadge: () => JudgemeVerifiedBadge,
|
|
31
|
+
useJudgeme: () => useJudgeme
|
|
32
|
+
});
|
|
33
|
+
module.exports = __toCommonJS(index_exports);
|
|
34
|
+
|
|
35
|
+
// src/useJudgeme.ts
|
|
36
|
+
var import_react = require("react");
|
|
37
|
+
var import_react2 = require("@remix-run/react");
|
|
38
|
+
function useJudgeme({
|
|
39
|
+
shopDomain,
|
|
40
|
+
publicToken,
|
|
41
|
+
cdnHost,
|
|
42
|
+
delay = 500
|
|
43
|
+
}) {
|
|
44
|
+
const location = (0, import_react2.useLocation)();
|
|
45
|
+
const isLoadedRef = (0, import_react.useRef)(false);
|
|
46
|
+
const rerenderTimeoutRef = (0, import_react.useRef)(null);
|
|
47
|
+
(0, import_react.useEffect)(() => {
|
|
48
|
+
if (isLoadedRef.current) return;
|
|
49
|
+
if (!shopDomain || !publicToken || !cdnHost) {
|
|
50
|
+
console.warn(
|
|
51
|
+
"Judge.me: Missing config values for store domain, store public token, or cdn host"
|
|
52
|
+
);
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
const shopCredentials = `
|
|
56
|
+
if (typeof window.jdgm === 'undefined') {
|
|
57
|
+
window.jdgm = {};
|
|
58
|
+
window.jdgm.SHOP_DOMAIN = '${shopDomain}';
|
|
59
|
+
window.jdgm.PLATFORM = 'shopify';
|
|
60
|
+
window.jdgm.PUBLIC_TOKEN = '${publicToken}';
|
|
61
|
+
}
|
|
62
|
+
`;
|
|
63
|
+
fetch(`${cdnHost}/widget_preloader.js`).then((res) => {
|
|
64
|
+
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
65
|
+
return res.text();
|
|
66
|
+
}).then((text) => {
|
|
67
|
+
const preloaderFunction = `function jdgm_preloader(){${text}}`;
|
|
68
|
+
const shopCredentialsScript = document.createElement("script");
|
|
69
|
+
const preloaderScript = document.createElement("script");
|
|
70
|
+
const installedScript = document.createElement("script");
|
|
71
|
+
shopCredentialsScript.innerText = shopCredentials;
|
|
72
|
+
preloaderScript.innerText = preloaderFunction;
|
|
73
|
+
installedScript.src = `${cdnHost}/assets/installed.js`;
|
|
74
|
+
document.head.append(
|
|
75
|
+
shopCredentialsScript,
|
|
76
|
+
preloaderScript,
|
|
77
|
+
installedScript
|
|
78
|
+
);
|
|
79
|
+
isLoadedRef.current = true;
|
|
80
|
+
console.log("Judge.me scripts loaded");
|
|
81
|
+
}).catch((error) => {
|
|
82
|
+
console.error("Judge.me: Failed to load scripts", error);
|
|
83
|
+
});
|
|
84
|
+
return () => {
|
|
85
|
+
if (rerenderTimeoutRef.current) {
|
|
86
|
+
clearTimeout(rerenderTimeoutRef.current);
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
}, [shopDomain, publicToken, cdnHost]);
|
|
90
|
+
(0, import_react.useEffect)(() => {
|
|
91
|
+
if (rerenderTimeoutRef.current) {
|
|
92
|
+
clearTimeout(rerenderTimeoutRef.current);
|
|
93
|
+
}
|
|
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);
|
|
101
|
+
return () => {
|
|
102
|
+
if (rerenderTimeoutRef.current) {
|
|
103
|
+
clearTimeout(rerenderTimeoutRef.current);
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
}, [location.pathname, location.search, delay]);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// src/components.tsx
|
|
110
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
111
|
+
function JudgemePreviewBadge({
|
|
112
|
+
id,
|
|
113
|
+
template = "product"
|
|
114
|
+
}) {
|
|
115
|
+
const shopifyId = id ? id.replace("gid://shopify/Product/", "") : "";
|
|
116
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
117
|
+
"div",
|
|
118
|
+
{
|
|
119
|
+
className: "jdgm-widget jdgm-preview-badge",
|
|
120
|
+
"data-id": shopifyId,
|
|
121
|
+
"data-template": template,
|
|
122
|
+
"data-auto-install": "false"
|
|
123
|
+
}
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
function JudgemeReviewWidget({
|
|
127
|
+
id
|
|
128
|
+
}) {
|
|
129
|
+
const shopifyId = id ? id.replace("gid://shopify/Product/", "") : "";
|
|
130
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "jdgm-widget jdgm-review-widget", "data-id": shopifyId });
|
|
131
|
+
}
|
|
132
|
+
function JudgemeCarousel() {
|
|
133
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "jdgm-widget jdgm-carousel-widget" });
|
|
134
|
+
}
|
|
135
|
+
function JudgemeReviewsTab() {
|
|
136
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "jdgm-widget jdgm-reviews-tab" });
|
|
137
|
+
}
|
|
138
|
+
function JudgemeAllReviewsRating() {
|
|
139
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "jdgm-widget jdgm-all-reviews-rating" });
|
|
140
|
+
}
|
|
141
|
+
function JudgemeVerifiedBadge() {
|
|
142
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "jdgm-widget jdgm-verified-badge" });
|
|
143
|
+
}
|
|
144
|
+
function JudgemeAllReviewsCount() {
|
|
145
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "jdgm-widget jdgm-all-reviews-count" });
|
|
146
|
+
}
|
|
147
|
+
function JudgemeMedals() {
|
|
148
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "jdgm-widget jdgm-medals-wrapper" });
|
|
149
|
+
}
|
|
150
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
151
|
+
0 && (module.exports = {
|
|
152
|
+
JudgemeAllReviewsCount,
|
|
153
|
+
JudgemeAllReviewsRating,
|
|
154
|
+
JudgemeCarousel,
|
|
155
|
+
JudgemeMedals,
|
|
156
|
+
JudgemePreviewBadge,
|
|
157
|
+
JudgemeReviewWidget,
|
|
158
|
+
JudgemeReviewsTab,
|
|
159
|
+
JudgemeVerifiedBadge,
|
|
160
|
+
useJudgeme
|
|
161
|
+
});
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
// src/useJudgeme.ts
|
|
2
|
+
import { useEffect, useRef } from "react";
|
|
3
|
+
import { useLocation } from "@remix-run/react";
|
|
4
|
+
function useJudgeme({
|
|
5
|
+
shopDomain,
|
|
6
|
+
publicToken,
|
|
7
|
+
cdnHost,
|
|
8
|
+
delay = 500
|
|
9
|
+
}) {
|
|
10
|
+
const location = useLocation();
|
|
11
|
+
const isLoadedRef = useRef(false);
|
|
12
|
+
const rerenderTimeoutRef = useRef(null);
|
|
13
|
+
useEffect(() => {
|
|
14
|
+
if (isLoadedRef.current) return;
|
|
15
|
+
if (!shopDomain || !publicToken || !cdnHost) {
|
|
16
|
+
console.warn(
|
|
17
|
+
"Judge.me: Missing config values for store domain, store public token, or cdn host"
|
|
18
|
+
);
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
const shopCredentials = `
|
|
22
|
+
if (typeof window.jdgm === 'undefined') {
|
|
23
|
+
window.jdgm = {};
|
|
24
|
+
window.jdgm.SHOP_DOMAIN = '${shopDomain}';
|
|
25
|
+
window.jdgm.PLATFORM = 'shopify';
|
|
26
|
+
window.jdgm.PUBLIC_TOKEN = '${publicToken}';
|
|
27
|
+
}
|
|
28
|
+
`;
|
|
29
|
+
fetch(`${cdnHost}/widget_preloader.js`).then((res) => {
|
|
30
|
+
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
31
|
+
return res.text();
|
|
32
|
+
}).then((text) => {
|
|
33
|
+
const preloaderFunction = `function jdgm_preloader(){${text}}`;
|
|
34
|
+
const shopCredentialsScript = document.createElement("script");
|
|
35
|
+
const preloaderScript = document.createElement("script");
|
|
36
|
+
const installedScript = document.createElement("script");
|
|
37
|
+
shopCredentialsScript.innerText = shopCredentials;
|
|
38
|
+
preloaderScript.innerText = preloaderFunction;
|
|
39
|
+
installedScript.src = `${cdnHost}/assets/installed.js`;
|
|
40
|
+
document.head.append(
|
|
41
|
+
shopCredentialsScript,
|
|
42
|
+
preloaderScript,
|
|
43
|
+
installedScript
|
|
44
|
+
);
|
|
45
|
+
isLoadedRef.current = true;
|
|
46
|
+
console.log("Judge.me scripts loaded");
|
|
47
|
+
}).catch((error) => {
|
|
48
|
+
console.error("Judge.me: Failed to load scripts", error);
|
|
49
|
+
});
|
|
50
|
+
return () => {
|
|
51
|
+
if (rerenderTimeoutRef.current) {
|
|
52
|
+
clearTimeout(rerenderTimeoutRef.current);
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
}, [shopDomain, publicToken, cdnHost]);
|
|
56
|
+
useEffect(() => {
|
|
57
|
+
if (rerenderTimeoutRef.current) {
|
|
58
|
+
clearTimeout(rerenderTimeoutRef.current);
|
|
59
|
+
}
|
|
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);
|
|
67
|
+
return () => {
|
|
68
|
+
if (rerenderTimeoutRef.current) {
|
|
69
|
+
clearTimeout(rerenderTimeoutRef.current);
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
}, [location.pathname, location.search, delay]);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// src/components.tsx
|
|
76
|
+
import { jsx } from "react/jsx-runtime";
|
|
77
|
+
function JudgemePreviewBadge({
|
|
78
|
+
id,
|
|
79
|
+
template = "product"
|
|
80
|
+
}) {
|
|
81
|
+
const shopifyId = id ? id.replace("gid://shopify/Product/", "") : "";
|
|
82
|
+
return /* @__PURE__ */ jsx(
|
|
83
|
+
"div",
|
|
84
|
+
{
|
|
85
|
+
className: "jdgm-widget jdgm-preview-badge",
|
|
86
|
+
"data-id": shopifyId,
|
|
87
|
+
"data-template": template,
|
|
88
|
+
"data-auto-install": "false"
|
|
89
|
+
}
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
function JudgemeReviewWidget({
|
|
93
|
+
id
|
|
94
|
+
}) {
|
|
95
|
+
const shopifyId = id ? id.replace("gid://shopify/Product/", "") : "";
|
|
96
|
+
return /* @__PURE__ */ jsx("div", { className: "jdgm-widget jdgm-review-widget", "data-id": shopifyId });
|
|
97
|
+
}
|
|
98
|
+
function JudgemeCarousel() {
|
|
99
|
+
return /* @__PURE__ */ jsx("div", { className: "jdgm-widget jdgm-carousel-widget" });
|
|
100
|
+
}
|
|
101
|
+
function JudgemeReviewsTab() {
|
|
102
|
+
return /* @__PURE__ */ jsx("div", { className: "jdgm-widget jdgm-reviews-tab" });
|
|
103
|
+
}
|
|
104
|
+
function JudgemeAllReviewsRating() {
|
|
105
|
+
return /* @__PURE__ */ jsx("div", { className: "jdgm-widget jdgm-all-reviews-rating" });
|
|
106
|
+
}
|
|
107
|
+
function JudgemeVerifiedBadge() {
|
|
108
|
+
return /* @__PURE__ */ jsx("div", { className: "jdgm-widget jdgm-verified-badge" });
|
|
109
|
+
}
|
|
110
|
+
function JudgemeAllReviewsCount() {
|
|
111
|
+
return /* @__PURE__ */ jsx("div", { className: "jdgm-widget jdgm-all-reviews-count" });
|
|
112
|
+
}
|
|
113
|
+
function JudgemeMedals() {
|
|
114
|
+
return /* @__PURE__ */ jsx("div", { className: "jdgm-widget jdgm-medals-wrapper" });
|
|
115
|
+
}
|
|
116
|
+
export {
|
|
117
|
+
JudgemeAllReviewsCount,
|
|
118
|
+
JudgemeAllReviewsRating,
|
|
119
|
+
JudgemeCarousel,
|
|
120
|
+
JudgemeMedals,
|
|
121
|
+
JudgemePreviewBadge,
|
|
122
|
+
JudgemeReviewWidget,
|
|
123
|
+
JudgemeReviewsTab,
|
|
124
|
+
JudgemeVerifiedBadge,
|
|
125
|
+
useJudgeme
|
|
126
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "judgeme-hydrogen-fixed",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Fixed version of @judgeme/shopify-hydrogen with proper React hooks implementation. Fixes infinite refresh loop bug.",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"module": "./dist/index.mjs",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.mjs",
|
|
12
|
+
"require": "./dist/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist",
|
|
17
|
+
"README.md",
|
|
18
|
+
"LICENSE"
|
|
19
|
+
],
|
|
20
|
+
"scripts": {
|
|
21
|
+
"build": "tsup src/index.ts --format cjs,esm --dts --clean",
|
|
22
|
+
"dev": "tsup src/index.ts --format cjs,esm --dts --watch",
|
|
23
|
+
"prepublishOnly": "npm run build"
|
|
24
|
+
},
|
|
25
|
+
"keywords": [
|
|
26
|
+
"judgeme",
|
|
27
|
+
"judge.me",
|
|
28
|
+
"shopify",
|
|
29
|
+
"hydrogen",
|
|
30
|
+
"react",
|
|
31
|
+
"reviews",
|
|
32
|
+
"remix",
|
|
33
|
+
"bug-fix"
|
|
34
|
+
],
|
|
35
|
+
"author": "Ben Goodman",
|
|
36
|
+
"license": "MIT",
|
|
37
|
+
"peerDependencies": {
|
|
38
|
+
"react": ">=18.0.0",
|
|
39
|
+
"@remix-run/react": ">=2.0.0"
|
|
40
|
+
},
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"@types/react": "^18.2.0",
|
|
43
|
+
"react": "^18.2.0",
|
|
44
|
+
"@remix-run/react": "^2.0.0",
|
|
45
|
+
"tsup": "^8.0.0",
|
|
46
|
+
"typescript": "^5.0.0"
|
|
47
|
+
}
|
|
48
|
+
}
|