medusa-storefront-data 2.3.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 +133 -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/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/edge.d.ts.map +1 -0
- package/dist/src/middleware.d.ts.map +1 -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.d.ts.map +1 -0
- package/dist/{server → src/server}/cart.js +20 -20
- 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/{server → 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 +157 -0
- package/dist/src/server/dynamic-config.d.ts.map +1 -0
- package/dist/src/server/dynamic-config.js +573 -0
- package/dist/src/server/fulfillment.d.ts.map +1 -0
- package/dist/{server → src/server}/fulfillment.js +3 -3
- 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/{server → src/server}/home.d.ts +18 -9
- package/dist/src/server/home.d.ts.map +1 -0
- package/dist/src/server/home.js +1 -0
- 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/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/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/{server → src/server}/orders.js +6 -6
- 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 +42 -0
- package/dist/src/server/payment-details.d.ts.map +1 -0
- package/dist/{server → src/server}/payment-details.js +5 -5
- package/dist/src/server/payment.d.ts.map +1 -0
- package/dist/{server → src/server}/payment.js +2 -2
- 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/{server → src/server}/regions.js +2 -2
- 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/{util → src/util}/store-client.d.ts +0 -2
- package/dist/src/util/store-client.d.ts.map +1 -0
- package/dist/{util → src/util}/store-client.js +0 -2
- package/homepage-config.example.json +209 -0
- package/homepage-sections.example.json +55 -0
- package/package.json +120 -156
- package/segment-data/default-page-input.json +191 -0
- package/src/server/brand-pillars-from-categories.ts +156 -0
- package/src/server/cart.ts +20 -20
- package/src/server/config-merge.ts +31 -0
- package/src/server/customer.ts +11 -11
- package/src/server/dynamic-config.ts +507 -566
- package/src/server/fulfillment.ts +3 -3
- 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 +46 -207
- 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/normalize-homepage-config.ts +240 -0
- package/src/server/orders.ts +6 -6
- package/src/server/page-input.ts +66 -0
- 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/resolve-home-segment-data.ts +63 -0
- package/src/server/shoppable-looks.ts +178 -0
- package/src/util/store-client.ts +0 -3
- 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.map +0 -1
- package/dist/server/home.js +0 -124
- 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}/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}/fulfillment.d.ts +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}/payment-details.d.ts +0 -0
- /package/dist/{server → src/server}/payment.d.ts +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}/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
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"
|
|
1
|
+
import "server-only"
|
|
2
2
|
|
|
3
3
|
import { cache } from "react"
|
|
4
4
|
import { getAuthHeaders } from "../cookies"
|
|
@@ -7,74 +7,20 @@ import {
|
|
|
7
7
|
HOME_SECTION_COPY_ID_LIST,
|
|
8
8
|
type DefaultHomeSectionId,
|
|
9
9
|
} from "./homepage-section-defaults"
|
|
10
|
+
import type { DynamicConfigResponse, HomepageConfig } from "./homepage-config.types"
|
|
11
|
+
import { mergeSectionBlock } from "./config-merge"
|
|
12
|
+
import { mergePageInputWithDefaults, resolvePageInput } from "./page-input"
|
|
13
|
+
|
|
14
|
+
export {
|
|
15
|
+
DEFAULT_PAGE_INPUT,
|
|
16
|
+
mergePageInputWithDefaults,
|
|
17
|
+
resolvePageInput,
|
|
18
|
+
homepageConfigFromDynamicResponse,
|
|
19
|
+
type StorefrontPageInput,
|
|
20
|
+
} from "./page-input"
|
|
10
21
|
|
|
11
|
-
// Define the structure based on the actual API response and client usage
|
|
12
|
-
export interface DynamicConfig {
|
|
13
|
-
"homepage-config"?: {
|
|
14
|
-
logo?: string
|
|
15
|
-
"homepage-banner-array"?: Array<{
|
|
16
|
-
"homepage-banner"?: {
|
|
17
|
-
"homepage-banner-image"?: string
|
|
18
|
-
"homepage-banner-title"?: string
|
|
19
|
-
"homepage-banner-subtitle"?: string
|
|
20
|
-
"homepage-banner-description"?: string
|
|
21
|
-
"homepage-banner-button-name"?: string
|
|
22
|
-
"homepage-banner-button-link"?: string
|
|
23
|
-
}
|
|
24
|
-
}>
|
|
25
|
-
"app-banner-array"?: Array<{
|
|
26
|
-
"app-banner"?: {
|
|
27
|
-
"app-banner-image"?: string
|
|
28
|
-
"app-banner-title"?: string
|
|
29
|
-
"app-banner-subtitle"?: string
|
|
30
|
-
"app-banner-description"?: string
|
|
31
|
-
"app-banner-button-name"?: string
|
|
32
|
-
"app-banner-button-link"?: string
|
|
33
|
-
"app-banner-link"?: string
|
|
34
|
-
}
|
|
35
|
-
}>
|
|
36
|
-
"website-description"?: string
|
|
37
|
-
"website_description"?: string
|
|
38
|
-
"why-choose-us-title"?: string
|
|
39
|
-
"why-choose-us-features"?: Array<{
|
|
40
|
-
feature?: {
|
|
41
|
-
"feature-name"?: string
|
|
42
|
-
"feature-icon"?: string
|
|
43
|
-
}
|
|
44
|
-
// Handle potential direct structure if any
|
|
45
|
-
"feature-name"?: string
|
|
46
|
-
"feature-icon"?: string
|
|
47
|
-
}>
|
|
48
|
-
"contact-us"?: {
|
|
49
|
-
"contact-phone"?: string
|
|
50
|
-
"contact-email"?: string
|
|
51
|
-
"contact-address"?: string
|
|
52
|
-
}
|
|
53
|
-
"social-links"?: Array<{
|
|
54
|
-
"social-link"?: {
|
|
55
|
-
"social-platform-name"?: string
|
|
56
|
-
"social-platform-icon"?: string
|
|
57
|
-
"social-platform-url"?: string
|
|
58
|
-
}
|
|
59
|
-
// Handle potential direct structure if any
|
|
60
|
-
"social-platform-name"?: string
|
|
61
|
-
"social-platform-icon"?: string
|
|
62
|
-
"social-platform-url"?: string
|
|
63
|
-
}>
|
|
64
|
-
"promo-bar"?: {
|
|
65
|
-
"promo-text"?: string
|
|
66
|
-
"promo-code"?: string
|
|
67
|
-
"promo-value"?: string
|
|
68
|
-
"promo-active"?: boolean
|
|
69
|
-
}
|
|
70
|
-
/** Central homepage section copy (Option 1). Keys: camelCase or kebab-case section ids. */
|
|
71
|
-
sections?: Record<string, unknown>
|
|
72
|
-
// Allow for other properties
|
|
73
|
-
[key: string]: any
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
22
|
|
|
77
|
-
export const getDynamicConfig = cache(async (): Promise<
|
|
23
|
+
export const getDynamicConfig = cache(async (): Promise<DynamicConfigResponse | null> => {
|
|
78
24
|
try {
|
|
79
25
|
const publishableKey = process.env.NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY
|
|
80
26
|
const baseUrl = process.env.MEDUSA_BACKEND_URL || "http://localhost:9000"
|
|
@@ -123,166 +69,96 @@ export const getDynamicConfig = cache(async (): Promise<DynamicConfig | null> =>
|
|
|
123
69
|
}
|
|
124
70
|
})
|
|
125
71
|
|
|
126
|
-
export
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
return logo || null
|
|
132
|
-
} catch (error) {
|
|
133
|
-
|
|
134
|
-
return null
|
|
135
|
-
}
|
|
72
|
+
export function getLogoFromPageInput(
|
|
73
|
+
pageInput?: HomepageConfig | null
|
|
74
|
+
): string | null {
|
|
75
|
+
const config = resolvePageInput(pageInput)
|
|
76
|
+
return config.logo || null
|
|
136
77
|
}
|
|
137
78
|
|
|
138
|
-
export const getBannerImageFromConfig = async (): Promise<string | null> => {
|
|
139
|
-
try {
|
|
140
|
-
const config = await getDynamicConfig()
|
|
141
|
-
const bannerArray = config?.["homepage-config"]?.["homepage-banner-array"]
|
|
142
79
|
|
|
143
|
-
if (bannerArray && bannerArray.length > 0) {
|
|
144
|
-
const firstBanner = bannerArray[0]
|
|
145
|
-
const image = firstBanner?.["homepage-banner"]?.["homepage-banner-image"]
|
|
146
80
|
|
|
147
|
-
return image || null
|
|
148
|
-
}
|
|
149
81
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
82
|
+
export type HomepageBanner = {
|
|
83
|
+
image?: string
|
|
84
|
+
title?: string
|
|
85
|
+
subtitle?: string
|
|
86
|
+
description?: string
|
|
87
|
+
buttonName?: string
|
|
88
|
+
buttonLink?: string
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export function getHomeBannersFromPageInput(
|
|
92
|
+
pageInput?: HomepageConfig | null
|
|
93
|
+
): HomepageBanner[] | null {
|
|
94
|
+
const config = resolvePageInput(pageInput)
|
|
95
|
+
const bannerArray = config["homepage-banner-array"]
|
|
96
|
+
if (bannerArray && bannerArray.length > 0) {
|
|
97
|
+
return bannerArray.map((item) => {
|
|
98
|
+
const banner = item["homepage-banner"]
|
|
99
|
+
return {
|
|
100
|
+
image: banner?.["homepage-banner-image"],
|
|
101
|
+
title: normalizeCmsText(banner?.["homepage-banner-title"]),
|
|
102
|
+
subtitle: normalizeCmsText(banner?.["homepage-banner-subtitle"]),
|
|
103
|
+
description: normalizeCmsText(banner?.["homepage-banner-description"]),
|
|
104
|
+
buttonName: normalizeBannerButtonName(banner?.["homepage-banner-button-name"]),
|
|
105
|
+
buttonLink: banner?.["homepage-banner-button-link"],
|
|
106
|
+
}
|
|
107
|
+
})
|
|
155
108
|
}
|
|
109
|
+
return null
|
|
156
110
|
}
|
|
157
111
|
|
|
158
|
-
export
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
const
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
return { image: null, link: null }
|
|
112
|
+
export function getAppBannersFromPageInput(
|
|
113
|
+
pageInput?: HomepageConfig | null
|
|
114
|
+
): HomepageBanner[] | null {
|
|
115
|
+
const config = resolvePageInput(pageInput)
|
|
116
|
+
const bannerArray = config["app-banner-array"]
|
|
117
|
+
if (bannerArray && bannerArray.length > 0) {
|
|
118
|
+
return bannerArray.map((item) => {
|
|
119
|
+
const banner = item["app-banner"]
|
|
120
|
+
return {
|
|
121
|
+
image: banner?.["app-banner-image"],
|
|
122
|
+
title: normalizeCmsText(banner?.["app-banner-title"]),
|
|
123
|
+
subtitle: normalizeCmsText(banner?.["app-banner-subtitle"]),
|
|
124
|
+
description: normalizeCmsText(banner?.["app-banner-description"]),
|
|
125
|
+
buttonName: normalizeBannerButtonName(banner?.["app-banner-button-name"]),
|
|
126
|
+
buttonLink: banner?.["app-banner-button-link"],
|
|
127
|
+
}
|
|
128
|
+
})
|
|
176
129
|
}
|
|
130
|
+
return null
|
|
177
131
|
}
|
|
178
132
|
|
|
179
|
-
export const getHomeBannersFromConfig = async (): Promise<Array<{
|
|
180
|
-
image?: string;
|
|
181
|
-
title?: string;
|
|
182
|
-
subtitle?: string;
|
|
183
|
-
description?: string;
|
|
184
|
-
buttonName?: string;
|
|
185
|
-
buttonLink?: string;
|
|
186
|
-
}> | null> => {
|
|
187
|
-
try {
|
|
188
|
-
const config = await getDynamicConfig()
|
|
189
|
-
const bannerArray = config?.["homepage-config"]?.["homepage-banner-array"]
|
|
190
|
-
|
|
191
|
-
if (bannerArray && bannerArray.length > 0) {
|
|
192
|
-
return bannerArray.map(item => {
|
|
193
|
-
const banner = item["homepage-banner"]
|
|
194
|
-
return {
|
|
195
|
-
image: banner?.["homepage-banner-image"],
|
|
196
|
-
title: normalizeCmsText(banner?.["homepage-banner-title"]),
|
|
197
|
-
subtitle: normalizeCmsText(banner?.["homepage-banner-subtitle"]),
|
|
198
|
-
description: normalizeCmsText(banner?.["homepage-banner-description"]),
|
|
199
|
-
buttonName: normalizeBannerButtonName(banner?.["homepage-banner-button-name"]),
|
|
200
|
-
buttonLink: banner?.["homepage-banner-button-link"],
|
|
201
|
-
}
|
|
202
|
-
})
|
|
203
|
-
}
|
|
204
|
-
return null
|
|
205
|
-
} catch (error) {
|
|
206
133
|
|
|
207
|
-
return null
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
export const getAppBannersFromConfig = async (): Promise<Array<{
|
|
212
|
-
image?: string;
|
|
213
|
-
title?: string;
|
|
214
|
-
subtitle?: string;
|
|
215
|
-
description?: string;
|
|
216
|
-
buttonName?: string;
|
|
217
|
-
buttonLink?: string;
|
|
218
|
-
}> | null> => {
|
|
219
|
-
try {
|
|
220
|
-
const config = await getDynamicConfig()
|
|
221
|
-
const bannerArray = config?.["homepage-config"]?.["app-banner-array"]
|
|
222
|
-
|
|
223
|
-
if (bannerArray && bannerArray.length > 0) {
|
|
224
|
-
return bannerArray.map(item => {
|
|
225
|
-
const banner = item["app-banner"]
|
|
226
|
-
return {
|
|
227
|
-
image: banner?.["app-banner-image"],
|
|
228
|
-
title: normalizeCmsText(banner?.["app-banner-title"]),
|
|
229
|
-
subtitle: normalizeCmsText(banner?.["app-banner-subtitle"]),
|
|
230
|
-
description: normalizeCmsText(banner?.["app-banner-description"]),
|
|
231
|
-
buttonName: normalizeBannerButtonName(banner?.["app-banner-button-name"]),
|
|
232
|
-
buttonLink: banner?.["app-banner-button-link"],
|
|
233
|
-
}
|
|
234
|
-
})
|
|
235
|
-
}
|
|
236
|
-
return null
|
|
237
|
-
} catch (error) {
|
|
238
|
-
|
|
239
|
-
return null
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
134
|
|
|
243
135
|
// Legacy function for backward compatibility
|
|
244
|
-
export const getMobileBannerImageFromConfig = async (): Promise<string | null> => {
|
|
245
|
-
const { image } = await getMobileBannerFromConfig()
|
|
246
|
-
return image
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
export const getWebsiteDescriptionFromConfig = async (): Promise<string | null> => {
|
|
250
|
-
try {
|
|
251
|
-
const config = await getDynamicConfig()
|
|
252
|
-
const homepageConfig = config?.["homepage-config"]
|
|
253
|
-
const desc = homepageConfig?.["website-description"] || homepageConfig?.["website_description"]
|
|
254
|
-
|
|
255
136
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
137
|
+
export function getWebsiteDescriptionFromPageInput(
|
|
138
|
+
pageInput?: HomepageConfig | null
|
|
139
|
+
): string | null {
|
|
140
|
+
const config = resolvePageInput(pageInput)
|
|
141
|
+
const desc = config["website-description"] || config["website_description"]
|
|
142
|
+
return desc || null
|
|
261
143
|
}
|
|
262
144
|
|
|
145
|
+
|
|
263
146
|
/** Why choose us — defaults + `sections.whyChooseUs` override. */
|
|
264
|
-
export
|
|
147
|
+
export function getFeaturesFromPageInput(
|
|
148
|
+
pageInput?: HomepageConfig | null
|
|
149
|
+
): {
|
|
265
150
|
title: string
|
|
266
151
|
features: Array<{ name: string; icon: string }>
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
return { title, features }
|
|
276
|
-
} catch {
|
|
277
|
-
const block = DEFAULT_HOMEPAGE_SECTIONS.whyChooseUs
|
|
278
|
-
const copy = parseSectionCopy(block)
|
|
279
|
-
return {
|
|
280
|
-
title: copy.title ?? copy.name ?? "",
|
|
281
|
-
features: parseFeatureIconList(block.features ?? []),
|
|
282
|
-
}
|
|
283
|
-
}
|
|
152
|
+
} {
|
|
153
|
+
const block = getMergedSectionBlock("whyChooseUs", pageInput)
|
|
154
|
+
const copy = parseSectionCopy(block)
|
|
155
|
+
const title = copy.title ?? copy.name ?? ""
|
|
156
|
+
const featuresRaw = block.features ?? block.items ?? []
|
|
157
|
+
const features = parseFeatureIconList(featuresRaw)
|
|
158
|
+
return { title, features }
|
|
284
159
|
}
|
|
285
160
|
|
|
161
|
+
|
|
286
162
|
function parseFeatureIconList(raw: unknown): Array<{ name: string; icon: string }> {
|
|
287
163
|
if (!Array.isArray(raw)) return []
|
|
288
164
|
return raw
|
|
@@ -318,6 +194,9 @@ export type SectionCopy = {
|
|
|
318
194
|
description: string | null
|
|
319
195
|
subtitle: string | null
|
|
320
196
|
eyebrow: string | null
|
|
197
|
+
/** Layout variant, e.g. new arrivals `grid` | `classic`. */
|
|
198
|
+
variant: string | null
|
|
199
|
+
layout: string | null
|
|
321
200
|
}
|
|
322
201
|
|
|
323
202
|
const EMPTY_SECTION_COPY: SectionCopy = {
|
|
@@ -327,6 +206,8 @@ const EMPTY_SECTION_COPY: SectionCopy = {
|
|
|
327
206
|
description: null,
|
|
328
207
|
subtitle: null,
|
|
329
208
|
eyebrow: null,
|
|
209
|
+
variant: null,
|
|
210
|
+
layout: null,
|
|
330
211
|
}
|
|
331
212
|
|
|
332
213
|
export function parseSectionCopy(block: unknown): SectionCopy {
|
|
@@ -339,6 +220,8 @@ export function parseSectionCopy(block: unknown): SectionCopy {
|
|
|
339
220
|
description: normalizeCmsText(row.description) ?? null,
|
|
340
221
|
subtitle: normalizeCmsText(row.subtitle) ?? null,
|
|
341
222
|
eyebrow: normalizeCmsText(row.eyebrow) ?? null,
|
|
223
|
+
variant: normalizeCmsText(row.variant) ?? null,
|
|
224
|
+
layout: normalizeCmsText(row.layout) ?? null,
|
|
342
225
|
}
|
|
343
226
|
}
|
|
344
227
|
|
|
@@ -355,9 +238,11 @@ function sectionIdFromConfigKey(key: string): HomeSectionCopyId | null {
|
|
|
355
238
|
return HOME_SECTION_COPY_IDS.has(id) ? id : null
|
|
356
239
|
}
|
|
357
240
|
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
241
|
+
function getHomepageSectionsRoot(
|
|
242
|
+
pageInput?: HomepageConfig | null
|
|
243
|
+
): Record<string, unknown> {
|
|
244
|
+
const config = resolvePageInput(pageInput)
|
|
245
|
+
const root = config.sections
|
|
361
246
|
return root && typeof root === "object"
|
|
362
247
|
? (root as Record<string, unknown>)
|
|
363
248
|
: {}
|
|
@@ -379,42 +264,13 @@ function findSectionBlock(
|
|
|
379
264
|
return null
|
|
380
265
|
}
|
|
381
266
|
|
|
382
|
-
|
|
383
|
-
export function mergeSectionBlock(
|
|
384
|
-
defaults: Record<string, unknown>,
|
|
385
|
-
override: Record<string, unknown> | null
|
|
386
|
-
): Record<string, unknown> {
|
|
387
|
-
if (!override) return { ...defaults }
|
|
388
|
-
const merged = { ...defaults }
|
|
389
|
-
for (const [key, value] of Object.entries(override)) {
|
|
390
|
-
if (value === undefined || value === null) continue
|
|
391
|
-
if (Array.isArray(value)) {
|
|
392
|
-
if (value.length > 0) merged[key] = value
|
|
393
|
-
continue
|
|
394
|
-
}
|
|
395
|
-
if (typeof value === "string") {
|
|
396
|
-
if (value.trim()) merged[key] = value.trim()
|
|
397
|
-
continue
|
|
398
|
-
}
|
|
399
|
-
if (typeof value === "boolean" || typeof value === "number") {
|
|
400
|
-
merged[key] = value
|
|
401
|
-
continue
|
|
402
|
-
}
|
|
403
|
-
if (typeof value === "object") {
|
|
404
|
-
const base =
|
|
405
|
-
merged[key] && typeof merged[key] === "object" && !Array.isArray(merged[key])
|
|
406
|
-
? (merged[key] as Record<string, unknown>)
|
|
407
|
-
: {}
|
|
408
|
-
merged[key] = mergeSectionBlock(base, value as Record<string, unknown>)
|
|
409
|
-
}
|
|
410
|
-
}
|
|
411
|
-
return merged
|
|
412
|
-
}
|
|
267
|
+
export { mergeSectionBlock } from "./config-merge"
|
|
413
268
|
|
|
414
|
-
|
|
415
|
-
id: HomeSectionCopyId
|
|
416
|
-
|
|
417
|
-
|
|
269
|
+
export function getMergedSectionBlock(
|
|
270
|
+
id: HomeSectionCopyId,
|
|
271
|
+
pageInput?: HomepageConfig | null
|
|
272
|
+
): Record<string, unknown> {
|
|
273
|
+
const root = getHomepageSectionsRoot(pageInput)
|
|
418
274
|
const defaults = DEFAULT_HOMEPAGE_SECTIONS[id] ?? {}
|
|
419
275
|
const override = findSectionBlock(root, id)
|
|
420
276
|
return mergeSectionBlock(
|
|
@@ -433,6 +289,8 @@ function mergeSectionCopy(base: SectionCopy, patch: SectionCopy): SectionCopy {
|
|
|
433
289
|
description: pick(patch.description, base.description),
|
|
434
290
|
subtitle: pick(patch.subtitle, base.subtitle),
|
|
435
291
|
eyebrow: pick(patch.eyebrow, base.eyebrow),
|
|
292
|
+
variant: pick(patch.variant ?? patch.layout, base.variant ?? base.layout),
|
|
293
|
+
layout: pick(patch.layout ?? patch.variant, base.layout ?? base.variant),
|
|
436
294
|
}
|
|
437
295
|
}
|
|
438
296
|
|
|
@@ -456,23 +314,18 @@ function parseAnnouncementMessages(block: Record<string, unknown> | null): strin
|
|
|
456
314
|
/**
|
|
457
315
|
* Merged section copy: package defaults + `homepage-config.sections` overrides.
|
|
458
316
|
*/
|
|
459
|
-
export
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
return copy
|
|
467
|
-
} catch {
|
|
468
|
-
const fallback = {} as HomeSectionsCopy
|
|
469
|
-
for (const id of HOME_SECTION_COPY_ID_LIST) {
|
|
470
|
-
fallback[id] = parseSectionCopy(DEFAULT_HOMEPAGE_SECTIONS[id])
|
|
471
|
-
}
|
|
472
|
-
return fallback
|
|
317
|
+
export function getHomeSectionsCopyFromPageInput(
|
|
318
|
+
pageInput?: HomepageConfig | null
|
|
319
|
+
): HomeSectionsCopy {
|
|
320
|
+
const copy = {} as HomeSectionsCopy
|
|
321
|
+
for (const id of HOME_SECTION_COPY_ID_LIST) {
|
|
322
|
+
const block = getMergedSectionBlock(id, pageInput)
|
|
323
|
+
copy[id] = parseSectionCopy(block)
|
|
473
324
|
}
|
|
325
|
+
return copy
|
|
474
326
|
}
|
|
475
327
|
|
|
328
|
+
|
|
476
329
|
export type TrustFeaturesConfig = {
|
|
477
330
|
title: string | null
|
|
478
331
|
description: string | null
|
|
@@ -480,27 +333,19 @@ export type TrustFeaturesConfig = {
|
|
|
480
333
|
}
|
|
481
334
|
|
|
482
335
|
/** Trust badge row — defaults + `sections.features` override. */
|
|
483
|
-
export
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
} catch {
|
|
494
|
-
const block = DEFAULT_HOMEPAGE_SECTIONS.features
|
|
495
|
-
const copy = parseSectionCopy(block)
|
|
496
|
-
return {
|
|
497
|
-
title: copy.title,
|
|
498
|
-
description: copy.description,
|
|
499
|
-
features: parseFeatureIconList(block.features ?? []),
|
|
500
|
-
}
|
|
501
|
-
}
|
|
336
|
+
export function getTrustFeaturesFromPageInput(
|
|
337
|
+
pageInput?: HomepageConfig | null
|
|
338
|
+
): TrustFeaturesConfig {
|
|
339
|
+
const block = getMergedSectionBlock("features", pageInput)
|
|
340
|
+
const copy = parseSectionCopy(block)
|
|
341
|
+
const title = copy.title ?? copy.name
|
|
342
|
+
const description = copy.description ?? copy.text
|
|
343
|
+
const rawList = block.features ?? block.items ?? []
|
|
344
|
+
const features = parseFeatureIconList(rawList)
|
|
345
|
+
return { title: title ?? null, description: description ?? null, features }
|
|
502
346
|
}
|
|
503
347
|
|
|
348
|
+
|
|
504
349
|
function normalizeBannerButtonName(value: unknown): string | undefined {
|
|
505
350
|
const text = normalizeCmsText(value)
|
|
506
351
|
if (!text) return undefined
|
|
@@ -514,29 +359,22 @@ function normalizeConfigEmail(value: unknown): string | undefined {
|
|
|
514
359
|
return EMAIL_PATTERN.test(trimmed) ? trimmed : undefined
|
|
515
360
|
}
|
|
516
361
|
|
|
517
|
-
export
|
|
518
|
-
try {
|
|
519
|
-
const config = await getDynamicConfig()
|
|
520
|
-
const contactConfig = config?.["homepage-config"]?.["contact-us"]
|
|
362
|
+
export type ContactInfo = { phone?: string; email?: string; address?: string }
|
|
521
363
|
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
address: contactConfig["contact-address"],
|
|
533
|
-
}
|
|
534
|
-
} catch (error) {
|
|
535
|
-
|
|
536
|
-
return null
|
|
364
|
+
export function getContactInfoFromPageInput(
|
|
365
|
+
pageInput?: HomepageConfig | null
|
|
366
|
+
): ContactInfo | null {
|
|
367
|
+
const config = resolvePageInput(pageInput)
|
|
368
|
+
const contactConfig = config["contact-us"]
|
|
369
|
+
if (!contactConfig) return null
|
|
370
|
+
return {
|
|
371
|
+
phone: contactConfig["contact-phone"],
|
|
372
|
+
email: normalizeConfigEmail(contactConfig["contact-email"]),
|
|
373
|
+
address: contactConfig["contact-address"],
|
|
537
374
|
}
|
|
538
375
|
}
|
|
539
376
|
|
|
377
|
+
|
|
540
378
|
function normalizeVideoStoryUrl(entry: unknown): string | null {
|
|
541
379
|
if (typeof entry === "string" && entry.trim()) return entry.trim()
|
|
542
380
|
if (!entry || typeof entry !== "object") return null
|
|
@@ -557,144 +395,173 @@ function normalizeVideoStoryUrl(entry: unknown): string | null {
|
|
|
557
395
|
/**
|
|
558
396
|
* Homepage video stories/reviews carousel (`homepage-config.video-stories`).
|
|
559
397
|
*/
|
|
560
|
-
export
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
398
|
+
export function getVideoStoriesFromPageInput(
|
|
399
|
+
pageInput?: HomepageConfig | null
|
|
400
|
+
): { title: string; videoUrls: string[] } {
|
|
401
|
+
const homepageConfig = resolvePageInput(pageInput)
|
|
402
|
+
const block = getMergedSectionBlock("videoStories", pageInput)
|
|
403
|
+
const copy = parseSectionCopy(block)
|
|
404
|
+
const title = copy.title ?? copy.name ?? ""
|
|
405
|
+
const raw =
|
|
406
|
+
block["video-urls"] ??
|
|
407
|
+
block.videoUrls ??
|
|
408
|
+
block.videos ??
|
|
409
|
+
block["video-stories"] ??
|
|
410
|
+
homepageConfig["video-stories"] ??
|
|
411
|
+
homepageConfig["video-stories-array"] ??
|
|
412
|
+
homepageConfig["video_stories"] ??
|
|
413
|
+
[]
|
|
414
|
+
const list = Array.isArray(raw) ? raw : [raw]
|
|
415
|
+
const videoUrls = list
|
|
416
|
+
.map(normalizeVideoStoryUrl)
|
|
417
|
+
.filter((url): url is string => Boolean(url))
|
|
418
|
+
return { title, videoUrls }
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
|
|
422
|
+
export type TestimonialItem = {
|
|
423
|
+
id: string
|
|
424
|
+
text: string
|
|
425
|
+
name: string
|
|
426
|
+
rating?: number
|
|
427
|
+
avatar?: string
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
function parseTestimonialRow(
|
|
431
|
+
item: unknown,
|
|
432
|
+
index: number
|
|
433
|
+
): TestimonialItem | null {
|
|
434
|
+
if (!item || typeof item !== "object") return null
|
|
435
|
+
const row = (item as Record<string, unknown>).testimonial ??
|
|
436
|
+
(item as Record<string, unknown>).review ??
|
|
437
|
+
item
|
|
438
|
+
const r = row as Record<string, unknown>
|
|
439
|
+
const text = String(
|
|
440
|
+
r.text ?? r["review-description"] ?? r.description ?? r.quote ?? ""
|
|
441
|
+
).trim()
|
|
442
|
+
const name = String(
|
|
443
|
+
r.name ?? r["review-user-name"] ?? r.author ?? r["user-name"] ?? ""
|
|
444
|
+
).trim()
|
|
445
|
+
if (!text || !name) return null
|
|
446
|
+
const ratingRaw = r.rating ?? r["review-rating"]
|
|
447
|
+
const rating =
|
|
448
|
+
ratingRaw != null && ratingRaw !== ""
|
|
449
|
+
? parseFloat(String(ratingRaw))
|
|
450
|
+
: undefined
|
|
451
|
+
return {
|
|
452
|
+
id: String(r.id ?? `review-${index}`),
|
|
453
|
+
text,
|
|
454
|
+
name,
|
|
455
|
+
rating: Number.isFinite(rating) ? rating : undefined,
|
|
456
|
+
avatar: (r.avatar ?? r["review-profile-image"] ?? r.image) as string | undefined,
|
|
596
457
|
}
|
|
597
458
|
}
|
|
598
459
|
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
let testimonials = (Array.isArray(ratings) ? ratings : []).map(
|
|
612
|
-
(item: unknown, index: number) => {
|
|
613
|
-
const row = item as Record<string, unknown>
|
|
614
|
-
const review = (row?.review ?? row) as Record<string, unknown>
|
|
615
|
-
return {
|
|
616
|
-
id: `review-${index}`,
|
|
617
|
-
text: String(review?.["review-description"] ?? "").trim(),
|
|
618
|
-
name: String(review?.["review-user-name"] ?? "").trim(),
|
|
619
|
-
rating: parseFloat(String(review?.["review-rating"] ?? "5")),
|
|
620
|
-
avatar: review?.["review-profile-image"] as string | undefined,
|
|
621
|
-
}
|
|
622
|
-
}
|
|
623
|
-
).filter((t) => t.text && t.name)
|
|
624
|
-
|
|
625
|
-
return { title, testimonials }
|
|
626
|
-
} catch {
|
|
627
|
-
const block = DEFAULT_HOMEPAGE_SECTIONS.testimonials
|
|
628
|
-
const copy = parseSectionCopy(block)
|
|
629
|
-
return { title: copy.title ?? copy.name ?? "", testimonials: [] }
|
|
630
|
-
}
|
|
460
|
+
function parseTestimonialsFromBlock(block: Record<string, unknown>): TestimonialItem[] {
|
|
461
|
+
const raw =
|
|
462
|
+
block.items ??
|
|
463
|
+
block.testimonials ??
|
|
464
|
+
block.reviews ??
|
|
465
|
+
block["testimonial-items"] ??
|
|
466
|
+
[]
|
|
467
|
+
if (!Array.isArray(raw)) return []
|
|
468
|
+
return raw
|
|
469
|
+
.map((item, index) => parseTestimonialRow(item, index))
|
|
470
|
+
.filter((t): t is TestimonialItem => t !== null)
|
|
631
471
|
}
|
|
632
472
|
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
name: link?.["social-platform-name"] || "",
|
|
642
|
-
url: link?.["social-platform-url"] || "",
|
|
643
|
-
icon: link?.["social-platform-icon"] || undefined,
|
|
644
|
-
}
|
|
645
|
-
}).filter((l: any) => l.name && l.url)
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
return socialLinks.length > 0 ? socialLinks : null
|
|
649
|
-
} catch (error) {
|
|
473
|
+
function parseRatingsFromHomepage(
|
|
474
|
+
ratings: unknown
|
|
475
|
+
): TestimonialItem[] {
|
|
476
|
+
if (!Array.isArray(ratings)) return []
|
|
477
|
+
return ratings
|
|
478
|
+
.map((item, index) => parseTestimonialRow(item, index))
|
|
479
|
+
.filter((t): t is TestimonialItem => t !== null)
|
|
480
|
+
}
|
|
650
481
|
|
|
651
|
-
|
|
482
|
+
export function getTestimonialsFromPageInput(
|
|
483
|
+
pageInput?: HomepageConfig | null
|
|
484
|
+
): {
|
|
485
|
+
title: string
|
|
486
|
+
subtitle: string | null
|
|
487
|
+
testimonials: TestimonialItem[]
|
|
488
|
+
} {
|
|
489
|
+
const homepageConfig = resolvePageInput(pageInput)
|
|
490
|
+
const block = getMergedSectionBlock("testimonials", pageInput)
|
|
491
|
+
const copy = parseSectionCopy(block)
|
|
492
|
+
const title = copy.title ?? copy.name ?? ""
|
|
493
|
+
const subtitle = (copy.description ?? copy.text ?? null) as string | null
|
|
494
|
+
let testimonials = parseTestimonialsFromBlock(block)
|
|
495
|
+
if (testimonials.length === 0) {
|
|
496
|
+
testimonials = parseRatingsFromHomepage(homepageConfig["ratings"])
|
|
497
|
+
}
|
|
498
|
+
if (testimonials.length === 0) {
|
|
499
|
+
testimonials = parseTestimonialsFromBlock(
|
|
500
|
+
DEFAULT_HOMEPAGE_SECTIONS.testimonials as Record<string, unknown>
|
|
501
|
+
)
|
|
652
502
|
}
|
|
503
|
+
return { title, subtitle, testimonials }
|
|
653
504
|
}
|
|
654
505
|
|
|
655
|
-
export const getFaqsFromConfig = async (): Promise<Array<{ category: string; items: Array<{ q: string; a: string }> }> | null> => {
|
|
656
|
-
try {
|
|
657
|
-
const config = await getDynamicConfig()
|
|
658
|
-
const faqsRaw = config?.["homepage-config"]?.["faq-array"] || []
|
|
659
|
-
|
|
660
|
-
if (!Array.isArray(faqsRaw) || faqsRaw.length === 0) return null
|
|
661
|
-
|
|
662
|
-
const categoriesMap: Record<string, { displayCategory: string, items: Array<{q: string; a: string}> }> = {}
|
|
663
506
|
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
507
|
+
export function getSocialLinksFromPageInput(
|
|
508
|
+
pageInput?: HomepageConfig | null
|
|
509
|
+
): Array<{ name: string; url: string; icon?: string }> | null {
|
|
510
|
+
const config = resolvePageInput(pageInput)
|
|
511
|
+
const socialLinksRaw = config["social-links"] || []
|
|
512
|
+
const socialLinks = socialLinksRaw
|
|
513
|
+
.map((item: Record<string, unknown>) => {
|
|
514
|
+
const link = (item?.["social-link"] || item) as Record<string, unknown>
|
|
515
|
+
return {
|
|
516
|
+
name: String(link?.["social-platform-name"] || ""),
|
|
517
|
+
url: String(link?.["social-platform-url"] || ""),
|
|
518
|
+
icon: link?.["social-platform-icon"] as string | undefined,
|
|
674
519
|
}
|
|
675
520
|
})
|
|
521
|
+
.filter((l) => l.name && l.url)
|
|
522
|
+
return socialLinks.length > 0 ? socialLinks : null
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
|
|
526
|
+
export function getFaqsFromPageInput(
|
|
527
|
+
pageInput?: HomepageConfig | null
|
|
528
|
+
): Array<{ category: string; items: Array<{ q: string; a: string }> }> | null {
|
|
529
|
+
const config = resolvePageInput(pageInput)
|
|
530
|
+
const faqsRaw = config["faq-array"] || []
|
|
531
|
+
if (!Array.isArray(faqsRaw) || faqsRaw.length === 0) return null
|
|
532
|
+
const categoriesMap: Record<
|
|
533
|
+
string,
|
|
534
|
+
{ displayCategory: string; items: Array<{ q: string; a: string }> }
|
|
535
|
+
> = {}
|
|
536
|
+
faqsRaw.forEach((item: Record<string, unknown>) => {
|
|
537
|
+
const faq = (item?.["faq"] || item) as Record<string, unknown>
|
|
538
|
+
const displayCategory = String(faq?.["faq-category"] || "General Questions").trim()
|
|
539
|
+
const categoryKey = displayCategory.toLowerCase()
|
|
540
|
+
const q = String(faq?.["faq-question"] || "").trim()
|
|
541
|
+
const a = String(faq?.["faq-answer"] || "").trim()
|
|
542
|
+
if (q && a) {
|
|
543
|
+
if (!categoriesMap[categoryKey]) {
|
|
544
|
+
categoriesMap[categoryKey] = { displayCategory, items: [] }
|
|
545
|
+
}
|
|
546
|
+
categoriesMap[categoryKey].items.push({ q, a })
|
|
547
|
+
}
|
|
548
|
+
})
|
|
549
|
+
const faqs = Object.values(categoriesMap).map((catData) => ({
|
|
550
|
+
category: catData.displayCategory,
|
|
551
|
+
items: catData.items,
|
|
552
|
+
}))
|
|
553
|
+
return faqs.length > 0 ? faqs : null
|
|
554
|
+
}
|
|
676
555
|
|
|
677
|
-
const faqs = Object.values(categoriesMap).map(catData => ({
|
|
678
|
-
category: catData.displayCategory,
|
|
679
|
-
items: catData.items
|
|
680
|
-
}))
|
|
681
556
|
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
export const getAnnouncementMessagesFromConfig = async (): Promise<string[]> => {
|
|
688
|
-
try {
|
|
689
|
-
const block = await getMergedSectionBlock("promoAnnouncements")
|
|
690
|
-
return parseAnnouncementMessages(block)
|
|
691
|
-
} catch {
|
|
692
|
-
return parseAnnouncementMessages(
|
|
693
|
-
DEFAULT_HOMEPAGE_SECTIONS.promoAnnouncements as Record<string, unknown>
|
|
694
|
-
)
|
|
695
|
-
}
|
|
557
|
+
export function getAnnouncementMessagesFromPageInput(
|
|
558
|
+
pageInput?: HomepageConfig | null
|
|
559
|
+
): string[] {
|
|
560
|
+
const block = getMergedSectionBlock("promoAnnouncements", pageInput)
|
|
561
|
+
return parseAnnouncementMessages(block)
|
|
696
562
|
}
|
|
697
563
|
|
|
564
|
+
|
|
698
565
|
export type AboutBrandConfig = {
|
|
699
566
|
eyebrow: string
|
|
700
567
|
title: string
|
|
@@ -703,93 +570,71 @@ export type AboutBrandConfig = {
|
|
|
703
570
|
stats: Array<{ label: string; value: string }>
|
|
704
571
|
}
|
|
705
572
|
|
|
706
|
-
export
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
readMoreHref: String(b.readMoreHref ?? b["read-more-link"] ?? "/about"),
|
|
739
|
-
stats,
|
|
740
|
-
}
|
|
741
|
-
} catch {
|
|
742
|
-
const b = DEFAULT_HOMEPAGE_SECTIONS.aboutBrand
|
|
743
|
-
const copy = parseSectionCopy(b)
|
|
744
|
-
return {
|
|
745
|
-
eyebrow: copy.eyebrow ?? "",
|
|
746
|
-
title: copy.title ?? copy.name ?? "",
|
|
747
|
-
description: copy.description ?? copy.text ?? "",
|
|
748
|
-
readMoreHref: String(b.readMoreHref ?? "/about"),
|
|
749
|
-
stats: (b.stats ?? []) as unknown as Array<{ label: string; value: string }>,
|
|
750
|
-
}
|
|
573
|
+
export function getAboutBrandFromPageInput(
|
|
574
|
+
pageInput?: HomepageConfig | null
|
|
575
|
+
): AboutBrandConfig {
|
|
576
|
+
const homepageConfig = resolvePageInput(pageInput)
|
|
577
|
+
const merged = getMergedSectionBlock("aboutBrand", pageInput)
|
|
578
|
+
const legacy =
|
|
579
|
+
homepageConfig["about-brand"] ?? homepageConfig["who-we-are"]
|
|
580
|
+
const b = mergeSectionBlock(
|
|
581
|
+
merged,
|
|
582
|
+
legacy && typeof legacy === "object"
|
|
583
|
+
? (legacy as Record<string, unknown>)
|
|
584
|
+
: null
|
|
585
|
+
)
|
|
586
|
+
const statsRaw = (b.stats ?? b["about-stats"] ?? []) as unknown[]
|
|
587
|
+
const stats = Array.isArray(statsRaw)
|
|
588
|
+
? statsRaw
|
|
589
|
+
.map((s: unknown) => {
|
|
590
|
+
if (!s || typeof s !== "object") return null
|
|
591
|
+
const row = s as Record<string, unknown>
|
|
592
|
+
const label = String(row.label ?? row.name ?? "").trim()
|
|
593
|
+
const value = String(row.value ?? "").trim()
|
|
594
|
+
return label && value ? { label, value } : null
|
|
595
|
+
})
|
|
596
|
+
.filter(Boolean) as Array<{ label: string; value: string }>
|
|
597
|
+
: []
|
|
598
|
+
const copy = parseSectionCopy(b)
|
|
599
|
+
return {
|
|
600
|
+
eyebrow: copy.eyebrow ?? "",
|
|
601
|
+
title: copy.title ?? copy.name ?? "",
|
|
602
|
+
description: copy.description ?? copy.text ?? "",
|
|
603
|
+
readMoreHref: String(b.readMoreHref ?? b["read-more-link"] ?? "/about"),
|
|
604
|
+
stats,
|
|
751
605
|
}
|
|
752
606
|
}
|
|
753
607
|
|
|
608
|
+
|
|
754
609
|
export type BrandPillarConfig = {
|
|
755
610
|
title: string
|
|
756
611
|
description: string
|
|
757
612
|
image?: string
|
|
613
|
+
href?: string
|
|
758
614
|
}
|
|
759
615
|
|
|
760
|
-
export
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
.filter(Boolean) as BrandPillarConfig[]
|
|
780
|
-
|
|
781
|
-
return { sectionTitle, pillars }
|
|
782
|
-
} catch {
|
|
783
|
-
const block = DEFAULT_HOMEPAGE_SECTIONS.brandPillars
|
|
784
|
-
const copy = parseSectionCopy(block)
|
|
785
|
-
const raw = block.pillars ?? []
|
|
786
|
-
return {
|
|
787
|
-
sectionTitle: copy.title ?? copy.name ?? "",
|
|
788
|
-
pillars: [...(Array.isArray(raw) ? raw : [])] as BrandPillarConfig[],
|
|
789
|
-
}
|
|
790
|
-
}
|
|
616
|
+
export function getBrandPillarsFromPageInput(
|
|
617
|
+
pageInput?: HomepageConfig | null
|
|
618
|
+
): { sectionTitle: string; pillars: BrandPillarConfig[] } {
|
|
619
|
+
const block = getMergedSectionBlock("brandPillars", pageInput)
|
|
620
|
+
const copy = parseSectionCopy(block)
|
|
621
|
+
const sectionTitle = copy.title ?? copy.name ?? ""
|
|
622
|
+
const raw = block.pillars ?? block["brand-pillars"] ?? []
|
|
623
|
+
const pillars = (Array.isArray(raw) ? raw : [])
|
|
624
|
+
.map((item: unknown) => {
|
|
625
|
+
if (!item || typeof item !== "object") return null
|
|
626
|
+
const row = (item as Record<string, unknown>)["pillar"] ?? item
|
|
627
|
+
const p = row as Record<string, unknown>
|
|
628
|
+
const title = String(p.title ?? p.name ?? "").trim()
|
|
629
|
+
const description = String(p.description ?? p.text ?? "").trim()
|
|
630
|
+
const image = (p.image ?? p.icon) as string | undefined
|
|
631
|
+
return title && description ? { title, description, image } : null
|
|
632
|
+
})
|
|
633
|
+
.filter(Boolean) as BrandPillarConfig[]
|
|
634
|
+
return { sectionTitle, pillars }
|
|
791
635
|
}
|
|
792
636
|
|
|
637
|
+
|
|
793
638
|
export type BlogPostConfig = {
|
|
794
639
|
title: string
|
|
795
640
|
excerpt?: string
|
|
@@ -799,53 +644,49 @@ export type BlogPostConfig = {
|
|
|
799
644
|
image?: string
|
|
800
645
|
}
|
|
801
646
|
|
|
802
|
-
export
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
}
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
} catch {
|
|
826
|
-
const block = DEFAULT_HOMEPAGE_SECTIONS.blogPosts
|
|
827
|
-
const raw = block.posts ?? []
|
|
828
|
-
return (Array.isArray(raw) ? raw : [])
|
|
829
|
-
.map((item: unknown) => {
|
|
830
|
-
if (!item || typeof item !== "object") return null
|
|
831
|
-
const b = item as Record<string, unknown>
|
|
832
|
-
const title = String(b.title ?? "").trim()
|
|
833
|
-
const href = String(b.href ?? b.link ?? "").trim()
|
|
834
|
-
if (!title || !href) return null
|
|
835
|
-
return { title, href } as BlogPostConfig
|
|
836
|
-
})
|
|
837
|
-
.filter(Boolean) as BlogPostConfig[]
|
|
838
|
-
}
|
|
647
|
+
export function getBlogPostsFromPageInput(
|
|
648
|
+
pageInput?: HomepageConfig | null
|
|
649
|
+
): BlogPostConfig[] {
|
|
650
|
+
const block = getMergedSectionBlock("blogPosts", pageInput)
|
|
651
|
+
const raw = block.posts ?? block["blog-posts"] ?? block["blog-array"] ?? []
|
|
652
|
+
return (Array.isArray(raw) ? raw : [])
|
|
653
|
+
.map((item: unknown) => {
|
|
654
|
+
if (!item || typeof item !== "object") return null
|
|
655
|
+
const row = (item as Record<string, unknown>)["blog"] ?? item
|
|
656
|
+
const b = row as Record<string, unknown>
|
|
657
|
+
const title = String(b.title ?? "").trim()
|
|
658
|
+
const href = String(b.href ?? b.link ?? b.url ?? "").trim()
|
|
659
|
+
if (!title || !href) return null
|
|
660
|
+
return {
|
|
661
|
+
title,
|
|
662
|
+
href,
|
|
663
|
+
excerpt: String(b.excerpt ?? b.description ?? "").trim() || undefined,
|
|
664
|
+
category: String(b.category ?? b.tag ?? "").trim() || undefined,
|
|
665
|
+
date: String(b.date ?? "").trim() || undefined,
|
|
666
|
+
image: (b.image ?? b.thumbnail) as string | undefined,
|
|
667
|
+
}
|
|
668
|
+
})
|
|
669
|
+
.filter(Boolean) as BlogPostConfig[]
|
|
839
670
|
}
|
|
840
671
|
|
|
672
|
+
|
|
841
673
|
function readPromoCountdownBlock(block: unknown): {
|
|
842
674
|
code: string | null
|
|
843
675
|
message: string | null
|
|
844
676
|
endAt: string | null
|
|
845
677
|
active: boolean | undefined
|
|
678
|
+
ctaLabel: string | null
|
|
679
|
+
ctaHref: string | null
|
|
846
680
|
} {
|
|
847
681
|
if (!block || typeof block !== "object") {
|
|
848
|
-
return {
|
|
682
|
+
return {
|
|
683
|
+
code: null,
|
|
684
|
+
message: null,
|
|
685
|
+
endAt: null,
|
|
686
|
+
active: undefined,
|
|
687
|
+
ctaLabel: null,
|
|
688
|
+
ctaHref: null,
|
|
689
|
+
}
|
|
849
690
|
}
|
|
850
691
|
const row = block as Record<string, unknown>
|
|
851
692
|
const code =
|
|
@@ -856,52 +697,152 @@ function readPromoCountdownBlock(block: unknown): {
|
|
|
856
697
|
const endAt = typeof endAtRaw === "string" && endAtRaw.trim() ? endAtRaw.trim() : null
|
|
857
698
|
const activeRaw = row["promo-active"] ?? row.active
|
|
858
699
|
const active = typeof activeRaw === "boolean" ? activeRaw : undefined
|
|
859
|
-
|
|
700
|
+
const ctaLabel =
|
|
701
|
+
normalizeCmsText(row["cta-label"] ?? row.ctaLabel ?? row["button-label"]) ?? null
|
|
702
|
+
const ctaHref =
|
|
703
|
+
normalizeCmsText(row["cta-href"] ?? row.ctaHref ?? row["button-href"]) ?? null
|
|
704
|
+
return { code, message, endAt, active, ctaLabel, ctaHref }
|
|
860
705
|
}
|
|
861
706
|
|
|
862
707
|
/** Promo countdown — defaults + `sections.promoCountdown` override. */
|
|
863
|
-
export
|
|
708
|
+
export function getPromoCountdownFromPageInput(
|
|
709
|
+
pageInput?: HomepageConfig | null
|
|
710
|
+
): {
|
|
864
711
|
code: string | null
|
|
865
712
|
message: string | null
|
|
866
713
|
endAt: string | null
|
|
867
714
|
active: boolean
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
const defaults = readPromoCountdownBlock(DEFAULT_HOMEPAGE_SECTIONS.promoCountdown)
|
|
882
|
-
return {
|
|
883
|
-
code: defaults.code,
|
|
884
|
-
message: defaults.message,
|
|
885
|
-
endAt: defaults.endAt,
|
|
886
|
-
active: defaults.active ?? false,
|
|
887
|
-
}
|
|
715
|
+
ctaLabel: string | null
|
|
716
|
+
ctaHref: string | null
|
|
717
|
+
} {
|
|
718
|
+
const block = getMergedSectionBlock("promoCountdown", pageInput)
|
|
719
|
+
const fromBlock = readPromoCountdownBlock(block)
|
|
720
|
+
const defaults = readPromoCountdownBlock(DEFAULT_HOMEPAGE_SECTIONS.promoCountdown)
|
|
721
|
+
return {
|
|
722
|
+
code: fromBlock.code ?? defaults.code,
|
|
723
|
+
message: fromBlock.message ?? defaults.message,
|
|
724
|
+
endAt: fromBlock.endAt ?? defaults.endAt,
|
|
725
|
+
active: fromBlock.active ?? defaults.active ?? false,
|
|
726
|
+
ctaLabel: fromBlock.ctaLabel ?? defaults.ctaLabel,
|
|
727
|
+
ctaHref: fromBlock.ctaHref ?? defaults.ctaHref,
|
|
888
728
|
}
|
|
889
729
|
}
|
|
890
730
|
|
|
891
|
-
export { DEFAULT_HOMEPAGE_SECTIONS } from "./homepage-section-defaults"
|
|
892
731
|
|
|
893
|
-
export
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
732
|
+
export type InstagramPostConfig = {
|
|
733
|
+
id: string
|
|
734
|
+
image: string
|
|
735
|
+
url?: string
|
|
736
|
+
}
|
|
897
737
|
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
738
|
+
export type InstagramPostsData = {
|
|
739
|
+
title: string
|
|
740
|
+
handle: string
|
|
741
|
+
profileUrl: string
|
|
742
|
+
profileImage?: string
|
|
743
|
+
posts: InstagramPostConfig[]
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
function parseInstagramPostRow(
|
|
747
|
+
item: unknown,
|
|
748
|
+
index: number
|
|
749
|
+
): InstagramPostConfig | null {
|
|
750
|
+
if (!item || typeof item !== "object") return null
|
|
751
|
+
const row = (item as Record<string, unknown>).post ??
|
|
752
|
+
(item as Record<string, unknown>).instagram ??
|
|
753
|
+
item
|
|
754
|
+
const p = row as Record<string, unknown>
|
|
755
|
+
const image = String(p.image ?? p["post-image"] ?? p.thumbnail ?? p.src ?? "").trim()
|
|
756
|
+
if (!image) return null
|
|
757
|
+
const url = String(p.url ?? p.link ?? p.href ?? p["post-url"] ?? "").trim() || undefined
|
|
758
|
+
return {
|
|
759
|
+
id: String(p.id ?? `ig-${index}`),
|
|
760
|
+
image,
|
|
761
|
+
url,
|
|
906
762
|
}
|
|
907
763
|
}
|
|
764
|
+
|
|
765
|
+
function parseInstagramPostsFromBlock(
|
|
766
|
+
block: Record<string, unknown>
|
|
767
|
+
): InstagramPostConfig[] {
|
|
768
|
+
const raw =
|
|
769
|
+
block.posts ??
|
|
770
|
+
block.items ??
|
|
771
|
+
block["instagram-posts"] ??
|
|
772
|
+
block["posts-array"] ??
|
|
773
|
+
[]
|
|
774
|
+
if (!Array.isArray(raw)) return []
|
|
775
|
+
return raw
|
|
776
|
+
.map((item, index) => parseInstagramPostRow(item, index))
|
|
777
|
+
.filter((p): p is InstagramPostConfig => p !== null)
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
/** Instagram feed — `sections.instagramPosts` + optional social-links fallback. */
|
|
781
|
+
export function getInstagramPostsFromPageInput(
|
|
782
|
+
pageInput?: HomepageConfig | null
|
|
783
|
+
): InstagramPostsData {
|
|
784
|
+
const defaultsBlock = DEFAULT_HOMEPAGE_SECTIONS.instagramPosts as Record<
|
|
785
|
+
string,
|
|
786
|
+
unknown
|
|
787
|
+
>
|
|
788
|
+
const defaultCopy = parseSectionCopy(defaultsBlock)
|
|
789
|
+
const defaultPosts = parseInstagramPostsFromBlock(defaultsBlock)
|
|
790
|
+
const block = getMergedSectionBlock("instagramPosts", pageInput)
|
|
791
|
+
const copy = parseSectionCopy(block)
|
|
792
|
+
let posts = parseInstagramPostsFromBlock(block)
|
|
793
|
+
if (posts.length === 0) posts = defaultPosts
|
|
794
|
+
const handle =
|
|
795
|
+
normalizeCmsText(
|
|
796
|
+
block.handle ??
|
|
797
|
+
block.username ??
|
|
798
|
+
block["instagram-handle"] ??
|
|
799
|
+
defaultsBlock.handle
|
|
800
|
+
) ?? "yourbrand"
|
|
801
|
+
const profileUrl =
|
|
802
|
+
normalizeCmsText(
|
|
803
|
+
block["profile-url"] ??
|
|
804
|
+
block.profileUrl ??
|
|
805
|
+
block["instagram-url"] ??
|
|
806
|
+
defaultsBlock["profile-url"]
|
|
807
|
+
) ?? `https://www.instagram.com/${handle.replace(/^@/, "")}/`
|
|
808
|
+
const profileImage =
|
|
809
|
+
(block["profile-image"] ??
|
|
810
|
+
block.profileImage ??
|
|
811
|
+
defaultsBlock["profile-image"]) as string | undefined
|
|
812
|
+
return {
|
|
813
|
+
title:
|
|
814
|
+
copy.title ?? copy.name ?? defaultCopy.title ?? "Follow Us on Instagram",
|
|
815
|
+
handle,
|
|
816
|
+
profileUrl,
|
|
817
|
+
profileImage,
|
|
818
|
+
posts,
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
|
|
823
|
+
export {
|
|
824
|
+
DEFAULT_HOMEPAGE_SECTIONS,
|
|
825
|
+
type DefaultHomeSectionId,
|
|
826
|
+
} from "./homepage-section-defaults"
|
|
827
|
+
export type {
|
|
828
|
+
DynamicConfigResponse,
|
|
829
|
+
HomepageConfig,
|
|
830
|
+
HomepageSectionsConfig,
|
|
831
|
+
HomepageSectionId,
|
|
832
|
+
HomepageSectionCopyFields,
|
|
833
|
+
HomepageNewArrivalsSection,
|
|
834
|
+
} from "./homepage-config.types"
|
|
835
|
+
export { HOMEPAGE_SECTION_IDS } from "./homepage-config.types"
|
|
836
|
+
|
|
837
|
+
export function getPromoBarFromPageInput(
|
|
838
|
+
pageInput?: HomepageConfig | null
|
|
839
|
+
): { text: string | null; code: string | null; value: string | null; active: boolean } {
|
|
840
|
+
const config = resolvePageInput(pageInput)
|
|
841
|
+
const promoConfig = config["promo-bar"]
|
|
842
|
+
const text = normalizeCmsText(promoConfig?.["promo-text"]) ?? null
|
|
843
|
+
const code = normalizeCmsText(promoConfig?.["promo-code"]) ?? null
|
|
844
|
+
const value = normalizeCmsText(promoConfig?.["promo-value"]) ?? null
|
|
845
|
+
const active = Boolean(promoConfig?.["promo-active"])
|
|
846
|
+
return { text, code, value, active }
|
|
847
|
+
}
|
|
848
|
+
|