@pradip1995/segment-powerhouse-deals 0.1.1

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 ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "@pradip1995/segment-powerhouse-deals",
3
+ "version": "0.1.1",
4
+ "license": "MIT",
5
+ "publishConfig": {
6
+ "access": "public"
7
+ },
8
+ "sideEffects": [
9
+ "./src/deals.css"
10
+ ],
11
+ "files": [
12
+ "src",
13
+ "public"
14
+ ],
15
+ "exports": {
16
+ ".": "./src/index.ts",
17
+ "./manifest": "./src/manifest.ts"
18
+ },
19
+ "peerDependencies": {
20
+ "@pradip1995/plugin-sdk": "^0.2.0",
21
+ "next": ">=15",
22
+ "react": ">=19",
23
+ "react-dom": ">=19"
24
+ },
25
+ "dependencies": {
26
+ "@pradip1995/commerce-core": "^4.0.0",
27
+ "@pradip1995/medusa-connector": "^0.2.0",
28
+ "@pradip1995/segment-primitives": "^0.4.0"
29
+ },
30
+ "devDependencies": {
31
+ "@medusajs/types": ">=2",
32
+ "@pradip1995/plugin-sdk": "^0.2.0",
33
+ "@types/react": "^19",
34
+ "react": "19.0.3",
35
+ "typescript": "^5.7.2"
36
+ },
37
+ "scripts": {
38
+ "typecheck": "tsc --noEmit",
39
+ "lint": "tsc --noEmit"
40
+ }
41
+ }
Binary file
@@ -0,0 +1,101 @@
1
+ "use client"
2
+
3
+ import { useState } from "react"
4
+ import { useRouter } from "next/navigation"
5
+ import { addToCart } from "@pradip1995/commerce-core/client/actions/cart"
6
+ import LocalizedLink from "@pradip1995/segment-primitives/localized-link"
7
+ import { formatPrice } from "@pradip1995/segment-primitives/format-price"
8
+ import { isNextRedirect } from "@pradip1995/segment-primitives/is-next-redirect"
9
+ import type { HttpTypes } from "@medusajs/types"
10
+
11
+ type Props = {
12
+ product: HttpTypes.StoreProduct
13
+ region?: HttpTypes.StoreRegion
14
+ countryCode: string
15
+ }
16
+
17
+ export default function DealCard({ product, region, countryCode }: Props) {
18
+ const router = useRouter()
19
+ const [adding, setAdding] = useState(false)
20
+ const variant = product.variants?.[0]
21
+ const price = variant?.calculated_price?.calculated_amount
22
+ const originalPrice = variant?.calculated_price?.original_amount
23
+ const currency = region?.currency_code || variant?.calculated_price?.currency_code || "inr"
24
+ const onSale = originalPrice != null && price != null && originalPrice > price
25
+ const saved = onSale && originalPrice != null && price != null ? originalPrice - price : null
26
+ const inventory = variant?.inventory_quantity
27
+ const href = `/products/${product.handle}`
28
+
29
+ const handleAdd = async (event: React.MouseEvent) => {
30
+ event.preventDefault()
31
+ event.stopPropagation()
32
+ if (!variant?.id || adding) return
33
+ setAdding(true)
34
+ try {
35
+ await addToCart({
36
+ variantId: variant.id,
37
+ quantity: 1,
38
+ countryCode: countryCode.toLowerCase(),
39
+ })
40
+ window.dispatchEvent(new CustomEvent("cart:item-added", { detail: { message: "Added to cart" } }))
41
+ router.refresh()
42
+ } catch (err) {
43
+ if (isNextRedirect(err)) throw err
44
+ const message = err instanceof Error ? err.message : "Could not add to cart"
45
+ window.dispatchEvent(new CustomEvent("cart:item-added", { detail: { message, variant: "error" } }))
46
+ } finally {
47
+ setAdding(false)
48
+ }
49
+ }
50
+
51
+ return (
52
+ <article className={`powerhouse-deals__card${onSale ? " is-sale" : ""}`}>
53
+ <LocalizedLink href={href} countryCode={countryCode} className="powerhouse-deals__card-media">
54
+ {product.thumbnail?.trim() ? (
55
+ <img src={product.thumbnail.trim()} alt={product.title || ""} className="powerhouse-deals__card-image" />
56
+ ) : (
57
+ <div className="powerhouse-deals__card-placeholder" />
58
+ )}
59
+ {onSale && saved != null ? (
60
+ <span className="powerhouse-deals__badge">Save {formatPrice(saved, currency)}</span>
61
+ ) : null}
62
+ </LocalizedLink>
63
+
64
+ <div className="powerhouse-deals__card-info">
65
+ {price != null ? (
66
+ <div className="powerhouse-deals__price">
67
+ {onSale && originalPrice != null ? (
68
+ <span className="powerhouse-deals__price-compare">{formatPrice(originalPrice, currency)}</span>
69
+ ) : null}
70
+ <span className="powerhouse-deals__price-current">{formatPrice(price, currency)}</span>
71
+ </div>
72
+ ) : null}
73
+
74
+ <h3 className="powerhouse-deals__card-title">
75
+ <LocalizedLink href={href} countryCode={countryCode}>
76
+ {product.title}
77
+ </LocalizedLink>
78
+ </h3>
79
+
80
+ {inventory != null && inventory > 0 && inventory <= 5 ? (
81
+ <p className="powerhouse-deals__stock">Only {inventory} left!</p>
82
+ ) : null}
83
+
84
+ <div className="powerhouse-deals__actions">
85
+ <LocalizedLink href={href} countryCode={countryCode} className="powerhouse-deals__quickshop">
86
+ Quick shop
87
+ </LocalizedLink>
88
+ <button
89
+ type="button"
90
+ className="powerhouse-deals__atc"
91
+ onClick={handleAdd}
92
+ disabled={adding || !variant?.id}
93
+ aria-label="Add to cart"
94
+ >
95
+ {adding ? "Adding…" : "Add to cart"}
96
+ </button>
97
+ </div>
98
+ </div>
99
+ </article>
100
+ )
101
+ }
package/src/deals.css ADDED
@@ -0,0 +1,329 @@
1
+ .powerhouse-deals {
2
+ --layout-container-max-width: 1400px;
3
+ max-width: var(--layout-container-max-width);
4
+ margin: 3.125rem auto 0;
5
+ padding: 0 10px;
6
+ }
7
+
8
+ .powerhouse-deals__heading {
9
+ margin: 0 0 1.25rem;
10
+ color: #1d1d1d;
11
+ font-family: var(--font-sans, inherit);
12
+ font-size: 1.5rem;
13
+ font-weight: 700;
14
+ letter-spacing: 0.08em;
15
+ line-height: 1.2;
16
+ text-align: center;
17
+ text-transform: uppercase;
18
+ }
19
+
20
+ .powerhouse-deals__grid {
21
+ display: grid;
22
+ grid-template-columns: repeat(2, 1fr);
23
+ gap: 10px;
24
+ }
25
+
26
+ .powerhouse-deals__promo {
27
+ position: relative;
28
+ grid-column: 1 / -1;
29
+ min-height: 355px;
30
+ overflow: hidden;
31
+ background: #1b1b1b;
32
+ }
33
+
34
+ .powerhouse-deals__promo-image {
35
+ position: absolute;
36
+ inset: 0;
37
+ width: 100%;
38
+ height: 100%;
39
+ object-fit: cover;
40
+ object-position: center;
41
+ }
42
+
43
+ .powerhouse-deals__promo-link {
44
+ position: relative;
45
+ z-index: 1;
46
+ display: flex;
47
+ flex-direction: column;
48
+ justify-content: flex-end;
49
+ align-items: flex-start;
50
+ width: 100%;
51
+ height: 100%;
52
+ min-height: inherit;
53
+ padding: 15px;
54
+ color: #fff;
55
+ text-decoration: none;
56
+ }
57
+
58
+ .powerhouse-deals__promo-link::before {
59
+ content: "";
60
+ position: absolute;
61
+ inset: 0;
62
+ background: #000;
63
+ opacity: 0.23;
64
+ z-index: -1;
65
+ }
66
+
67
+ .powerhouse-deals__promo-eyebrow {
68
+ display: block;
69
+ font-family: var(--font-sans, inherit);
70
+ font-size: 0.875rem;
71
+ font-weight: 300;
72
+ line-height: 1.2;
73
+ }
74
+
75
+ .powerhouse-deals__promo-title {
76
+ display: block;
77
+ margin: 0.75rem 0;
78
+ font-family: var(--font-heading, Georgia, serif);
79
+ font-size: 2.25rem;
80
+ font-weight: 700;
81
+ line-height: 1.15;
82
+ }
83
+
84
+ .powerhouse-deals__promo-cta {
85
+ display: inline-flex;
86
+ align-items: center;
87
+ gap: 0.45rem;
88
+ font-family: var(--font-sans, inherit);
89
+ font-size: 1rem;
90
+ font-weight: 500;
91
+ letter-spacing: 0.02em;
92
+ }
93
+
94
+ .powerhouse-deals__arrow path:first-child {
95
+ transform: translate(-8px);
96
+ }
97
+
98
+ .powerhouse-deals__arrow path:last-child {
99
+ transform: translate(-100%);
100
+ }
101
+
102
+ .powerhouse-deals__arrow path {
103
+ transition: transform 125ms cubic-bezier(0.4, 0, 0.2, 1);
104
+ }
105
+
106
+ .powerhouse-deals__promo-link:hover .powerhouse-deals__arrow path {
107
+ transform: translate(0);
108
+ }
109
+
110
+ .powerhouse-deals__empty {
111
+ grid-column: 1 / -1;
112
+ margin: 0;
113
+ padding: 2rem 0;
114
+ color: #6b6b6b;
115
+ font-size: 0.9375rem;
116
+ text-align: center;
117
+ }
118
+
119
+ .powerhouse-deals__card {
120
+ display: flex;
121
+ flex-direction: column;
122
+ height: 100%;
123
+ padding: 0.6875rem;
124
+ background: #fff;
125
+ transition: box-shadow 0.25s cubic-bezier(0.4, 0, 0.2, 1);
126
+ }
127
+
128
+ .powerhouse-deals__card:hover {
129
+ box-shadow: 0 2px 8px #80808033;
130
+ }
131
+
132
+ .powerhouse-deals__card-media {
133
+ position: relative;
134
+ display: block;
135
+ aspect-ratio: 1;
136
+ overflow: hidden;
137
+ background: #f3f3f3;
138
+ }
139
+
140
+ .powerhouse-deals__card-image,
141
+ .powerhouse-deals__card-placeholder {
142
+ width: 100%;
143
+ height: 100%;
144
+ object-fit: cover;
145
+ display: block;
146
+ }
147
+
148
+ .powerhouse-deals__badge {
149
+ position: absolute;
150
+ top: 0.6rem;
151
+ left: 0.6rem;
152
+ padding: 0.2rem 0.45rem;
153
+ background: #688600;
154
+ color: #fff;
155
+ font-family: var(--font-sans, inherit);
156
+ font-size: 0.75rem;
157
+ font-weight: 600;
158
+ line-height: 1.2;
159
+ }
160
+
161
+ .powerhouse-deals__card-info {
162
+ display: flex;
163
+ flex-direction: column;
164
+ flex: 1;
165
+ min-width: 0;
166
+ }
167
+
168
+ .powerhouse-deals__price {
169
+ margin-top: 0.25rem;
170
+ }
171
+
172
+ .powerhouse-deals__price-compare {
173
+ display: block;
174
+ color: #949494;
175
+ font-size: 0.875rem;
176
+ text-decoration: line-through;
177
+ }
178
+
179
+ .powerhouse-deals__price-current {
180
+ display: block;
181
+ margin-top: 0.125rem;
182
+ color: #1d1d1d;
183
+ font-size: 1.375rem;
184
+ font-weight: 500;
185
+ line-height: 1.2;
186
+ }
187
+
188
+ .powerhouse-deals__card.is-sale .powerhouse-deals__price-current {
189
+ color: #688600;
190
+ }
191
+
192
+ .powerhouse-deals__card-title {
193
+ margin: 0.625rem 0 0;
194
+ font-family: var(--font-sans, inherit);
195
+ font-size: 1rem;
196
+ font-weight: 300;
197
+ line-height: 1.3125;
198
+ }
199
+
200
+ .powerhouse-deals__card-title a {
201
+ color: #1d1d1d;
202
+ text-decoration: none;
203
+ }
204
+
205
+ .powerhouse-deals__stock {
206
+ margin: 0.5rem 0 0;
207
+ color: #688600;
208
+ font-size: 0.875rem;
209
+ }
210
+
211
+ .powerhouse-deals__actions {
212
+ display: flex;
213
+ flex-wrap: wrap;
214
+ gap: 0.5rem;
215
+ margin-top: auto;
216
+ padding-top: 0.75rem;
217
+ }
218
+
219
+ .powerhouse-deals__quickshop,
220
+ .powerhouse-deals__atc {
221
+ display: inline-flex;
222
+ align-items: center;
223
+ justify-content: center;
224
+ min-height: 2.5rem;
225
+ padding: 0.55rem 0.9rem;
226
+ border-radius: 2px;
227
+ font-family: var(--font-sans, inherit);
228
+ font-size: 0.875rem;
229
+ font-weight: 500;
230
+ letter-spacing: 0.04em;
231
+ text-decoration: none;
232
+ cursor: pointer;
233
+ }
234
+
235
+ .powerhouse-deals__quickshop {
236
+ background: #f1eeae;
237
+ border: 1px solid #f2f682;
238
+ color: #1d1d1d;
239
+ }
240
+
241
+ .powerhouse-deals__quickshop:hover {
242
+ background: #f4f1be;
243
+ }
244
+
245
+ .powerhouse-deals__atc {
246
+ background: #2c2b2b;
247
+ border: 1px solid #2c2b2b;
248
+ color: #fff;
249
+ }
250
+
251
+ .powerhouse-deals__atc:hover {
252
+ background: #414040;
253
+ }
254
+
255
+ .powerhouse-deals__atc:disabled {
256
+ opacity: 0.65;
257
+ cursor: wait;
258
+ }
259
+
260
+ @media screen and (min-width: 720px) {
261
+ .powerhouse-deals {
262
+ padding: 0 20px;
263
+ }
264
+
265
+ .powerhouse-deals__grid {
266
+ grid-template-columns: repeat(4, 1fr);
267
+ gap: 10px;
268
+ }
269
+ }
270
+
271
+ @media screen and (min-width: 860px) {
272
+ .powerhouse-deals {
273
+ margin-top: 4.25rem;
274
+ }
275
+
276
+ .powerhouse-deals__heading {
277
+ margin-bottom: 1.75rem;
278
+ }
279
+
280
+ .powerhouse-deals__promo-link {
281
+ padding: 1.75rem;
282
+ }
283
+
284
+ .powerhouse-deals__card {
285
+ padding: 1rem;
286
+ }
287
+ }
288
+
289
+ @media screen and (min-width: 1080px) {
290
+ .powerhouse-deals__grid {
291
+ grid-template-columns: repeat(5, 1fr);
292
+ gap: 20px;
293
+ }
294
+
295
+ .powerhouse-deals__promo {
296
+ grid-column: span 2;
297
+ grid-row: span 2;
298
+ min-height: 0;
299
+ }
300
+
301
+ .powerhouse-deals__promo-title {
302
+ font-size: 2.55rem;
303
+ }
304
+
305
+ .powerhouse-deals__actions {
306
+ opacity: 0;
307
+ pointer-events: none;
308
+ transition: opacity 0.2s ease;
309
+ }
310
+
311
+ .powerhouse-deals__card:hover .powerhouse-deals__actions {
312
+ opacity: 1;
313
+ pointer-events: auto;
314
+ }
315
+ }
316
+
317
+ @media screen and (max-width: 859px) {
318
+ .powerhouse-deals__promo-title {
319
+ font-size: 2.109375rem;
320
+ }
321
+
322
+ .powerhouse-deals__price-current {
323
+ font-size: 1.2890625rem;
324
+ }
325
+
326
+ .powerhouse-deals__card-title {
327
+ font-size: 0.9375rem;
328
+ }
329
+ }
@@ -0,0 +1,7 @@
1
+ export const DEFAULT_TITLE = "Deals of the Week"
2
+ export const DEFAULT_PROMO_EYEBROW = "Seasonal Clearance Sale"
3
+ export const DEFAULT_PROMO_TITLE = "Save up to 40%"
4
+ export const DEFAULT_PROMO_BUTTON = "Shop Sale"
5
+ export const DEFAULT_PROMO_LINK = "/store"
6
+ export const DEFAULT_PROMO_IMAGE = "/deals-promo.jpg"
7
+ export const DEFAULT_EMPTY = "No deals right now. Check back soon!"
package/src/index.ts ADDED
@@ -0,0 +1,2 @@
1
+ export { default } from "./segment"
2
+ export { default as manifest } from "./manifest"
@@ -0,0 +1,10 @@
1
+ import type { SegmentManifest } from "@pradip1995/plugin-sdk"
2
+
3
+ const manifest: SegmentManifest = {
4
+ id: "powerhouse-deals",
5
+ type: "segment",
6
+ version: "0.1.0",
7
+ compatibleFramework: ["^1.0.0"],
8
+ dataKey: "powerhouseDeals",
9
+ }
10
+ export default manifest
@@ -0,0 +1,104 @@
1
+ import { listStoreProductsWithSort } from "@pradip1995/medusa-connector"
2
+ import LocalizedLink from "@pradip1995/segment-primitives/localized-link"
3
+ import DealCard from "./deal-card"
4
+ import {
5
+ DEFAULT_EMPTY,
6
+ DEFAULT_PROMO_BUTTON,
7
+ DEFAULT_PROMO_EYEBROW,
8
+ DEFAULT_PROMO_IMAGE,
9
+ DEFAULT_PROMO_LINK,
10
+ DEFAULT_PROMO_TITLE,
11
+ DEFAULT_TITLE,
12
+ } from "./defaults"
13
+ import type { PowerhouseDealsProps } from "./types"
14
+ import "./deals.css"
15
+
16
+ export default async function PowerhouseDeals({
17
+ products: fallbackProducts,
18
+ region,
19
+ countryCode: countryCodeProp,
20
+ title = DEFAULT_TITLE,
21
+ promoEyebrow = DEFAULT_PROMO_EYEBROW,
22
+ promoTitle = DEFAULT_PROMO_TITLE,
23
+ promoButton = DEFAULT_PROMO_BUTTON,
24
+ promoLink = DEFAULT_PROMO_LINK,
25
+ promoImage = DEFAULT_PROMO_IMAGE,
26
+ emptyMessage = DEFAULT_EMPTY,
27
+ }: PowerhouseDealsProps) {
28
+ const countryCode =
29
+ countryCodeProp?.toLowerCase() ||
30
+ region?.countries?.[0]?.iso_2?.toLowerCase() ||
31
+ "in"
32
+
33
+ let products = fallbackProducts ?? []
34
+ let displayRegion = region ?? null
35
+
36
+ if (products.length === 0) {
37
+ try {
38
+ const result = await listStoreProductsWithSort({
39
+ page: 1,
40
+ queryParams: { limit: 8 },
41
+ sortBy: "created_at_desc",
42
+ countryCode,
43
+ region,
44
+ })
45
+ if (result.response.products?.length) {
46
+ products = result.response.products
47
+ }
48
+ if (result.region) {
49
+ displayRegion = result.region
50
+ }
51
+ } catch {
52
+ products = fallbackProducts ?? []
53
+ }
54
+ }
55
+
56
+ const list = products.slice(0, 6)
57
+
58
+ return (
59
+ <section className="powerhouse-deals" aria-label={title}>
60
+ <h2 className="powerhouse-deals__heading">{title}</h2>
61
+ <div className="powerhouse-deals__grid">
62
+ <article className="powerhouse-deals__promo">
63
+ {promoImage ? (
64
+ <img src={promoImage} alt="" className="powerhouse-deals__promo-image" />
65
+ ) : null}
66
+ <LocalizedLink href={promoLink} countryCode={countryCode} className="powerhouse-deals__promo-link">
67
+ <span className="powerhouse-deals__promo-eyebrow">{promoEyebrow}</span>
68
+ <span className="powerhouse-deals__promo-title">{promoTitle}</span>
69
+ <span className="powerhouse-deals__promo-cta">
70
+ {promoButton}
71
+ <svg className="powerhouse-deals__arrow" width="18" height="12" viewBox="0 0 18 12" fill="none" aria-hidden="true">
72
+ <path
73
+ fillRule="evenodd"
74
+ clipRule="evenodd"
75
+ d="M14.7272 5.6364L10.3636 1.27279L11.6364 0L17.2728 5.6364L11.6364 11.2728L10.3636 10L14.7272 5.6364Z"
76
+ fill="currentColor"
77
+ />
78
+ <path
79
+ fillRule="evenodd"
80
+ clipRule="evenodd"
81
+ d="M0 4.73645H16V6.53645H0V4.73645Z"
82
+ fill="currentColor"
83
+ />
84
+ </svg>
85
+ </span>
86
+ </LocalizedLink>
87
+ </article>
88
+
89
+ {list.length === 0 ? (
90
+ <p className="powerhouse-deals__empty">{emptyMessage}</p>
91
+ ) : (
92
+ list.map((product) => (
93
+ <DealCard
94
+ key={product.id}
95
+ product={product}
96
+ region={displayRegion ?? undefined}
97
+ countryCode={countryCode}
98
+ />
99
+ ))
100
+ )}
101
+ </div>
102
+ </section>
103
+ )
104
+ }
package/src/types.ts ADDED
@@ -0,0 +1,15 @@
1
+ import type { HttpTypes } from "@medusajs/types"
2
+
3
+ export type PowerhouseDealsProps = {
4
+ products?: HttpTypes.StoreProduct[]
5
+ region?: HttpTypes.StoreRegion | null
6
+ countryCode?: string
7
+ title?: string
8
+ promoEyebrow?: string
9
+ promoTitle?: string
10
+ promoButton?: string
11
+ promoLink?: string
12
+ promoImage?: string
13
+ emptyMessage?: string
14
+ wishlistProductIds?: string[]
15
+ }