@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 +2 -1
- package/src/deal-card.tsx +21 -12
- package/src/deals.css +49 -0
- package/src/segment.tsx +2 -0
- package/src/wishlist-button.tsx +93 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pradip1995/segment-powerhouse-deals",
|
|
3
|
-
"version": "0.1.
|
|
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
|
-
<
|
|
59
|
-
{
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
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
|
+
}
|