@pradip1995/segment-powerhouse-deals 0.1.2 → 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-deals",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "license": "MIT",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -25,6 +25,7 @@
25
25
  "dependencies": {
26
26
  "@pradip1995/commerce-core": "^4.0.0",
27
27
  "@pradip1995/medusa-connector": "^0.2.0",
28
+ "@pradip1995/segment-login-popup": "^0.1.2",
28
29
  "@pradip1995/segment-primitives": "^0.4.0"
29
30
  },
30
31
  "devDependencies": {
package/src/deal-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 DealCard({ product, region, countryCode }: Props) {
19
+ export default function DealCard({ product, region, countryCode, wishlistProductIds }: Props) {
18
20
  const router = useRouter()
19
21
  const [adding, setAdding] = useState(false)
20
22
  const variant = product.variants?.[0]
@@ -55,17 +57,24 @@ export default function DealCard({ product, region, countryCode }: Props) {
55
57
 
56
58
  return (
57
59
  <article className={`powerhouse-deals__card${onSale ? " is-sale" : ""}`}>
58
- <LocalizedLink href={href} countryCode={countryCode} className="powerhouse-deals__card-media">
59
- {product.thumbnail?.trim() ? (
60
- <img src={product.thumbnail.trim()} alt={product.title || ""} className="powerhouse-deals__card-image" />
61
- ) : (
62
- <div className="powerhouse-deals__card-placeholder" />
63
- )}
64
- {onSale && saved != null ? (
65
- <span className="powerhouse-deals__badge">Save {formatPrice(saved, currency)}</span>
66
- ) : null}
67
- {!inStock ? <span className="powerhouse-deals__sold">Sold out</span> : null}
68
- </LocalizedLink>
60
+ <div className="powerhouse-deals__media-wrap">
61
+ <LocalizedLink href={href} countryCode={countryCode} className="powerhouse-deals__card-media">
62
+ {product.thumbnail?.trim() ? (
63
+ <img src={product.thumbnail.trim()} alt={product.title || ""} className="powerhouse-deals__card-image" />
64
+ ) : (
65
+ <div className="powerhouse-deals__card-placeholder" />
66
+ )}
67
+ {onSale && saved != null ? (
68
+ <span className="powerhouse-deals__badge">Save {formatPrice(saved, currency)}</span>
69
+ ) : null}
70
+ {!inStock ? <span className="powerhouse-deals__sold">Sold out</span> : null}
71
+ </LocalizedLink>
72
+ <WishlistButton
73
+ productId={product.id}
74
+ countryCode={countryCode}
75
+ wishlistProductIds={wishlistProductIds}
76
+ />
77
+ </div>
69
78
 
70
79
  <div className="powerhouse-deals__card-info">
71
80
  {price != null ? (
package/src/deals.css CHANGED
@@ -133,6 +133,10 @@
133
133
  background: #fff;
134
134
  }
135
135
 
136
+ .powerhouse-deals__media-wrap {
137
+ position: relative;
138
+ }
139
+
136
140
  .powerhouse-deals__card-media {
137
141
  position: relative;
138
142
  display: block;
@@ -141,6 +145,51 @@
141
145
  background: #f3f3f3;
142
146
  }
143
147
 
148
+ .powerhouse-deals__wishlist {
149
+ position: absolute;
150
+ top: 0.5rem;
151
+ right: 0.5rem;
152
+ z-index: 2;
153
+ display: inline-flex;
154
+ align-items: center;
155
+ justify-content: center;
156
+ width: 2.25rem;
157
+ height: 2.25rem;
158
+ padding: 0;
159
+ border: 1px solid rgba(29, 29, 29, 0.12);
160
+ background: rgba(255, 255, 255, 0.94);
161
+ color: #1d1d1d;
162
+ cursor: pointer;
163
+ transition: color 0.2s ease, border-color 0.2s ease;
164
+ }
165
+
166
+ .powerhouse-deals__wishlist:hover {
167
+ border-color: #1d1d1d;
168
+ }
169
+
170
+ .powerhouse-deals__wishlist.is-active {
171
+ color: #c1272d;
172
+ border-color: #c1272d;
173
+ }
174
+
175
+ .powerhouse-deals__wishlist.is-loading {
176
+ opacity: 0.55;
177
+ cursor: wait;
178
+ }
179
+
180
+ .powerhouse-deals__wishlist-icon {
181
+ width: 1.05rem;
182
+ height: 1.05rem;
183
+ fill: none;
184
+ stroke: currentColor;
185
+ stroke-width: 1.75;
186
+ stroke-linejoin: round;
187
+ }
188
+
189
+ .powerhouse-deals__wishlist.is-active .powerhouse-deals__wishlist-icon {
190
+ fill: currentColor;
191
+ }
192
+
144
193
  .powerhouse-deals__card-image,
145
194
  .powerhouse-deals__card-placeholder {
146
195
  width: 100%;
package/src/segment.tsx CHANGED
@@ -24,6 +24,7 @@ export default async function PowerhouseDeals({
24
24
  promoLink = DEFAULT_PROMO_LINK,
25
25
  promoImage = DEFAULT_PROMO_IMAGE,
26
26
  emptyMessage = DEFAULT_EMPTY,
27
+ wishlistProductIds,
27
28
  }: PowerhouseDealsProps) {
28
29
  const countryCode =
29
30
  countryCodeProp?.toLowerCase() ||
@@ -95,6 +96,7 @@ export default async function PowerhouseDeals({
95
96
  product={product}
96
97
  region={displayRegion ?? undefined}
97
98
  countryCode={countryCode}
99
+ wishlistProductIds={wishlistProductIds}
98
100
  />
99
101
  ))
100
102
  )}
@@ -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-deals__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
+ }