medusa-storefront-data 2.4.0 → 2.5.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/HOMEPAGE_CONFIG.md +38 -4
- package/dist/src/dynamic-config-schema/index.d.ts +103 -0
- package/dist/src/dynamic-config-schema/index.d.ts.map +1 -0
- package/dist/src/dynamic-config-schema/index.js +172 -0
- package/dist/src/dynamic-config-schema/sections/about-brand.d.ts +5 -0
- package/dist/src/dynamic-config-schema/sections/about-brand.d.ts.map +1 -0
- package/dist/src/dynamic-config-schema/sections/about-brand.js +30 -0
- package/dist/src/dynamic-config-schema/sections/baptism-picks.d.ts +5 -0
- package/dist/src/dynamic-config-schema/sections/baptism-picks.d.ts.map +1 -0
- package/dist/src/dynamic-config-schema/sections/baptism-picks.js +17 -0
- package/dist/src/dynamic-config-schema/sections/baptism.d.ts +5 -0
- package/dist/src/dynamic-config-schema/sections/baptism.d.ts.map +1 -0
- package/dist/src/dynamic-config-schema/sections/baptism.js +4 -0
- package/dist/src/dynamic-config-schema/sections/blog-posts.d.ts +5 -0
- package/dist/src/dynamic-config-schema/sections/blog-posts.d.ts.map +1 -0
- package/dist/src/dynamic-config-schema/sections/blog-posts.js +31 -0
- package/dist/src/dynamic-config-schema/sections/brand-marquee.d.ts +5 -0
- package/dist/src/dynamic-config-schema/sections/brand-marquee.d.ts.map +1 -0
- package/dist/src/dynamic-config-schema/sections/brand-marquee.js +9 -0
- package/dist/src/dynamic-config-schema/sections/brand-pillars.d.ts +5 -0
- package/dist/src/dynamic-config-schema/sections/brand-pillars.d.ts.map +1 -0
- package/dist/src/dynamic-config-schema/sections/brand-pillars.js +29 -0
- package/dist/src/dynamic-config-schema/sections/category-pills.d.ts +5 -0
- package/dist/src/dynamic-config-schema/sections/category-pills.d.ts.map +1 -0
- package/dist/src/dynamic-config-schema/sections/category-pills.js +4 -0
- package/dist/src/dynamic-config-schema/sections/celebrity-trust.d.ts +5 -0
- package/dist/src/dynamic-config-schema/sections/celebrity-trust.d.ts.map +1 -0
- package/dist/src/dynamic-config-schema/sections/celebrity-trust.js +4 -0
- package/dist/src/dynamic-config-schema/sections/features.d.ts +5 -0
- package/dist/src/dynamic-config-schema/sections/features.d.ts.map +1 -0
- package/dist/src/dynamic-config-schema/sections/features.js +12 -0
- package/dist/src/dynamic-config-schema/sections/hero.d.ts +6 -0
- package/dist/src/dynamic-config-schema/sections/hero.d.ts.map +1 -0
- package/dist/src/dynamic-config-schema/sections/hero.js +9 -0
- package/dist/src/dynamic-config-schema/sections/index.d.ts +24 -0
- package/dist/src/dynamic-config-schema/sections/index.d.ts.map +1 -0
- package/dist/src/dynamic-config-schema/sections/index.js +23 -0
- package/dist/src/dynamic-config-schema/sections/instagram-posts.d.ts +5 -0
- package/dist/src/dynamic-config-schema/sections/instagram-posts.d.ts.map +1 -0
- package/dist/src/dynamic-config-schema/sections/instagram-posts.js +30 -0
- package/dist/src/dynamic-config-schema/sections/loved-by-moms.d.ts +5 -0
- package/dist/src/dynamic-config-schema/sections/loved-by-moms.d.ts.map +1 -0
- package/dist/src/dynamic-config-schema/sections/loved-by-moms.js +4 -0
- package/dist/src/dynamic-config-schema/sections/luxe-favourites.d.ts +5 -0
- package/dist/src/dynamic-config-schema/sections/luxe-favourites.d.ts.map +1 -0
- package/dist/src/dynamic-config-schema/sections/luxe-favourites.js +4 -0
- package/dist/src/dynamic-config-schema/sections/new-arrivals-classic.d.ts +5 -0
- package/dist/src/dynamic-config-schema/sections/new-arrivals-classic.d.ts.map +1 -0
- package/dist/src/dynamic-config-schema/sections/new-arrivals-classic.js +12 -0
- package/dist/src/dynamic-config-schema/sections/new-arrivals.d.ts +5 -0
- package/dist/src/dynamic-config-schema/sections/new-arrivals.d.ts.map +1 -0
- package/dist/src/dynamic-config-schema/sections/new-arrivals.js +12 -0
- package/dist/src/dynamic-config-schema/sections/promo-announcements.d.ts +5 -0
- package/dist/src/dynamic-config-schema/sections/promo-announcements.d.ts.map +1 -0
- package/dist/src/dynamic-config-schema/sections/promo-announcements.js +16 -0
- package/dist/src/dynamic-config-schema/sections/promo-countdown.d.ts +5 -0
- package/dist/src/dynamic-config-schema/sections/promo-countdown.d.ts.map +1 -0
- package/dist/src/dynamic-config-schema/sections/promo-countdown.js +16 -0
- package/dist/src/dynamic-config-schema/sections/shop-by-age.d.ts +5 -0
- package/dist/src/dynamic-config-schema/sections/shop-by-age.d.ts.map +1 -0
- package/dist/src/dynamic-config-schema/sections/shop-by-age.js +4 -0
- package/dist/src/dynamic-config-schema/sections/shop-by-category.d.ts +5 -0
- package/dist/src/dynamic-config-schema/sections/shop-by-category.d.ts.map +1 -0
- package/dist/src/dynamic-config-schema/sections/shop-by-category.js +4 -0
- package/dist/src/dynamic-config-schema/sections/testimonials.d.ts +5 -0
- package/dist/src/dynamic-config-schema/sections/testimonials.d.ts.map +1 -0
- package/dist/src/dynamic-config-schema/sections/testimonials.js +9 -0
- package/dist/src/dynamic-config-schema/sections/theme-dresses.d.ts +5 -0
- package/dist/src/dynamic-config-schema/sections/theme-dresses.d.ts.map +1 -0
- package/dist/src/dynamic-config-schema/sections/theme-dresses.js +4 -0
- package/dist/src/dynamic-config-schema/sections/video-stories.d.ts +5 -0
- package/dist/src/dynamic-config-schema/sections/video-stories.d.ts.map +1 -0
- package/dist/src/dynamic-config-schema/sections/video-stories.js +24 -0
- package/dist/src/dynamic-config-schema/sections/why-choose-us.d.ts +5 -0
- package/dist/src/dynamic-config-schema/sections/why-choose-us.d.ts.map +1 -0
- package/dist/src/dynamic-config-schema/sections/why-choose-us.js +9 -0
- package/dist/src/dynamic-config-schema/shared.d.ts +35 -0
- package/dist/src/dynamic-config-schema/shared.d.ts.map +1 -0
- package/dist/src/dynamic-config-schema/shared.js +99 -0
- package/dist/src/dynamic-config-schema/site-configs.d.ts +11 -0
- package/dist/src/dynamic-config-schema/site-configs.d.ts.map +1 -0
- package/dist/src/dynamic-config-schema/site-configs.js +70 -0
- package/dist/src/server/brand-pillars-from-categories.d.ts +8 -0
- package/dist/src/server/brand-pillars-from-categories.d.ts.map +1 -0
- package/dist/src/server/brand-pillars-from-categories.js +92 -0
- package/dist/src/server/cart.js +20 -20
- package/dist/src/server/customer.js +11 -11
- package/dist/src/server/dynamic-config-api.d.ts +11 -0
- package/dist/src/server/dynamic-config-api.d.ts.map +1 -0
- package/dist/src/server/dynamic-config-api.js +46 -0
- package/dist/src/server/dynamic-config.d.ts +1 -84
- package/dist/src/server/dynamic-config.d.ts.map +1 -1
- package/dist/src/server/dynamic-config.js +0 -130
- package/dist/src/server/fulfillment.js +3 -3
- package/dist/src/server/home.d.ts +4 -15
- package/dist/src/server/home.d.ts.map +1 -1
- package/dist/src/server/home.js +1 -122
- package/dist/src/server/normalize-homepage-config.d.ts +7 -0
- package/dist/src/server/normalize-homepage-config.d.ts.map +1 -0
- package/dist/src/server/normalize-homepage-config.js +213 -0
- package/dist/src/server/orders.js +6 -6
- package/dist/src/server/page-input.d.ts.map +1 -1
- package/dist/src/server/page-input.js +3 -1
- package/dist/src/server/payment-details.js +5 -5
- package/dist/src/server/payment.js +2 -2
- package/dist/src/server/regions.js +2 -2
- package/dist/src/server/shoppable-looks.js +1 -1
- package/dist/src/util/store-client.d.ts +0 -2
- package/dist/src/util/store-client.d.ts.map +1 -1
- package/dist/src/util/store-client.js +0 -2
- package/package.json +1 -156
- package/src/server/brand-pillars-from-categories.ts +156 -0
- package/src/server/cart.ts +20 -20
- package/src/server/customer.ts +11 -11
- package/src/server/dynamic-config.ts +1 -172
- package/src/server/fulfillment.ts +3 -3
- package/src/server/home.ts +36 -211
- package/src/server/normalize-homepage-config.ts +240 -0
- package/src/server/orders.ts +6 -6
- package/src/server/page-input.ts +3 -1
- package/src/server/payment-details.ts +5 -5
- package/src/server/payment.ts +2 -2
- package/src/server/regions.ts +2 -2
- package/src/server/shoppable-looks.ts +1 -1
- package/src/util/store-client.ts +0 -3
package/src/server/customer.ts
CHANGED
|
@@ -33,7 +33,7 @@ import { medusaCartMerge, medusaCartTransfer } from "medusa-services/cart"
|
|
|
33
33
|
import {
|
|
34
34
|
getAuthClientOptions,
|
|
35
35
|
getMedusaBackendUrl,
|
|
36
|
-
|
|
36
|
+
getStoreClientOptions,
|
|
37
37
|
} from "../util/store-client"
|
|
38
38
|
|
|
39
39
|
import { cache } from "react"
|
|
@@ -52,7 +52,7 @@ export const retrieveCustomer = cache(
|
|
|
52
52
|
if (!("authorization" in authHeaders)) return null
|
|
53
53
|
|
|
54
54
|
try {
|
|
55
|
-
const options = await
|
|
55
|
+
const options = await getStoreClientOptions()
|
|
56
56
|
const { customer } = await medusaCustomerRetrieve(options, { fields: "*addresses" })
|
|
57
57
|
return customer as unknown as HttpTypes.StoreCustomer
|
|
58
58
|
} catch (error: unknown) {
|
|
@@ -68,7 +68,7 @@ export const retrieveCustomer = cache(
|
|
|
68
68
|
|
|
69
69
|
export const updateCustomer = async (body: HttpTypes.StoreUpdateCustomer) => {
|
|
70
70
|
try {
|
|
71
|
-
const options = await
|
|
71
|
+
const options = await getStoreClientOptions()
|
|
72
72
|
const { customer } = await medusaCustomerUpdate(body as Record<string, unknown>, options)
|
|
73
73
|
|
|
74
74
|
const cacheTag = await getCacheTag("customers")
|
|
@@ -98,7 +98,7 @@ export async function signup(_currentState: unknown, formData: FormData) {
|
|
|
98
98
|
|
|
99
99
|
await setAuthToken(token)
|
|
100
100
|
|
|
101
|
-
const options = await
|
|
101
|
+
const options = await getStoreClientOptions()
|
|
102
102
|
const { customer: createdCustomer } = await medusaCustomerCreate(customerForm, options)
|
|
103
103
|
|
|
104
104
|
const loginToken = await medusaAuthLogin(
|
|
@@ -142,7 +142,7 @@ export async function login(
|
|
|
142
142
|
cookieStore.set("_medusa_customer_email", email, { maxAge: 60 * 60 * 24 * 7, path: "/" })
|
|
143
143
|
|
|
144
144
|
try {
|
|
145
|
-
const options = await
|
|
145
|
+
const options = await getStoreClientOptions()
|
|
146
146
|
await medusaCustomerRetrieve({
|
|
147
147
|
...options,
|
|
148
148
|
authorization: `Bearer ${token}`,
|
|
@@ -219,7 +219,7 @@ export async function signout(countryCode: string) {
|
|
|
219
219
|
|
|
220
220
|
export async function transferCart(token?: string) {
|
|
221
221
|
const cartId = await getCartId()
|
|
222
|
-
const options = await
|
|
222
|
+
const options = await getStoreClientOptions()
|
|
223
223
|
const mergeOptions = token
|
|
224
224
|
? { ...options, authorization: `Bearer ${token}` }
|
|
225
225
|
: options
|
|
@@ -285,7 +285,7 @@ export const addCustomerAddress = async (
|
|
|
285
285
|
}
|
|
286
286
|
|
|
287
287
|
try {
|
|
288
|
-
const options = await
|
|
288
|
+
const options = await getStoreClientOptions()
|
|
289
289
|
await medusaCustomerCreateAddress(address, options)
|
|
290
290
|
|
|
291
291
|
const customerCacheTag = await getCacheTag("customers")
|
|
@@ -300,7 +300,7 @@ export const deleteCustomerAddress = async (
|
|
|
300
300
|
addressId: string
|
|
301
301
|
): Promise<void> => {
|
|
302
302
|
try {
|
|
303
|
-
const options = await
|
|
303
|
+
const options = await getStoreClientOptions()
|
|
304
304
|
await medusaCustomerDeleteAddress(addressId, options)
|
|
305
305
|
|
|
306
306
|
const customerCacheTag = await getCacheTag("customers")
|
|
@@ -344,7 +344,7 @@ export const updateCustomerAddress = async (
|
|
|
344
344
|
}
|
|
345
345
|
|
|
346
346
|
try {
|
|
347
|
-
const options = await
|
|
347
|
+
const options = await getStoreClientOptions()
|
|
348
348
|
await medusaCustomerUpdateAddress(addressId, address, options)
|
|
349
349
|
|
|
350
350
|
const customerCacheTag = await getCacheTag("customers")
|
|
@@ -357,7 +357,7 @@ export const updateCustomerAddress = async (
|
|
|
357
357
|
|
|
358
358
|
export const setDefaultAddress = async (addressId: string) => {
|
|
359
359
|
try {
|
|
360
|
-
const options = await
|
|
360
|
+
const options = await getStoreClientOptions()
|
|
361
361
|
await medusaCustomerUpdateAddress(addressId, { is_default_shipping: true }, options)
|
|
362
362
|
|
|
363
363
|
const customerCacheTag = await getCacheTag("customers")
|
|
@@ -469,7 +469,7 @@ export async function handleGoogleCallback(token: string, email?: string, first_
|
|
|
469
469
|
const cookieStore = await cookies()
|
|
470
470
|
cookieStore.set("_medusa_customer_email", email, { maxAge: 60 * 60 * 24 * 7, path: "/" })
|
|
471
471
|
|
|
472
|
-
const options = await
|
|
472
|
+
const options = await getStoreClientOptions()
|
|
473
473
|
if (options.authorization) {
|
|
474
474
|
try {
|
|
475
475
|
await medusaCustomerCreate(
|
|
@@ -19,8 +19,6 @@ export {
|
|
|
19
19
|
type StorefrontPageInput,
|
|
20
20
|
} from "./page-input"
|
|
21
21
|
|
|
22
|
-
/** @deprecated Use `DynamicConfigResponse` from `medusa-storefront-data/homepage-config-schema`. */
|
|
23
|
-
export type DynamicConfig = DynamicConfigResponse
|
|
24
22
|
|
|
25
23
|
export const getDynamicConfig = cache(async (): Promise<DynamicConfigResponse | null> => {
|
|
26
24
|
try {
|
|
@@ -78,52 +76,8 @@ export function getLogoFromPageInput(
|
|
|
78
76
|
return config.logo || null
|
|
79
77
|
}
|
|
80
78
|
|
|
81
|
-
/** @deprecated Fetch in main project; pass `pageInput` into layout/pages instead. */
|
|
82
|
-
export const getLogoFromConfig = async (): Promise<string | null> => {
|
|
83
|
-
const config = await getDynamicConfig()
|
|
84
|
-
return getLogoFromPageInput(config?.["homepage-config"] ?? null)
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
export const getBannerImageFromConfig = async (): Promise<string | null> => {
|
|
88
|
-
try {
|
|
89
|
-
const config = await getDynamicConfig()
|
|
90
|
-
const bannerArray = config?.["homepage-config"]?.["homepage-banner-array"]
|
|
91
|
-
|
|
92
|
-
if (bannerArray && bannerArray.length > 0) {
|
|
93
|
-
const firstBanner = bannerArray[0]
|
|
94
|
-
const image = firstBanner?.["homepage-banner"]?.["homepage-banner-image"]
|
|
95
79
|
|
|
96
|
-
return image || null
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
return null
|
|
101
|
-
} catch (error) {
|
|
102
|
-
|
|
103
|
-
return null
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
export const getMobileBannerFromConfig = async (): Promise<{ image: string | null; link: string | null }> => {
|
|
108
|
-
try {
|
|
109
|
-
const config = await getDynamicConfig()
|
|
110
|
-
const bannerArray = config?.["homepage-config"]?.["app-banner-array"]
|
|
111
80
|
|
|
112
|
-
if (bannerArray && bannerArray.length > 0) {
|
|
113
|
-
const firstBanner = bannerArray[0]
|
|
114
|
-
const image = firstBanner?.["app-banner"]?.["app-banner-image"] || null
|
|
115
|
-
const link = firstBanner?.["app-banner"]?.["app-banner-button-link"] || firstBanner?.["app-banner"]?.["app-banner-link"] || null
|
|
116
|
-
|
|
117
|
-
return { image, link }
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
return { image: null, link: null }
|
|
122
|
-
} catch (error) {
|
|
123
|
-
|
|
124
|
-
return { image: null, link: null }
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
81
|
|
|
128
82
|
export type HomepageBanner = {
|
|
129
83
|
image?: string
|
|
@@ -176,23 +130,9 @@ export function getAppBannersFromPageInput(
|
|
|
176
130
|
return null
|
|
177
131
|
}
|
|
178
132
|
|
|
179
|
-
/** @deprecated Pass `pageInput` from main project. */
|
|
180
|
-
export const getHomeBannersFromConfig = async (): Promise<HomepageBanner[] | null> => {
|
|
181
|
-
const config = await getDynamicConfig()
|
|
182
|
-
return getHomeBannersFromPageInput(config?.["homepage-config"] ?? null)
|
|
183
|
-
}
|
|
184
133
|
|
|
185
|
-
/** @deprecated Pass `pageInput` from main project. */
|
|
186
|
-
export const getAppBannersFromConfig = async (): Promise<HomepageBanner[] | null> => {
|
|
187
|
-
const config = await getDynamicConfig()
|
|
188
|
-
return getAppBannersFromPageInput(config?.["homepage-config"] ?? null)
|
|
189
|
-
}
|
|
190
134
|
|
|
191
135
|
// Legacy function for backward compatibility
|
|
192
|
-
export const getMobileBannerImageFromConfig = async (): Promise<string | null> => {
|
|
193
|
-
const { image } = await getMobileBannerFromConfig()
|
|
194
|
-
return image
|
|
195
|
-
}
|
|
196
136
|
|
|
197
137
|
export function getWebsiteDescriptionFromPageInput(
|
|
198
138
|
pageInput?: HomepageConfig | null
|
|
@@ -202,11 +142,6 @@ export function getWebsiteDescriptionFromPageInput(
|
|
|
202
142
|
return desc || null
|
|
203
143
|
}
|
|
204
144
|
|
|
205
|
-
/** @deprecated Pass `pageInput` from main project. */
|
|
206
|
-
export const getWebsiteDescriptionFromConfig = async (): Promise<string | null> => {
|
|
207
|
-
const config = await getDynamicConfig()
|
|
208
|
-
return getWebsiteDescriptionFromPageInput(config?.["homepage-config"] ?? null)
|
|
209
|
-
}
|
|
210
145
|
|
|
211
146
|
/** Why choose us — defaults + `sections.whyChooseUs` override. */
|
|
212
147
|
export function getFeaturesFromPageInput(
|
|
@@ -223,14 +158,6 @@ export function getFeaturesFromPageInput(
|
|
|
223
158
|
return { title, features }
|
|
224
159
|
}
|
|
225
160
|
|
|
226
|
-
/** @deprecated Pass `pageInput` from main project. */
|
|
227
|
-
export const getFeaturesFromConfig = async (): Promise<{
|
|
228
|
-
title: string
|
|
229
|
-
features: Array<{ name: string; icon: string }>
|
|
230
|
-
}> => {
|
|
231
|
-
const config = await getDynamicConfig()
|
|
232
|
-
return getFeaturesFromPageInput(config?.["homepage-config"] ?? null)
|
|
233
|
-
}
|
|
234
161
|
|
|
235
162
|
function parseFeatureIconList(raw: unknown): Array<{ name: string; icon: string }> {
|
|
236
163
|
if (!Array.isArray(raw)) return []
|
|
@@ -398,11 +325,6 @@ export function getHomeSectionsCopyFromPageInput(
|
|
|
398
325
|
return copy
|
|
399
326
|
}
|
|
400
327
|
|
|
401
|
-
/** @deprecated Pass `pageInput` from main project instead of fetching here. */
|
|
402
|
-
export const getHomeSectionsCopyFromConfig = async (): Promise<HomeSectionsCopy> => {
|
|
403
|
-
const config = await getDynamicConfig()
|
|
404
|
-
return getHomeSectionsCopyFromPageInput(config?.["homepage-config"] ?? null)
|
|
405
|
-
}
|
|
406
328
|
|
|
407
329
|
export type TrustFeaturesConfig = {
|
|
408
330
|
title: string | null
|
|
@@ -423,11 +345,6 @@ export function getTrustFeaturesFromPageInput(
|
|
|
423
345
|
return { title: title ?? null, description: description ?? null, features }
|
|
424
346
|
}
|
|
425
347
|
|
|
426
|
-
/** @deprecated Pass `pageInput` from main project. */
|
|
427
|
-
export const getTrustFeaturesFromConfig = async (): Promise<TrustFeaturesConfig> => {
|
|
428
|
-
const config = await getDynamicConfig()
|
|
429
|
-
return getTrustFeaturesFromPageInput(config?.["homepage-config"] ?? null)
|
|
430
|
-
}
|
|
431
348
|
|
|
432
349
|
function normalizeBannerButtonName(value: unknown): string | undefined {
|
|
433
350
|
const text = normalizeCmsText(value)
|
|
@@ -457,11 +374,6 @@ export function getContactInfoFromPageInput(
|
|
|
457
374
|
}
|
|
458
375
|
}
|
|
459
376
|
|
|
460
|
-
/** @deprecated Pass `pageInput` from main project. */
|
|
461
|
-
export const getContactInfoFromConfig = async (): Promise<ContactInfo | null> => {
|
|
462
|
-
const config = await getDynamicConfig()
|
|
463
|
-
return getContactInfoFromPageInput(config?.["homepage-config"] ?? null)
|
|
464
|
-
}
|
|
465
377
|
|
|
466
378
|
function normalizeVideoStoryUrl(entry: unknown): string | null {
|
|
467
379
|
if (typeof entry === "string" && entry.trim()) return entry.trim()
|
|
@@ -506,14 +418,6 @@ export function getVideoStoriesFromPageInput(
|
|
|
506
418
|
return { title, videoUrls }
|
|
507
419
|
}
|
|
508
420
|
|
|
509
|
-
/** @deprecated Pass `pageInput` from main project. */
|
|
510
|
-
export const getVideoStoriesFromConfig = async (): Promise<{
|
|
511
|
-
title: string
|
|
512
|
-
videoUrls: string[]
|
|
513
|
-
} | null> => {
|
|
514
|
-
const config = await getDynamicConfig()
|
|
515
|
-
return getVideoStoriesFromPageInput(config?.["homepage-config"] ?? null)
|
|
516
|
-
}
|
|
517
421
|
|
|
518
422
|
export type TestimonialItem = {
|
|
519
423
|
id: string
|
|
@@ -599,15 +503,6 @@ export function getTestimonialsFromPageInput(
|
|
|
599
503
|
return { title, subtitle, testimonials }
|
|
600
504
|
}
|
|
601
505
|
|
|
602
|
-
/** @deprecated Pass `pageInput` from main project. */
|
|
603
|
-
export const getTestimonialsFromConfig = async (): Promise<{
|
|
604
|
-
title: string
|
|
605
|
-
subtitle: string | null
|
|
606
|
-
testimonials: TestimonialItem[]
|
|
607
|
-
}> => {
|
|
608
|
-
const config = await getDynamicConfig()
|
|
609
|
-
return getTestimonialsFromPageInput(config?.["homepage-config"] ?? null)
|
|
610
|
-
}
|
|
611
506
|
|
|
612
507
|
export function getSocialLinksFromPageInput(
|
|
613
508
|
pageInput?: HomepageConfig | null
|
|
@@ -627,15 +522,6 @@ export function getSocialLinksFromPageInput(
|
|
|
627
522
|
return socialLinks.length > 0 ? socialLinks : null
|
|
628
523
|
}
|
|
629
524
|
|
|
630
|
-
/** @deprecated Pass `pageInput` from main project. */
|
|
631
|
-
export const getSocialLinksFromConfig = async (): Promise<Array<{
|
|
632
|
-
name: string
|
|
633
|
-
url: string
|
|
634
|
-
icon?: string
|
|
635
|
-
}> | null> => {
|
|
636
|
-
const config = await getDynamicConfig()
|
|
637
|
-
return getSocialLinksFromPageInput(config?.["homepage-config"] ?? null)
|
|
638
|
-
}
|
|
639
525
|
|
|
640
526
|
export function getFaqsFromPageInput(
|
|
641
527
|
pageInput?: HomepageConfig | null
|
|
@@ -667,14 +553,6 @@ export function getFaqsFromPageInput(
|
|
|
667
553
|
return faqs.length > 0 ? faqs : null
|
|
668
554
|
}
|
|
669
555
|
|
|
670
|
-
/** @deprecated Pass `pageInput` from main project. */
|
|
671
|
-
export const getFaqsFromConfig = async (): Promise<Array<{
|
|
672
|
-
category: string
|
|
673
|
-
items: Array<{ q: string; a: string }>
|
|
674
|
-
}> | null> => {
|
|
675
|
-
const config = await getDynamicConfig()
|
|
676
|
-
return getFaqsFromPageInput(config?.["homepage-config"] ?? null)
|
|
677
|
-
}
|
|
678
556
|
|
|
679
557
|
export function getAnnouncementMessagesFromPageInput(
|
|
680
558
|
pageInput?: HomepageConfig | null
|
|
@@ -683,11 +561,6 @@ export function getAnnouncementMessagesFromPageInput(
|
|
|
683
561
|
return parseAnnouncementMessages(block)
|
|
684
562
|
}
|
|
685
563
|
|
|
686
|
-
/** @deprecated Pass `pageInput` from main project. */
|
|
687
|
-
export const getAnnouncementMessagesFromConfig = async (): Promise<string[]> => {
|
|
688
|
-
const config = await getDynamicConfig()
|
|
689
|
-
return getAnnouncementMessagesFromPageInput(config?.["homepage-config"] ?? null)
|
|
690
|
-
}
|
|
691
564
|
|
|
692
565
|
export type AboutBrandConfig = {
|
|
693
566
|
eyebrow: string
|
|
@@ -732,16 +605,12 @@ export function getAboutBrandFromPageInput(
|
|
|
732
605
|
}
|
|
733
606
|
}
|
|
734
607
|
|
|
735
|
-
/** @deprecated Pass `pageInput` from main project. */
|
|
736
|
-
export const getAboutBrandFromConfig = async (): Promise<AboutBrandConfig> => {
|
|
737
|
-
const config = await getDynamicConfig()
|
|
738
|
-
return getAboutBrandFromPageInput(config?.["homepage-config"] ?? null)
|
|
739
|
-
}
|
|
740
608
|
|
|
741
609
|
export type BrandPillarConfig = {
|
|
742
610
|
title: string
|
|
743
611
|
description: string
|
|
744
612
|
image?: string
|
|
613
|
+
href?: string
|
|
745
614
|
}
|
|
746
615
|
|
|
747
616
|
export function getBrandPillarsFromPageInput(
|
|
@@ -765,14 +634,6 @@ export function getBrandPillarsFromPageInput(
|
|
|
765
634
|
return { sectionTitle, pillars }
|
|
766
635
|
}
|
|
767
636
|
|
|
768
|
-
/** @deprecated Pass `pageInput` from main project. */
|
|
769
|
-
export const getBrandPillarsFromConfig = async (): Promise<{
|
|
770
|
-
sectionTitle: string
|
|
771
|
-
pillars: BrandPillarConfig[]
|
|
772
|
-
}> => {
|
|
773
|
-
const config = await getDynamicConfig()
|
|
774
|
-
return getBrandPillarsFromPageInput(config?.["homepage-config"] ?? null)
|
|
775
|
-
}
|
|
776
637
|
|
|
777
638
|
export type BlogPostConfig = {
|
|
778
639
|
title: string
|
|
@@ -808,11 +669,6 @@ export function getBlogPostsFromPageInput(
|
|
|
808
669
|
.filter(Boolean) as BlogPostConfig[]
|
|
809
670
|
}
|
|
810
671
|
|
|
811
|
-
/** @deprecated Pass `pageInput` from main project. */
|
|
812
|
-
export const getBlogPostsFromConfig = async (): Promise<BlogPostConfig[]> => {
|
|
813
|
-
const config = await getDynamicConfig()
|
|
814
|
-
return getBlogPostsFromPageInput(config?.["homepage-config"] ?? null)
|
|
815
|
-
}
|
|
816
672
|
|
|
817
673
|
function readPromoCountdownBlock(block: unknown): {
|
|
818
674
|
code: string | null
|
|
@@ -872,18 +728,6 @@ export function getPromoCountdownFromPageInput(
|
|
|
872
728
|
}
|
|
873
729
|
}
|
|
874
730
|
|
|
875
|
-
/** @deprecated Pass `pageInput` from main project. */
|
|
876
|
-
export const getPromoCountdownFromConfig = async (): Promise<{
|
|
877
|
-
code: string | null
|
|
878
|
-
message: string | null
|
|
879
|
-
endAt: string | null
|
|
880
|
-
active: boolean
|
|
881
|
-
ctaLabel: string | null
|
|
882
|
-
ctaHref: string | null
|
|
883
|
-
}> => {
|
|
884
|
-
const config = await getDynamicConfig()
|
|
885
|
-
return getPromoCountdownFromPageInput(config?.["homepage-config"] ?? null)
|
|
886
|
-
}
|
|
887
731
|
|
|
888
732
|
export type InstagramPostConfig = {
|
|
889
733
|
id: string
|
|
@@ -975,11 +819,6 @@ export function getInstagramPostsFromPageInput(
|
|
|
975
819
|
}
|
|
976
820
|
}
|
|
977
821
|
|
|
978
|
-
/** @deprecated Pass `pageInput` from main project. */
|
|
979
|
-
export const getInstagramPostsFromConfig = async (): Promise<InstagramPostsData> => {
|
|
980
|
-
const config = await getDynamicConfig()
|
|
981
|
-
return getInstagramPostsFromPageInput(config?.["homepage-config"] ?? null)
|
|
982
|
-
}
|
|
983
822
|
|
|
984
823
|
export {
|
|
985
824
|
DEFAULT_HOMEPAGE_SECTIONS,
|
|
@@ -1007,13 +846,3 @@ export function getPromoBarFromPageInput(
|
|
|
1007
846
|
return { text, code, value, active }
|
|
1008
847
|
}
|
|
1009
848
|
|
|
1010
|
-
/** @deprecated Pass `pageInput` from main project. */
|
|
1011
|
-
export const getPromoBarConfig = async (): Promise<{
|
|
1012
|
-
text: string | null
|
|
1013
|
-
code: string | null
|
|
1014
|
-
value: string | null
|
|
1015
|
-
active: boolean
|
|
1016
|
-
}> => {
|
|
1017
|
-
const config = await getDynamicConfig()
|
|
1018
|
-
return getPromoBarFromPageInput(config?.["homepage-config"] ?? null)
|
|
1019
|
-
}
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
medusaShippingOptionCalculate,
|
|
9
9
|
medusaShiprocketServiceability,
|
|
10
10
|
} from "medusa-services/fulfillment"
|
|
11
|
-
import {
|
|
11
|
+
import { getStoreClientOptions } from "../util/store-client"
|
|
12
12
|
|
|
13
13
|
export const listCartShippingMethods = async (cartId: string) => {
|
|
14
14
|
const headers = {
|
|
@@ -44,7 +44,7 @@ export const calculatePriceForShippingOption = async (
|
|
|
44
44
|
data?: Record<string, unknown>
|
|
45
45
|
) => {
|
|
46
46
|
try {
|
|
47
|
-
const options = await
|
|
47
|
+
const options = await getStoreClientOptions()
|
|
48
48
|
const { shipping_option } = await medusaShippingOptionCalculate(
|
|
49
49
|
optionId,
|
|
50
50
|
cartId,
|
|
@@ -59,7 +59,7 @@ export const calculatePriceForShippingOption = async (
|
|
|
59
59
|
|
|
60
60
|
export const getShiprocketServiceability = async (pincode: string, variant_id: string, cod: number = 0) => {
|
|
61
61
|
try {
|
|
62
|
-
const options = await
|
|
62
|
+
const options = await getStoreClientOptions()
|
|
63
63
|
return await medusaShiprocketServiceability(
|
|
64
64
|
{ pincode, variant_id, cod },
|
|
65
65
|
options
|
package/src/server/home.ts
CHANGED
|
@@ -1,11 +1,4 @@
|
|
|
1
|
-
import "
|
|
2
|
-
|
|
3
|
-
import { HttpTypes } from "@medusajs/types";
|
|
4
|
-
import { listCollections } from "./collections";
|
|
5
|
-
import { listCategories } from "./categories";
|
|
6
|
-
import { listProductsWithSort, getProductsByTag, listProducts } from "./products";
|
|
7
|
-
import { getRegion } from "./regions";
|
|
8
|
-
import type { HomepageConfig } from "./homepage-config.types";
|
|
1
|
+
import type { HttpTypes } from "@medusajs/types"
|
|
9
2
|
import type {
|
|
10
3
|
InstagramPostsData,
|
|
11
4
|
AboutBrandConfig,
|
|
@@ -14,212 +7,44 @@ import type {
|
|
|
14
7
|
HomeSectionsCopy,
|
|
15
8
|
TrustFeaturesConfig,
|
|
16
9
|
HomepageBanner,
|
|
17
|
-
} from "./dynamic-config"
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
20
|
-
getBaptismPicksLooks,
|
|
21
|
-
type ShoppableLook,
|
|
22
|
-
} from "./shoppable-looks";
|
|
23
|
-
import { resolveHomeSegmentConfigData } from "./resolve-home-segment-data";
|
|
24
|
-
|
|
25
|
-
async function productsForCategoryIds(
|
|
26
|
-
countryCode: string,
|
|
27
|
-
categoryIds: string[],
|
|
28
|
-
limit: number
|
|
29
|
-
): Promise<HttpTypes.StoreProduct[]> {
|
|
30
|
-
if (!categoryIds.length) return [];
|
|
31
|
-
try {
|
|
32
|
-
const { response } = await listProducts({
|
|
33
|
-
countryCode,
|
|
34
|
-
queryParams: {
|
|
35
|
-
category_id: categoryIds,
|
|
36
|
-
limit,
|
|
37
|
-
} as HttpTypes.FindParams & HttpTypes.StoreProductListParams,
|
|
38
|
-
});
|
|
39
|
-
return response.products ?? [];
|
|
40
|
-
} catch {
|
|
41
|
-
return [];
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
function categoryIdsMatching(
|
|
46
|
-
categories: HttpTypes.StoreProductCategory[],
|
|
47
|
-
pattern: RegExp
|
|
48
|
-
): string[] {
|
|
49
|
-
return categories
|
|
50
|
-
.filter((c) => pattern.test((c.name || c.handle || "").toLowerCase()))
|
|
51
|
-
.map((c) => c.id)
|
|
52
|
-
.filter(Boolean) as string[];
|
|
53
|
-
}
|
|
10
|
+
} from "./dynamic-config"
|
|
11
|
+
import type { ShoppableLook } from "./shoppable-looks"
|
|
54
12
|
|
|
13
|
+
/** Shape returned by the legacy `loadHomePageData` loader (removed — use per-section loaders). */
|
|
55
14
|
export type HomePageData = {
|
|
56
|
-
region:
|
|
57
|
-
collections: Array<Record<string, unknown
|
|
58
|
-
categories: HttpTypes.StoreProductCategory[]
|
|
59
|
-
newArrivals: HttpTypes.StoreProduct[]
|
|
60
|
-
bestsellers: HttpTypes.StoreProduct[]
|
|
61
|
-
testimonials: unknown | null
|
|
62
|
-
ratings: unknown[]
|
|
63
|
-
videoStories: { title: string; videoUrls: string[] } | null
|
|
64
|
-
announcementMessages: string[]
|
|
15
|
+
region: HttpTypes.StoreRegion | null
|
|
16
|
+
collections: Array<Record<string, unknown>>
|
|
17
|
+
categories: HttpTypes.StoreProductCategory[]
|
|
18
|
+
newArrivals: HttpTypes.StoreProduct[]
|
|
19
|
+
bestsellers: HttpTypes.StoreProduct[]
|
|
20
|
+
testimonials: unknown | null
|
|
21
|
+
ratings: unknown[]
|
|
22
|
+
videoStories: { title: string; videoUrls: string[] } | null
|
|
23
|
+
announcementMessages: string[]
|
|
65
24
|
promoCountdown: {
|
|
66
|
-
code: string | null
|
|
67
|
-
message: string | null
|
|
68
|
-
endAt: string | null
|
|
69
|
-
active: boolean
|
|
70
|
-
ctaLabel: string | null
|
|
71
|
-
ctaHref: string | null
|
|
72
|
-
}
|
|
73
|
-
luxeFavourites: HttpTypes.StoreProduct[]
|
|
74
|
-
celebrityProduct: HttpTypes.StoreProduct | null
|
|
75
|
-
baptismGirl: HttpTypes.StoreProduct[]
|
|
76
|
-
baptismBoy: HttpTypes.StoreProduct[]
|
|
77
|
-
baptismPicks: ShoppableLook[]
|
|
78
|
-
themeProducts: HttpTypes.StoreProduct[]
|
|
79
|
-
aboutBrand: AboutBrandConfig
|
|
80
|
-
brandPillars: { sectionTitle: string; pillars: BrandPillarConfig[] }
|
|
81
|
-
blogPosts: BlogPostConfig[]
|
|
82
|
-
instagramPosts: InstagramPostsData
|
|
83
|
-
sectionsCopy: HomeSectionsCopy
|
|
84
|
-
trustFeatures: TrustFeaturesConfig
|
|
85
|
-
homeBanners: HomepageBanner[] | null
|
|
86
|
-
appBanners: HomepageBanner[] | null
|
|
25
|
+
code: string | null
|
|
26
|
+
message: string | null
|
|
27
|
+
endAt: string | null
|
|
28
|
+
active: boolean
|
|
29
|
+
ctaLabel: string | null
|
|
30
|
+
ctaHref: string | null
|
|
31
|
+
}
|
|
32
|
+
luxeFavourites: HttpTypes.StoreProduct[]
|
|
33
|
+
celebrityProduct: HttpTypes.StoreProduct | null
|
|
34
|
+
baptismGirl: HttpTypes.StoreProduct[]
|
|
35
|
+
baptismBoy: HttpTypes.StoreProduct[]
|
|
36
|
+
baptismPicks: ShoppableLook[]
|
|
37
|
+
themeProducts: HttpTypes.StoreProduct[]
|
|
38
|
+
aboutBrand: AboutBrandConfig
|
|
39
|
+
brandPillars: { sectionTitle: string; pillars: BrandPillarConfig[] }
|
|
40
|
+
blogPosts: BlogPostConfig[]
|
|
41
|
+
instagramPosts: InstagramPostsData
|
|
42
|
+
sectionsCopy: HomeSectionsCopy
|
|
43
|
+
trustFeatures: TrustFeaturesConfig
|
|
44
|
+
homeBanners: HomepageBanner[] | null
|
|
45
|
+
appBanners: HomepageBanner[] | null
|
|
87
46
|
whyChooseUsFeatures: {
|
|
88
|
-
title: string
|
|
89
|
-
features: Array<{ name: string; icon: string }
|
|
90
|
-
};
|
|
91
|
-
};
|
|
92
|
-
|
|
93
|
-
export type LoadHomePageDataOptions = {
|
|
94
|
-
/** Merged `homepage-config` from main project (fetched via dynamic-config API there). */
|
|
95
|
-
pageInput?: HomepageConfig | null;
|
|
96
|
-
};
|
|
97
|
-
|
|
98
|
-
/**
|
|
99
|
-
* Parallel home page data loader. Catalog APIs run here; segment copy comes from
|
|
100
|
-
* `pageInput` (or package JSON defaults) — no dynamic-config fetch in this package.
|
|
101
|
-
*/
|
|
102
|
-
export async function loadHomePageData(
|
|
103
|
-
countryCode: string,
|
|
104
|
-
options?: LoadHomePageDataOptions
|
|
105
|
-
): Promise<HomePageData | null> {
|
|
106
|
-
const pageInput = options?.pageInput ?? null;
|
|
107
|
-
const segmentConfig = resolveHomeSegmentConfigData(pageInput);
|
|
108
|
-
|
|
109
|
-
const region = await getRegion(countryCode);
|
|
110
|
-
if (!region) return null;
|
|
111
|
-
|
|
112
|
-
const [
|
|
113
|
-
collectionsResult,
|
|
114
|
-
categoriesResult,
|
|
115
|
-
newArrivalsResult,
|
|
116
|
-
bestsellersResult,
|
|
117
|
-
allRatings,
|
|
118
|
-
themeByTag,
|
|
119
|
-
baptismByTag,
|
|
120
|
-
] = await Promise.all([
|
|
121
|
-
listCollections({ fields: "id, handle, title, metadata" }).catch(() => ({
|
|
122
|
-
collections: [],
|
|
123
|
-
})),
|
|
124
|
-
listCategories({
|
|
125
|
-
limit: 100,
|
|
126
|
-
fields:
|
|
127
|
-
"id,handle,name,metadata,parent_category_id,*parent_category,*parent_category.parent_category",
|
|
128
|
-
}).catch(() => []),
|
|
129
|
-
listProductsWithSort({
|
|
130
|
-
page: 1,
|
|
131
|
-
queryParams: { limit: 12 },
|
|
132
|
-
sortBy: "created_at",
|
|
133
|
-
countryCode,
|
|
134
|
-
}).catch(() => ({ response: { products: [] } })),
|
|
135
|
-
getProductsByTag({
|
|
136
|
-
tagValue: "bestseller",
|
|
137
|
-
limit: 10,
|
|
138
|
-
countryCode,
|
|
139
|
-
}).catch(() => []),
|
|
140
|
-
fetchRatings(),
|
|
141
|
-
getProductsByTag({ tagValue: "theme", limit: 8, countryCode }).catch(() => []),
|
|
142
|
-
getProductsByTag({ tagValue: "baptism", limit: 12, countryCode }).catch(() => []),
|
|
143
|
-
]);
|
|
144
|
-
|
|
145
|
-
const categories = (categoriesResult ?? []) as HttpTypes.StoreProductCategory[];
|
|
146
|
-
const collections =
|
|
147
|
-
(collectionsResult as { collections?: unknown[] }).collections ?? [];
|
|
148
|
-
const newArrivals =
|
|
149
|
-
(newArrivalsResult as { response?: { products?: HttpTypes.StoreProduct[] } })
|
|
150
|
-
.response?.products ?? [];
|
|
151
|
-
const bestsellers = (bestsellersResult ?? []) as HttpTypes.StoreProduct[];
|
|
152
|
-
|
|
153
|
-
const girlIds = categoryIdsMatching(categories, /baptism.*girl|girl.*baptism|^girl$/);
|
|
154
|
-
const boyIds = categoryIdsMatching(categories, /baptism.*boy|boy.*baptism|^boy$/);
|
|
155
|
-
const baptismIds = categoryIdsMatching(categories, /baptism/);
|
|
156
|
-
|
|
157
|
-
const [baptismGirl, baptismBoy] = await Promise.all([
|
|
158
|
-
girlIds.length
|
|
159
|
-
? productsForCategoryIds(countryCode, girlIds, 8)
|
|
160
|
-
: baptismByTag.filter((p) => /girl/i.test(p.title || "")).slice(0, 8),
|
|
161
|
-
boyIds.length
|
|
162
|
-
? productsForCategoryIds(countryCode, boyIds, 8)
|
|
163
|
-
: baptismByTag.filter((p) => /boy/i.test(p.title || "")).slice(0, 8),
|
|
164
|
-
]);
|
|
165
|
-
|
|
166
|
-
let baptismFallback: HttpTypes.StoreProduct[] = [];
|
|
167
|
-
if (baptismGirl.length === 0 && baptismBoy.length === 0) {
|
|
168
|
-
baptismFallback =
|
|
169
|
-
baptismIds.length > 0
|
|
170
|
-
? await productsForCategoryIds(countryCode, baptismIds, 12)
|
|
171
|
-
: baptismByTag;
|
|
47
|
+
title: string
|
|
48
|
+
features: Array<{ name: string; icon: string }>
|
|
172
49
|
}
|
|
173
|
-
|
|
174
|
-
const resolvedBaptismGirl =
|
|
175
|
-
baptismGirl.length > 0 ? baptismGirl : baptismFallback.slice(0, 8);
|
|
176
|
-
const resolvedBaptismBoy =
|
|
177
|
-
baptismBoy.length > 0 ? baptismBoy : baptismFallback.slice(0, 8);
|
|
178
|
-
|
|
179
|
-
const themeProducts =
|
|
180
|
-
themeByTag.length > 0
|
|
181
|
-
? themeByTag
|
|
182
|
-
: await productsForCategoryIds(
|
|
183
|
-
countryCode,
|
|
184
|
-
categoryIdsMatching(categories, /theme/),
|
|
185
|
-
8
|
|
186
|
-
);
|
|
187
|
-
|
|
188
|
-
const baptismPicksFallback = (baptismByTag.length ? baptismByTag : baptismFallback).slice(
|
|
189
|
-
0,
|
|
190
|
-
8
|
|
191
|
-
);
|
|
192
|
-
const baptismPicks = await getBaptismPicksLooks(
|
|
193
|
-
countryCode,
|
|
194
|
-
baptismPicksFallback,
|
|
195
|
-
pageInput
|
|
196
|
-
);
|
|
197
|
-
|
|
198
|
-
return {
|
|
199
|
-
region,
|
|
200
|
-
collections: collections as Array<Record<string, unknown>>,
|
|
201
|
-
categories,
|
|
202
|
-
newArrivals,
|
|
203
|
-
bestsellers,
|
|
204
|
-
testimonials: segmentConfig.testimonials,
|
|
205
|
-
ratings: allRatings ?? [],
|
|
206
|
-
videoStories: segmentConfig.videoStories,
|
|
207
|
-
announcementMessages: segmentConfig.announcementMessages,
|
|
208
|
-
promoCountdown: segmentConfig.promoCountdown,
|
|
209
|
-
luxeFavourites: bestsellers.slice(0, 4),
|
|
210
|
-
celebrityProduct: bestsellers[0] ?? newArrivals[0] ?? null,
|
|
211
|
-
baptismGirl: resolvedBaptismGirl,
|
|
212
|
-
baptismBoy: resolvedBaptismBoy,
|
|
213
|
-
baptismPicks,
|
|
214
|
-
themeProducts,
|
|
215
|
-
aboutBrand: segmentConfig.aboutBrand,
|
|
216
|
-
brandPillars: segmentConfig.brandPillars,
|
|
217
|
-
blogPosts: segmentConfig.blogPosts,
|
|
218
|
-
instagramPosts: segmentConfig.instagramPosts,
|
|
219
|
-
sectionsCopy: segmentConfig.sectionsCopy,
|
|
220
|
-
trustFeatures: segmentConfig.trustFeatures,
|
|
221
|
-
homeBanners: segmentConfig.homeBanners,
|
|
222
|
-
appBanners: segmentConfig.appBanners,
|
|
223
|
-
whyChooseUsFeatures: segmentConfig.whyChooseUsFeatures,
|
|
224
|
-
};
|
|
225
50
|
}
|