medusa-storefront-data 2.1.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.
Files changed (269) hide show
  1. package/HOMEPAGE_CONFIG.md +99 -0
  2. package/dist/segment-data/default-page-input.json +191 -0
  3. package/dist/src/config.d.ts.map +1 -0
  4. package/dist/src/cookies.d.ts.map +1 -0
  5. package/dist/src/edge.d.ts.map +1 -0
  6. package/dist/src/middleware.d.ts.map +1 -0
  7. package/dist/src/server/cart.d.ts.map +1 -0
  8. package/dist/src/server/categories.d.ts.map +1 -0
  9. package/dist/src/server/collections.d.ts.map +1 -0
  10. package/dist/src/server/config-merge.d.ts +3 -0
  11. package/dist/src/server/config-merge.d.ts.map +1 -0
  12. package/dist/src/server/config-merge.js +31 -0
  13. package/dist/src/server/contact.d.ts.map +1 -0
  14. package/dist/src/server/customer-registration.d.ts.map +1 -0
  15. package/dist/src/server/customer.d.ts.map +1 -0
  16. package/dist/src/server/dynamic-config.d.ts +240 -0
  17. package/dist/src/server/dynamic-config.d.ts.map +1 -0
  18. package/dist/src/server/dynamic-config.js +703 -0
  19. package/dist/src/server/fulfillment.d.ts.map +1 -0
  20. package/dist/src/server/guest.d.ts.map +1 -0
  21. package/dist/src/server/home-sections/about-brand.d.ts +9 -0
  22. package/dist/src/server/home-sections/about-brand.d.ts.map +1 -0
  23. package/dist/src/server/home-sections/about-brand.js +9 -0
  24. package/dist/src/server/home-sections/baptism-picks.d.ts +10 -0
  25. package/dist/src/server/home-sections/baptism-picks.d.ts.map +1 -0
  26. package/dist/src/server/home-sections/baptism-picks.js +27 -0
  27. package/dist/src/server/home-sections/baptism.d.ts +13 -0
  28. package/dist/src/server/home-sections/baptism.d.ts.map +1 -0
  29. package/dist/src/server/home-sections/baptism.js +43 -0
  30. package/dist/src/server/home-sections/blog-posts.d.ts +9 -0
  31. package/dist/src/server/home-sections/blog-posts.d.ts.map +1 -0
  32. package/dist/src/server/home-sections/blog-posts.js +9 -0
  33. package/dist/src/server/home-sections/brand-marquee.d.ts +8 -0
  34. package/dist/src/server/home-sections/brand-marquee.d.ts.map +1 -0
  35. package/dist/src/server/home-sections/brand-marquee.js +7 -0
  36. package/dist/src/server/home-sections/brand-pillars.d.ts +9 -0
  37. package/dist/src/server/home-sections/brand-pillars.d.ts.map +1 -0
  38. package/dist/src/server/home-sections/brand-pillars.js +9 -0
  39. package/dist/src/server/home-sections/category-pills.d.ts +9 -0
  40. package/dist/src/server/home-sections/category-pills.d.ts.map +1 -0
  41. package/dist/src/server/home-sections/category-pills.js +19 -0
  42. package/dist/src/server/home-sections/celebrity-trust.d.ts +12 -0
  43. package/dist/src/server/home-sections/celebrity-trust.d.ts.map +1 -0
  44. package/dist/src/server/home-sections/celebrity-trust.js +27 -0
  45. package/dist/src/server/home-sections/features.d.ts +9 -0
  46. package/dist/src/server/home-sections/features.d.ts.map +1 -0
  47. package/dist/src/server/home-sections/features.js +9 -0
  48. package/dist/src/server/home-sections/hero.d.ts +9 -0
  49. package/dist/src/server/home-sections/hero.d.ts.map +1 -0
  50. package/dist/src/server/home-sections/hero.js +9 -0
  51. package/dist/src/server/home-sections/instagram-posts.d.ts +9 -0
  52. package/dist/src/server/home-sections/instagram-posts.d.ts.map +1 -0
  53. package/dist/src/server/home-sections/instagram-posts.js +9 -0
  54. package/dist/src/server/home-sections/loved-by-moms.d.ts +12 -0
  55. package/dist/src/server/home-sections/loved-by-moms.d.ts.map +1 -0
  56. package/dist/src/server/home-sections/loved-by-moms.js +20 -0
  57. package/dist/src/server/home-sections/luxe-favourites.d.ts +11 -0
  58. package/dist/src/server/home-sections/luxe-favourites.d.ts.map +1 -0
  59. package/dist/src/server/home-sections/luxe-favourites.js +19 -0
  60. package/dist/src/server/home-sections/new-arrivals-classic.d.ts +8 -0
  61. package/dist/src/server/home-sections/new-arrivals-classic.d.ts.map +1 -0
  62. package/dist/src/server/home-sections/new-arrivals-classic.js +10 -0
  63. package/dist/src/server/home-sections/new-arrivals.d.ts +12 -0
  64. package/dist/src/server/home-sections/new-arrivals.d.ts.map +1 -0
  65. package/dist/src/server/home-sections/new-arrivals.js +28 -0
  66. package/dist/src/server/home-sections/promo-announcements.d.ts +7 -0
  67. package/dist/src/server/home-sections/promo-announcements.d.ts.map +1 -0
  68. package/dist/src/server/home-sections/promo-announcements.js +7 -0
  69. package/dist/src/server/home-sections/promo-countdown.d.ts +6 -0
  70. package/dist/src/server/home-sections/promo-countdown.d.ts.map +1 -0
  71. package/dist/src/server/home-sections/promo-countdown.js +5 -0
  72. package/dist/src/server/home-sections/shared.d.ts +10 -0
  73. package/dist/src/server/home-sections/shared.d.ts.map +1 -0
  74. package/dist/src/server/home-sections/shared.js +29 -0
  75. package/dist/src/server/home-sections/shop-by-age.d.ts +9 -0
  76. package/dist/src/server/home-sections/shop-by-age.d.ts.map +1 -0
  77. package/dist/src/server/home-sections/shop-by-age.js +17 -0
  78. package/dist/src/server/home-sections/shop-by-category.d.ts +10 -0
  79. package/dist/src/server/home-sections/shop-by-category.d.ts.map +1 -0
  80. package/dist/src/server/home-sections/shop-by-category.js +17 -0
  81. package/dist/src/server/home-sections/testimonials.d.ts +9 -0
  82. package/dist/src/server/home-sections/testimonials.d.ts.map +1 -0
  83. package/dist/src/server/home-sections/testimonials.js +9 -0
  84. package/dist/src/server/home-sections/theme-dresses.d.ts +12 -0
  85. package/dist/src/server/home-sections/theme-dresses.d.ts.map +1 -0
  86. package/dist/src/server/home-sections/theme-dresses.js +27 -0
  87. package/dist/src/server/home-sections/video-stories.d.ts +9 -0
  88. package/dist/src/server/home-sections/video-stories.d.ts.map +1 -0
  89. package/dist/src/server/home-sections/video-stories.js +9 -0
  90. package/dist/src/server/home-sections/why-choose-us.d.ts +9 -0
  91. package/dist/src/server/home-sections/why-choose-us.d.ts.map +1 -0
  92. package/dist/src/server/home-sections/why-choose-us.js +9 -0
  93. package/dist/src/server/home.d.ts +62 -0
  94. package/dist/src/server/home.d.ts.map +1 -0
  95. package/dist/src/server/home.js +122 -0
  96. package/dist/src/server/homepage-config.types.d.ts +274 -0
  97. package/dist/src/server/homepage-config.types.d.ts.map +1 -0
  98. package/dist/src/server/homepage-config.types.js +33 -0
  99. package/dist/src/server/homepage-section-defaults.d.ts +188 -0
  100. package/dist/src/server/homepage-section-defaults.d.ts.map +1 -0
  101. package/dist/src/server/homepage-section-defaults.js +188 -0
  102. package/dist/{server → src/server}/index.d.ts +2 -0
  103. package/dist/src/server/index.d.ts.map +1 -0
  104. package/dist/{server → src/server}/index.js +2 -0
  105. package/dist/src/server/locale-actions.d.ts.map +1 -0
  106. package/dist/src/server/locales.d.ts.map +1 -0
  107. package/dist/src/server/notifications.d.ts.map +1 -0
  108. package/dist/src/server/onboarding.d.ts.map +1 -0
  109. package/dist/src/server/orders.d.ts.map +1 -0
  110. package/dist/src/server/page-input.d.ts +19 -0
  111. package/dist/src/server/page-input.d.ts.map +1 -0
  112. package/dist/src/server/page-input.js +40 -0
  113. package/dist/src/server/payment-details.d.ts.map +1 -0
  114. package/dist/src/server/payment.d.ts.map +1 -0
  115. package/dist/src/server/pincode.d.ts.map +1 -0
  116. package/dist/src/server/products.d.ts.map +1 -0
  117. package/dist/src/server/regions.d.ts.map +1 -0
  118. package/dist/src/server/resolve-home-segment-data.d.ts +25 -0
  119. package/dist/src/server/resolve-home-segment-data.d.ts.map +1 -0
  120. package/dist/src/server/resolve-home-segment-data.js +20 -0
  121. package/dist/src/server/returns.d.ts.map +1 -0
  122. package/dist/src/server/shoppable-looks.d.ts +17 -0
  123. package/dist/src/server/shoppable-looks.d.ts.map +1 -0
  124. package/dist/src/server/shoppable-looks.js +136 -0
  125. package/dist/src/server/swaps.d.ts.map +1 -0
  126. package/dist/src/server/variants.d.ts.map +1 -0
  127. package/dist/src/server/wishlist.d.ts.map +1 -0
  128. package/dist/src/util/get-locale-header.d.ts.map +1 -0
  129. package/dist/src/util/medusa-error.d.ts.map +1 -0
  130. package/dist/src/util/revalidate-cart.d.ts.map +1 -0
  131. package/dist/src/util/sort-products.d.ts.map +1 -0
  132. package/dist/src/util/store-client.d.ts.map +1 -0
  133. package/homepage-config.example.json +209 -0
  134. package/homepage-sections.example.json +55 -0
  135. package/package.json +121 -2
  136. package/segment-data/default-page-input.json +191 -0
  137. package/src/server/config-merge.ts +31 -0
  138. package/src/server/dynamic-config.ts +838 -248
  139. package/src/server/home-sections/about-brand.ts +24 -0
  140. package/src/server/home-sections/baptism-picks.ts +46 -0
  141. package/src/server/home-sections/baptism.ts +64 -0
  142. package/src/server/home-sections/blog-posts.ts +23 -0
  143. package/src/server/home-sections/brand-marquee.ts +17 -0
  144. package/src/server/home-sections/brand-pillars.ts +23 -0
  145. package/src/server/home-sections/category-pills.ts +32 -0
  146. package/src/server/home-sections/celebrity-trust.ts +42 -0
  147. package/src/server/home-sections/features.ts +23 -0
  148. package/src/server/home-sections/hero.ts +24 -0
  149. package/src/server/home-sections/instagram-posts.ts +23 -0
  150. package/src/server/home-sections/loved-by-moms.ts +34 -0
  151. package/src/server/home-sections/luxe-favourites.ts +30 -0
  152. package/src/server/home-sections/new-arrivals-classic.ts +21 -0
  153. package/src/server/home-sections/new-arrivals.ts +47 -0
  154. package/src/server/home-sections/promo-announcements.ts +17 -0
  155. package/src/server/home-sections/promo-countdown.ts +15 -0
  156. package/src/server/home-sections/shared.ts +44 -0
  157. package/src/server/home-sections/shop-by-age.ts +26 -0
  158. package/src/server/home-sections/shop-by-category.ts +28 -0
  159. package/src/server/home-sections/testimonials.ts +23 -0
  160. package/src/server/home-sections/theme-dresses.ts +49 -0
  161. package/src/server/home-sections/video-stories.ts +23 -0
  162. package/src/server/home-sections/why-choose-us.ts +23 -0
  163. package/src/server/home.ts +173 -16
  164. package/src/server/homepage-config.types.ts +335 -0
  165. package/src/server/homepage-section-defaults.ts +199 -0
  166. package/src/server/index.ts +2 -0
  167. package/src/server/page-input.ts +64 -0
  168. package/src/server/resolve-home-segment-data.ts +63 -0
  169. package/src/server/shoppable-looks.ts +178 -0
  170. package/dist/config.d.ts.map +0 -1
  171. package/dist/cookies.d.ts.map +0 -1
  172. package/dist/edge.d.ts.map +0 -1
  173. package/dist/middleware.d.ts.map +0 -1
  174. package/dist/server/cart.d.ts.map +0 -1
  175. package/dist/server/categories.d.ts.map +0 -1
  176. package/dist/server/collections.d.ts.map +0 -1
  177. package/dist/server/contact.d.ts.map +0 -1
  178. package/dist/server/customer-registration.d.ts.map +0 -1
  179. package/dist/server/customer.d.ts.map +0 -1
  180. package/dist/server/dynamic-config.d.ts +0 -125
  181. package/dist/server/dynamic-config.d.ts.map +0 -1
  182. package/dist/server/dynamic-config.js +0 -289
  183. package/dist/server/fulfillment.d.ts.map +0 -1
  184. package/dist/server/guest.d.ts.map +0 -1
  185. package/dist/server/home.d.ts +0 -15
  186. package/dist/server/home.d.ts.map +0 -1
  187. package/dist/server/home.js +0 -45
  188. package/dist/server/index.d.ts.map +0 -1
  189. package/dist/server/locale-actions.d.ts.map +0 -1
  190. package/dist/server/locales.d.ts.map +0 -1
  191. package/dist/server/notifications.d.ts.map +0 -1
  192. package/dist/server/onboarding.d.ts.map +0 -1
  193. package/dist/server/orders.d.ts.map +0 -1
  194. package/dist/server/payment-details.d.ts.map +0 -1
  195. package/dist/server/payment.d.ts.map +0 -1
  196. package/dist/server/pincode.d.ts.map +0 -1
  197. package/dist/server/products.d.ts.map +0 -1
  198. package/dist/server/regions.d.ts.map +0 -1
  199. package/dist/server/returns.d.ts.map +0 -1
  200. package/dist/server/swaps.d.ts.map +0 -1
  201. package/dist/server/variants.d.ts.map +0 -1
  202. package/dist/server/wishlist.d.ts.map +0 -1
  203. package/dist/util/get-locale-header.d.ts.map +0 -1
  204. package/dist/util/medusa-error.d.ts.map +0 -1
  205. package/dist/util/revalidate-cart.d.ts.map +0 -1
  206. package/dist/util/sort-products.d.ts.map +0 -1
  207. package/dist/util/store-client.d.ts.map +0 -1
  208. /package/dist/{config.d.ts → src/config.d.ts} +0 -0
  209. /package/dist/{config.js → src/config.js} +0 -0
  210. /package/dist/{cookies.d.ts → src/cookies.d.ts} +0 -0
  211. /package/dist/{cookies.js → src/cookies.js} +0 -0
  212. /package/dist/{edge.d.ts → src/edge.d.ts} +0 -0
  213. /package/dist/{edge.js → src/edge.js} +0 -0
  214. /package/dist/{middleware.d.ts → src/middleware.d.ts} +0 -0
  215. /package/dist/{middleware.js → src/middleware.js} +0 -0
  216. /package/dist/{server → src/server}/cart.d.ts +0 -0
  217. /package/dist/{server → src/server}/cart.js +0 -0
  218. /package/dist/{server → src/server}/categories.d.ts +0 -0
  219. /package/dist/{server → src/server}/categories.js +0 -0
  220. /package/dist/{server → src/server}/collections.d.ts +0 -0
  221. /package/dist/{server → src/server}/collections.js +0 -0
  222. /package/dist/{server → src/server}/contact.d.ts +0 -0
  223. /package/dist/{server → src/server}/contact.js +0 -0
  224. /package/dist/{server → src/server}/customer-registration.d.ts +0 -0
  225. /package/dist/{server → src/server}/customer-registration.js +0 -0
  226. /package/dist/{server → src/server}/customer.d.ts +0 -0
  227. /package/dist/{server → src/server}/customer.js +0 -0
  228. /package/dist/{server → src/server}/fulfillment.d.ts +0 -0
  229. /package/dist/{server → src/server}/fulfillment.js +0 -0
  230. /package/dist/{server → src/server}/guest.d.ts +0 -0
  231. /package/dist/{server → src/server}/guest.js +0 -0
  232. /package/dist/{server → src/server}/locale-actions.d.ts +0 -0
  233. /package/dist/{server → src/server}/locale-actions.js +0 -0
  234. /package/dist/{server → src/server}/locales.d.ts +0 -0
  235. /package/dist/{server → src/server}/locales.js +0 -0
  236. /package/dist/{server → src/server}/notifications.d.ts +0 -0
  237. /package/dist/{server → src/server}/notifications.js +0 -0
  238. /package/dist/{server → src/server}/onboarding.d.ts +0 -0
  239. /package/dist/{server → src/server}/onboarding.js +0 -0
  240. /package/dist/{server → src/server}/orders.d.ts +0 -0
  241. /package/dist/{server → src/server}/orders.js +0 -0
  242. /package/dist/{server → src/server}/payment-details.d.ts +0 -0
  243. /package/dist/{server → src/server}/payment-details.js +0 -0
  244. /package/dist/{server → src/server}/payment.d.ts +0 -0
  245. /package/dist/{server → src/server}/payment.js +0 -0
  246. /package/dist/{server → src/server}/pincode.d.ts +0 -0
  247. /package/dist/{server → src/server}/pincode.js +0 -0
  248. /package/dist/{server → src/server}/products.d.ts +0 -0
  249. /package/dist/{server → src/server}/products.js +0 -0
  250. /package/dist/{server → src/server}/regions.d.ts +0 -0
  251. /package/dist/{server → src/server}/regions.js +0 -0
  252. /package/dist/{server → src/server}/returns.d.ts +0 -0
  253. /package/dist/{server → src/server}/returns.js +0 -0
  254. /package/dist/{server → src/server}/swaps.d.ts +0 -0
  255. /package/dist/{server → src/server}/swaps.js +0 -0
  256. /package/dist/{server → src/server}/variants.d.ts +0 -0
  257. /package/dist/{server → src/server}/variants.js +0 -0
  258. /package/dist/{server → src/server}/wishlist.d.ts +0 -0
  259. /package/dist/{server → src/server}/wishlist.js +0 -0
  260. /package/dist/{util → src/util}/get-locale-header.d.ts +0 -0
  261. /package/dist/{util → src/util}/get-locale-header.js +0 -0
  262. /package/dist/{util → src/util}/medusa-error.d.ts +0 -0
  263. /package/dist/{util → src/util}/medusa-error.js +0 -0
  264. /package/dist/{util → src/util}/revalidate-cart.d.ts +0 -0
  265. /package/dist/{util → src/util}/revalidate-cart.js +0 -0
  266. /package/dist/{util → src/util}/sort-products.d.ts +0 -0
  267. /package/dist/{util → src/util}/sort-products.js +0 -0
  268. /package/dist/{util → src/util}/store-client.d.ts +0 -0
  269. /package/dist/{util → src/util}/store-client.js +0 -0
