@pradip1995/segment-powerhouse-carousel 0.1.1 → 0.1.3
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/package.json +2 -1
- package/src/carousel.css +149 -22
- package/src/carousel.tsx +8 -1
- package/src/product-card.tsx +46 -22
- package/src/segment.tsx +7 -1
- package/src/wishlist-button.tsx +93 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pradip1995/segment-powerhouse-carousel",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
"dependencies": {
|
|
25
25
|
"@pradip1995/commerce-core": "^4.0.0",
|
|
26
26
|
"@pradip1995/medusa-connector": "^0.2.0",
|
|
27
|
+
"@pradip1995/segment-login-popup": "^0.1.2",
|
|
27
28
|
"@pradip1995/segment-primitives": "^0.4.0"
|
|
28
29
|
},
|
|
29
30
|
"devDependencies": {
|
package/src/carousel.css
CHANGED
|
@@ -90,16 +90,18 @@
|
|
|
90
90
|
}
|
|
91
91
|
|
|
92
92
|
.powerhouse-carousel__card {
|
|
93
|
+
position: relative;
|
|
94
|
+
z-index: 1;
|
|
93
95
|
display: flex;
|
|
94
96
|
flex-direction: column;
|
|
95
97
|
height: 100%;
|
|
96
98
|
padding: 0.6875rem;
|
|
99
|
+
border: 1px solid #dddddd;
|
|
97
100
|
background: #fff;
|
|
98
|
-
transition: box-shadow 0.25s cubic-bezier(0.4, 0, 0.2, 1);
|
|
99
101
|
}
|
|
100
102
|
|
|
101
|
-
.powerhouse-
|
|
102
|
-
|
|
103
|
+
.powerhouse-carousel__media-wrap {
|
|
104
|
+
position: relative;
|
|
103
105
|
}
|
|
104
106
|
|
|
105
107
|
.powerhouse-carousel__card-media {
|
|
@@ -110,12 +112,63 @@
|
|
|
110
112
|
background: #f3f3f3;
|
|
111
113
|
}
|
|
112
114
|
|
|
115
|
+
.powerhouse-carousel__wishlist {
|
|
116
|
+
position: absolute;
|
|
117
|
+
top: 0.5rem;
|
|
118
|
+
right: 0.5rem;
|
|
119
|
+
z-index: 2;
|
|
120
|
+
display: inline-flex;
|
|
121
|
+
align-items: center;
|
|
122
|
+
justify-content: center;
|
|
123
|
+
width: 2.25rem;
|
|
124
|
+
height: 2.25rem;
|
|
125
|
+
padding: 0;
|
|
126
|
+
border: 1px solid rgba(29, 29, 29, 0.12);
|
|
127
|
+
background: rgba(255, 255, 255, 0.94);
|
|
128
|
+
color: #1d1d1d;
|
|
129
|
+
cursor: pointer;
|
|
130
|
+
transition: color 0.2s ease, border-color 0.2s ease;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
.powerhouse-carousel__wishlist:hover {
|
|
134
|
+
border-color: #1d1d1d;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
.powerhouse-carousel__wishlist.is-active {
|
|
138
|
+
color: #c1272d;
|
|
139
|
+
border-color: #c1272d;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
.powerhouse-carousel__wishlist.is-loading {
|
|
143
|
+
opacity: 0.55;
|
|
144
|
+
cursor: wait;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
.powerhouse-carousel__wishlist-icon {
|
|
148
|
+
width: 1.05rem;
|
|
149
|
+
height: 1.05rem;
|
|
150
|
+
fill: none;
|
|
151
|
+
stroke: currentColor;
|
|
152
|
+
stroke-width: 1.75;
|
|
153
|
+
stroke-linejoin: round;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
.powerhouse-carousel__wishlist.is-active .powerhouse-carousel__wishlist-icon {
|
|
157
|
+
fill: currentColor;
|
|
158
|
+
}
|
|
159
|
+
|
|
113
160
|
.powerhouse-carousel__card-image,
|
|
114
161
|
.powerhouse-carousel__card-placeholder {
|
|
115
162
|
width: 100%;
|
|
116
163
|
height: 100%;
|
|
117
164
|
object-fit: cover;
|
|
118
165
|
display: block;
|
|
166
|
+
transform: scale(1);
|
|
167
|
+
transition: transform 0.5s cubic-bezier(0, 0, 0.2, 1);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
.powerhouse-carousel__card:hover .powerhouse-carousel__card-image {
|
|
171
|
+
transform: scale(1.05);
|
|
119
172
|
}
|
|
120
173
|
|
|
121
174
|
.powerhouse-carousel__badge {
|
|
@@ -131,6 +184,19 @@
|
|
|
131
184
|
line-height: 1.2;
|
|
132
185
|
}
|
|
133
186
|
|
|
187
|
+
.powerhouse-carousel__sold {
|
|
188
|
+
position: absolute;
|
|
189
|
+
bottom: 0.6rem;
|
|
190
|
+
left: 0.6rem;
|
|
191
|
+
padding: 0.2rem 0.45rem;
|
|
192
|
+
background: #1d1d1d;
|
|
193
|
+
color: #fff;
|
|
194
|
+
font-family: var(--font-sans, inherit);
|
|
195
|
+
font-size: 0.75rem;
|
|
196
|
+
font-weight: 600;
|
|
197
|
+
line-height: 1.2;
|
|
198
|
+
}
|
|
199
|
+
|
|
134
200
|
.powerhouse-carousel__card-info {
|
|
135
201
|
display: flex;
|
|
136
202
|
flex-direction: column;
|
|
@@ -140,6 +206,7 @@
|
|
|
140
206
|
|
|
141
207
|
.powerhouse-carousel__price {
|
|
142
208
|
margin-top: 0.25rem;
|
|
209
|
+
min-height: 2.7rem;
|
|
143
210
|
}
|
|
144
211
|
|
|
145
212
|
.powerhouse-carousel__price-compare {
|
|
@@ -163,7 +230,12 @@
|
|
|
163
230
|
}
|
|
164
231
|
|
|
165
232
|
.powerhouse-carousel__card-title {
|
|
233
|
+
display: -webkit-box;
|
|
234
|
+
-webkit-box-orient: vertical;
|
|
235
|
+
-webkit-line-clamp: 2;
|
|
236
|
+
overflow: hidden;
|
|
166
237
|
margin: 0.625rem 0 0;
|
|
238
|
+
min-height: calc(1em * 1.3125 * 2);
|
|
167
239
|
font-family: var(--font-sans, inherit);
|
|
168
240
|
font-size: 1rem;
|
|
169
241
|
font-weight: 300;
|
|
@@ -177,31 +249,41 @@
|
|
|
177
249
|
|
|
178
250
|
.powerhouse-carousel__stock {
|
|
179
251
|
margin: 0.5rem 0 0;
|
|
252
|
+
min-height: 1.2em;
|
|
180
253
|
color: #688600;
|
|
181
254
|
font-size: 0.875rem;
|
|
182
255
|
}
|
|
183
256
|
|
|
257
|
+
.powerhouse-carousel__stock.is-out {
|
|
258
|
+
color: #6e6e6e;
|
|
259
|
+
}
|
|
260
|
+
|
|
184
261
|
.powerhouse-carousel__actions {
|
|
185
262
|
display: flex;
|
|
186
|
-
flex-
|
|
187
|
-
|
|
263
|
+
flex-direction: column;
|
|
264
|
+
flex-wrap: nowrap;
|
|
265
|
+
gap: 0.4rem;
|
|
188
266
|
margin-top: auto;
|
|
189
267
|
padding-top: 0.75rem;
|
|
190
268
|
}
|
|
191
269
|
|
|
192
270
|
.powerhouse-carousel__quickshop,
|
|
193
271
|
.powerhouse-carousel__atc {
|
|
194
|
-
display:
|
|
272
|
+
display: flex;
|
|
195
273
|
align-items: center;
|
|
196
274
|
justify-content: center;
|
|
275
|
+
width: 100%;
|
|
197
276
|
min-height: 2.5rem;
|
|
198
|
-
padding: 0.
|
|
277
|
+
padding: 0.5rem 0.45rem;
|
|
199
278
|
border-radius: 2px;
|
|
279
|
+
box-sizing: border-box;
|
|
200
280
|
font-family: var(--font-sans, inherit);
|
|
201
|
-
font-size: 0.
|
|
202
|
-
font-weight:
|
|
203
|
-
letter-spacing: 0
|
|
281
|
+
font-size: 0.8125rem;
|
|
282
|
+
font-weight: 600;
|
|
283
|
+
letter-spacing: 0;
|
|
204
284
|
text-decoration: none;
|
|
285
|
+
text-align: center;
|
|
286
|
+
white-space: nowrap;
|
|
205
287
|
cursor: pointer;
|
|
206
288
|
}
|
|
207
289
|
|
|
@@ -227,7 +309,7 @@
|
|
|
227
309
|
|
|
228
310
|
.powerhouse-carousel__atc:disabled {
|
|
229
311
|
opacity: 0.65;
|
|
230
|
-
cursor:
|
|
312
|
+
cursor: not-allowed;
|
|
231
313
|
}
|
|
232
314
|
|
|
233
315
|
@media screen and (min-width: 720px) {
|
|
@@ -239,16 +321,40 @@
|
|
|
239
321
|
@media screen and (min-width: 860px) {
|
|
240
322
|
.powerhouse-carousel {
|
|
241
323
|
margin-top: 1.75rem;
|
|
324
|
+
overflow: visible;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
.powerhouse-carousel__viewport,
|
|
328
|
+
.powerhouse-carousel__track {
|
|
329
|
+
overflow: visible;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
.powerhouse-carousel__track {
|
|
333
|
+
overflow-x: auto;
|
|
334
|
+
padding-bottom: 4.5rem;
|
|
335
|
+
margin-bottom: -3rem;
|
|
242
336
|
}
|
|
243
337
|
|
|
244
338
|
.powerhouse-carousel__heading {
|
|
245
339
|
margin-bottom: 1.75rem;
|
|
246
340
|
}
|
|
247
341
|
|
|
342
|
+
.powerhouse-carousel__slide {
|
|
343
|
+
display: flex;
|
|
344
|
+
align-items: stretch;
|
|
345
|
+
}
|
|
346
|
+
|
|
248
347
|
.powerhouse-carousel__card {
|
|
348
|
+
width: 100%;
|
|
249
349
|
padding: 1rem;
|
|
250
350
|
}
|
|
251
351
|
|
|
352
|
+
.powerhouse-carousel__card:hover,
|
|
353
|
+
.powerhouse-carousel__card:focus-within {
|
|
354
|
+
z-index: 8;
|
|
355
|
+
box-shadow: 0 6px 18px rgba(29, 29, 29, 0.12);
|
|
356
|
+
}
|
|
357
|
+
|
|
252
358
|
.powerhouse-carousel__arrow--prev {
|
|
253
359
|
left: 2.1875rem;
|
|
254
360
|
}
|
|
@@ -256,6 +362,38 @@
|
|
|
256
362
|
.powerhouse-carousel__arrow--next {
|
|
257
363
|
right: 2.1875rem;
|
|
258
364
|
}
|
|
365
|
+
|
|
366
|
+
.powerhouse-carousel__actions {
|
|
367
|
+
position: absolute;
|
|
368
|
+
left: -1px;
|
|
369
|
+
right: -1px;
|
|
370
|
+
top: calc(100% - 1px);
|
|
371
|
+
flex-direction: row;
|
|
372
|
+
margin-top: 0;
|
|
373
|
+
padding: 0.75rem 1rem 1rem;
|
|
374
|
+
border: 1px solid #dddddd;
|
|
375
|
+
border-top: 0;
|
|
376
|
+
background: #fff;
|
|
377
|
+
box-sizing: border-box;
|
|
378
|
+
opacity: 0;
|
|
379
|
+
visibility: hidden;
|
|
380
|
+
pointer-events: none;
|
|
381
|
+
transition: opacity 0.2s ease, visibility 0.2s ease;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
.powerhouse-carousel__quickshop,
|
|
385
|
+
.powerhouse-carousel__atc {
|
|
386
|
+
flex: 1 1 0;
|
|
387
|
+
width: auto;
|
|
388
|
+
min-width: 0;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
.powerhouse-carousel__card:hover .powerhouse-carousel__actions,
|
|
392
|
+
.powerhouse-carousel__card:focus-within .powerhouse-carousel__actions {
|
|
393
|
+
opacity: 1;
|
|
394
|
+
visibility: visible;
|
|
395
|
+
pointer-events: auto;
|
|
396
|
+
}
|
|
259
397
|
}
|
|
260
398
|
|
|
261
399
|
@media screen and (min-width: 1080px) {
|
|
@@ -266,17 +404,6 @@
|
|
|
266
404
|
.powerhouse-carousel__slide {
|
|
267
405
|
flex-basis: calc(25% - 15px);
|
|
268
406
|
}
|
|
269
|
-
|
|
270
|
-
.powerhouse-carousel__actions {
|
|
271
|
-
opacity: 0;
|
|
272
|
-
pointer-events: none;
|
|
273
|
-
transition: opacity 0.2s ease;
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
.powerhouse-carousel__card:hover .powerhouse-carousel__actions {
|
|
277
|
-
opacity: 1;
|
|
278
|
-
pointer-events: auto;
|
|
279
|
-
}
|
|
280
407
|
}
|
|
281
408
|
|
|
282
409
|
@media screen and (min-width: 1280px) {
|
package/src/carousel.tsx
CHANGED
|
@@ -20,10 +20,12 @@ export default function ProductCarousel({
|
|
|
20
20
|
products,
|
|
21
21
|
region,
|
|
22
22
|
countryCode,
|
|
23
|
+
wishlistProductIds,
|
|
23
24
|
}: {
|
|
24
25
|
products: HttpTypes.StoreProduct[]
|
|
25
26
|
region?: HttpTypes.StoreRegion
|
|
26
27
|
countryCode: string
|
|
28
|
+
wishlistProductIds?: string[]
|
|
27
29
|
}) {
|
|
28
30
|
const trackRef = useRef<HTMLDivElement>(null)
|
|
29
31
|
const [canPrev, setCanPrev] = useState(false)
|
|
@@ -87,7 +89,12 @@ export default function ProductCarousel({
|
|
|
87
89
|
<div ref={trackRef} className="powerhouse-carousel__track">
|
|
88
90
|
{products.map((product) => (
|
|
89
91
|
<div key={product.id} className="powerhouse-carousel__slide">
|
|
90
|
-
<ProductCard
|
|
92
|
+
<ProductCard
|
|
93
|
+
product={product}
|
|
94
|
+
region={region}
|
|
95
|
+
countryCode={countryCode}
|
|
96
|
+
wishlistProductIds={wishlistProductIds}
|
|
97
|
+
/>
|
|
91
98
|
</div>
|
|
92
99
|
))}
|
|
93
100
|
</div>
|
package/src/product-card.tsx
CHANGED
|
@@ -7,14 +7,16 @@ import LocalizedLink from "@pradip1995/segment-primitives/localized-link"
|
|
|
7
7
|
import { formatPrice } from "@pradip1995/segment-primitives/format-price"
|
|
8
8
|
import { isNextRedirect } from "@pradip1995/segment-primitives/is-next-redirect"
|
|
9
9
|
import type { HttpTypes } from "@medusajs/types"
|
|
10
|
+
import WishlistButton from "./wishlist-button"
|
|
10
11
|
|
|
11
12
|
type Props = {
|
|
12
13
|
product: HttpTypes.StoreProduct
|
|
13
14
|
region?: HttpTypes.StoreRegion
|
|
14
15
|
countryCode: string
|
|
16
|
+
wishlistProductIds?: string[]
|
|
15
17
|
}
|
|
16
18
|
|
|
17
|
-
export default function ProductCard({ product, region, countryCode }: Props) {
|
|
19
|
+
export default function ProductCard({ product, region, countryCode, wishlistProductIds }: Props) {
|
|
18
20
|
const router = useRouter()
|
|
19
21
|
const [adding, setAdding] = useState(false)
|
|
20
22
|
const variant = product.variants?.[0]
|
|
@@ -24,12 +26,17 @@ export default function ProductCard({ product, region, countryCode }: Props) {
|
|
|
24
26
|
const onSale = originalPrice != null && price != null && originalPrice > price
|
|
25
27
|
const saved = onSale && originalPrice != null && price != null ? originalPrice - price : null
|
|
26
28
|
const inventory = variant?.inventory_quantity
|
|
29
|
+
const inStock =
|
|
30
|
+
variant?.manage_inventory === false ||
|
|
31
|
+
variant?.allow_backorder === true ||
|
|
32
|
+
(inventory ?? 0) > 0
|
|
27
33
|
const href = `/products/${product.handle}`
|
|
34
|
+
const hasOptions = (product.variants?.length ?? 0) > 1
|
|
28
35
|
|
|
29
36
|
const handleAdd = async (event: React.MouseEvent) => {
|
|
30
37
|
event.preventDefault()
|
|
31
38
|
event.stopPropagation()
|
|
32
|
-
if (!variant?.id || adding) return
|
|
39
|
+
if (!variant?.id || adding || !inStock || hasOptions) return
|
|
33
40
|
setAdding(true)
|
|
34
41
|
try {
|
|
35
42
|
await addToCart({
|
|
@@ -50,16 +57,24 @@ export default function ProductCard({ product, region, countryCode }: Props) {
|
|
|
50
57
|
|
|
51
58
|
return (
|
|
52
59
|
<article className={`powerhouse-carousel__card${onSale ? " is-sale" : ""}`}>
|
|
53
|
-
<
|
|
54
|
-
{
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
60
|
+
<div className="powerhouse-carousel__media-wrap">
|
|
61
|
+
<LocalizedLink href={href} countryCode={countryCode} className="powerhouse-carousel__card-media">
|
|
62
|
+
{product.thumbnail?.trim() ? (
|
|
63
|
+
<img src={product.thumbnail.trim()} alt={product.title || ""} className="powerhouse-carousel__card-image" />
|
|
64
|
+
) : (
|
|
65
|
+
<div className="powerhouse-carousel__card-placeholder" />
|
|
66
|
+
)}
|
|
67
|
+
{onSale && saved != null ? (
|
|
68
|
+
<span className="powerhouse-carousel__badge">Save {formatPrice(saved, currency)}</span>
|
|
69
|
+
) : null}
|
|
70
|
+
{!inStock ? <span className="powerhouse-carousel__sold">Sold out</span> : null}
|
|
71
|
+
</LocalizedLink>
|
|
72
|
+
<WishlistButton
|
|
73
|
+
productId={product.id}
|
|
74
|
+
countryCode={countryCode}
|
|
75
|
+
wishlistProductIds={wishlistProductIds}
|
|
76
|
+
/>
|
|
77
|
+
</div>
|
|
63
78
|
|
|
64
79
|
<div className="powerhouse-carousel__card-info">
|
|
65
80
|
{price != null ? (
|
|
@@ -79,21 +94,30 @@ export default function ProductCard({ product, region, countryCode }: Props) {
|
|
|
79
94
|
|
|
80
95
|
{inventory != null && inventory > 0 && inventory <= 5 ? (
|
|
81
96
|
<p className="powerhouse-carousel__stock">Only {inventory} left!</p>
|
|
82
|
-
) :
|
|
97
|
+
) : !inStock ? (
|
|
98
|
+
<p className="powerhouse-carousel__stock is-out">Out of stock</p>
|
|
99
|
+
) : (
|
|
100
|
+
<p className="powerhouse-carousel__stock">in stock</p>
|
|
101
|
+
)}
|
|
83
102
|
|
|
84
103
|
<div className="powerhouse-carousel__actions">
|
|
85
104
|
<LocalizedLink href={href} countryCode={countryCode} className="powerhouse-carousel__quickshop">
|
|
86
105
|
Quick shop
|
|
87
106
|
</LocalizedLink>
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
107
|
+
{hasOptions ? (
|
|
108
|
+
<LocalizedLink href={href} countryCode={countryCode} className="powerhouse-carousel__atc">
|
|
109
|
+
Choose options
|
|
110
|
+
</LocalizedLink>
|
|
111
|
+
) : (
|
|
112
|
+
<button
|
|
113
|
+
type="button"
|
|
114
|
+
className="powerhouse-carousel__atc"
|
|
115
|
+
onClick={handleAdd}
|
|
116
|
+
disabled={adding || !variant?.id || !inStock}
|
|
117
|
+
>
|
|
118
|
+
{adding ? "Adding…" : !inStock ? "Sold out" : "Add to cart"}
|
|
119
|
+
</button>
|
|
120
|
+
)}
|
|
97
121
|
</div>
|
|
98
122
|
</div>
|
|
99
123
|
</article>
|
package/src/segment.tsx
CHANGED
|
@@ -10,6 +10,7 @@ export default async function PowerhouseCarousel({
|
|
|
10
10
|
countryCode: countryCodeProp,
|
|
11
11
|
title = DEFAULT_TITLE,
|
|
12
12
|
emptyMessage = DEFAULT_EMPTY,
|
|
13
|
+
wishlistProductIds,
|
|
13
14
|
}: PowerhouseCarouselProps) {
|
|
14
15
|
const countryCode =
|
|
15
16
|
countryCodeProp?.toLowerCase() ||
|
|
@@ -47,7 +48,12 @@ export default async function PowerhouseCarousel({
|
|
|
47
48
|
{list.length === 0 ? (
|
|
48
49
|
<p className="powerhouse-carousel__empty">{emptyMessage}</p>
|
|
49
50
|
) : (
|
|
50
|
-
<ProductCarousel
|
|
51
|
+
<ProductCarousel
|
|
52
|
+
products={list}
|
|
53
|
+
region={displayRegion ?? undefined}
|
|
54
|
+
countryCode={countryCode}
|
|
55
|
+
wishlistProductIds={wishlistProductIds}
|
|
56
|
+
/>
|
|
51
57
|
)}
|
|
52
58
|
</section>
|
|
53
59
|
)
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import { useEffect, useState, type MouseEvent } from "react"
|
|
4
|
+
import { useRouter } from "next/navigation"
|
|
5
|
+
import {
|
|
6
|
+
addToWishlist,
|
|
7
|
+
getWishlistProductIds,
|
|
8
|
+
removeFromWishlist,
|
|
9
|
+
} from "@pradip1995/commerce-core/client/actions/wishlist"
|
|
10
|
+
import LoginRequiredModal from "@pradip1995/segment-login-popup/required"
|
|
11
|
+
|
|
12
|
+
type WishlistButtonProps = {
|
|
13
|
+
productId?: string | null
|
|
14
|
+
countryCode: string
|
|
15
|
+
wishlistProductIds?: string[]
|
|
16
|
+
className?: string
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export default function WishlistButton({
|
|
20
|
+
productId,
|
|
21
|
+
countryCode,
|
|
22
|
+
wishlistProductIds,
|
|
23
|
+
className = "powerhouse-carousel__wishlist",
|
|
24
|
+
}: WishlistButtonProps) {
|
|
25
|
+
const router = useRouter()
|
|
26
|
+
const [wishlisted, setWishlisted] = useState(false)
|
|
27
|
+
const [loading, setLoading] = useState(false)
|
|
28
|
+
const [loginRequired, setLoginRequired] = useState(false)
|
|
29
|
+
|
|
30
|
+
useEffect(() => {
|
|
31
|
+
if (!productId || wishlistProductIds === undefined) return
|
|
32
|
+
setWishlisted(wishlistProductIds.includes(productId))
|
|
33
|
+
}, [productId, wishlistProductIds])
|
|
34
|
+
|
|
35
|
+
async function handleToggle(event: MouseEvent) {
|
|
36
|
+
event.preventDefault()
|
|
37
|
+
event.stopPropagation()
|
|
38
|
+
if (!productId || loading) return
|
|
39
|
+
|
|
40
|
+
setLoading(true)
|
|
41
|
+
try {
|
|
42
|
+
let currentlyWishlisted = wishlisted
|
|
43
|
+
if (wishlistProductIds === undefined) {
|
|
44
|
+
try {
|
|
45
|
+
const ids = await getWishlistProductIds()
|
|
46
|
+
currentlyWishlisted = ids.includes(productId)
|
|
47
|
+
setWishlisted(currentlyWishlisted)
|
|
48
|
+
} catch {
|
|
49
|
+
currentlyWishlisted = false
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const result = currentlyWishlisted
|
|
54
|
+
? await removeFromWishlist(productId)
|
|
55
|
+
: await addToWishlist(productId)
|
|
56
|
+
|
|
57
|
+
if (result.success) {
|
|
58
|
+
setWishlisted(!currentlyWishlisted)
|
|
59
|
+
router.refresh()
|
|
60
|
+
return
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (result.error?.toLowerCase().includes("login")) {
|
|
64
|
+
setLoginRequired(true)
|
|
65
|
+
}
|
|
66
|
+
} finally {
|
|
67
|
+
setLoading(false)
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return (
|
|
72
|
+
<>
|
|
73
|
+
<button
|
|
74
|
+
type="button"
|
|
75
|
+
className={`${className}${wishlisted ? " is-active" : ""}${loading ? " is-loading" : ""}`}
|
|
76
|
+
onClick={handleToggle}
|
|
77
|
+
disabled={loading || !productId}
|
|
78
|
+
aria-label={wishlisted ? "Remove from wishlist" : "Add to wishlist"}
|
|
79
|
+
aria-pressed={wishlisted}
|
|
80
|
+
>
|
|
81
|
+
<svg viewBox="0 0 24 24" aria-hidden className={`${className}-icon`}>
|
|
82
|
+
<path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z" />
|
|
83
|
+
</svg>
|
|
84
|
+
</button>
|
|
85
|
+
<LoginRequiredModal
|
|
86
|
+
isOpen={loginRequired}
|
|
87
|
+
onClose={() => setLoginRequired(false)}
|
|
88
|
+
countryCode={countryCode}
|
|
89
|
+
message="Please log in to save items to your wishlist."
|
|
90
|
+
/>
|
|
91
|
+
</>
|
|
92
|
+
)
|
|
93
|
+
}
|