medusa-storefront-data 1.0.0 → 2.1.0
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/dist/cookies.d.ts +2 -2
- package/dist/cookies.d.ts.map +1 -1
- package/dist/edge.d.ts +3 -0
- package/dist/edge.d.ts.map +1 -0
- package/dist/edge.js +1 -0
- package/dist/middleware.d.ts +3 -0
- package/dist/middleware.d.ts.map +1 -0
- package/dist/middleware.js +1 -0
- package/dist/server/cart.d.ts +9 -5
- package/dist/server/cart.d.ts.map +1 -1
- package/dist/server/cart.js +164 -194
- package/dist/server/categories.d.ts +3 -2
- package/dist/server/categories.d.ts.map +1 -1
- package/dist/server/categories.js +14 -51
- package/dist/server/collections.d.ts.map +1 -1
- package/dist/server/collections.js +16 -61
- package/dist/server/contact.d.ts +34 -0
- package/dist/server/contact.d.ts.map +1 -0
- package/dist/server/contact.js +57 -0
- package/dist/server/customer.d.ts +7 -7
- package/dist/server/customer.d.ts.map +1 -1
- package/dist/server/customer.js +96 -145
- package/dist/server/dynamic-config.d.ts.map +1 -1
- package/dist/server/dynamic-config.js +38 -12
- package/dist/server/fulfillment.d.ts +4 -3
- package/dist/server/fulfillment.d.ts.map +1 -1
- package/dist/server/fulfillment.js +16 -41
- package/dist/server/guest.d.ts +35 -63
- package/dist/server/guest.d.ts.map +1 -1
- package/dist/server/guest.js +81 -202
- package/dist/server/home.d.ts +15 -0
- package/dist/server/home.d.ts.map +1 -0
- package/dist/server/home.js +45 -0
- package/dist/server/index.d.ts +2 -0
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +2 -0
- package/dist/server/locale-actions.d.ts +1 -1
- package/dist/server/locale-actions.d.ts.map +1 -1
- package/dist/server/locale-actions.js +8 -13
- package/dist/server/locales.d.ts +2 -4
- package/dist/server/locales.d.ts.map +1 -1
- package/dist/server/locales.js +5 -13
- package/dist/server/orders.d.ts +5 -11
- package/dist/server/orders.d.ts.map +1 -1
- package/dist/server/orders.js +126 -267
- package/dist/server/payment-details.d.ts +4 -4
- package/dist/server/payment-details.d.ts.map +1 -1
- package/dist/server/payment-details.js +17 -42
- package/dist/server/payment.d.ts +2 -1
- package/dist/server/payment.d.ts.map +1 -1
- package/dist/server/payment.js +9 -21
- package/dist/server/pincode.d.ts +7 -0
- package/dist/server/pincode.d.ts.map +1 -0
- package/dist/server/pincode.js +30 -0
- package/dist/server/products.d.ts +15 -19
- package/dist/server/products.d.ts.map +1 -1
- package/dist/server/products.js +47 -178
- package/dist/server/regions.d.ts +1 -1
- package/dist/server/regions.d.ts.map +1 -1
- package/dist/server/regions.js +6 -3
- package/dist/server/returns.d.ts +4 -4
- package/dist/server/returns.d.ts.map +1 -1
- package/dist/server/returns.js +50 -154
- package/dist/server/swaps.d.ts +7 -6
- package/dist/server/swaps.d.ts.map +1 -1
- package/dist/server/swaps.js +23 -57
- package/dist/server/variants.d.ts.map +1 -1
- package/dist/server/variants.js +11 -22
- package/dist/server/wishlist.d.ts +11 -0
- package/dist/server/wishlist.d.ts.map +1 -0
- package/dist/server/wishlist.js +49 -0
- package/dist/util/get-locale-header.d.ts +1 -1
- package/dist/util/revalidate-cart.d.ts +2 -0
- package/dist/util/revalidate-cart.d.ts.map +1 -0
- package/dist/util/revalidate-cart.js +8 -0
- package/dist/util/sort-products.d.ts +3 -0
- package/dist/util/sort-products.d.ts.map +1 -0
- package/dist/util/sort-products.js +1 -0
- package/dist/util/store-client.d.ts +13 -0
- package/dist/util/store-client.d.ts.map +1 -0
- package/dist/util/store-client.js +77 -0
- package/package.json +95 -37
- package/src/edge.ts +2 -0
- package/src/middleware.ts +2 -2
- package/src/server/cart.ts +214 -267
- package/src/server/categories.ts +19 -72
- package/src/server/collections.ts +25 -82
- package/src/server/contact.ts +92 -0
- package/src/server/customer.ts +146 -190
- package/src/server/dynamic-config.ts +38 -12
- package/src/server/fulfillment.ts +27 -53
- package/src/server/guest.ts +159 -276
- package/src/server/home.ts +68 -0
- package/src/server/index.ts +1 -0
- package/src/server/locale-actions.ts +8 -15
- package/src/server/locales.ts +6 -18
- package/src/server/orders.ts +167 -337
- package/src/server/payment-details.ts +24 -52
- package/src/server/payment.ts +8 -28
- package/src/server/pincode.ts +49 -0
- package/src/server/products.ts +72 -235
- package/src/server/regions.ts +10 -6
- package/src/server/returns.ts +75 -189
- package/src/server/swaps.ts +94 -123
- package/src/server/variants.ts +9 -28
- package/src/server/wishlist.ts +1 -1
- package/src/util/revalidate-cart.ts +10 -0
- package/src/util/sort-products.ts +2 -47
- package/src/util/store-client.ts +93 -0
- package/src/services/middleware.ts +0 -54
|
@@ -1,69 +1,41 @@
|
|
|
1
1
|
"use server"
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
|
|
3
|
+
import {
|
|
4
|
+
medusaPaymentDetailCreate,
|
|
5
|
+
medusaPaymentDetailDelete,
|
|
6
|
+
medusaPaymentDetailMakeDefault,
|
|
7
|
+
medusaPaymentDetailsList,
|
|
8
|
+
} from "medusa-services/payment"
|
|
9
|
+
import { getStoreCartClientOptions } from "../util/store-client"
|
|
5
10
|
|
|
6
11
|
export const listPaymentDetails = async () => {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
return []
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
const headers = {
|
|
15
|
-
...authHeaders,
|
|
12
|
+
try {
|
|
13
|
+
const options = await getStoreCartClientOptions()
|
|
14
|
+
if (!options.authorization) {
|
|
15
|
+
return []
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
.fetch<any>(`/store/payment-details`, {
|
|
24
|
-
method: "GET",
|
|
25
|
-
headers,
|
|
26
|
-
next,
|
|
27
|
-
cache: "no-store",
|
|
28
|
-
})
|
|
29
|
-
.then((res: any) => res.payment_details || [])
|
|
30
|
-
.catch(() => [])
|
|
18
|
+
const { payment_details } = await medusaPaymentDetailsList(options)
|
|
19
|
+
return payment_details ?? []
|
|
20
|
+
} catch {
|
|
21
|
+
return []
|
|
22
|
+
}
|
|
31
23
|
}
|
|
32
24
|
|
|
33
25
|
export const createPaymentDetail = async (
|
|
34
|
-
|
|
35
|
-
|
|
26
|
+
type: "upi" | "bank" | "card",
|
|
27
|
+
detail_json: Record<string, string>
|
|
36
28
|
) => {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
return sdk.client.fetch<any>(`/store/payment-details`, {
|
|
42
|
-
method: "POST",
|
|
43
|
-
headers,
|
|
44
|
-
body: { type, detail_json },
|
|
45
|
-
})
|
|
29
|
+
const options = await getStoreCartClientOptions()
|
|
30
|
+
return medusaPaymentDetailCreate(type, detail_json, options)
|
|
46
31
|
}
|
|
47
32
|
|
|
48
33
|
export const makeDefaultPaymentDetail = async (id: string) => {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
return sdk.client.fetch<any>(`/store/payment-details/${id}/make-default`, {
|
|
54
|
-
method: "POST",
|
|
55
|
-
headers,
|
|
56
|
-
})
|
|
34
|
+
const options = await getStoreCartClientOptions()
|
|
35
|
+
return medusaPaymentDetailMakeDefault(id, options)
|
|
57
36
|
}
|
|
58
37
|
|
|
59
38
|
export const deletePaymentDetail = async (id: string) => {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
return sdk.client.fetch<any>(`/store/payment-details/${id}`, {
|
|
65
|
-
method: "DELETE",
|
|
66
|
-
headers,
|
|
67
|
-
})
|
|
39
|
+
const options = await getStoreCartClientOptions()
|
|
40
|
+
return medusaPaymentDetailDelete(id, options)
|
|
68
41
|
}
|
|
69
|
-
|
package/src/server/payment.ts
CHANGED
|
@@ -1,35 +1,15 @@
|
|
|
1
1
|
"use server"
|
|
2
2
|
|
|
3
|
-
import { sdk } from "../config"
|
|
4
|
-
import { getAuthHeaders, getCacheOptions } from "../cookies"
|
|
5
3
|
import { HttpTypes } from "@medusajs/types"
|
|
4
|
+
import { medusaPaymentProvidersList } from "medusa-services/payment"
|
|
5
|
+
import { getStoreCartClientOptions } from "../util/store-client"
|
|
6
6
|
|
|
7
7
|
export const listCartPaymentMethods = async (regionId: string) => {
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
try {
|
|
9
|
+
const options = await getStoreCartClientOptions()
|
|
10
|
+
const { payment_providers } = await medusaPaymentProvidersList(regionId, options)
|
|
11
|
+
return payment_providers.sort((a, b) => (a.id > b.id ? 1 : -1)) as HttpTypes.StorePaymentProvider[]
|
|
12
|
+
} catch {
|
|
13
|
+
return null
|
|
10
14
|
}
|
|
11
|
-
|
|
12
|
-
const next = {
|
|
13
|
-
...(await getCacheOptions("payment_providers")),
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
return sdk.client
|
|
17
|
-
.fetch<HttpTypes.StorePaymentProviderListResponse>(
|
|
18
|
-
`/store/payment-providers`,
|
|
19
|
-
{
|
|
20
|
-
method: "GET",
|
|
21
|
-
query: { region_id: regionId },
|
|
22
|
-
headers,
|
|
23
|
-
next,
|
|
24
|
-
cache: "no-store",
|
|
25
|
-
}
|
|
26
|
-
)
|
|
27
|
-
.then(({ payment_providers }) =>
|
|
28
|
-
payment_providers.sort((a, b) => {
|
|
29
|
-
return a.id > b.id ? 1 : -1
|
|
30
|
-
})
|
|
31
|
-
)
|
|
32
|
-
.catch(() => {
|
|
33
|
-
return null
|
|
34
|
-
})
|
|
35
15
|
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use server"
|
|
2
|
+
|
|
3
|
+
export type PincodeLookupResult = {
|
|
4
|
+
city: string
|
|
5
|
+
province: string
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
function titleCase(value: string): string {
|
|
9
|
+
return value
|
|
10
|
+
.toLowerCase()
|
|
11
|
+
.replace(/\b\w/g, (char) => char.toUpperCase())
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/** Resolve Indian pincode to district (city) and state. */
|
|
15
|
+
export async function lookupIndianPincode(
|
|
16
|
+
postalCode: string
|
|
17
|
+
): Promise<PincodeLookupResult | null> {
|
|
18
|
+
const cleaned = postalCode.replace(/\D/g, "")
|
|
19
|
+
if (cleaned.length !== 6) return null
|
|
20
|
+
|
|
21
|
+
try {
|
|
22
|
+
const response = await fetch(
|
|
23
|
+
`https://postal-pincode-api.vercel.app/api/v1/pincode/${cleaned}`,
|
|
24
|
+
{ next: { revalidate: 86400 } } as RequestInit
|
|
25
|
+
)
|
|
26
|
+
if (!response.ok) return null
|
|
27
|
+
|
|
28
|
+
const payload = await response.json()
|
|
29
|
+
const offices = payload?.data as Array<{
|
|
30
|
+
district?: string
|
|
31
|
+
state?: string
|
|
32
|
+
delivery?: boolean
|
|
33
|
+
}> | undefined
|
|
34
|
+
|
|
35
|
+
const match =
|
|
36
|
+
offices?.find((office) => office.delivery) ?? offices?.[0]
|
|
37
|
+
|
|
38
|
+
if (match?.district && match?.state) {
|
|
39
|
+
return {
|
|
40
|
+
city: titleCase(match.district),
|
|
41
|
+
province: titleCase(match.state),
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
} catch {
|
|
45
|
+
// ignore network errors
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return null
|
|
49
|
+
}
|
package/src/server/products.ts
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
"use server"
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
import { sortProducts, type SortOptions } from "../util/sort-products"
|
|
3
|
+
import { type SortOptions } from "../util/sort-products"
|
|
5
4
|
import { HttpTypes } from "@medusajs/types"
|
|
6
|
-
import { getAuthHeaders, getCacheOptions } from "../cookies"
|
|
7
5
|
import { getRegion, retrieveRegion } from "./regions"
|
|
8
6
|
import Color from "color"
|
|
7
|
+
import {
|
|
8
|
+
medusaProductByHandle,
|
|
9
|
+
medusaProductHelperFilters,
|
|
10
|
+
medusaProductList,
|
|
11
|
+
} from "medusa-services/products"
|
|
12
|
+
import { getStoreClientOptions } from "../util/store-client"
|
|
9
13
|
|
|
10
14
|
export const listProducts = async ({
|
|
11
15
|
pageParam = 1,
|
|
@@ -22,24 +26,17 @@ export const listProducts = async ({
|
|
|
22
26
|
nextPage: number | null
|
|
23
27
|
queryParams?: HttpTypes.FindParams & HttpTypes.StoreProductListParams
|
|
24
28
|
}> => {
|
|
25
|
-
|
|
26
|
-
|
|
27
29
|
if (!countryCode && !regionId) {
|
|
28
|
-
|
|
29
30
|
throw new Error("Country code or region ID is required")
|
|
30
31
|
}
|
|
31
32
|
|
|
32
33
|
const limit = queryParams?.limit || 12
|
|
33
|
-
const _pageParam = Math.max(pageParam, 1)
|
|
34
|
-
const offset = _pageParam === 1 ? 0 : (_pageParam - 1) * limit
|
|
35
34
|
|
|
36
35
|
let region: HttpTypes.StoreRegion | undefined | null
|
|
37
36
|
|
|
38
37
|
if (countryCode) {
|
|
39
|
-
|
|
40
38
|
region = await getRegion(countryCode)
|
|
41
39
|
} else {
|
|
42
|
-
|
|
43
40
|
region = await retrieveRegion(regionId!)
|
|
44
41
|
}
|
|
45
42
|
|
|
@@ -50,156 +47,24 @@ export const listProducts = async ({
|
|
|
50
47
|
}
|
|
51
48
|
}
|
|
52
49
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
...(await getAuthHeaders()),
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
const next = {
|
|
60
|
-
...(await getCacheOptions("products")),
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
// 1. Standard Medusa query parameters
|
|
64
|
-
const standardQuery: any = {
|
|
50
|
+
const options = await getStoreClientOptions()
|
|
51
|
+
const { products, count, nextPage } = await medusaProductList(options, {
|
|
52
|
+
pageParam,
|
|
65
53
|
limit,
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
"*variants.calculated_price,+variants.inventory_quantity,*variants.images,+variants.metadata,+variants.options,+metadata,+tags,+average_rating,+total_rating_count,+total_rating_sum,",
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
// 2. Identify advanced filters that require the product-helper API
|
|
73
|
-
const advancedFilterKeys = [
|
|
74
|
-
"metadata", "min_price", "max_price", "q", "collection_id", "category_id",
|
|
75
|
-
"tags", "option_value", "gender", "color", "material", "style", "brand",
|
|
76
|
-
"type", "product_type", "order"
|
|
77
|
-
]
|
|
78
|
-
|
|
79
|
-
const hasAdvancedFilters = !!(queryParams && Object.keys(queryParams).some(key =>
|
|
80
|
-
advancedFilterKeys.includes(key) && (queryParams as any)[key] !== undefined
|
|
81
|
-
))
|
|
82
|
-
|
|
83
|
-
const endpoint = hasAdvancedFilters ? "/store/product-helper/products" : "/store/products";
|
|
84
|
-
|
|
85
|
-
let finalQuery: any = { ...standardQuery }
|
|
86
|
-
|
|
87
|
-
if (hasAdvancedFilters) {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
// We use URLSearchParams to ensure correct formatting and handle repeated keys if needed
|
|
91
|
-
const params = new URLSearchParams()
|
|
92
|
-
|
|
93
|
-
// 1. Add standard params
|
|
94
|
-
params.append("limit", limit.toString())
|
|
95
|
-
params.append("offset", offset.toString())
|
|
96
|
-
if (region?.id) params.append("region_id", region.id)
|
|
97
|
-
|
|
98
|
-
// Use '*' for helper endpoint to let it resolve necessary relations
|
|
99
|
-
params.append("fields", "*")
|
|
100
|
-
|
|
101
|
-
// 2. Map queryParams
|
|
102
|
-
for (const [key, value] of Object.entries(queryParams || {})) {
|
|
103
|
-
if (["metadata", "min_price", "max_price", "limit", "offset", "region_id", "fields"].includes(key)) continue
|
|
104
|
-
|
|
105
|
-
const values = Array.isArray(value) ? value : [value]
|
|
106
|
-
const lowerKey = key.toLowerCase()
|
|
107
|
-
|
|
108
|
-
if (lowerKey === "color") {
|
|
109
|
-
// Map 'color' filter to 'option_value' which backend understands for variants
|
|
110
|
-
values.forEach(v => params.append("option_value[]", String(v)))
|
|
111
|
-
} else if (["material", "gender", "product_type", "type", "style", "brand"].includes(lowerKey)) {
|
|
112
|
-
// Map these to metadata as they are defined as metadata in your config
|
|
113
|
-
const metaKey = lowerKey === "type" ? "product_type" : lowerKey
|
|
114
|
-
values.forEach(v => params.append(`metadata[${metaKey}]`, String(v)))
|
|
115
|
-
} else {
|
|
116
|
-
// Standard mapping for others (tags, collection_id, etc.)
|
|
117
|
-
if (Array.isArray(value)) {
|
|
118
|
-
value.forEach(v => params.append(`${key}[]`, String(v)))
|
|
119
|
-
} else if (value !== undefined && value !== null) {
|
|
120
|
-
params.append(key, String(value))
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
// 3. Map price filters (min_price -> price_min, max_price -> price_max)
|
|
126
|
-
if ((queryParams as any).min_price) params.append("price_min", String((queryParams as any).min_price))
|
|
127
|
-
if ((queryParams as any).max_price) params.append("price_max", String((queryParams as any).max_price))
|
|
128
|
-
|
|
129
|
-
// 4. Map metadata filters to metadata[key] format
|
|
130
|
-
if ((queryParams as any).metadata) {
|
|
131
|
-
for (const [key, value] of Object.entries((queryParams as any).metadata)) {
|
|
132
|
-
const values = Array.isArray(value) ? value : [value]
|
|
133
|
-
|
|
134
|
-
values.forEach(v => {
|
|
135
|
-
if (key.toLowerCase() === "color") {
|
|
136
|
-
// Map color in metadata to option_value[]
|
|
137
|
-
params.append("option_value[]", String(v))
|
|
138
|
-
} else {
|
|
139
|
-
// Standard metadata format: metadata[key]=value
|
|
140
|
-
params.append(`metadata[${key}]`, String(v))
|
|
141
|
-
}
|
|
142
|
-
})
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
finalQuery = params
|
|
54
|
+
regionId: region.id,
|
|
55
|
+
queryParams: queryParams as Record<string, unknown> | undefined,
|
|
56
|
+
})
|
|
147
57
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
}
|
|
156
|
-
}
|
|
58
|
+
return {
|
|
59
|
+
response: {
|
|
60
|
+
products: products as unknown as HttpTypes.StoreProduct[],
|
|
61
|
+
count,
|
|
62
|
+
},
|
|
63
|
+
nextPage,
|
|
64
|
+
queryParams,
|
|
157
65
|
}
|
|
158
|
-
|
|
159
|
-
// Use the appended query string to avoid SDK's default serialization issues with brackets
|
|
160
|
-
const requestUrl = hasAdvancedFilters ? `${endpoint}?${finalQuery.toString()}` : endpoint;
|
|
161
|
-
|
|
162
|
-
return sdk.client
|
|
163
|
-
.fetch<{ products: HttpTypes.StoreProduct[]; count: number }>(
|
|
164
|
-
requestUrl,
|
|
165
|
-
{
|
|
166
|
-
method: "GET",
|
|
167
|
-
query: hasAdvancedFilters ? undefined : finalQuery,
|
|
168
|
-
headers,
|
|
169
|
-
next: {
|
|
170
|
-
...next,
|
|
171
|
-
revalidate: 0, // Disable Next.js cache for now to show logs
|
|
172
|
-
},
|
|
173
|
-
cache: "no-store", // Ensure it hits backend every time for testing
|
|
174
|
-
}
|
|
175
|
-
)
|
|
176
|
-
.then(({ products, count }) => {
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
const nextPage = count > offset + limit ? _pageParam + 1 : null
|
|
180
|
-
|
|
181
|
-
if (products && products.length > 0) {
|
|
182
|
-
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
return {
|
|
186
|
-
response: {
|
|
187
|
-
products: products || [],
|
|
188
|
-
count: count || 0,
|
|
189
|
-
},
|
|
190
|
-
nextPage: nextPage,
|
|
191
|
-
queryParams,
|
|
192
|
-
}
|
|
193
|
-
})
|
|
194
|
-
.catch((error) => {
|
|
195
|
-
throw error
|
|
196
|
-
})
|
|
197
66
|
}
|
|
198
67
|
|
|
199
|
-
/**
|
|
200
|
-
* This will fetch 100 products to the Next.js cache and sort them based on the sortBy parameter.
|
|
201
|
-
* It will then return the paginated products based on the page and limit parameters.
|
|
202
|
-
*/
|
|
203
68
|
export const listProductsWithSort = async ({
|
|
204
69
|
page = 1,
|
|
205
70
|
queryParams,
|
|
@@ -217,10 +82,9 @@ export const listProductsWithSort = async ({
|
|
|
217
82
|
}> => {
|
|
218
83
|
const limit = queryParams?.limit || 12
|
|
219
84
|
|
|
220
|
-
// Directly fetch from backend with correct pagination
|
|
221
|
-
// This ensures the backend terminal logs the specific request
|
|
222
85
|
const {
|
|
223
86
|
response: { products, count },
|
|
87
|
+
nextPage,
|
|
224
88
|
} = await listProducts({
|
|
225
89
|
pageParam: page,
|
|
226
90
|
queryParams: {
|
|
@@ -230,14 +94,9 @@ export const listProductsWithSort = async ({
|
|
|
230
94
|
countryCode,
|
|
231
95
|
})
|
|
232
96
|
|
|
233
|
-
// Sorting is now handled natively by the backend API via the 'order' query param.
|
|
234
|
-
const finalProducts = products
|
|
235
|
-
|
|
236
|
-
const nextPage = count > page * limit ? page + 1 : null
|
|
237
|
-
|
|
238
97
|
return {
|
|
239
98
|
response: {
|
|
240
|
-
products
|
|
99
|
+
products,
|
|
241
100
|
count,
|
|
242
101
|
},
|
|
243
102
|
nextPage,
|
|
@@ -245,9 +104,6 @@ export const listProductsWithSort = async ({
|
|
|
245
104
|
}
|
|
246
105
|
}
|
|
247
106
|
|
|
248
|
-
/**
|
|
249
|
-
* Fetch products that have a specific tag value
|
|
250
|
-
*/
|
|
251
107
|
export async function getProductsByTag({
|
|
252
108
|
tagValue,
|
|
253
109
|
limit = 12,
|
|
@@ -259,7 +115,7 @@ export async function getProductsByTag({
|
|
|
259
115
|
}) {
|
|
260
116
|
try {
|
|
261
117
|
const result = await listProducts({
|
|
262
|
-
queryParams: { tags: [tagValue], limit },
|
|
118
|
+
queryParams: { tags: [tagValue], limit } as HttpTypes.FindParams & HttpTypes.StoreProductListParams,
|
|
263
119
|
countryCode,
|
|
264
120
|
})
|
|
265
121
|
|
|
@@ -270,94 +126,81 @@ export async function getProductsByTag({
|
|
|
270
126
|
}
|
|
271
127
|
}
|
|
272
128
|
|
|
273
|
-
|
|
274
|
-
* Fetch dynamic filter options from the backend API
|
|
275
|
-
*/
|
|
276
|
-
export const getDynamicFilters = async (countryCode: string) => {
|
|
277
|
-
const backendUrl = process.env.MEDUSA_BACKEND_URL || "http://localhost:9000"
|
|
278
|
-
const publishableKey = process.env.NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY
|
|
279
|
-
|
|
129
|
+
export const getDynamicFilters = async (_countryCode: string) => {
|
|
280
130
|
try {
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
const response = await fetch(`${backendUrl}/store/product-helper/filters`, {
|
|
284
|
-
method: "GET",
|
|
285
|
-
headers: {
|
|
286
|
-
"Content-Type": "application/json",
|
|
287
|
-
"x-publishable-api-key": publishableKey,
|
|
288
|
-
},
|
|
289
|
-
cache: "no-store",
|
|
290
|
-
})
|
|
291
|
-
|
|
292
|
-
if (!response.ok) {
|
|
131
|
+
const options = await getStoreClientOptions()
|
|
132
|
+
if (!options.publishableApiKey) {
|
|
293
133
|
return { genders: [], productTypes: [], materials: [], colors: [] }
|
|
294
134
|
}
|
|
295
135
|
|
|
296
|
-
const data = await
|
|
297
|
-
|
|
136
|
+
const data = await medusaProductHelperFilters(options)
|
|
137
|
+
|
|
298
138
|
const formatLabel = (str: string) => {
|
|
299
139
|
return str
|
|
300
140
|
.split(/[_-]/)
|
|
301
|
-
.map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
|
|
302
|
-
.join(
|
|
141
|
+
.map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
|
|
142
|
+
.join(" ")
|
|
303
143
|
}
|
|
304
144
|
|
|
305
|
-
const metadata = data.metadata || {}
|
|
306
|
-
const variantOptions = data.variant_options || []
|
|
145
|
+
const metadata = (data.metadata as Record<string, string[]>) || {}
|
|
146
|
+
const variantOptions = (data.variant_options as Array<{ option_title: string; values?: string[] }>) || []
|
|
307
147
|
|
|
308
|
-
// Gather all unique colors from all possible sources
|
|
309
148
|
const colorSet = new Set<string>()
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
o.values?.forEach((v: string) => {
|
|
149
|
+
|
|
150
|
+
variantOptions.forEach((o) => {
|
|
151
|
+
if (o.option_title.toLowerCase() === "color" || o.option_title.toLowerCase() === "colour") {
|
|
152
|
+
o.values?.forEach((v) => {
|
|
315
153
|
if (v) colorSet.add(v.trim().toLowerCase())
|
|
316
154
|
})
|
|
317
155
|
}
|
|
318
156
|
})
|
|
319
157
|
|
|
320
|
-
// 2. From metadata colors (handle newline/comma separated values)
|
|
321
158
|
if (metadata.color) {
|
|
322
|
-
metadata.color.forEach((c
|
|
159
|
+
metadata.color.forEach((c) => {
|
|
323
160
|
if (c) {
|
|
324
|
-
const parts = c
|
|
325
|
-
|
|
161
|
+
const parts = c
|
|
162
|
+
.split(/[,/\n\r]+/)
|
|
163
|
+
.map((s) => s.trim())
|
|
164
|
+
.filter(Boolean)
|
|
165
|
+
parts.forEach((p) => colorSet.add(p.toLowerCase()))
|
|
326
166
|
}
|
|
327
167
|
})
|
|
328
168
|
}
|
|
329
169
|
|
|
330
170
|
return {
|
|
331
|
-
genders: (metadata.gender || []).sort().map((g
|
|
171
|
+
genders: (metadata.gender || []).sort().map((g) => ({
|
|
332
172
|
value: g,
|
|
333
|
-
label: formatLabel(g)
|
|
334
|
-
})),
|
|
335
|
-
productTypes: (data.product_types || []).sort((a: any, b: any) => a.label.localeCompare(b.label)).map((t: any) => ({
|
|
336
|
-
value: t.label,
|
|
337
|
-
label: formatLabel(t.label)
|
|
173
|
+
label: formatLabel(g),
|
|
338
174
|
})),
|
|
339
|
-
|
|
175
|
+
productTypes: ((data.product_types as Array<{ label: string }>) || [])
|
|
176
|
+
.sort((a, b) => a.label.localeCompare(b.label))
|
|
177
|
+
.map((t) => ({
|
|
178
|
+
value: t.label,
|
|
179
|
+
label: formatLabel(t.label),
|
|
180
|
+
})),
|
|
181
|
+
materials: (metadata.material || []).sort().map((m) => ({
|
|
340
182
|
value: m,
|
|
341
|
-
label: formatLabel(m)
|
|
183
|
+
label: formatLabel(m),
|
|
342
184
|
})),
|
|
343
|
-
colors: Array.from(colorSet)
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
hex = Color(c.replace(/\s+/g, '').toLowerCase()).hex()
|
|
348
|
-
} catch (e) {
|
|
185
|
+
colors: Array.from(colorSet)
|
|
186
|
+
.sort()
|
|
187
|
+
.map((c) => {
|
|
188
|
+
let hex = ""
|
|
349
189
|
try {
|
|
350
|
-
hex = Color(c.toLowerCase()).hex()
|
|
351
|
-
} catch
|
|
352
|
-
|
|
190
|
+
hex = Color(c.replace(/\s+/g, "").toLowerCase()).hex()
|
|
191
|
+
} catch {
|
|
192
|
+
try {
|
|
193
|
+
hex = Color(c.toLowerCase()).hex()
|
|
194
|
+
} catch {
|
|
195
|
+
// no hex
|
|
196
|
+
}
|
|
353
197
|
}
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
}
|
|
360
|
-
})
|
|
198
|
+
return {
|
|
199
|
+
value: c,
|
|
200
|
+
label: formatLabel(c),
|
|
201
|
+
hex,
|
|
202
|
+
}
|
|
203
|
+
}),
|
|
361
204
|
}
|
|
362
205
|
} catch (error) {
|
|
363
206
|
console.error("Error fetching dynamic filters:", error)
|
|
@@ -365,14 +208,8 @@ export const getDynamicFilters = async (countryCode: string) => {
|
|
|
365
208
|
}
|
|
366
209
|
}
|
|
367
210
|
|
|
368
|
-
/**
|
|
369
|
-
* Fetch a single product by its handle
|
|
370
|
-
*/
|
|
371
211
|
export async function getProductByHandle(handle: string) {
|
|
372
|
-
const
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
)
|
|
376
|
-
|
|
377
|
-
return result.products[0]
|
|
212
|
+
const options = await getStoreClientOptions()
|
|
213
|
+
const product = await medusaProductByHandle(handle, options)
|
|
214
|
+
return product as unknown as HttpTypes.StoreProduct | undefined
|
|
378
215
|
}
|
package/src/server/regions.ts
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
"use server"
|
|
2
2
|
|
|
3
|
+
import type { FetchArgs } from "@medusajs/js-sdk"
|
|
3
4
|
import { sdk } from "../config"
|
|
4
5
|
import medusaError from "../util/medusa-error"
|
|
5
6
|
import { HttpTypes } from "@medusajs/types"
|
|
6
7
|
import { getCacheOptions } from "../cookies"
|
|
8
|
+
import { medusaRegionList } from "medusa-services/regions"
|
|
9
|
+
import { getStoreCartClientOptions } from "../util/store-client"
|
|
7
10
|
|
|
8
11
|
export const listRegions = async () => {
|
|
9
12
|
const next = {
|
|
@@ -15,7 +18,7 @@ export const listRegions = async () => {
|
|
|
15
18
|
method: "GET",
|
|
16
19
|
next,
|
|
17
20
|
cache: "force-cache",
|
|
18
|
-
})
|
|
21
|
+
} as FetchArgs & { next?: typeof next; cache?: RequestCache })
|
|
19
22
|
.then(({ regions }) => regions)
|
|
20
23
|
.catch(medusaError)
|
|
21
24
|
}
|
|
@@ -30,7 +33,7 @@ export const retrieveRegion = async (id: string) => {
|
|
|
30
33
|
method: "GET",
|
|
31
34
|
next,
|
|
32
35
|
cache: "force-cache",
|
|
33
|
-
})
|
|
36
|
+
} as FetchArgs & { next?: typeof next; cache?: RequestCache })
|
|
34
37
|
.then(({ region }) => region)
|
|
35
38
|
.catch(medusaError)
|
|
36
39
|
}
|
|
@@ -43,15 +46,16 @@ export const getRegion = async (countryCode: string) => {
|
|
|
43
46
|
return regionMap.get(countryCode)
|
|
44
47
|
}
|
|
45
48
|
|
|
46
|
-
const
|
|
49
|
+
const options = await getStoreCartClientOptions()
|
|
50
|
+
const { regions } = await medusaRegionList(options)
|
|
47
51
|
|
|
48
|
-
if (!regions) {
|
|
52
|
+
if (!regions?.length) {
|
|
49
53
|
return null
|
|
50
54
|
}
|
|
51
55
|
|
|
52
56
|
regions.forEach((region) => {
|
|
53
57
|
region.countries?.forEach((c) => {
|
|
54
|
-
regionMap.set(c?.iso_2 ?? "", region)
|
|
58
|
+
regionMap.set(c?.iso_2 ?? "", region as unknown as HttpTypes.StoreRegion)
|
|
55
59
|
})
|
|
56
60
|
})
|
|
57
61
|
|
|
@@ -59,7 +63,7 @@ export const getRegion = async (countryCode: string) => {
|
|
|
59
63
|
? regionMap.get(countryCode)
|
|
60
64
|
: regionMap.get("us")
|
|
61
65
|
|
|
62
|
-
return region
|
|
66
|
+
return region ?? null
|
|
63
67
|
} catch (e: any) {
|
|
64
68
|
return null
|
|
65
69
|
}
|