@@ -0,0 +1,24 @@
1
+ import "server-only"
2
+
3
+ import {
4
+ getAboutBrandFromPageInput,
5
+ getHomeSectionsCopyFromPageInput,
6
+ type AboutBrandConfig,
7
+ } from "../dynamic-config"
8
+ import type { SectionLoaderOptions } from "./shared"
9
+
10
+ export type AboutBrandSectionData = {
11
+ aboutBrand: AboutBrandConfig
12
+ copy: ReturnType<typeof getHomeSectionsCopyFromPageInput>["aboutBrand"]
13
+ }
14
+
15
+ export async function loadAboutBrandSectionData(
16
+ _countryCode: string,
17
+ options?: SectionLoaderOptions
18
+ ): Promise<AboutBrandSectionData> {
19
+ const pageInput = options?.pageInput ?? null
20
+ return {
21
+ aboutBrand: getAboutBrandFromPageInput(pageInput),
22
+ copy: getHomeSectionsCopyFromPageInput(pageInput).aboutBrand,
23
+ }
24
+ }
@@ -0,0 +1,46 @@
1
+ import "server-only"
2
+
3
+ import { HttpTypes } from "@medusajs/types"
4
+ import { getHomeSectionsCopyFromPageInput } from "../dynamic-config"
5
+ import { listCategories } from "../categories"
6
+ import { getProductsByTag } from "../products"
7
+ import { getBaptismPicksLooks, type ShoppableLook } from "../shoppable-looks"
8
+ import {
9
+ categoryIdsMatching,
10
+ productsForCategoryIds,
11
+ requireRegion,
12
+ type SectionLoaderOptions,
13
+ } from "./shared"
14
+
15
+ export type BaptismPicksSectionData = {
16
+ baptismPicks: ShoppableLook[]
17
+ copy: ReturnType<typeof getHomeSectionsCopyFromPageInput>["baptismPicks"]
18
+ }
19
+
20
+ export async function loadBaptismPicksSectionData(
21
+ countryCode: string,
22
+ options?: SectionLoaderOptions
23
+ ): Promise<BaptismPicksSectionData | null> {
24
+ const region = await requireRegion(countryCode)
25
+ if (!region) return null
26
+ const pageInput = options?.pageInput ?? null
27
+ const [categoriesResult, baptismByTag] = await Promise.all([
28
+ listCategories({ limit: 100 }).catch(() => []),
29
+ getProductsByTag({ tagValue: "baptism", limit: 12, countryCode }).catch(() => []),
30
+ ])
31
+ const categories = (categoriesResult ?? []) as HttpTypes.StoreProductCategory[]
32
+ const baptismIds = categoryIdsMatching(categories, /baptism/)
33
+ let baptismFallback = baptismByTag
34
+ if (baptismIds.length > 0) {
35
+ baptismFallback = await productsForCategoryIds(countryCode, baptismIds, 12)
36
+ }
37
+ const baptismPicks = await getBaptismPicksLooks(
38
+ countryCode,
39
+ baptismFallback.slice(0, 8),
40
+ pageInput
41
+ )
42
+ return {
43
+ baptismPicks,
44
+ copy: getHomeSectionsCopyFromPageInput(pageInput).baptismPicks,
45
+ }
46
+ }
@@ -0,0 +1,64 @@
1
+ import "server-only"
2
+
3
+ import { HttpTypes } from "@medusajs/types"
4
+ import { fetchRatings } from "medusa-reviews-logic/server"
5
+ import { getHomeSectionsCopyFromPageInput } from "../dynamic-config"
6
+ import { listCategories } from "../categories"
7
+ import { getProductsByTag } from "../products"
8
+ import {
9
+ categoryIdsMatching,
10
+ productsForCategoryIds,
11
+ requireRegion,
12
+ type SectionLoaderOptions,
13
+ } from "./shared"
14
+
15
+ export type BaptismSectionData = {
16
+ region: NonNullable<Awaited<ReturnType<typeof requireRegion>>>
17
+ baptismGirl: HttpTypes.StoreProduct[]
18
+ baptismBoy: HttpTypes.StoreProduct[]
19
+ ratings: unknown[]
20
+ copy: ReturnType<typeof getHomeSectionsCopyFromPageInput>["baptism"]
21
+ }
22
+
23
+ export async function loadBaptismSectionData(
24
+ countryCode: string,
25
+ options?: SectionLoaderOptions
26
+ ): Promise<BaptismSectionData | null> {
27
+ const region = await requireRegion(countryCode)
28
+ if (!region) return null
29
+ const ratings = await fetchRatings()
30
+ const pageInput = options?.pageInput ?? null
31
+ const [categoriesResult, baptismByTag] = await Promise.all([
32
+ listCategories({ limit: 100 }).catch(() => []),
33
+ getProductsByTag({ tagValue: "baptism", limit: 12, countryCode }).catch(() => []),
34
+ ])
35
+ const categories = (categoriesResult ?? []) as HttpTypes.StoreProductCategory[]
36
+ const girlIds = categoryIdsMatching(categories, /baptism.*girl|girl.*baptism|^girl$/)
37
+ const boyIds = categoryIdsMatching(categories, /baptism.*boy|boy.*baptism|^boy$/)
38
+ const baptismIds = categoryIdsMatching(categories, /baptism/)
39
+
40
+ const [baptismGirl, baptismBoy] = await Promise.all([
41
+ girlIds.length
42
+ ? productsForCategoryIds(countryCode, girlIds, 8)
43
+ : baptismByTag.filter((p) => /girl/i.test(p.title || "")).slice(0, 8),
44
+ boyIds.length
45
+ ? productsForCategoryIds(countryCode, boyIds, 8)
46
+ : baptismByTag.filter((p) => /boy/i.test(p.title || "")).slice(0, 8),
47
+ ])
48
+
49
+ let baptismFallback: HttpTypes.StoreProduct[] = []
50
+ if (baptismGirl.length === 0 && baptismBoy.length === 0) {
51
+ baptismFallback =
52
+ baptismIds.length > 0
53
+ ? await productsForCategoryIds(countryCode, baptismIds, 12)
54
+ : baptismByTag
55
+ }
56
+
57
+ return {
58
+ region,
59
+ baptismGirl: baptismGirl.length > 0 ? baptismGirl : baptismFallback.slice(0, 8),
60
+ baptismBoy: baptismBoy.length > 0 ? baptismBoy : baptismFallback.slice(0, 8),
61
+ ratings: ratings ?? [],
62
+ copy: getHomeSectionsCopyFromPageInput(pageInput).baptism,
63
+ }
64
+ }
@@ -0,0 +1,23 @@
1
+ import "server-only"
2
+
3
+ import {
4
+ getBlogPostsFromPageInput,
5
+ getHomeSectionsCopyFromPageInput,
6
+ } from "../dynamic-config"
7
+ import type { SectionLoaderOptions } from "./shared"
8
+
9
+ export type BlogPostsSectionData = {
10
+ blogPosts: ReturnType<typeof getBlogPostsFromPageInput>
11
+ copy: ReturnType<typeof getHomeSectionsCopyFromPageInput>["blogPosts"]
12
+ }
13
+
14
+ export async function loadBlogPostsSectionData(
15
+ _countryCode: string,
16
+ options?: SectionLoaderOptions
17
+ ): Promise<BlogPostsSectionData> {
18
+ const pageInput = options?.pageInput ?? null
19
+ return {
20
+ blogPosts: getBlogPostsFromPageInput(pageInput),
21
+ copy: getHomeSectionsCopyFromPageInput(pageInput).blogPosts,
22
+ }
23
+ }
@@ -0,0 +1,17 @@
1
+ import "server-only"
2
+
3
+ import { getHomeSectionsCopyFromPageInput } from "../dynamic-config"
4
+ import type { SectionLoaderOptions } from "./shared"
5
+
6
+ export type BrandMarqueeSectionData = {
7
+ copy: ReturnType<typeof getHomeSectionsCopyFromPageInput>["brandMarquee"]
8
+ }
9
+
10
+ export async function loadBrandMarqueeSectionData(
11
+ _countryCode: string,
12
+ options?: SectionLoaderOptions
13
+ ): Promise<BrandMarqueeSectionData> {
14
+ return {
15
+ copy: getHomeSectionsCopyFromPageInput(options?.pageInput ?? null).brandMarquee,
16
+ }
17
+ }
@@ -0,0 +1,23 @@
1
+ import "server-only"
2
+
3
+ import {
4
+ getBrandPillarsFromPageInput,
5
+ getHomeSectionsCopyFromPageInput,
6
+ } from "../dynamic-config"
7
+ import type { SectionLoaderOptions } from "./shared"
8
+
9
+ export type BrandPillarsSectionData = {
10
+ brandPillars: ReturnType<typeof getBrandPillarsFromPageInput>
11
+ copy: ReturnType<typeof getHomeSectionsCopyFromPageInput>["brandPillars"]
12
+ }
13
+
14
+ export async function loadBrandPillarsSectionData(
15
+ _countryCode: string,
16
+ options?: SectionLoaderOptions
17
+ ): Promise<BrandPillarsSectionData> {
18
+ const pageInput = options?.pageInput ?? null
19
+ return {
20
+ brandPillars: getBrandPillarsFromPageInput(pageInput),
21
+ copy: getHomeSectionsCopyFromPageInput(pageInput).brandPillars,
22
+ }
23
+ }
@@ -0,0 +1,32 @@
1
+ import "server-only"
2
+
3
+ import { HttpTypes } from "@medusajs/types"
4
+ import { listCategories } from "../categories"
5
+ import { listCollections } from "../collections"
6
+ import type { SectionLoaderOptions } from "./shared"
7
+
8
+ export type CategoryPillsSectionData = {
9
+ categories: HttpTypes.StoreProductCategory[]
10
+ collections: Array<Record<string, unknown>>
11
+ }
12
+
13
+ export async function loadCategoryPillsSectionData(
14
+ _countryCode: string,
15
+ _options?: SectionLoaderOptions
16
+ ): Promise<CategoryPillsSectionData> {
17
+ const [categoriesResult, collectionsResult] = await Promise.all([
18
+ listCategories({
19
+ limit: 100,
20
+ fields:
21
+ "id,handle,name,metadata,parent_category_id,*parent_category,*parent_category.parent_category",
22
+ }).catch(() => []),
23
+ listCollections({ fields: "id, handle, title, metadata" }).catch(() => ({
24
+ collections: [],
25
+ })),
26
+ ])
27
+ return {
28
+ categories: (categoriesResult ?? []) as HttpTypes.StoreProductCategory[],
29
+ collections: ((collectionsResult as { collections?: unknown[] }).collections ??
30
+ []) as Array<Record<string, unknown>>,
31
+ }
32
+ }
@@ -0,0 +1,42 @@
1
+ import "server-only"
2
+
3
+ import { HttpTypes } from "@medusajs/types"
4
+ import { getHomeSectionsCopyFromPageInput } from "../dynamic-config"
5
+ import { getProductsByTag, listProductsWithSort } from "../products"
6
+ import { getRegion } from "../regions"
7
+ import type { SectionLoaderOptions } from "./shared"
8
+
9
+ export type CelebrityTrustSectionData = {
10
+ region: NonNullable<Awaited<ReturnType<typeof getRegion>>>
11
+ celebrityProduct: HttpTypes.StoreProduct | null
12
+ copy: ReturnType<typeof getHomeSectionsCopyFromPageInput>["celebrityTrust"]
13
+ }
14
+
15
+ export async function loadCelebrityTrustSectionData(
16
+ countryCode: string,
17
+ options?: SectionLoaderOptions
18
+ ): Promise<CelebrityTrustSectionData | null> {
19
+ const region = await getRegion(countryCode)
20
+ if (!region) return null
21
+ const pageInput = options?.pageInput ?? null
22
+ const [bestsellers, newArrivalsResult] = await Promise.all([
23
+ getProductsByTag({ tagValue: "bestseller", limit: 10, countryCode }).catch(
24
+ () => []
25
+ ),
26
+ listProductsWithSort({
27
+ page: 1,
28
+ queryParams: { limit: 12 },
29
+ sortBy: "created_at",
30
+ countryCode,
31
+ }).catch(() => ({ response: { products: [] } })),
32
+ ])
33
+ const newArrivals =
34
+ (newArrivalsResult as { response?: { products?: HttpTypes.StoreProduct[] } })
35
+ .response?.products ?? []
36
+ const bestsellerList = (bestsellers ?? []) as HttpTypes.StoreProduct[]
37
+ return {
38
+ region,
39
+ celebrityProduct: bestsellerList[0] ?? newArrivals[0] ?? null,
40
+ copy: getHomeSectionsCopyFromPageInput(pageInput).celebrityTrust,
41
+ }
42
+ }
@@ -0,0 +1,23 @@
1
+ import "server-only"
2
+
3
+ import {
4
+ getHomeSectionsCopyFromPageInput,
5
+ getTrustFeaturesFromPageInput,
6
+ } from "../dynamic-config"
7
+ import type { SectionLoaderOptions } from "./shared"
8
+
9
+ export type FeaturesSectionData = {
10
+ trustFeatures: ReturnType<typeof getTrustFeaturesFromPageInput>
11
+ copy: ReturnType<typeof getHomeSectionsCopyFromPageInput>["features"]
12
+ }
13
+
14
+ export async function loadFeaturesSectionData(
15
+ _countryCode: string,
16
+ options?: SectionLoaderOptions
17
+ ): Promise<FeaturesSectionData> {
18
+ const pageInput = options?.pageInput ?? null
19
+ return {
20
+ trustFeatures: getTrustFeaturesFromPageInput(pageInput),
21
+ copy: getHomeSectionsCopyFromPageInput(pageInput).features,
22
+ }
23
+ }
@@ -0,0 +1,24 @@
1
+ import "server-only"
2
+
3
+ import {
4
+ getAppBannersFromPageInput,
5
+ getHomeBannersFromPageInput,
6
+ type HomepageBanner,
7
+ } from "../dynamic-config"
8
+ import type { SectionLoaderOptions } from "./shared"
9
+
10
+ export type HeroSectionData = {
11
+ homeBanners: HomepageBanner[] | null
12
+ appBanners: HomepageBanner[] | null
13
+ }
14
+
15
+ export async function loadHeroSectionData(
16
+ _countryCode: string,
17
+ options?: SectionLoaderOptions
18
+ ): Promise<HeroSectionData> {
19
+ const pageInput = options?.pageInput ?? null
20
+ return {
21
+ homeBanners: getHomeBannersFromPageInput(pageInput),
22
+ appBanners: getAppBannersFromPageInput(pageInput),
23
+ }
24
+ }
@@ -0,0 +1,23 @@
1
+ import "server-only"
2
+
3
+ import {
4
+ getHomeSectionsCopyFromPageInput,
5
+ getInstagramPostsFromPageInput,
6
+ } from "../dynamic-config"
7
+ import type { SectionLoaderOptions } from "./shared"
8
+
9
+ export type InstagramPostsSectionData = {
10
+ instagramPosts: ReturnType<typeof getInstagramPostsFromPageInput>
11
+ copy: ReturnType<typeof getHomeSectionsCopyFromPageInput>["instagramPosts"]
12
+ }
13
+
14
+ export async function loadInstagramPostsSectionData(
15
+ _countryCode: string,
16
+ options?: SectionLoaderOptions
17
+ ): Promise<InstagramPostsSectionData> {
18
+ const pageInput = options?.pageInput ?? null
19
+ return {
20
+ instagramPosts: getInstagramPostsFromPageInput(pageInput),
21
+ copy: getHomeSectionsCopyFromPageInput(pageInput).instagramPosts,
22
+ }
23
+ }
@@ -0,0 +1,34 @@
1
+ import "server-only"
2
+
3
+ import { HttpTypes } from "@medusajs/types"
4
+ import { fetchRatings } from "medusa-reviews-logic/server"
5
+ import { getHomeSectionsCopyFromPageInput } from "../dynamic-config"
6
+ import { getProductsByTag } from "../products"
7
+ import { requireRegion, type SectionLoaderOptions } from "./shared"
8
+
9
+ export type LovedByMomsSectionData = {
10
+ region: NonNullable<Awaited<ReturnType<typeof requireRegion>>>
11
+ bestsellers: HttpTypes.StoreProduct[]
12
+ ratings: unknown[]
13
+ copy: ReturnType<typeof getHomeSectionsCopyFromPageInput>["lovedByMoms"]
14
+ }
15
+
16
+ export async function loadLovedByMomsSectionData(
17
+ countryCode: string,
18
+ options?: SectionLoaderOptions
19
+ ): Promise<LovedByMomsSectionData | null> {
20
+ const region = await requireRegion(countryCode)
21
+ if (!region) return null
22
+ const [bestsellers, ratings] = await Promise.all([
23
+ getProductsByTag({ tagValue: "bestseller", limit: 10, countryCode }).catch(
24
+ () => []
25
+ ),
26
+ fetchRatings(),
27
+ ])
28
+ return {
29
+ region,
30
+ bestsellers: (bestsellers ?? []) as HttpTypes.StoreProduct[],
31
+ ratings: ratings ?? [],
32
+ copy: getHomeSectionsCopyFromPageInput(options?.pageInput ?? null).lovedByMoms,
33
+ }
34
+ }
@@ -0,0 +1,30 @@
1
+ import "server-only"
2
+
3
+ import { HttpTypes } from "@medusajs/types"
4
+ import { getHomeSectionsCopyFromPageInput } from "../dynamic-config"
5
+ import { getProductsByTag } from "../products"
6
+ import { requireRegion, type SectionLoaderOptions } from "./shared"
7
+
8
+ export type LuxeFavouritesSectionData = {
9
+ region: NonNullable<Awaited<ReturnType<typeof requireRegion>>>
10
+ luxeFavourites: HttpTypes.StoreProduct[]
11
+ copy: ReturnType<typeof getHomeSectionsCopyFromPageInput>["luxeFavourites"]
12
+ }
13
+
14
+ export async function loadLuxeFavouritesSectionData(
15
+ countryCode: string,
16
+ options?: SectionLoaderOptions
17
+ ): Promise<LuxeFavouritesSectionData | null> {
18
+ const region = await requireRegion(countryCode)
19
+ if (!region) return null
20
+ const bestsellers = (await getProductsByTag({
21
+ tagValue: "bestseller",
22
+ limit: 10,
23
+ countryCode,
24
+ }).catch(() => [])) as HttpTypes.StoreProduct[]
25
+ return {
26
+ region,
27
+ luxeFavourites: bestsellers.slice(0, 4),
28
+ copy: getHomeSectionsCopyFromPageInput(options?.pageInput ?? null).luxeFavourites,
29
+ }
30
+ }
@@ -0,0 +1,21 @@
1
+ import "server-only"
2
+
3
+ import { loadNewArrivalsSectionData, type NewArrivalsSectionData } from "./new-arrivals"
4
+ import {
5
+ getHomeSectionsCopyFromPageInput,
6
+ } from "../dynamic-config"
7
+ import type { SectionLoaderOptions } from "./shared"
8
+
9
+ export type NewArrivalsClassicSectionData = NewArrivalsSectionData & {
10
+ copy: NewArrivalsSectionData["copy"]
11
+ }
12
+
13
+ export async function loadNewArrivalsClassicSectionData(
14
+ countryCode: string,
15
+ options?: SectionLoaderOptions
16
+ ): Promise<NewArrivalsClassicSectionData | null> {
17
+ const base = await loadNewArrivalsSectionData(countryCode, options)
18
+ if (!base) return null
19
+ const sectionsCopy = getHomeSectionsCopyFromPageInput(options?.pageInput ?? null)
20
+ return { ...base, copy: sectionsCopy.newArrivalsClassic }
21
+ }
@@ -0,0 +1,47 @@
1
+ import "server-only"
2
+
3
+ import { HttpTypes } from "@medusajs/types"
4
+ import { fetchRatings } from "medusa-reviews-logic/server"
5
+ import {
6
+ getHomeSectionsCopyFromPageInput,
7
+ type SectionCopy,
8
+ } from "../dynamic-config"
9
+ import { listProductsWithSort } from "../products"
10
+ import {
11
+ requireRegion,
12
+ type SectionLoaderOptions,
13
+ } from "./shared"
14
+
15
+ export type NewArrivalsSectionData = {
16
+ region: NonNullable<Awaited<ReturnType<typeof requireRegion>>>
17
+ products: HttpTypes.StoreProduct[]
18
+ ratings: unknown[]
19
+ copy: SectionCopy
20
+ }
21
+
22
+ export async function loadNewArrivalsSectionData(
23
+ countryCode: string,
24
+ options?: SectionLoaderOptions
25
+ ): Promise<NewArrivalsSectionData | null> {
26
+ const region = await requireRegion(countryCode)
27
+ if (!region) return null
28
+ const pageInput = options?.pageInput ?? null
29
+ const [newArrivalsResult, ratings] = await Promise.all([
30
+ listProductsWithSort({
31
+ page: 1,
32
+ queryParams: { limit: 12 },
33
+ sortBy: "created_at",
34
+ countryCode,
35
+ }).catch(() => ({ response: { products: [] } })),
36
+ fetchRatings(),
37
+ ])
38
+ const sectionsCopy = getHomeSectionsCopyFromPageInput(pageInput)
39
+ return {
40
+ region,
41
+ products:
42
+ (newArrivalsResult as { response?: { products?: HttpTypes.StoreProduct[] } })
43
+ .response?.products ?? [],
44
+ ratings: ratings ?? [],
45
+ copy: sectionsCopy.newArrivals,
46
+ }
47
+ }
@@ -0,0 +1,17 @@
1
+ import "server-only"
2
+
3
+ import { getAnnouncementMessagesFromPageInput } from "../dynamic-config"
4
+ import type { SectionLoaderOptions } from "./shared"
5
+
6
+ export type PromoAnnouncementsSectionData = {
7
+ messages: string[]
8
+ }
9
+
10
+ export async function loadPromoAnnouncementsSectionData(
11
+ _countryCode: string,
12
+ options?: SectionLoaderOptions
13
+ ): Promise<PromoAnnouncementsSectionData> {
14
+ return {
15
+ messages: getAnnouncementMessagesFromPageInput(options?.pageInput ?? null),
16
+ }
17
+ }
@@ -0,0 +1,15 @@
1
+ import "server-only"
2
+
3
+ import { getPromoCountdownFromPageInput } from "../dynamic-config"
4
+ import type { SectionLoaderOptions } from "./shared"
5
+
6
+ export type PromoCountdownSectionData = Awaited<
7
+ ReturnType<typeof getPromoCountdownFromPageInput>
8
+ >
9
+
10
+ export async function loadPromoCountdownSectionData(
11
+ _countryCode: string,
12
+ options?: SectionLoaderOptions
13
+ ): Promise<PromoCountdownSectionData> {
14
+ return getPromoCountdownFromPageInput(options?.pageInput ?? null)
15
+ }
@@ -0,0 +1,44 @@
1
+ import "server-only"
2
+
3
+ import { HttpTypes } from "@medusajs/types"
4
+ import { listProducts } from "../products"
5
+ import { getRegion } from "../regions"
6
+ import type { HomepageConfig } from "../homepage-config.types"
7
+
8
+ export type SectionLoaderOptions = {
9
+ pageInput?: HomepageConfig | null
10
+ }
11
+
12
+ export async function requireRegion(countryCode: string) {
13
+ return getRegion(countryCode)
14
+ }
15
+
16
+ export async function productsForCategoryIds(
17
+ countryCode: string,
18
+ categoryIds: string[],
19
+ limit: number
20
+ ): Promise<HttpTypes.StoreProduct[]> {
21
+ if (!categoryIds.length) return []
22
+ try {
23
+ const { response } = await listProducts({
24
+ countryCode,
25
+ queryParams: {
26
+ category_id: categoryIds,
27
+ limit,
28
+ } as HttpTypes.FindParams & HttpTypes.StoreProductListParams,
29
+ })
30
+ return response.products ?? []
31
+ } catch {
32
+ return []
33
+ }
34
+ }
35
+
36
+ export function categoryIdsMatching(
37
+ categories: HttpTypes.StoreProductCategory[],
38
+ pattern: RegExp
39
+ ): string[] {
40
+ return categories
41
+ .filter((c) => pattern.test((c.name || c.handle || "").toLowerCase()))
42
+ .map((c) => c.id)
43
+ .filter(Boolean) as string[]
44
+ }
@@ -0,0 +1,26 @@
1
+ import "server-only"
2
+
3
+ import { getHomeSectionsCopyFromPageInput } from "../dynamic-config"
4
+ import { listCollections } from "../collections"
5
+ import { requireRegion, type SectionLoaderOptions } from "./shared"
6
+
7
+ export type ShopByAgeSectionData = {
8
+ collections: Array<Record<string, unknown>>
9
+ copy: ReturnType<typeof getHomeSectionsCopyFromPageInput>["shopByAge"]
10
+ }
11
+
12
+ export async function loadShopByAgeSectionData(
13
+ countryCode: string,
14
+ options?: SectionLoaderOptions
15
+ ): Promise<ShopByAgeSectionData | null> {
16
+ const region = await requireRegion(countryCode)
17
+ if (!region) return null
18
+ const collectionsResult = await listCollections({
19
+ fields: "id, handle, title, metadata",
20
+ }).catch(() => ({ collections: [] }))
21
+ return {
22
+ collections: ((collectionsResult as { collections?: unknown[] }).collections ??
23
+ []) as Array<Record<string, unknown>>,
24
+ copy: getHomeSectionsCopyFromPageInput(options?.pageInput ?? null).shopByAge,
25
+ }
26
+ }
@@ -0,0 +1,28 @@
1
+ import "server-only"
2
+
3
+ import { HttpTypes } from "@medusajs/types"
4
+ import { getHomeSectionsCopyFromPageInput } from "../dynamic-config"
5
+ import { listCategories } from "../categories"
6
+ import { requireRegion, type SectionLoaderOptions } from "./shared"
7
+
8
+ export type ShopByCategorySectionData = {
9
+ categories: HttpTypes.StoreProductCategory[]
10
+ copy: ReturnType<typeof getHomeSectionsCopyFromPageInput>["shopByCategory"]
11
+ }
12
+
13
+ export async function loadShopByCategorySectionData(
14
+ countryCode: string,
15
+ options?: SectionLoaderOptions
16
+ ): Promise<ShopByCategorySectionData | null> {
17
+ const region = await requireRegion(countryCode)
18
+ if (!region) return null
19
+ const categories = (await listCategories({
20
+ limit: 100,
21
+ fields:
22
+ "id,handle,name,metadata,parent_category_id,*parent_category,*parent_category.parent_category",
23
+ }).catch(() => [])) as HttpTypes.StoreProductCategory[]
24
+ return {
25
+ categories,
26
+ copy: getHomeSectionsCopyFromPageInput(options?.pageInput ?? null).shopByCategory,
27
+ }
28
+ }
@@ -0,0 +1,23 @@
1
+ import "server-only"
2
+
3
+ import {
4
+ getHomeSectionsCopyFromPageInput,
5
+ getTestimonialsFromPageInput,
6
+ } from "../dynamic-config"
7
+ import type { SectionLoaderOptions } from "./shared"
8
+
9
+ export type TestimonialsSectionData = {
10
+ testimonials: ReturnType<typeof getTestimonialsFromPageInput>
11
+ copy: ReturnType<typeof getHomeSectionsCopyFromPageInput>["testimonials"]
12
+ }
13
+
14
+ export async function loadTestimonialsSectionData(
15
+ _countryCode: string,
16
+ options?: SectionLoaderOptions
17
+ ): Promise<TestimonialsSectionData> {
18
+ const pageInput = options?.pageInput ?? null
19
+ return {
20
+ testimonials: getTestimonialsFromPageInput(pageInput),
21
+ copy: getHomeSectionsCopyFromPageInput(pageInput).testimonials,
22
+ }
23
+ }