@pradip1995/segment-powerhouse-cart 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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pradip1995/segment-powerhouse-cart",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "license": "MIT",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -26,7 +26,8 @@
26
26
  },
27
27
  "dependencies": {
28
28
  "@pradip1995/segment-analytics": "^0.2.4",
29
- "@pradip1995/segment-primitives": "^0.4.0"
29
+ "@pradip1995/segment-login-popup": "^0.1.3",
30
+ "@pradip1995/segment-primitives": "^0.4.11"
30
31
  },
31
32
  "devDependencies": {
32
33
  "@medusajs/types": "^2.0.0",
package/src/cart.css CHANGED
@@ -411,3 +411,156 @@
411
411
  text-align: center;
412
412
  }
413
413
  }
414
+
415
+ @keyframes powerhouseModalFadeIn {
416
+ from {
417
+ opacity: 0;
418
+ transform: scale(0.95) translateY(10px);
419
+ }
420
+ to {
421
+ opacity: 1;
422
+ transform: scale(1) translateY(0);
423
+ }
424
+ }
425
+
426
+ @keyframes powerhouseBackdropFade {
427
+ from { opacity: 0; }
428
+ to { opacity: 1; }
429
+ }
430
+
431
+ .powerhouse-cart-confirm {
432
+ position: fixed;
433
+ inset: 0;
434
+ z-index: 99999;
435
+ display: flex;
436
+ align-items: center;
437
+ justify-content: center;
438
+ padding: 1.25rem;
439
+ }
440
+
441
+ .powerhouse-cart-confirm__backdrop {
442
+ position: absolute;
443
+ inset: 0;
444
+ border: 0;
445
+ background: rgba(15, 10, 25, 0.55);
446
+ backdrop-filter: blur(6px);
447
+ -webkit-backdrop-filter: blur(6px);
448
+ animation: powerhouseBackdropFade 0.2s ease-out forwards;
449
+ }
450
+
451
+ .powerhouse-cart-confirm__panel {
452
+ position: relative;
453
+ width: min(25.5rem, 100%);
454
+ padding: 2.25rem 2rem 1.75rem;
455
+ background: #ffffff;
456
+ border-radius: 1.25rem;
457
+ border: 1px solid rgba(59, 31, 78, 0.1);
458
+ box-shadow:
459
+ 0 20px 40px -10px rgba(30, 15, 45, 0.25),
460
+ 0 2px 10px rgba(0, 0, 0, 0.05);
461
+ text-align: center;
462
+ animation: powerhouseModalFadeIn 0.25s cubic-bezier(0.16, 1, 0.3, 1) forwards;
463
+ }
464
+
465
+ .powerhouse-cart-confirm__close {
466
+ position: absolute;
467
+ top: 1rem;
468
+ right: 1rem;
469
+ display: flex;
470
+ align-items: center;
471
+ justify-content: center;
472
+ width: 2rem;
473
+ height: 2rem;
474
+ padding: 0;
475
+ border: none;
476
+ border-radius: 9999px;
477
+ background: rgba(59, 31, 78, 0.05);
478
+ color: #6b7280;
479
+ font-size: 0.875rem;
480
+ line-height: 1;
481
+ cursor: pointer;
482
+ transition: all 0.2s ease;
483
+ }
484
+
485
+ .powerhouse-cart-confirm__close:hover {
486
+ background: rgba(59, 31, 78, 0.12);
487
+ color: #111827;
488
+ }
489
+
490
+ .powerhouse-cart-confirm__title {
491
+ margin: 0 0 0.5rem;
492
+ font-family: var(--font-heading, Georgia, serif);
493
+ font-size: 1.4rem;
494
+ font-weight: 500;
495
+ letter-spacing: -0.01em;
496
+ color: #111827;
497
+ }
498
+
499
+ .powerhouse-cart-confirm__text {
500
+ margin: 0 0 1.5rem;
501
+ font-size: 0.875rem;
502
+ line-height: 1.5;
503
+ color: #4b5563;
504
+ }
505
+
506
+ .powerhouse-cart-confirm__actions {
507
+ display: flex;
508
+ flex-direction: column;
509
+ gap: 0.625rem;
510
+ }
511
+
512
+ .powerhouse-cart-confirm__btn {
513
+ display: inline-flex;
514
+ align-items: center;
515
+ justify-content: center;
516
+ min-height: 2.75rem;
517
+ padding: 0.7rem 1.25rem;
518
+ border-radius: 9999px;
519
+ font-size: 0.75rem;
520
+ font-weight: 600;
521
+ letter-spacing: 0.09em;
522
+ text-transform: uppercase;
523
+ cursor: pointer;
524
+ transition: all 0.2s ease;
525
+ }
526
+
527
+ .powerhouse-cart-confirm__btn--primary {
528
+ border: 1px solid #362447;
529
+ background: #362447;
530
+ color: #ffffff;
531
+ box-shadow: 0 4px 14px rgba(54, 36, 71, 0.25);
532
+ }
533
+
534
+ .powerhouse-cart-confirm__btn--primary:hover:not(:disabled) {
535
+ background: #4a3260;
536
+ border-color: #4a3260;
537
+ box-shadow: 0 6px 18px rgba(54, 36, 71, 0.35);
538
+ }
539
+
540
+ .powerhouse-cart-confirm__btn--danger {
541
+ border: 1px solid #dc2626;
542
+ background: #ffffff;
543
+ color: #dc2626;
544
+ }
545
+
546
+ .powerhouse-cart-confirm__btn--danger:hover:not(:disabled) {
547
+ background: #fef2f2;
548
+ border-color: #b91c1c;
549
+ color: #b91c1c;
550
+ }
551
+
552
+ .powerhouse-cart-confirm__btn--ghost {
553
+ border: 1px solid transparent;
554
+ background: transparent;
555
+ color: #6b7280;
556
+ }
557
+
558
+ .powerhouse-cart-confirm__btn--ghost:hover:not(:disabled) {
559
+ background: rgba(59, 31, 78, 0.05);
560
+ color: #111827;
561
+ }
562
+
563
+ .powerhouse-cart-confirm__btn:disabled {
564
+ opacity: 0.75;
565
+ cursor: not-allowed;
566
+ }
package/src/segment.tsx CHANGED
@@ -2,9 +2,11 @@
2
2
 
