@pradip1995/segment-powerhouse-shop 0.1.3 → 0.1.5
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/product-card.tsx +21 -11
- package/src/shop.css +93 -8
- package/src/shop.tsx +1 -0
- package/src/types.ts +1 -0
- package/src/wishlist-button.tsx +94 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pradip1995/segment-powerhouse-shop",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
26
|
"@pradip1995/commerce-core": "^4.0.0",
|
|
27
|
+
"@pradip1995/segment-login-popup": "^0.1.2",
|
|
27
28
|
"@pradip1995/segment-primitives": "^0.4.0"
|
|
28
29
|
},
|
|
29
30
|
"devDependencies": {
|
package/src/product-card.tsx
CHANGED
|
@@ -7,6 +7,7 @@ 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
|
function stripHtml(value?: string | null) {
|
|
12
13
|
if (!value) return ""
|
|
@@ -23,10 +24,12 @@ export default function ShopProductCard({
|
|
|
23
24
|
product,
|
|
24
25
|
countryCode,
|
|
25
26
|
layout = "grid",
|
|
27
|
+
wishlistProductIds,
|
|
26
28
|
}: {
|
|
27
29
|
product: HttpTypes.StoreProduct
|
|
28
30
|
countryCode: string
|
|
29
31
|
layout?: "grid" | "list"
|
|
32
|
+
wishlistProductIds?: string[]
|
|
30
33
|
}) {
|
|
31
34
|
const router = useRouter()
|
|
32
35
|
const [adding, setAdding] = useState(false)
|
|
@@ -110,17 +113,24 @@ export default function ShopProductCard({
|
|
|
110
113
|
|
|
111
114
|
return (
|
|
112
115
|
<article className={`powerhouse-shop__card${onSale ? " is-sale" : ""}${isList ? " is-list-card" : ""}`}>
|
|
113
|
-
<
|
|
114
|
-
{
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
116
|
+
<div className="powerhouse-shop__media-wrap">
|
|
117
|
+
<LocalizedLink href={href} countryCode={countryCode} className="powerhouse-shop__media" tabIndex={-1}>
|
|
118
|
+
{product.thumbnail?.trim() ? (
|
|
119
|
+
<img src={product.thumbnail.trim()} alt={product.title || ""} />
|
|
120
|
+
) : (
|
|
121
|
+
<div className="powerhouse-shop__placeholder" />
|
|
122
|
+
)}
|
|
123
|
+
{onSale && saved != null ? (
|
|
124
|
+
<span className="powerhouse-shop__badge">Save {formatPrice(saved, currency)}</span>
|
|
125
|
+
) : null}
|
|
126
|
+
{!inStock && !isList ? <span className="powerhouse-shop__sold">Sold out</span> : null}
|
|
127
|
+
</LocalizedLink>
|
|
128
|
+
<WishlistButton
|
|
129
|
+
productId={product.id}
|
|
130
|
+
countryCode={countryCode}
|
|
131
|
+
wishlistProductIds={wishlistProductIds}
|
|
132
|
+
/>
|
|
133
|
+
</div>
|
|
124
134
|
|
|
125
135
|
{isList ? (
|
|
126
136
|
<>
|
package/src/shop.css
CHANGED
|
@@ -458,7 +458,7 @@ html.powerhouse-filters-open body {
|
|
|
458
458
|
border: 1px solid #dddddd;
|
|
459
459
|
}
|
|
460
460
|
|
|
461
|
-
.powerhouse-shop__grid.is-list .powerhouse-shop__media {
|
|
461
|
+
.powerhouse-shop__grid.is-list .powerhouse-shop__media-wrap {
|
|
462
462
|
grid-row: 1 / 3;
|
|
463
463
|
}
|
|
464
464
|
|
|
@@ -544,11 +544,21 @@ html.powerhouse-filters-open body {
|
|
|
544
544
|
}
|
|
545
545
|
|
|
546
546
|
.powerhouse-shop__card {
|
|
547
|
+
position: relative;
|
|
548
|
+
z-index: 1;
|
|
547
549
|
display: flex;
|
|
548
550
|
flex-direction: column;
|
|
549
551
|
height: 100%;
|
|
550
552
|
min-width: 0;
|
|
551
553
|
max-width: 100%;
|
|
554
|
+
padding: 0.6875rem;
|
|
555
|
+
border: 1px solid #dddddd;
|
|
556
|
+
box-sizing: border-box;
|
|
557
|
+
background: #fff;
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
.powerhouse-shop__media-wrap {
|
|
561
|
+
position: relative;
|
|
552
562
|
}
|
|
553
563
|
|
|
554
564
|
.powerhouse-shop__media {
|
|
@@ -560,6 +570,51 @@ html.powerhouse-filters-open body {
|
|
|
560
570
|
aspect-ratio: 1;
|
|
561
571
|
}
|
|
562
572
|
|
|
573
|
+
.powerhouse-shop__wishlist {
|
|
574
|
+
position: absolute;
|
|
575
|
+
top: 0.5rem;
|
|
576
|
+
right: 0.5rem;
|
|
577
|
+
z-index: 2;
|
|
578
|
+
display: inline-flex;
|
|
579
|
+
align-items: center;
|
|
580
|
+
justify-content: center;
|
|
581
|
+
width: 2.25rem;
|
|
582
|
+
height: 2.25rem;
|
|
583
|
+
padding: 0;
|
|
584
|
+
border: 1px solid rgba(29, 29, 29, 0.12);
|
|
585
|
+
background: rgba(255, 255, 255, 0.94);
|
|
586
|
+
color: #1d1d1d;
|
|
587
|
+
cursor: pointer;
|
|
588
|
+
transition: color 0.2s ease, background 0.2s ease, border-color 0.2s ease;
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
.powerhouse-shop__wishlist:hover {
|
|
592
|
+
border-color: #1d1d1d;
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
.powerhouse-shop__wishlist.is-active {
|
|
596
|
+
color: #c1272d;
|
|
597
|
+
border-color: #c1272d;
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
.powerhouse-shop__wishlist.is-loading {
|
|
601
|
+
opacity: 0.55;
|
|
602
|
+
cursor: wait;
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
.powerhouse-shop__wishlist-icon {
|
|
606
|
+
width: 1.05rem;
|
|
607
|
+
height: 1.05rem;
|
|
608
|
+
fill: none;
|
|
609
|
+
stroke: currentColor;
|
|
610
|
+
stroke-width: 1.75;
|
|
611
|
+
stroke-linejoin: round;
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
.powerhouse-shop__wishlist.is-active .powerhouse-shop__wishlist-icon {
|
|
615
|
+
fill: currentColor;
|
|
616
|
+
}
|
|
617
|
+
|
|
563
618
|
.powerhouse-shop__media img,
|
|
564
619
|
.powerhouse-shop__placeholder {
|
|
565
620
|
position: absolute;
|
|
@@ -586,8 +641,10 @@ html.powerhouse-filters-open body {
|
|
|
586
641
|
}
|
|
587
642
|
|
|
588
643
|
.powerhouse-shop__sold {
|
|
589
|
-
left:
|
|
590
|
-
right:
|
|
644
|
+
left: 0.5rem;
|
|
645
|
+
right: auto;
|
|
646
|
+
top: auto;
|
|
647
|
+
bottom: 0.5rem;
|
|
591
648
|
background: #1d1d1d;
|
|
592
649
|
color: #fff;
|
|
593
650
|
}
|
|
@@ -851,7 +908,7 @@ html.powerhouse-filters-open body {
|
|
|
851
908
|
padding: 1.25rem;
|
|
852
909
|
}
|
|
853
910
|
|
|
854
|
-
.powerhouse-shop__grid.is-list .powerhouse-shop__media {
|
|
911
|
+
.powerhouse-shop__grid.is-list .powerhouse-shop__media-wrap {
|
|
855
912
|
grid-row: auto;
|
|
856
913
|
}
|
|
857
914
|
|
|
@@ -921,9 +978,17 @@ html.powerhouse-filters-open body {
|
|
|
921
978
|
}
|
|
922
979
|
|
|
923
980
|
.powerhouse-shop__grid {
|
|
981
|
+
align-items: stretch;
|
|
982
|
+
overflow: visible;
|
|
924
983
|
grid-template-columns: repeat(3, minmax(0, 1fr));
|
|
925
984
|
}
|
|
926
985
|
|
|
986
|
+
.powerhouse-shop__grid:not(.is-list) .powerhouse-shop__card:hover,
|
|
987
|
+
.powerhouse-shop__grid:not(.is-list) .powerhouse-shop__card:focus-within {
|
|
988
|
+
z-index: 8;
|
|
989
|
+
box-shadow: 0 6px 18px rgba(29, 29, 29, 0.12);
|
|
990
|
+
}
|
|
991
|
+
|
|
927
992
|
.powerhouse-shop__grid.is-list {
|
|
928
993
|
grid-template-columns: 1fr;
|
|
929
994
|
}
|
|
@@ -946,11 +1011,22 @@ html.powerhouse-filters-open body {
|
|
|
946
1011
|
width: 100%;
|
|
947
1012
|
}
|
|
948
1013
|
|
|
949
|
-
.powerhouse-shop__actions {
|
|
1014
|
+
.powerhouse-shop__grid:not(.is-list) .powerhouse-shop__actions {
|
|
1015
|
+
position: absolute;
|
|
1016
|
+
left: -1px;
|
|
1017
|
+
right: -1px;
|
|
1018
|
+
top: calc(100% - 1px);
|
|
950
1019
|
flex-direction: row;
|
|
1020
|
+
margin-top: 0;
|
|
1021
|
+
padding: 0.75rem 0.6875rem 0.6875rem;
|
|
1022
|
+
border: 1px solid #dddddd;
|
|
1023
|
+
border-top: 0;
|
|
1024
|
+
background: #fff;
|
|
1025
|
+
box-sizing: border-box;
|
|
951
1026
|
opacity: 0;
|
|
1027
|
+
visibility: hidden;
|
|
952
1028
|
pointer-events: none;
|
|
953
|
-
transition: opacity 0.2s ease;
|
|
1029
|
+
transition: opacity 0.2s ease, visibility 0.2s ease;
|
|
954
1030
|
}
|
|
955
1031
|
|
|
956
1032
|
.powerhouse-shop__quickshop,
|
|
@@ -960,11 +1036,20 @@ html.powerhouse-filters-open body {
|
|
|
960
1036
|
min-width: 0;
|
|
961
1037
|
}
|
|
962
1038
|
|
|
963
|
-
.powerhouse-shop__card:hover .powerhouse-shop__actions,
|
|
964
|
-
.powerhouse-shop__card:focus-within .powerhouse-shop__actions
|
|
1039
|
+
.powerhouse-shop__grid:not(.is-list) .powerhouse-shop__card:hover .powerhouse-shop__actions,
|
|
1040
|
+
.powerhouse-shop__grid:not(.is-list) .powerhouse-shop__card:focus-within .powerhouse-shop__actions {
|
|
1041
|
+
opacity: 1;
|
|
1042
|
+
visibility: visible;
|
|
1043
|
+
pointer-events: auto;
|
|
1044
|
+
}
|
|
1045
|
+
|
|
965
1046
|
.powerhouse-shop__grid.is-list .powerhouse-shop__actions {
|
|
1047
|
+
position: static;
|
|
966
1048
|
opacity: 1;
|
|
1049
|
+
visibility: visible;
|
|
967
1050
|
pointer-events: auto;
|
|
1051
|
+
border: 0;
|
|
1052
|
+
background: transparent;
|
|
968
1053
|
}
|
|
969
1054
|
}
|
|
970
1055
|
|
package/src/shop.tsx
CHANGED
package/src/types.ts
CHANGED
|
@@ -0,0 +1,94 @@
|
|
|
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-shop__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
|
+
return
|
|
66
|
+
}
|
|
67
|
+
} finally {
|
|
68
|
+
setLoading(false)
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return (
|
|
73
|
+
<>
|
|
74
|
+
<button
|
|
75
|
+
type="button"
|
|
76
|
+
className={`${className}${wishlisted ? " is-active" : ""}${loading ? " is-loading" : ""}`}
|
|
77
|
+
onClick={handleToggle}
|
|
78
|
+
disabled={loading || !productId}
|
|
79
|
+
aria-label={wishlisted ? "Remove from wishlist" : "Add to wishlist"}
|
|
80
|
+
aria-pressed={wishlisted}
|
|
81
|
+
>
|
|
82
|
+
<svg viewBox="0 0 24 24" aria-hidden className={`${className}-icon`}>
|
|
83
|
+
<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" />
|
|
84
|
+
</svg>
|
|
85
|
+
</button>
|
|
86
|
+
<LoginRequiredModal
|
|
87
|
+
isOpen={loginRequired}
|
|
88
|
+
onClose={() => setLoginRequired(false)}
|
|
89
|
+
countryCode={countryCode}
|
|
90
|
+
message="Please log in to save items to your wishlist."
|
|
91
|
+
/>
|
|
92
|
+
</>
|
|
93
|
+
)
|
|
94
|
+
}
|