medusa-storefront-data 2.3.0 → 2.4.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/HOMEPAGE_CONFIG.md +99 -0
- package/dist/segment-data/default-page-input.json +191 -0
- package/dist/src/config.d.ts.map +1 -0
- package/dist/src/cookies.d.ts.map +1 -0
- package/dist/src/edge.d.ts.map +1 -0
- package/dist/src/middleware.d.ts.map +1 -0
- package/dist/src/server/cart.d.ts.map +1 -0
- package/dist/src/server/categories.d.ts.map +1 -0
- package/dist/src/server/collections.d.ts.map +1 -0
- package/dist/src/server/config-merge.d.ts +3 -0
- package/dist/src/server/config-merge.d.ts.map +1 -0
- package/dist/src/server/config-merge.js +31 -0
- package/dist/src/server/contact.d.ts.map +1 -0
- package/dist/src/server/customer-registration.d.ts.map +1 -0
- package/dist/src/server/customer.d.ts.map +1 -0
- package/dist/src/server/dynamic-config.d.ts +240 -0
- package/dist/src/server/dynamic-config.d.ts.map +1 -0
- package/dist/src/server/dynamic-config.js +703 -0
- package/dist/src/server/fulfillment.d.ts.map +1 -0
- package/dist/src/server/guest.d.ts.map +1 -0
- package/dist/src/server/home-sections/about-brand.d.ts +9 -0
- package/dist/src/server/home-sections/about-brand.d.ts.map +1 -0
- package/dist/src/server/home-sections/about-brand.js +9 -0
- package/dist/src/server/home-sections/baptism-picks.d.ts +10 -0
- package/dist/src/server/home-sections/baptism-picks.d.ts.map +1 -0
- package/dist/src/server/home-sections/baptism-picks.js +27 -0
- package/dist/src/server/home-sections/baptism.d.ts +13 -0
- package/dist/src/server/home-sections/baptism.d.ts.map +1 -0
- package/dist/src/server/home-sections/baptism.js +43 -0
- package/dist/src/server/home-sections/blog-posts.d.ts +9 -0
- package/dist/src/server/home-sections/blog-posts.d.ts.map +1 -0
- package/dist/src/server/home-sections/blog-posts.js +9 -0
- package/dist/src/server/home-sections/brand-marquee.d.ts +8 -0
- package/dist/src/server/home-sections/brand-marquee.d.ts.map +1 -0
- package/dist/src/server/home-sections/brand-marquee.js +7 -0
- package/dist/src/server/home-sections/brand-pillars.d.ts +9 -0
- package/dist/src/server/home-sections/brand-pillars.d.ts.map +1 -0
- package/dist/src/server/home-sections/brand-pillars.js +9 -0
- package/dist/src/server/home-sections/category-pills.d.ts +9 -0
- package/dist/src/server/home-sections/category-pills.d.ts.map +1 -0
- package/dist/src/server/home-sections/category-pills.js +19 -0
- package/dist/src/server/home-sections/celebrity-trust.d.ts +12 -0
- package/dist/src/server/home-sections/celebrity-trust.d.ts.map +1 -0
- package/dist/src/server/home-sections/celebrity-trust.js +27 -0
- package/dist/src/server/home-sections/features.d.ts +9 -0
- package/dist/src/server/home-sections/features.d.ts.map +1 -0
- package/dist/src/server/home-sections/features.js +9 -0
- package/dist/src/server/home-sections/hero.d.ts +9 -0
- package/dist/src/server/home-sections/hero.d.ts.map +1 -0
- package/dist/src/server/home-sections/hero.js +9 -0
- package/dist/src/server/home-sections/instagram-posts.d.ts +9 -0
- package/dist/src/server/home-sections/instagram-posts.d.ts.map +1 -0
- package/dist/src/server/home-sections/instagram-posts.js +9 -0
- package/dist/src/server/home-sections/loved-by-moms.d.ts +12 -0
- package/dist/src/server/home-sections/loved-by-moms.d.ts.map +1 -0
- package/dist/src/server/home-sections/loved-by-moms.js +20 -0
- package/dist/src/server/home-sections/luxe-favourites.d.ts +11 -0
- package/dist/src/server/home-sections/luxe-favourites.d.ts.map +1 -0
- package/dist/src/server/home-sections/luxe-favourites.js +19 -0
- package/dist/src/server/home-sections/new-arrivals-classic.d.ts +8 -0
- package/dist/src/server/home-sections/new-arrivals-classic.d.ts.map +1 -0
- package/dist/src/server/home-sections/new-arrivals-classic.js +10 -0
- package/dist/src/server/home-sections/new-arrivals.d.ts +12 -0
- package/dist/src/server/home-sections/new-arrivals.d.ts.map +1 -0
- package/dist/src/server/home-sections/new-arrivals.js +28 -0
- package/dist/src/server/home-sections/promo-announcements.d.ts +7 -0
- package/dist/src/server/home-sections/promo-announcements.d.ts.map +1 -0
- package/dist/src/server/home-sections/promo-announcements.js +7 -0
- package/dist/src/server/home-sections/promo-countdown.d.ts +6 -0
- package/dist/src/server/home-sections/promo-countdown.d.ts.map +1 -0
- package/dist/src/server/home-sections/promo-countdown.js +5 -0
- package/dist/src/server/home-sections/shared.d.ts +10 -0
- package/dist/src/server/home-sections/shared.d.ts.map +1 -0
- package/dist/src/server/home-sections/shared.js +29 -0
- package/dist/src/server/home-sections/shop-by-age.d.ts +9 -0
- package/dist/src/server/home-sections/shop-by-age.d.ts.map +1 -0
- package/dist/src/server/home-sections/shop-by-age.js +17 -0
- package/dist/src/server/home-sections/shop-by-category.d.ts +10 -0
- package/dist/src/server/home-sections/shop-by-category.d.ts.map +1 -0
- package/dist/src/server/home-sections/shop-by-category.js +17 -0
- package/dist/src/server/home-sections/testimonials.d.ts +9 -0
- package/dist/src/server/home-sections/testimonials.d.ts.map +1 -0
- package/dist/src/server/home-sections/testimonials.js +9 -0
- package/dist/src/server/home-sections/theme-dresses.d.ts +12 -0
- package/dist/src/server/home-sections/theme-dresses.d.ts.map +1 -0
- package/dist/src/server/home-sections/theme-dresses.js +27 -0
- package/dist/src/server/home-sections/video-stories.d.ts +9 -0
- package/dist/src/server/home-sections/video-stories.d.ts.map +1 -0
- package/dist/src/server/home-sections/video-stories.js +9 -0
- package/dist/src/server/home-sections/why-choose-us.d.ts +9 -0
- package/dist/src/server/home-sections/why-choose-us.d.ts.map +1 -0
- package/dist/src/server/home-sections/why-choose-us.js +9 -0
- package/dist/src/server/home.d.ts +62 -0
- package/dist/src/server/home.d.ts.map +1 -0
- package/dist/{server → src/server}/home.js +29 -31
- package/dist/src/server/homepage-config.types.d.ts +274 -0
- package/dist/src/server/homepage-config.types.d.ts.map +1 -0
- package/dist/src/server/homepage-config.types.js +33 -0
- package/dist/{server → src/server}/homepage-section-defaults.d.ts +35 -2
- package/dist/src/server/homepage-section-defaults.d.ts.map +1 -0
- package/dist/{server → src/server}/homepage-section-defaults.js +41 -2
- package/dist/{server → src/server}/index.d.ts +2 -0
- package/dist/src/server/index.d.ts.map +1 -0
- package/dist/{server → src/server}/index.js +2 -0
- package/dist/src/server/locale-actions.d.ts.map +1 -0
- package/dist/src/server/locales.d.ts.map +1 -0
- package/dist/src/server/notifications.d.ts.map +1 -0
- package/dist/src/server/onboarding.d.ts.map +1 -0
- package/dist/src/server/orders.d.ts.map +1 -0
- package/dist/src/server/page-input.d.ts +19 -0
- package/dist/src/server/page-input.d.ts.map +1 -0
- package/dist/src/server/page-input.js +40 -0
- package/dist/src/server/payment-details.d.ts.map +1 -0
- package/dist/src/server/payment.d.ts.map +1 -0
- package/dist/src/server/pincode.d.ts.map +1 -0
- package/dist/src/server/products.d.ts.map +1 -0
- package/dist/src/server/regions.d.ts.map +1 -0
- package/dist/src/server/resolve-home-segment-data.d.ts +25 -0
- package/dist/src/server/resolve-home-segment-data.d.ts.map +1 -0
- package/dist/src/server/resolve-home-segment-data.js +20 -0
- package/dist/src/server/returns.d.ts.map +1 -0
- package/dist/src/server/shoppable-looks.d.ts +17 -0
- package/dist/src/server/shoppable-looks.d.ts.map +1 -0
- package/dist/src/server/shoppable-looks.js +136 -0
- package/dist/src/server/swaps.d.ts.map +1 -0
- package/dist/src/server/variants.d.ts.map +1 -0
- package/dist/src/server/wishlist.d.ts.map +1 -0
- package/dist/src/util/get-locale-header.d.ts.map +1 -0
- package/dist/src/util/medusa-error.d.ts.map +1 -0
- package/dist/src/util/revalidate-cart.d.ts.map +1 -0
- package/dist/src/util/sort-products.d.ts.map +1 -0
- package/dist/src/util/store-client.d.ts.map +1 -0
- package/homepage-config.example.json +209 -0
- package/homepage-sections.example.json +55 -0
- package/package.json +121 -2
- package/segment-data/default-page-input.json +191 -0
- package/src/server/config-merge.ts +31 -0
- package/src/server/dynamic-config.ts +620 -508
- package/src/server/home-sections/about-brand.ts +24 -0
- package/src/server/home-sections/baptism-picks.ts +46 -0
- package/src/server/home-sections/baptism.ts +64 -0
- package/src/server/home-sections/blog-posts.ts +23 -0
- package/src/server/home-sections/brand-marquee.ts +17 -0
- package/src/server/home-sections/brand-pillars.ts +23 -0
- package/src/server/home-sections/category-pills.ts +32 -0
- package/src/server/home-sections/celebrity-trust.ts +42 -0
- package/src/server/home-sections/features.ts +23 -0
- package/src/server/home-sections/hero.ts +24 -0
- package/src/server/home-sections/instagram-posts.ts +23 -0
- package/src/server/home-sections/loved-by-moms.ts +34 -0
- package/src/server/home-sections/luxe-favourites.ts +30 -0
- package/src/server/home-sections/new-arrivals-classic.ts +21 -0
- package/src/server/home-sections/new-arrivals.ts +47 -0
- package/src/server/home-sections/promo-announcements.ts +17 -0
- package/src/server/home-sections/promo-countdown.ts +15 -0
- package/src/server/home-sections/shared.ts +44 -0
- package/src/server/home-sections/shop-by-age.ts +26 -0
- package/src/server/home-sections/shop-by-category.ts +28 -0
- package/src/server/home-sections/testimonials.ts +23 -0
- package/src/server/home-sections/theme-dresses.ts +49 -0
- package/src/server/home-sections/video-stories.ts +23 -0
- package/src/server/home-sections/why-choose-us.ts +23 -0
- package/src/server/home.ts +68 -54
- package/src/server/homepage-config.types.ts +335 -0
- package/src/server/homepage-section-defaults.ts +41 -2
- package/src/server/index.ts +2 -0
- package/src/server/page-input.ts +64 -0
- package/src/server/resolve-home-segment-data.ts +63 -0
- package/src/server/shoppable-looks.ts +178 -0
- package/dist/config.d.ts.map +0 -1
- package/dist/cookies.d.ts.map +0 -1
- package/dist/edge.d.ts.map +0 -1
- package/dist/middleware.d.ts.map +0 -1
- package/dist/server/cart.d.ts.map +0 -1
- package/dist/server/categories.d.ts.map +0 -1
- package/dist/server/collections.d.ts.map +0 -1
- package/dist/server/contact.d.ts.map +0 -1
- package/dist/server/customer-registration.d.ts.map +0 -1
- package/dist/server/customer.d.ts.map +0 -1
- package/dist/server/dynamic-config.d.ts +0 -202
- package/dist/server/dynamic-config.d.ts.map +0 -1
- package/dist/server/dynamic-config.js +0 -675
- package/dist/server/fulfillment.d.ts.map +0 -1
- package/dist/server/guest.d.ts.map +0 -1
- package/dist/server/home.d.ts +0 -42
- package/dist/server/home.d.ts.map +0 -1
- package/dist/server/homepage-section-defaults.d.ts.map +0 -1
- package/dist/server/index.d.ts.map +0 -1
- package/dist/server/locale-actions.d.ts.map +0 -1
- package/dist/server/locales.d.ts.map +0 -1
- package/dist/server/notifications.d.ts.map +0 -1
- package/dist/server/onboarding.d.ts.map +0 -1
- package/dist/server/orders.d.ts.map +0 -1
- package/dist/server/payment-details.d.ts.map +0 -1
- package/dist/server/payment.d.ts.map +0 -1
- package/dist/server/pincode.d.ts.map +0 -1
- package/dist/server/products.d.ts.map +0 -1
- package/dist/server/regions.d.ts.map +0 -1
- package/dist/server/returns.d.ts.map +0 -1
- package/dist/server/swaps.d.ts.map +0 -1
- package/dist/server/variants.d.ts.map +0 -1
- package/dist/server/wishlist.d.ts.map +0 -1
- package/dist/util/get-locale-header.d.ts.map +0 -1
- package/dist/util/medusa-error.d.ts.map +0 -1
- package/dist/util/revalidate-cart.d.ts.map +0 -1
- package/dist/util/sort-products.d.ts.map +0 -1
- package/dist/util/store-client.d.ts.map +0 -1
- /package/dist/{config.d.ts → src/config.d.ts} +0 -0
- /package/dist/{config.js → src/config.js} +0 -0
- /package/dist/{cookies.d.ts → src/cookies.d.ts} +0 -0
- /package/dist/{cookies.js → src/cookies.js} +0 -0
- /package/dist/{edge.d.ts → src/edge.d.ts} +0 -0
- /package/dist/{edge.js → src/edge.js} +0 -0
- /package/dist/{middleware.d.ts → src/middleware.d.ts} +0 -0
- /package/dist/{middleware.js → src/middleware.js} +0 -0
- /package/dist/{server → src/server}/cart.d.ts +0 -0
- /package/dist/{server → src/server}/cart.js +0 -0
- /package/dist/{server → src/server}/categories.d.ts +0 -0
- /package/dist/{server → src/server}/categories.js +0 -0
- /package/dist/{server → src/server}/collections.d.ts +0 -0
- /package/dist/{server → src/server}/collections.js +0 -0
- /package/dist/{server → src/server}/contact.d.ts +0 -0
- /package/dist/{server → src/server}/contact.js +0 -0
- /package/dist/{server → src/server}/customer-registration.d.ts +0 -0
- /package/dist/{server → src/server}/customer-registration.js +0 -0
- /package/dist/{server → src/server}/customer.d.ts +0 -0
- /package/dist/{server → src/server}/customer.js +0 -0
- /package/dist/{server → src/server}/fulfillment.d.ts +0 -0
- /package/dist/{server → src/server}/fulfillment.js +0 -0
- /package/dist/{server → src/server}/guest.d.ts +0 -0
- /package/dist/{server → src/server}/guest.js +0 -0
- /package/dist/{server → src/server}/locale-actions.d.ts +0 -0
- /package/dist/{server → src/server}/locale-actions.js +0 -0
- /package/dist/{server → src/server}/locales.d.ts +0 -0
- /package/dist/{server → src/server}/locales.js +0 -0
- /package/dist/{server → src/server}/notifications.d.ts +0 -0
- /package/dist/{server → src/server}/notifications.js +0 -0
- /package/dist/{server → src/server}/onboarding.d.ts +0 -0
- /package/dist/{server → src/server}/onboarding.js +0 -0
- /package/dist/{server → src/server}/orders.d.ts +0 -0
- /package/dist/{server → src/server}/orders.js +0 -0
- /package/dist/{server → src/server}/payment-details.d.ts +0 -0
- /package/dist/{server → src/server}/payment-details.js +0 -0
- /package/dist/{server → src/server}/payment.d.ts +0 -0
- /package/dist/{server → src/server}/payment.js +0 -0
- /package/dist/{server → src/server}/pincode.d.ts +0 -0
- /package/dist/{server → src/server}/pincode.js +0 -0
- /package/dist/{server → src/server}/products.d.ts +0 -0
- /package/dist/{server → src/server}/products.js +0 -0
- /package/dist/{server → src/server}/regions.d.ts +0 -0
- /package/dist/{server → src/server}/regions.js +0 -0
- /package/dist/{server → src/server}/returns.d.ts +0 -0
- /package/dist/{server → src/server}/returns.js +0 -0
- /package/dist/{server → src/server}/swaps.d.ts +0 -0
- /package/dist/{server → src/server}/swaps.js +0 -0
- /package/dist/{server → src/server}/variants.d.ts +0 -0
- /package/dist/{server → src/server}/variants.js +0 -0
- /package/dist/{server → src/server}/wishlist.d.ts +0 -0
- /package/dist/{server → src/server}/wishlist.js +0 -0
- /package/dist/{util → src/util}/get-locale-header.d.ts +0 -0
- /package/dist/{util → src/util}/get-locale-header.js +0 -0
- /package/dist/{util → src/util}/medusa-error.d.ts +0 -0
- /package/dist/{util → src/util}/medusa-error.js +0 -0
- /package/dist/{util → src/util}/revalidate-cart.d.ts +0 -0
- /package/dist/{util → src/util}/revalidate-cart.js +0 -0
- /package/dist/{util → src/util}/sort-products.d.ts +0 -0
- /package/dist/{util → src/util}/sort-products.js +0 -0
- /package/dist/{util → src/util}/store-client.d.ts +0 -0
- /package/dist/{util → src/util}/store-client.js +0 -0
|
@@ -0,0 +1,703 @@
|
|
|
1
|
+
import "server-only";
|
|
2
|
+
import { cache } from "react";
|
|
3
|
+
import { getAuthHeaders } from "../cookies";
|
|
4
|
+
import { DEFAULT_HOMEPAGE_SECTIONS, HOME_SECTION_COPY_ID_LIST, } from "./homepage-section-defaults";
|
|
5
|
+
import { mergeSectionBlock } from "./config-merge";
|
|
6
|
+
import { resolvePageInput } from "./page-input";
|
|
7
|
+
export { DEFAULT_PAGE_INPUT, mergePageInputWithDefaults, resolvePageInput, homepageConfigFromDynamicResponse, } from "./page-input";
|
|
8
|
+
export const getDynamicConfig = cache(async () => {
|
|
9
|
+
try {
|
|
10
|
+
const publishableKey = process.env.NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY;
|
|
11
|
+
const baseUrl = process.env.MEDUSA_BACKEND_URL || "http://localhost:9000";
|
|
12
|
+
if (!publishableKey) {
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
const authHeaders = await getAuthHeaders();
|
|
16
|
+
const headers = {
|
|
17
|
+
"Content-Type": "application/json",
|
|
18
|
+
"Accept": "application/json",
|
|
19
|
+
"x-publishable-api-key": publishableKey,
|
|
20
|
+
};
|
|
21
|
+
if (authHeaders && "authorization" in authHeaders) {
|
|
22
|
+
headers["authorization"] = authHeaders.authorization;
|
|
23
|
+
}
|
|
24
|
+
const fetchStart = Date.now();
|
|
25
|
+
const response = await fetch(`${baseUrl}/store/dynamic-config`, {
|
|
26
|
+
method: "GET",
|
|
27
|
+
headers,
|
|
28
|
+
cache: "no-store",
|
|
29
|
+
});
|
|
30
|
+
const duration = Date.now() - fetchStart;
|
|
31
|
+
if (!response.ok) {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
const data = await response.json();
|
|
35
|
+
return data;
|
|
36
|
+
}
|
|
37
|
+
catch (error) {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
export function getLogoFromPageInput(pageInput) {
|
|
42
|
+
const config = resolvePageInput(pageInput);
|
|
43
|
+
return config.logo || null;
|
|
44
|
+
}
|
|
45
|
+
/** @deprecated Fetch in main project; pass `pageInput` into layout/pages instead. */
|
|
46
|
+
export const getLogoFromConfig = async () => {
|
|
47
|
+
const config = await getDynamicConfig();
|
|
48
|
+
return getLogoFromPageInput(config?.["homepage-config"] ?? null);
|
|
49
|
+
};
|
|
50
|
+
export const getBannerImageFromConfig = async () => {
|
|
51
|
+
try {
|
|
52
|
+
const config = await getDynamicConfig();
|
|
53
|
+
const bannerArray = config?.["homepage-config"]?.["homepage-banner-array"];
|
|
54
|
+
if (bannerArray && bannerArray.length > 0) {
|
|
55
|
+
const firstBanner = bannerArray[0];
|
|
56
|
+
const image = firstBanner?.["homepage-banner"]?.["homepage-banner-image"];
|
|
57
|
+
return image || null;
|
|
58
|
+
}
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
export const getMobileBannerFromConfig = async () => {
|
|
66
|
+
try {
|
|
67
|
+
const config = await getDynamicConfig();
|
|
68
|
+
const bannerArray = config?.["homepage-config"]?.["app-banner-array"];
|
|
69
|
+
if (bannerArray && bannerArray.length > 0) {
|
|
70
|
+
const firstBanner = bannerArray[0];
|
|
71
|
+
const image = firstBanner?.["app-banner"]?.["app-banner-image"] || null;
|
|
72
|
+
const link = firstBanner?.["app-banner"]?.["app-banner-button-link"] || firstBanner?.["app-banner"]?.["app-banner-link"] || null;
|
|
73
|
+
return { image, link };
|
|
74
|
+
}
|
|
75
|
+
return { image: null, link: null };
|
|
76
|
+
}
|
|
77
|
+
catch (error) {
|
|
78
|
+
return { image: null, link: null };
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
export function getHomeBannersFromPageInput(pageInput) {
|
|
82
|
+
const config = resolvePageInput(pageInput);
|
|
83
|
+
const bannerArray = config["homepage-banner-array"];
|
|
84
|
+
if (bannerArray && bannerArray.length > 0) {
|
|
85
|
+
return bannerArray.map((item) => {
|
|
86
|
+
const banner = item["homepage-banner"];
|
|
87
|
+
return {
|
|
88
|
+
image: banner?.["homepage-banner-image"],
|
|
89
|
+
title: normalizeCmsText(banner?.["homepage-banner-title"]),
|
|
90
|
+
subtitle: normalizeCmsText(banner?.["homepage-banner-subtitle"]),
|
|
91
|
+
description: normalizeCmsText(banner?.["homepage-banner-description"]),
|
|
92
|
+
buttonName: normalizeBannerButtonName(banner?.["homepage-banner-button-name"]),
|
|
93
|
+
buttonLink: banner?.["homepage-banner-button-link"],
|
|
94
|
+
};
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
export function getAppBannersFromPageInput(pageInput) {
|
|
100
|
+
const config = resolvePageInput(pageInput);
|
|
101
|
+
const bannerArray = config["app-banner-array"];
|
|
102
|
+
if (bannerArray && bannerArray.length > 0) {
|
|
103
|
+
return bannerArray.map((item) => {
|
|
104
|
+
const banner = item["app-banner"];
|
|
105
|
+
return {
|
|
106
|
+
image: banner?.["app-banner-image"],
|
|
107
|
+
title: normalizeCmsText(banner?.["app-banner-title"]),
|
|
108
|
+
subtitle: normalizeCmsText(banner?.["app-banner-subtitle"]),
|
|
109
|
+
description: normalizeCmsText(banner?.["app-banner-description"]),
|
|
110
|
+
buttonName: normalizeBannerButtonName(banner?.["app-banner-button-name"]),
|
|
111
|
+
buttonLink: banner?.["app-banner-button-link"],
|
|
112
|
+
};
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
117
|
+
/** @deprecated Pass `pageInput` from main project. */
|
|
118
|
+
export const getHomeBannersFromConfig = async () => {
|
|
119
|
+
const config = await getDynamicConfig();
|
|
120
|
+
return getHomeBannersFromPageInput(config?.["homepage-config"] ?? null);
|
|
121
|
+
};
|
|
122
|
+
/** @deprecated Pass `pageInput` from main project. */
|
|
123
|
+
export const getAppBannersFromConfig = async () => {
|
|
124
|
+
const config = await getDynamicConfig();
|
|
125
|
+
return getAppBannersFromPageInput(config?.["homepage-config"] ?? null);
|
|
126
|
+
};
|
|
127
|
+
// Legacy function for backward compatibility
|
|
128
|
+
export const getMobileBannerImageFromConfig = async () => {
|
|
129
|
+
const { image } = await getMobileBannerFromConfig();
|
|
130
|
+
return image;
|
|
131
|
+
};
|
|
132
|
+
export function getWebsiteDescriptionFromPageInput(pageInput) {
|
|
133
|
+
const config = resolvePageInput(pageInput);
|
|
134
|
+
const desc = config["website-description"] || config["website_description"];
|
|
135
|
+
return desc || null;
|
|
136
|
+
}
|
|
137
|
+
/** @deprecated Pass `pageInput` from main project. */
|
|
138
|
+
export const getWebsiteDescriptionFromConfig = async () => {
|
|
139
|
+
const config = await getDynamicConfig();
|
|
140
|
+
return getWebsiteDescriptionFromPageInput(config?.["homepage-config"] ?? null);
|
|
141
|
+
};
|
|
142
|
+
/** Why choose us — defaults + `sections.whyChooseUs` override. */
|
|
143
|
+
export function getFeaturesFromPageInput(pageInput) {
|
|
144
|
+
const block = getMergedSectionBlock("whyChooseUs", pageInput);
|
|
145
|
+
const copy = parseSectionCopy(block);
|
|
146
|
+
const title = copy.title ?? copy.name ?? "";
|
|
147
|
+
const featuresRaw = block.features ?? block.items ?? [];
|
|
148
|
+
const features = parseFeatureIconList(featuresRaw);
|
|
149
|
+
return { title, features };
|
|
150
|
+
}
|
|
151
|
+
/** @deprecated Pass `pageInput` from main project. */
|
|
152
|
+
export const getFeaturesFromConfig = async () => {
|
|
153
|
+
const config = await getDynamicConfig();
|
|
154
|
+
return getFeaturesFromPageInput(config?.["homepage-config"] ?? null);
|
|
155
|
+
};
|
|
156
|
+
function parseFeatureIconList(raw) {
|
|
157
|
+
if (!Array.isArray(raw))
|
|
158
|
+
return [];
|
|
159
|
+
return raw
|
|
160
|
+
.map((item) => {
|
|
161
|
+
if (!item || typeof item !== "object")
|
|
162
|
+
return null;
|
|
163
|
+
const feature = item.feature ?? item;
|
|
164
|
+
const row = feature;
|
|
165
|
+
const name = normalizeCmsText(row["feature-name"] ?? row.name) ?? "";
|
|
166
|
+
const icon = normalizeCmsText(row["feature-icon"] ?? row.icon) ?? "";
|
|
167
|
+
return name && icon ? { name, icon } : null;
|
|
168
|
+
})
|
|
169
|
+
.filter(Boolean);
|
|
170
|
+
}
|
|
171
|
+
const EMAIL_PATTERN = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
|
|
172
|
+
/** Fix common UTF-8 mojibake from CMS copy-paste (e.g. em dash, apostrophe). */
|
|
173
|
+
function normalizeCmsText(value) {
|
|
174
|
+
if (typeof value !== "string" || !value.trim())
|
|
175
|
+
return undefined;
|
|
176
|
+
return value
|
|
177
|
+
.trim()
|
|
178
|
+
.replace(/ΓÇö/g, "—")
|
|
179
|
+
.replace(/ΓÇÖ/g, "'")
|
|
180
|
+
.replace(/ΓÇ£|ΓÇ¥/g, '"')
|
|
181
|
+
.replace(/≡ƒÿÄ≡ƒæòΓ£¿/g, " 👕✨");
|
|
182
|
+
}
|
|
183
|
+
const EMPTY_SECTION_COPY = {
|
|
184
|
+
title: null,
|
|
185
|
+
name: null,
|
|
186
|
+
text: null,
|
|
187
|
+
description: null,
|
|
188
|
+
subtitle: null,
|
|
189
|
+
eyebrow: null,
|
|
190
|
+
variant: null,
|
|
191
|
+
layout: null,
|
|
192
|
+
};
|
|
193
|
+
export function parseSectionCopy(block) {
|
|
194
|
+
if (!block || typeof block !== "object")
|
|
195
|
+
return { ...EMPTY_SECTION_COPY };
|
|
196
|
+
const row = block;
|
|
197
|
+
return {
|
|
198
|
+
title: normalizeCmsText(row.title) ?? null,
|
|
199
|
+
name: normalizeCmsText(row.name) ?? null,
|
|
200
|
+
text: normalizeCmsText(row.text) ?? null,
|
|
201
|
+
description: normalizeCmsText(row.description) ?? null,
|
|
202
|
+
subtitle: normalizeCmsText(row.subtitle) ?? null,
|
|
203
|
+
eyebrow: normalizeCmsText(row.eyebrow) ?? null,
|
|
204
|
+
variant: normalizeCmsText(row.variant) ?? null,
|
|
205
|
+
layout: normalizeCmsText(row.layout) ?? null,
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
const HOME_SECTION_COPY_IDS = new Set(HOME_SECTION_COPY_ID_LIST);
|
|
209
|
+
function sectionIdFromConfigKey(key) {
|
|
210
|
+
const id = key.replace(/-([a-z])/g, (_, c) => c.toUpperCase());
|
|
211
|
+
return HOME_SECTION_COPY_IDS.has(id) ? id : null;
|
|
212
|
+
}
|
|
213
|
+
function getHomepageSectionsRoot(pageInput) {
|
|
214
|
+
const config = resolvePageInput(pageInput);
|
|
215
|
+
const root = config.sections;
|
|
216
|
+
return root && typeof root === "object"
|
|
217
|
+
? root
|
|
218
|
+
: {};
|
|
219
|
+
}
|
|
220
|
+
function findSectionBlock(root, id) {
|
|
221
|
+
for (const [key, value] of Object.entries(root)) {
|
|
222
|
+
if (sectionIdFromConfigKey(key) !== id)
|
|
223
|
+
continue;
|
|
224
|
+
if (value && typeof value === "object") {
|
|
225
|
+
return value;
|
|
226
|
+
}
|
|
227
|
+
if (typeof value === "string") {
|
|
228
|
+
return { text: value };
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
return null;
|
|
232
|
+
}
|
|
233
|
+
export { mergeSectionBlock } from "./config-merge";
|
|
234
|
+
export function getMergedSectionBlock(id, pageInput) {
|
|
235
|
+
const root = getHomepageSectionsRoot(pageInput);
|
|
236
|
+
const defaults = DEFAULT_HOMEPAGE_SECTIONS[id] ?? {};
|
|
237
|
+
const override = findSectionBlock(root, id);
|
|
238
|
+
return mergeSectionBlock({ ...defaults }, override);
|
|
239
|
+
}
|
|
240
|
+
function mergeSectionCopy(base, patch) {
|
|
241
|
+
const pick = (override, fallback) => override ?? fallback;
|
|
242
|
+
return {
|
|
243
|
+
title: pick(patch.title ?? patch.name, base.title ?? base.name),
|
|
244
|
+
name: pick(patch.name, base.name),
|
|
245
|
+
text: pick(patch.text, base.text),
|
|
246
|
+
description: pick(patch.description, base.description),
|
|
247
|
+
subtitle: pick(patch.subtitle, base.subtitle),
|
|
248
|
+
eyebrow: pick(patch.eyebrow, base.eyebrow),
|
|
249
|
+
variant: pick(patch.variant ?? patch.layout, base.variant ?? base.layout),
|
|
250
|
+
layout: pick(patch.layout ?? patch.variant, base.layout ?? base.variant),
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
function parseAnnouncementMessages(block) {
|
|
254
|
+
if (!block)
|
|
255
|
+
return [];
|
|
256
|
+
const raw = block.messages ?? block.items ?? block["announcement-messages"];
|
|
257
|
+
if (!Array.isArray(raw))
|
|
258
|
+
return [];
|
|
259
|
+
return raw
|
|
260
|
+
.map((item) => {
|
|
261
|
+
if (typeof item === "string")
|
|
262
|
+
return item.trim();
|
|
263
|
+
if (item && typeof item === "object") {
|
|
264
|
+
const row = item;
|
|
265
|
+
const nested = (row.message ?? row.text);
|
|
266
|
+
return typeof nested === "string" ? nested.trim() : "";
|
|
267
|
+
}
|
|
268
|
+
return "";
|
|
269
|
+
})
|
|
270
|
+
.filter(Boolean);
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Merged section copy: package defaults + `homepage-config.sections` overrides.
|
|
274
|
+
*/
|
|
275
|
+
export function getHomeSectionsCopyFromPageInput(pageInput) {
|
|
276
|
+
const copy = {};
|
|
277
|
+
for (const id of HOME_SECTION_COPY_ID_LIST) {
|
|
278
|
+
const block = getMergedSectionBlock(id, pageInput);
|
|
279
|
+
copy[id] = parseSectionCopy(block);
|
|
280
|
+
}
|
|
281
|
+
return copy;
|
|
282
|
+
}
|
|
283
|
+
/** @deprecated Pass `pageInput` from main project instead of fetching here. */
|
|
284
|
+
export const getHomeSectionsCopyFromConfig = async () => {
|
|
285
|
+
const config = await getDynamicConfig();
|
|
286
|
+
return getHomeSectionsCopyFromPageInput(config?.["homepage-config"] ?? null);
|
|
287
|
+
};
|
|
288
|
+
/** Trust badge row — defaults + `sections.features` override. */
|
|
289
|
+
export function getTrustFeaturesFromPageInput(pageInput) {
|
|
290
|
+
const block = getMergedSectionBlock("features", pageInput);
|
|
291
|
+
const copy = parseSectionCopy(block);
|
|
292
|
+
const title = copy.title ?? copy.name;
|
|
293
|
+
const description = copy.description ?? copy.text;
|
|
294
|
+
const rawList = block.features ?? block.items ?? [];
|
|
295
|
+
const features = parseFeatureIconList(rawList);
|
|
296
|
+
return { title: title ?? null, description: description ?? null, features };
|
|
297
|
+
}
|
|
298
|
+
/** @deprecated Pass `pageInput` from main project. */
|
|
299
|
+
export const getTrustFeaturesFromConfig = async () => {
|
|
300
|
+
const config = await getDynamicConfig();
|
|
301
|
+
return getTrustFeaturesFromPageInput(config?.["homepage-config"] ?? null);
|
|
302
|
+
};
|
|
303
|
+
function normalizeBannerButtonName(value) {
|
|
304
|
+
const text = normalizeCmsText(value);
|
|
305
|
+
if (!text)
|
|
306
|
+
return undefined;
|
|
307
|
+
if (/^shop\s+now\s*1$/i.test(text))
|
|
308
|
+
return "Shop Now";
|
|
309
|
+
return text;
|
|
310
|
+
}
|
|
311
|
+
function normalizeConfigEmail(value) {
|
|
312
|
+
if (typeof value !== "string")
|
|
313
|
+
return undefined;
|
|
314
|
+
const trimmed = value.trim();
|
|
315
|
+
return EMAIL_PATTERN.test(trimmed) ? trimmed : undefined;
|
|
316
|
+
}
|
|
317
|
+
export function getContactInfoFromPageInput(pageInput) {
|
|
318
|
+
const config = resolvePageInput(pageInput);
|
|
319
|
+
const contactConfig = config["contact-us"];
|
|
320
|
+
if (!contactConfig)
|
|
321
|
+
return null;
|
|
322
|
+
return {
|
|
323
|
+
phone: contactConfig["contact-phone"],
|
|
324
|
+
email: normalizeConfigEmail(contactConfig["contact-email"]),
|
|
325
|
+
address: contactConfig["contact-address"],
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
/** @deprecated Pass `pageInput` from main project. */
|
|
329
|
+
export const getContactInfoFromConfig = async () => {
|
|
330
|
+
const config = await getDynamicConfig();
|
|
331
|
+
return getContactInfoFromPageInput(config?.["homepage-config"] ?? null);
|
|
332
|
+
};
|
|
333
|
+
function normalizeVideoStoryUrl(entry) {
|
|
334
|
+
if (typeof entry === "string" && entry.trim())
|
|
335
|
+
return entry.trim();
|
|
336
|
+
if (!entry || typeof entry !== "object")
|
|
337
|
+
return null;
|
|
338
|
+
const row = entry;
|
|
339
|
+
const nested = row["video-story"] ??
|
|
340
|
+
row["video_stories"] ??
|
|
341
|
+
row;
|
|
342
|
+
const url = nested["video-url"] ??
|
|
343
|
+
nested["video_url"] ??
|
|
344
|
+
nested.url ??
|
|
345
|
+
nested.src ??
|
|
346
|
+
nested.video;
|
|
347
|
+
return typeof url === "string" && url.trim() ? url.trim() : null;
|
|
348
|
+
}
|
|
349
|
+
/**
|
|
350
|
+
* Homepage video stories/reviews carousel (`homepage-config.video-stories`).
|
|
351
|
+
*/
|
|
352
|
+
export function getVideoStoriesFromPageInput(pageInput) {
|
|
353
|
+
const homepageConfig = resolvePageInput(pageInput);
|
|
354
|
+
const block = getMergedSectionBlock("videoStories", pageInput);
|
|
355
|
+
const copy = parseSectionCopy(block);
|
|
356
|
+
const title = copy.title ?? copy.name ?? "";
|
|
357
|
+
const raw = block["video-urls"] ??
|
|
358
|
+
block.videoUrls ??
|
|
359
|
+
block.videos ??
|
|
360
|
+
block["video-stories"] ??
|
|
361
|
+
homepageConfig["video-stories"] ??
|
|
362
|
+
homepageConfig["video-stories-array"] ??
|
|
363
|
+
homepageConfig["video_stories"] ??
|
|
364
|
+
[];
|
|
365
|
+
const list = Array.isArray(raw) ? raw : [raw];
|
|
366
|
+
const videoUrls = list
|
|
367
|
+
.map(normalizeVideoStoryUrl)
|
|
368
|
+
.filter((url) => Boolean(url));
|
|
369
|
+
return { title, videoUrls };
|
|
370
|
+
}
|
|
371
|
+
/** @deprecated Pass `pageInput` from main project. */
|
|
372
|
+
export const getVideoStoriesFromConfig = async () => {
|
|
373
|
+
const config = await getDynamicConfig();
|
|
374
|
+
return getVideoStoriesFromPageInput(config?.["homepage-config"] ?? null);
|
|
375
|
+
};
|
|
376
|
+
function parseTestimonialRow(item, index) {
|
|
377
|
+
if (!item || typeof item !== "object")
|
|
378
|
+
return null;
|
|
379
|
+
const row = item.testimonial ??
|
|
380
|
+
item.review ??
|
|
381
|
+
item;
|
|
382
|
+
const r = row;
|
|
383
|
+
const text = String(r.text ?? r["review-description"] ?? r.description ?? r.quote ?? "").trim();
|
|
384
|
+
const name = String(r.name ?? r["review-user-name"] ?? r.author ?? r["user-name"] ?? "").trim();
|
|
385
|
+
if (!text || !name)
|
|
386
|
+
return null;
|
|
387
|
+
const ratingRaw = r.rating ?? r["review-rating"];
|
|
388
|
+
const rating = ratingRaw != null && ratingRaw !== ""
|
|
389
|
+
? parseFloat(String(ratingRaw))
|
|
390
|
+
: undefined;
|
|
391
|
+
return {
|
|
392
|
+
id: String(r.id ?? `review-${index}`),
|
|
393
|
+
text,
|
|
394
|
+
name,
|
|
395
|
+
rating: Number.isFinite(rating) ? rating : undefined,
|
|
396
|
+
avatar: (r.avatar ?? r["review-profile-image"] ?? r.image),
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
function parseTestimonialsFromBlock(block) {
|
|
400
|
+
const raw = block.items ??
|
|
401
|
+
block.testimonials ??
|
|
402
|
+
block.reviews ??
|
|
403
|
+
block["testimonial-items"] ??
|
|
404
|
+
[];
|
|
405
|
+
if (!Array.isArray(raw))
|
|
406
|
+
return [];
|
|
407
|
+
return raw
|
|
408
|
+
.map((item, index) => parseTestimonialRow(item, index))
|
|
409
|
+
.filter((t) => t !== null);
|
|
410
|
+
}
|
|
411
|
+
function parseRatingsFromHomepage(ratings) {
|
|
412
|
+
if (!Array.isArray(ratings))
|
|
413
|
+
return [];
|
|
414
|
+
return ratings
|
|
415
|
+
.map((item, index) => parseTestimonialRow(item, index))
|
|
416
|
+
.filter((t) => t !== null);
|
|
417
|
+
}
|
|
418
|
+
export function getTestimonialsFromPageInput(pageInput) {
|
|
419
|
+
const homepageConfig = resolvePageInput(pageInput);
|
|
420
|
+
const block = getMergedSectionBlock("testimonials", pageInput);
|
|
421
|
+
const copy = parseSectionCopy(block);
|
|
422
|
+
const title = copy.title ?? copy.name ?? "";
|
|
423
|
+
const subtitle = (copy.description ?? copy.text ?? null);
|
|
424
|
+
let testimonials = parseTestimonialsFromBlock(block);
|
|
425
|
+
if (testimonials.length === 0) {
|
|
426
|
+
testimonials = parseRatingsFromHomepage(homepageConfig["ratings"]);
|
|
427
|
+
}
|
|
428
|
+
if (testimonials.length === 0) {
|
|
429
|
+
testimonials = parseTestimonialsFromBlock(DEFAULT_HOMEPAGE_SECTIONS.testimonials);
|
|
430
|
+
}
|
|
431
|
+
return { title, subtitle, testimonials };
|
|
432
|
+
}
|
|
433
|
+
/** @deprecated Pass `pageInput` from main project. */
|
|
434
|
+
export const getTestimonialsFromConfig = async () => {
|
|
435
|
+
const config = await getDynamicConfig();
|
|
436
|
+
return getTestimonialsFromPageInput(config?.["homepage-config"] ?? null);
|
|
437
|
+
};
|
|
438
|
+
export function getSocialLinksFromPageInput(pageInput) {
|
|
439
|
+
const config = resolvePageInput(pageInput);
|
|
440
|
+
const socialLinksRaw = config["social-links"] || [];
|
|
441
|
+
const socialLinks = socialLinksRaw
|
|
442
|
+
.map((item) => {
|
|
443
|
+
const link = (item?.["social-link"] || item);
|
|
444
|
+
return {
|
|
445
|
+
name: String(link?.["social-platform-name"] || ""),
|
|
446
|
+
url: String(link?.["social-platform-url"] || ""),
|
|
447
|
+
icon: link?.["social-platform-icon"],
|
|
448
|
+
};
|
|
449
|
+
})
|
|
450
|
+
.filter((l) => l.name && l.url);
|
|
451
|
+
return socialLinks.length > 0 ? socialLinks : null;
|
|
452
|
+
}
|
|
453
|
+
/** @deprecated Pass `pageInput` from main project. */
|
|
454
|
+
export const getSocialLinksFromConfig = async () => {
|
|
455
|
+
const config = await getDynamicConfig();
|
|
456
|
+
return getSocialLinksFromPageInput(config?.["homepage-config"] ?? null);
|
|
457
|
+
};
|
|
458
|
+
export function getFaqsFromPageInput(pageInput) {
|
|
459
|
+
const config = resolvePageInput(pageInput);
|
|
460
|
+
const faqsRaw = config["faq-array"] || [];
|
|
461
|
+
if (!Array.isArray(faqsRaw) || faqsRaw.length === 0)
|
|
462
|
+
return null;
|
|
463
|
+
const categoriesMap = {};
|
|
464
|
+
faqsRaw.forEach((item) => {
|
|
465
|
+
const faq = (item?.["faq"] || item);
|
|
466
|
+
const displayCategory = String(faq?.["faq-category"] || "General Questions").trim();
|
|
467
|
+
const categoryKey = displayCategory.toLowerCase();
|
|
468
|
+
const q = String(faq?.["faq-question"] || "").trim();
|
|
469
|
+
const a = String(faq?.["faq-answer"] || "").trim();
|
|
470
|
+
if (q && a) {
|
|
471
|
+
if (!categoriesMap[categoryKey]) {
|
|
472
|
+
categoriesMap[categoryKey] = { displayCategory, items: [] };
|
|
473
|
+
}
|
|
474
|
+
categoriesMap[categoryKey].items.push({ q, a });
|
|
475
|
+
}
|
|
476
|
+
});
|
|
477
|
+
const faqs = Object.values(categoriesMap).map((catData) => ({
|
|
478
|
+
category: catData.displayCategory,
|
|
479
|
+
items: catData.items,
|
|
480
|
+
}));
|
|
481
|
+
return faqs.length > 0 ? faqs : null;
|
|
482
|
+
}
|
|
483
|
+
/** @deprecated Pass `pageInput` from main project. */
|
|
484
|
+
export const getFaqsFromConfig = async () => {
|
|
485
|
+
const config = await getDynamicConfig();
|
|
486
|
+
return getFaqsFromPageInput(config?.["homepage-config"] ?? null);
|
|
487
|
+
};
|
|
488
|
+
export function getAnnouncementMessagesFromPageInput(pageInput) {
|
|
489
|
+
const block = getMergedSectionBlock("promoAnnouncements", pageInput);
|
|
490
|
+
return parseAnnouncementMessages(block);
|
|
491
|
+
}
|
|
492
|
+
/** @deprecated Pass `pageInput` from main project. */
|
|
493
|
+
export const getAnnouncementMessagesFromConfig = async () => {
|
|
494
|
+
const config = await getDynamicConfig();
|
|
495
|
+
return getAnnouncementMessagesFromPageInput(config?.["homepage-config"] ?? null);
|
|
496
|
+
};
|
|
497
|
+
export function getAboutBrandFromPageInput(pageInput) {
|
|
498
|
+
const homepageConfig = resolvePageInput(pageInput);
|
|
499
|
+
const merged = getMergedSectionBlock("aboutBrand", pageInput);
|
|
500
|
+
const legacy = homepageConfig["about-brand"] ?? homepageConfig["who-we-are"];
|
|
501
|
+
const b = mergeSectionBlock(merged, legacy && typeof legacy === "object"
|
|
502
|
+
? legacy
|
|
503
|
+
: null);
|
|
504
|
+
const statsRaw = (b.stats ?? b["about-stats"] ?? []);
|
|
505
|
+
const stats = Array.isArray(statsRaw)
|
|
506
|
+
? statsRaw
|
|
507
|
+
.map((s) => {
|
|
508
|
+
if (!s || typeof s !== "object")
|
|
509
|
+
return null;
|
|
510
|
+
const row = s;
|
|
511
|
+
const label = String(row.label ?? row.name ?? "").trim();
|
|
512
|
+
const value = String(row.value ?? "").trim();
|
|
513
|
+
return label && value ? { label, value } : null;
|
|
514
|
+
})
|
|
515
|
+
.filter(Boolean)
|
|
516
|
+
: [];
|
|
517
|
+
const copy = parseSectionCopy(b);
|
|
518
|
+
return {
|
|
519
|
+
eyebrow: copy.eyebrow ?? "",
|
|
520
|
+
title: copy.title ?? copy.name ?? "",
|
|
521
|
+
description: copy.description ?? copy.text ?? "",
|
|
522
|
+
readMoreHref: String(b.readMoreHref ?? b["read-more-link"] ?? "/about"),
|
|
523
|
+
stats,
|
|
524
|
+
};
|
|
525
|
+
}
|
|
526
|
+
/** @deprecated Pass `pageInput` from main project. */
|
|
527
|
+
export const getAboutBrandFromConfig = async () => {
|
|
528
|
+
const config = await getDynamicConfig();
|
|
529
|
+
return getAboutBrandFromPageInput(config?.["homepage-config"] ?? null);
|
|
530
|
+
};
|
|
531
|
+
export function getBrandPillarsFromPageInput(pageInput) {
|
|
532
|
+
const block = getMergedSectionBlock("brandPillars", pageInput);
|
|
533
|
+
const copy = parseSectionCopy(block);
|
|
534
|
+
const sectionTitle = copy.title ?? copy.name ?? "";
|
|
535
|
+
const raw = block.pillars ?? block["brand-pillars"] ?? [];
|
|
536
|
+
const pillars = (Array.isArray(raw) ? raw : [])
|
|
537
|
+
.map((item) => {
|
|
538
|
+
if (!item || typeof item !== "object")
|
|
539
|
+
return null;
|
|
540
|
+
const row = item["pillar"] ?? item;
|
|
541
|
+
const p = row;
|
|
542
|
+
const title = String(p.title ?? p.name ?? "").trim();
|
|
543
|
+
const description = String(p.description ?? p.text ?? "").trim();
|
|
544
|
+
const image = (p.image ?? p.icon);
|
|
545
|
+
return title && description ? { title, description, image } : null;
|
|
546
|
+
})
|
|
547
|
+
.filter(Boolean);
|
|
548
|
+
return { sectionTitle, pillars };
|
|
549
|
+
}
|
|
550
|
+
/** @deprecated Pass `pageInput` from main project. */
|
|
551
|
+
export const getBrandPillarsFromConfig = async () => {
|
|
552
|
+
const config = await getDynamicConfig();
|
|
553
|
+
return getBrandPillarsFromPageInput(config?.["homepage-config"] ?? null);
|
|
554
|
+
};
|
|
555
|
+
export function getBlogPostsFromPageInput(pageInput) {
|
|
556
|
+
const block = getMergedSectionBlock("blogPosts", pageInput);
|
|
557
|
+
const raw = block.posts ?? block["blog-posts"] ?? block["blog-array"] ?? [];
|
|
558
|
+
return (Array.isArray(raw) ? raw : [])
|
|
559
|
+
.map((item) => {
|
|
560
|
+
if (!item || typeof item !== "object")
|
|
561
|
+
return null;
|
|
562
|
+
const row = item["blog"] ?? item;
|
|
563
|
+
const b = row;
|
|
564
|
+
const title = String(b.title ?? "").trim();
|
|
565
|
+
const href = String(b.href ?? b.link ?? b.url ?? "").trim();
|
|
566
|
+
if (!title || !href)
|
|
567
|
+
return null;
|
|
568
|
+
return {
|
|
569
|
+
title,
|
|
570
|
+
href,
|
|
571
|
+
excerpt: String(b.excerpt ?? b.description ?? "").trim() || undefined,
|
|
572
|
+
category: String(b.category ?? b.tag ?? "").trim() || undefined,
|
|
573
|
+
date: String(b.date ?? "").trim() || undefined,
|
|
574
|
+
image: (b.image ?? b.thumbnail),
|
|
575
|
+
};
|
|
576
|
+
})
|
|
577
|
+
.filter(Boolean);
|
|
578
|
+
}
|
|
579
|
+
/** @deprecated Pass `pageInput` from main project. */
|
|
580
|
+
export const getBlogPostsFromConfig = async () => {
|
|
581
|
+
const config = await getDynamicConfig();
|
|
582
|
+
return getBlogPostsFromPageInput(config?.["homepage-config"] ?? null);
|
|
583
|
+
};
|
|
584
|
+
function readPromoCountdownBlock(block) {
|
|
585
|
+
if (!block || typeof block !== "object") {
|
|
586
|
+
return {
|
|
587
|
+
code: null,
|
|
588
|
+
message: null,
|
|
589
|
+
endAt: null,
|
|
590
|
+
active: undefined,
|
|
591
|
+
ctaLabel: null,
|
|
592
|
+
ctaHref: null,
|
|
593
|
+
};
|
|
594
|
+
}
|
|
595
|
+
const row = block;
|
|
596
|
+
const code = normalizeCmsText(row["promo-code"] ?? row.code ?? row["coupon-code"]) ?? null;
|
|
597
|
+
const message = normalizeCmsText(row["promo-text"] ?? row.message ?? row.text) ?? null;
|
|
598
|
+
const endAtRaw = row["end-at"] ?? row.endAt ?? row["ends-at"];
|
|
599
|
+
const endAt = typeof endAtRaw === "string" && endAtRaw.trim() ? endAtRaw.trim() : null;
|
|
600
|
+
const activeRaw = row["promo-active"] ?? row.active;
|
|
601
|
+
const active = typeof activeRaw === "boolean" ? activeRaw : undefined;
|
|
602
|
+
const ctaLabel = normalizeCmsText(row["cta-label"] ?? row.ctaLabel ?? row["button-label"]) ?? null;
|
|
603
|
+
const ctaHref = normalizeCmsText(row["cta-href"] ?? row.ctaHref ?? row["button-href"]) ?? null;
|
|
604
|
+
return { code, message, endAt, active, ctaLabel, ctaHref };
|
|
605
|
+
}
|
|
606
|
+
/** Promo countdown — defaults + `sections.promoCountdown` override. */
|
|
607
|
+
export function getPromoCountdownFromPageInput(pageInput) {
|
|
608
|
+
const block = getMergedSectionBlock("promoCountdown", pageInput);
|
|
609
|
+
const fromBlock = readPromoCountdownBlock(block);
|
|
610
|
+
const defaults = readPromoCountdownBlock(DEFAULT_HOMEPAGE_SECTIONS.promoCountdown);
|
|
611
|
+
return {
|
|
612
|
+
code: fromBlock.code ?? defaults.code,
|
|
613
|
+
message: fromBlock.message ?? defaults.message,
|
|
614
|
+
endAt: fromBlock.endAt ?? defaults.endAt,
|
|
615
|
+
active: fromBlock.active ?? defaults.active ?? false,
|
|
616
|
+
ctaLabel: fromBlock.ctaLabel ?? defaults.ctaLabel,
|
|
617
|
+
ctaHref: fromBlock.ctaHref ?? defaults.ctaHref,
|
|
618
|
+
};
|
|
619
|
+
}
|
|
620
|
+
/** @deprecated Pass `pageInput` from main project. */
|
|
621
|
+
export const getPromoCountdownFromConfig = async () => {
|
|
622
|
+
const config = await getDynamicConfig();
|
|
623
|
+
return getPromoCountdownFromPageInput(config?.["homepage-config"] ?? null);
|
|
624
|
+
};
|
|
625
|
+
function parseInstagramPostRow(item, index) {
|
|
626
|
+
if (!item || typeof item !== "object")
|
|
627
|
+
return null;
|
|
628
|
+
const row = item.post ??
|
|
629
|
+
item.instagram ??
|
|
630
|
+
item;
|
|
631
|
+
const p = row;
|
|
632
|
+
const image = String(p.image ?? p["post-image"] ?? p.thumbnail ?? p.src ?? "").trim();
|
|
633
|
+
if (!image)
|
|
634
|
+
return null;
|
|
635
|
+
const url = String(p.url ?? p.link ?? p.href ?? p["post-url"] ?? "").trim() || undefined;
|
|
636
|
+
return {
|
|
637
|
+
id: String(p.id ?? `ig-${index}`),
|
|
638
|
+
image,
|
|
639
|
+
url,
|
|
640
|
+
};
|
|
641
|
+
}
|
|
642
|
+
function parseInstagramPostsFromBlock(block) {
|
|
643
|
+
const raw = block.posts ??
|
|
644
|
+
block.items ??
|
|
645
|
+
block["instagram-posts"] ??
|
|
646
|
+
block["posts-array"] ??
|
|
647
|
+
[];
|
|
648
|
+
if (!Array.isArray(raw))
|
|
649
|
+
return [];
|
|
650
|
+
return raw
|
|
651
|
+
.map((item, index) => parseInstagramPostRow(item, index))
|
|
652
|
+
.filter((p) => p !== null);
|
|
653
|
+
}
|
|
654
|
+
/** Instagram feed — `sections.instagramPosts` + optional social-links fallback. */
|
|
655
|
+
export function getInstagramPostsFromPageInput(pageInput) {
|
|
656
|
+
const defaultsBlock = DEFAULT_HOMEPAGE_SECTIONS.instagramPosts;
|
|
657
|
+
const defaultCopy = parseSectionCopy(defaultsBlock);
|
|
658
|
+
const defaultPosts = parseInstagramPostsFromBlock(defaultsBlock);
|
|
659
|
+
const block = getMergedSectionBlock("instagramPosts", pageInput);
|
|
660
|
+
const copy = parseSectionCopy(block);
|
|
661
|
+
let posts = parseInstagramPostsFromBlock(block);
|
|
662
|
+
if (posts.length === 0)
|
|
663
|
+
posts = defaultPosts;
|
|
664
|
+
const handle = normalizeCmsText(block.handle ??
|
|
665
|
+
block.username ??
|
|
666
|
+
block["instagram-handle"] ??
|
|
667
|
+
defaultsBlock.handle) ?? "yourbrand";
|
|
668
|
+
const profileUrl = normalizeCmsText(block["profile-url"] ??
|
|
669
|
+
block.profileUrl ??
|
|
670
|
+
block["instagram-url"] ??
|
|
671
|
+
defaultsBlock["profile-url"]) ?? `https://www.instagram.com/${handle.replace(/^@/, "")}/`;
|
|
672
|
+
const profileImage = (block["profile-image"] ??
|
|
673
|
+
block.profileImage ??
|
|
674
|
+
defaultsBlock["profile-image"]);
|
|
675
|
+
return {
|
|
676
|
+
title: copy.title ?? copy.name ?? defaultCopy.title ?? "Follow Us on Instagram",
|
|
677
|
+
handle,
|
|
678
|
+
profileUrl,
|
|
679
|
+
profileImage,
|
|
680
|
+
posts,
|
|
681
|
+
};
|
|
682
|
+
}
|
|
683
|
+
/** @deprecated Pass `pageInput` from main project. */
|
|
684
|
+
export const getInstagramPostsFromConfig = async () => {
|
|
685
|
+
const config = await getDynamicConfig();
|
|
686
|
+
return getInstagramPostsFromPageInput(config?.["homepage-config"] ?? null);
|
|
687
|
+
};
|
|
688
|
+
export { DEFAULT_HOMEPAGE_SECTIONS, } from "./homepage-section-defaults";
|
|
689
|
+
export { HOMEPAGE_SECTION_IDS } from "./homepage-config.types";
|
|
690
|
+
export function getPromoBarFromPageInput(pageInput) {
|
|
691
|
+
const config = resolvePageInput(pageInput);
|
|
692
|
+
const promoConfig = config["promo-bar"];
|
|
693
|
+
const text = normalizeCmsText(promoConfig?.["promo-text"]) ?? null;
|
|
694
|
+
const code = normalizeCmsText(promoConfig?.["promo-code"]) ?? null;
|
|
695
|
+
const value = normalizeCmsText(promoConfig?.["promo-value"]) ?? null;
|
|
696
|
+
const active = Boolean(promoConfig?.["promo-active"]);
|
|
697
|
+
return { text, code, value, active };
|
|
698
|
+
}
|
|
699
|
+
/** @deprecated Pass `pageInput` from main project. */
|
|
700
|
+
export const getPromoBarConfig = async () => {
|
|
701
|
+
const config = await getDynamicConfig();
|
|
702
|
+
return getPromoBarFromPageInput(config?.["homepage-config"] ?? null);
|
|
703
|
+
};
|