3
3
  import Image from "next/image"
4
4
  import { useRouter } from "next/navigation"
5
- import { useTransition } from "react"
5
+ import { useEffect, useState, useTransition } from "react"
6
+ import { createPortal } from "react-dom"
6
7
  import type { HttpTypes } from "@medusajs/types"
7
8
  import { deleteLineItem, updateLineItem } from "@pradip1995/commerce-core/client/actions/cart"
9
+ import { addToWishlist } from "@pradip1995/commerce-core/client/actions/wishlist"
8
10
  import {
9
11
  trackCartLineItemQuantityChange,
10
12
  trackCartLineItemRemoved,
@@ -12,6 +14,7 @@ import {
12
14
  import LocalizedLink from "@pradip1995/segment-primitives/localized-link"
13
15
  import { formatPrice } from "@pradip1995/segment-primitives/format-price"
14
16
  import { resolveMediaUrl } from "@pradip1995/segment-primitives/resolve-media-url"
17
+ import LoginRequiredModal from "@pradip1995/segment-login-popup/required"
15
18
  import {
16
19
  DEFAULT_CHECKOUT_LABEL,
17
20
  DEFAULT_CONTINUE_HREF,
@@ -131,10 +134,17 @@ function LineItemRow({
131
134
  }) {
132
135
  const router = useRouter()
133
136
  const [pending, startTransition] = useTransition()
137
+ const [confirmOpen, setConfirmOpen] = useState(false)
138
+ const [loginRequired, setLoginRequired] = useState(false)
139
+ const [mounted, setMounted] = useState(false)
134
140
  const thumbnail = lineItemImage(item)
135
141
  const variantLabel = item.variant?.title
136
142
  const showVariant = Boolean(variantLabel && !isPlaceholderVariant(variantLabel))
137
143
 
144
+ useEffect(() => {
145
+ setMounted(true)
146
+ }, [])
147
+
138
148
  function changeQty(next: number) {
139
149
  if (next < 1 || !item.id) return
140
150
  const previousQuantity = item.quantity ?? 1
@@ -145,11 +155,36 @@ function LineItemRow({
145
155
  })
146
156
  }
147
157
 
148
- function remove() {
158
+ function removeFromCart() {
149
159
  if (!item.id) return
150
160
  startTransition(async () => {
151
161
  trackCartLineItemRemoved(item, currency)
152
162
  await deleteLineItem(item.id)
163
+ setConfirmOpen(false)
164
+ router.refresh()
165
+ })
166
+ }
167
+
168
+ function moveToWishlist() {
169
+ const productId = item.product_id
170
+ if (!productId) {
171
+ removeFromCart()
172
+ return
173
+ }
174
+ startTransition(async () => {
175
+ const result = await addToWishlist(productId)
176
+ if (!result.success && result.error?.toLowerCase().includes("login")) {
177
+ setConfirmOpen(false)
178
+ setLoginRequired(true)
179
+ return
180
+ }
181
+ if (!result.success) {
182
+ setConfirmOpen(false)
183
+ return
184
+ }
185
+ trackCartLineItemRemoved(item, currency)
186
+ if (item.id) await deleteLineItem(item.id)
187
+ setConfirmOpen(false)
153
188
  router.refresh()
154
189
  })
155
190
  }
@@ -201,11 +236,77 @@ function LineItemRow({
201
236
  +
202
237
  </button>
203
238
  </div>
204
- <button type="button" className="powerhouse-cart__remove" onClick={remove} disabled={pending}>
239
+ <button
240
+ type="button"
241
+ className="powerhouse-cart__remove"
242
+ onClick={() => setConfirmOpen(true)}
243
+ disabled={pending}
244
+ >
205
245
  Remove
206
246
  </button>
207
247
  </div>
208
248
  <p className="powerhouse-cart__total">{formatPrice(lineTotal(item), currency)}</p>
249
+
250
+ {confirmOpen && mounted
251
+ ? createPortal(
252
+ <div className="powerhouse-cart-confirm">
253
+ <button
254
+ type="button"
255
+ className="powerhouse-cart-confirm__backdrop"
256
+ aria-label="Close"
257
+ onClick={() => setConfirmOpen(false)}
258
+ />
259
+ <div className="powerhouse-cart-confirm__panel" role="dialog" aria-modal="true">
260
+ <button
261
+ type="button"
262
+ className="powerhouse-cart-confirm__close"
263
+ aria-label="Close dialog"
264
+ onClick={() => setConfirmOpen(false)}
265
+ >
266
+
267
+ </button>
268
+ <h3 className="powerhouse-cart-confirm__title">Remove this item?</h3>
269
+ <p className="powerhouse-cart-confirm__text">
270
+ Move it to your wishlist to save it for later, or remove it from your cart.
271
+ </p>
272
+ <div className="powerhouse-cart-confirm__actions">
273
+ <button
274
+ type="button"
275
+ className="powerhouse-cart-confirm__btn powerhouse-cart-confirm__btn--primary"
276
+ disabled={pending}
277
+ onClick={moveToWishlist}
278
+ >
279
+ {pending ? "Saving…" : "Move to Wishlist"}
280
+ </button>
281
+ <button
282
+ type="button"
283
+ className="powerhouse-cart-confirm__btn powerhouse-cart-confirm__btn--danger"
284
+ disabled={pending}
285
+ onClick={removeFromCart}
286
+ >
287
+ Remove the Product
288
+ </button>
289
+ <button
290
+ type="button"
291
+ className="powerhouse-cart-confirm__btn powerhouse-cart-confirm__btn--ghost"
292
+ disabled={pending}
293
+ onClick={() => setConfirmOpen(false)}
294
+ >
295
+ Keep in cart
296
+ </button>
297
+ </div>
298
+ </div>
299
+ </div>,
300
+ document.body
301
+ )
302
+ : null}
303
+
304
+ <LoginRequiredModal
305
+ isOpen={loginRequired}
306
+ onClose={() => setLoginRequired(false)}
307
+ countryCode={countryCode}
308
+ message="Please log in to move this item to your wishlist."
309
+ />
209
310
  </article>
210
311
  )
211
312
  }