@salifbiaye/create-boutique 0.1.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.
Files changed (316) hide show
  1. package/README.md +1 -0
  2. package/cli/dist/commands.js +382 -0
  3. package/cli/dist/create.js +194 -0
  4. package/cli/dist/docker.js +19 -0
  5. package/cli/dist/generate.js +322 -0
  6. package/cli/dist/guide.js +72 -0
  7. package/cli/dist/index.js +156 -0
  8. package/cli/dist/paths.js +29 -0
  9. package/cli/dist/ports.js +54 -0
  10. package/cli/dist/project.js +119 -0
  11. package/cli/dist/themes.js +24 -0
  12. package/docs/fiche-client.en.html +137 -0
  13. package/docs/fiche-client.html +137 -0
  14. package/docs/guide-complet.en.html +259 -0
  15. package/docs/guide-complet.fr.html +259 -0
  16. package/package.json +51 -0
  17. package/templates/backend/.dockerignore +9 -0
  18. package/templates/backend/Dockerfile +30 -0
  19. package/templates/backend/README.md +78 -0
  20. package/templates/backend/TEMPLATE_VERSION +1 -0
  21. package/templates/backend/docker/entrypoint.sh +28 -0
  22. package/templates/backend/instrumentation.ts +24 -0
  23. package/templates/backend/medusa-config.ts +114 -0
  24. package/templates/backend/package-lock.json +16222 -0
  25. package/templates/backend/package.json +39 -0
  26. package/templates/backend/src/admin/README.md +33 -0
  27. package/templates/backend/src/admin/components/image-field.tsx +61 -0
  28. package/templates/backend/src/admin/i18n/README.md +58 -0
  29. package/templates/backend/src/admin/i18n/index.ts +8 -0
  30. package/templates/backend/src/admin/i18n/json/en.json +66 -0
  31. package/templates/backend/src/admin/i18n/json/fr.json +66 -0
  32. package/templates/backend/src/admin/lib/client.ts +9 -0
  33. package/templates/backend/src/admin/routes/boutique-campaigns/campaign-drawer.tsx +286 -0
  34. package/templates/backend/src/admin/routes/boutique-campaigns/page.tsx +113 -0
  35. package/templates/backend/src/admin/tsconfig.json +24 -0
  36. package/templates/backend/src/admin/vite-env.d.ts +1 -0
  37. package/templates/backend/src/admin/widgets/category-image.tsx +56 -0
  38. package/templates/backend/src/api/README.md +135 -0
  39. package/templates/backend/src/api/admin/boutique-campaigns/[salesChannelId]/route.ts +30 -0
  40. package/templates/backend/src/api/admin/boutique-campaigns/route.ts +24 -0
  41. package/templates/backend/src/api/middlewares.ts +28 -0
  42. package/templates/backend/src/api/rate-limit.ts +30 -0
  43. package/templates/backend/src/api/route.ts +6 -0
  44. package/templates/backend/src/api/store/campaign/route.ts +25 -0
  45. package/templates/backend/src/api/store/order-lookup/route.ts +74 -0
  46. package/templates/backend/src/emails/en.json +64 -0
  47. package/templates/backend/src/emails/fr.json +64 -0
  48. package/templates/backend/src/jobs/README.md +38 -0
  49. package/templates/backend/src/lib/emails.ts +94 -0
  50. package/templates/backend/src/lib/notify.ts +148 -0
  51. package/templates/backend/src/lib/project.ts +146 -0
  52. package/templates/backend/src/links/README.md +26 -0
  53. package/templates/backend/src/links/campaign-sales-channel.ts +9 -0
  54. package/templates/backend/src/modules/README.md +117 -0
  55. package/templates/backend/src/modules/campaign/index.ts +9 -0
  56. package/templates/backend/src/modules/campaign/migrations/.snapshot-boutique-campaign.json +272 -0
  57. package/templates/backend/src/modules/campaign/migrations/Migration20260928141440.ts +16 -0
  58. package/templates/backend/src/modules/campaign/migrations/Migration20260928145243.ts +13 -0
  59. package/templates/backend/src/modules/campaign/models/campaign.ts +28 -0
  60. package/templates/backend/src/modules/campaign/service.ts +6 -0
  61. package/templates/backend/src/modules/campaign/validators.ts +94 -0
  62. package/templates/backend/src/modules/resend/index.ts +6 -0
  63. package/templates/backend/src/modules/resend/service.ts +63 -0
  64. package/templates/backend/src/scripts/README.md +63 -0
  65. package/templates/backend/src/scripts/campaign-export.ts +15 -0
  66. package/templates/backend/src/scripts/campaign-import.ts +38 -0
  67. package/templates/backend/src/scripts/price-report.ts +34 -0
  68. package/templates/backend/src/scripts/seed.ts +418 -0
  69. package/templates/backend/src/scripts/storage.ts +63 -0
  70. package/templates/backend/src/subscribers/README.md +61 -0
  71. package/templates/backend/src/subscribers/account-emails.ts +27 -0
  72. package/templates/backend/src/subscribers/fulfillment-emails.ts +42 -0
  73. package/templates/backend/src/subscribers/order-emails.ts +12 -0
  74. package/templates/backend/src/subscribers/return-refund-emails.ts +50 -0
  75. package/templates/backend/src/workflows/README.md +81 -0
  76. package/templates/backend/src/workflows/steps/upsert-campaign.ts +53 -0
  77. package/templates/backend/src/workflows/upsert-campaign.ts +30 -0
  78. package/templates/backend/tsconfig.json +36 -0
  79. package/templates/storefront/.dockerignore +7 -0
  80. package/templates/storefront/.github/ISSUE_TEMPLATE/bug-report.yml +71 -0
  81. package/templates/storefront/.prettierrc +8 -0
  82. package/templates/storefront/Dockerfile +37 -0
  83. package/templates/storefront/LICENSE +21 -0
  84. package/templates/storefront/README.md +127 -0
  85. package/templates/storefront/locales/en.json +269 -0
  86. package/templates/storefront/locales/fr.json +269 -0
  87. package/templates/storefront/next-env.d.ts +7 -0
  88. package/templates/storefront/next-sitemap.js +19 -0
  89. package/templates/storefront/next.config.js +29 -0
  90. package/templates/storefront/package-lock.json +9031 -0
  91. package/templates/storefront/package.json +49 -0
  92. package/templates/storefront/postcss.config.js +6 -0
  93. package/templates/storefront/public/favicon.ico +0 -0
  94. package/templates/storefront/scripts/sync-design.mjs +30 -0
  95. package/templates/storefront/src/app/(checkout)/checkout/page.tsx +31 -0
  96. package/templates/storefront/src/app/(checkout)/layout.tsx +29 -0
  97. package/templates/storefront/src/app/(checkout)/not-found.tsx +20 -0
  98. package/templates/storefront/src/app/(main)/account/@dashboard/addresses/page.tsx +34 -0
  99. package/templates/storefront/src/app/(main)/account/@dashboard/loading.tsx +9 -0
  100. package/templates/storefront/src/app/(main)/account/@dashboard/orders/details/[id]/page.tsx +33 -0
  101. package/templates/storefront/src/app/(main)/account/@dashboard/orders/page.tsx +37 -0
  102. package/templates/storefront/src/app/(main)/account/@dashboard/page.tsx +22 -0
  103. package/templates/storefront/src/app/(main)/account/@dashboard/profile/page.tsx +53 -0
  104. package/templates/storefront/src/app/(main)/account/@login/page.tsx +12 -0
  105. package/templates/storefront/src/app/(main)/account/layout.tsx +20 -0
  106. package/templates/storefront/src/app/(main)/account/loading.tsx +9 -0
  107. package/templates/storefront/src/app/(main)/cart/loading.tsx +5 -0
  108. package/templates/storefront/src/app/(main)/cart/not-found.tsx +21 -0
  109. package/templates/storefront/src/app/(main)/cart/page.tsx +21 -0
  110. package/templates/storefront/src/app/(main)/categories/[...category]/page.tsx +55 -0
  111. package/templates/storefront/src/app/(main)/collections/[handle]/page.tsx +55 -0
  112. package/templates/storefront/src/app/(main)/layout.tsx +43 -0
  113. package/templates/storefront/src/app/(main)/legal/[page]/page.tsx +42 -0
  114. package/templates/storefront/src/app/(main)/not-found.tsx +21 -0
  115. package/templates/storefront/src/app/(main)/order/[id]/confirmed/loading.tsx +5 -0
  116. package/templates/storefront/src/app/(main)/order/[id]/confirmed/page.tsx +23 -0
  117. package/templates/storefront/src/app/(main)/order/[id]/transfer/[token]/accept/page.tsx +42 -0
  118. package/templates/storefront/src/app/(main)/order/[id]/transfer/[token]/decline/page.tsx +42 -0
  119. package/templates/storefront/src/app/(main)/order/[id]/transfer/[token]/page.tsx +35 -0
  120. package/templates/storefront/src/app/(main)/order/track/page.tsx +32 -0
  121. package/templates/storefront/src/app/(main)/page.tsx +68 -0
  122. package/templates/storefront/src/app/(main)/products/[handle]/page.tsx +86 -0
  123. package/templates/storefront/src/app/(main)/store/page.tsx +28 -0
  124. package/templates/storefront/src/app/api/health/route.ts +13 -0
  125. package/templates/storefront/src/app/layout.tsx +42 -0
  126. package/templates/storefront/src/app/not-found.tsx +21 -0
  127. package/templates/storefront/src/app/opengraph-image.jpg +0 -0
  128. package/templates/storefront/src/app/twitter-image.jpg +0 -0
  129. package/templates/storefront/src/instrumentation-node.ts +18 -0
  130. package/templates/storefront/src/instrumentation.ts +9 -0
  131. package/templates/storefront/src/lib/boutique/campaign.ts +116 -0
  132. package/templates/storefront/src/lib/boutique/config.ts +152 -0
  133. package/templates/storefront/src/lib/boutique/fonts.ts +29 -0
  134. package/templates/storefront/src/lib/boutique/i18n-client.tsx +34 -0
  135. package/templates/storefront/src/lib/boutique/i18n.ts +43 -0
  136. package/templates/storefront/src/lib/boutique/schema.ts +131 -0
  137. package/templates/storefront/src/lib/config.ts +39 -0
  138. package/templates/storefront/src/lib/constants.tsx +75 -0
  139. package/templates/storefront/src/lib/context/modal-context.tsx +34 -0
  140. package/templates/storefront/src/lib/data/cart.ts +434 -0
  141. package/templates/storefront/src/lib/data/categories.ts +49 -0
  142. package/templates/storefront/src/lib/data/collections.ts +59 -0
  143. package/templates/storefront/src/lib/data/cookies.ts +103 -0
  144. package/templates/storefront/src/lib/data/customer.ts +261 -0
  145. package/templates/storefront/src/lib/data/fulfillment.ts +68 -0
  146. package/templates/storefront/src/lib/data/onboarding.ts +9 -0
  147. package/templates/storefront/src/lib/data/order-lookup.ts +34 -0
  148. package/templates/storefront/src/lib/data/orders.ts +112 -0
  149. package/templates/storefront/src/lib/data/payment.ts +35 -0
  150. package/templates/storefront/src/lib/data/products.ts +127 -0
  151. package/templates/storefront/src/lib/data/regions.ts +70 -0
  152. package/templates/storefront/src/lib/data/variants.ts +38 -0
  153. package/templates/storefront/src/lib/hooks/use-in-view.tsx +29 -0
  154. package/templates/storefront/src/lib/hooks/use-toggle-state.tsx +46 -0
  155. package/templates/storefront/src/lib/util/compare-addresses.ts +28 -0
  156. package/templates/storefront/src/lib/util/get-percentage-diff.ts +6 -0
  157. package/templates/storefront/src/lib/util/get-product-price.ts +79 -0
  158. package/templates/storefront/src/lib/util/isEmpty.ts +11 -0
  159. package/templates/storefront/src/lib/util/medusa-error.ts +22 -0
  160. package/templates/storefront/src/lib/util/money.ts +35 -0
  161. package/templates/storefront/src/lib/util/product.ts +5 -0
  162. package/templates/storefront/src/lib/util/repeat.ts +5 -0
  163. package/templates/storefront/src/lib/util/sort-products.ts +50 -0
  164. package/templates/storefront/src/modules/account/components/account-info/index.tsx +140 -0
  165. package/templates/storefront/src/modules/account/components/account-nav/index.tsx +198 -0
  166. package/templates/storefront/src/modules/account/components/address-book/index.tsx +28 -0
  167. package/templates/storefront/src/modules/account/components/address-card/add-address.tsx +169 -0
  168. package/templates/storefront/src/modules/account/components/address-card/edit-address-modal.tsx +241 -0
  169. package/templates/storefront/src/modules/account/components/login/index.tsx +65 -0
  170. package/templates/storefront/src/modules/account/components/order-card/index.tsx +88 -0
  171. package/templates/storefront/src/modules/account/components/order-overview/index.tsx +47 -0
  172. package/templates/storefront/src/modules/account/components/overview/index.tsx +169 -0
  173. package/templates/storefront/src/modules/account/components/profile-billing-address/index.tsx +193 -0
  174. package/templates/storefront/src/modules/account/components/profile-email/index.tsx +75 -0
  175. package/templates/storefront/src/modules/account/components/profile-name/index.tsx +79 -0
  176. package/templates/storefront/src/modules/account/components/profile-password/index.tsx +72 -0
  177. package/templates/storefront/src/modules/account/components/profile-phone/index.tsx +74 -0
  178. package/templates/storefront/src/modules/account/components/register/index.tsx +107 -0
  179. package/templates/storefront/src/modules/account/components/transfer-request-form/index.tsx +83 -0
  180. package/templates/storefront/src/modules/account/templates/account-layout.tsx +43 -0
  181. package/templates/storefront/src/modules/account/templates/login-template.tsx +27 -0
  182. package/templates/storefront/src/modules/cart/components/cart-item-select/index.tsx +75 -0
  183. package/templates/storefront/src/modules/cart/components/empty-cart-message/index.tsx +25 -0
  184. package/templates/storefront/src/modules/cart/components/item/index.tsx +144 -0
  185. package/templates/storefront/src/modules/cart/components/sign-in-prompt/index.tsx +27 -0
  186. package/templates/storefront/src/modules/cart/templates/index.tsx +51 -0
  187. package/templates/storefront/src/modules/cart/templates/items.tsx +58 -0
  188. package/templates/storefront/src/modules/cart/templates/preview.tsx +51 -0
  189. package/templates/storefront/src/modules/cart/templates/summary.tsx +50 -0
  190. package/templates/storefront/src/modules/categories/templates/index.tsx +94 -0
  191. package/templates/storefront/src/modules/checkout/components/address-select/index.tsx +117 -0
  192. package/templates/storefront/src/modules/checkout/components/addresses/index.tsx +186 -0
  193. package/templates/storefront/src/modules/checkout/components/billing_address/index.tsx +114 -0
  194. package/templates/storefront/src/modules/checkout/components/country-select/index.tsx +50 -0
  195. package/templates/storefront/src/modules/checkout/components/discount-code/index.tsx +181 -0
  196. package/templates/storefront/src/modules/checkout/components/error-message/index.tsx +13 -0
  197. package/templates/storefront/src/modules/checkout/components/payment/index.tsx +261 -0
  198. package/templates/storefront/src/modules/checkout/components/payment-button/index.tsx +195 -0
  199. package/templates/storefront/src/modules/checkout/components/payment-container/index.tsx +130 -0
  200. package/templates/storefront/src/modules/checkout/components/payment-test/index.tsx +12 -0
  201. package/templates/storefront/src/modules/checkout/components/payment-wrapper/index.tsx +42 -0
  202. package/templates/storefront/src/modules/checkout/components/payment-wrapper/stripe-wrapper.tsx +54 -0
  203. package/templates/storefront/src/modules/checkout/components/review/index.tsx +54 -0
  204. package/templates/storefront/src/modules/checkout/components/shipping/index.tsx +417 -0
  205. package/templates/storefront/src/modules/checkout/components/shipping-address/index.tsx +219 -0
  206. package/templates/storefront/src/modules/checkout/components/submit-button/index.tsx +32 -0
  207. package/templates/storefront/src/modules/checkout/templates/checkout-form/index.tsx +38 -0
  208. package/templates/storefront/src/modules/checkout/templates/checkout-summary/index.tsx +31 -0
  209. package/templates/storefront/src/modules/collections/templates/index.tsx +44 -0
  210. package/templates/storefront/src/modules/common/components/cart-totals/index.tsx +84 -0
  211. package/templates/storefront/src/modules/common/components/checkbox/index.tsx +44 -0
  212. package/templates/storefront/src/modules/common/components/delete-button/index.tsx +42 -0
  213. package/templates/storefront/src/modules/common/components/divider/index.tsx +9 -0
  214. package/templates/storefront/src/modules/common/components/filter-radio-group/index.tsx +61 -0
  215. package/templates/storefront/src/modules/common/components/input/index.tsx +79 -0
  216. package/templates/storefront/src/modules/common/components/interactive-link/index.tsx +33 -0
  217. package/templates/storefront/src/modules/common/components/line-item-options/index.tsx +26 -0
  218. package/templates/storefront/src/modules/common/components/line-item-price/index.tsx +63 -0
  219. package/templates/storefront/src/modules/common/components/line-item-unit-price/index.tsx +62 -0
  220. package/templates/storefront/src/modules/common/components/localized-client-link/index.tsx +29 -0
  221. package/templates/storefront/src/modules/common/components/modal/index.tsx +118 -0
  222. package/templates/storefront/src/modules/common/components/native-select/index.tsx +76 -0
  223. package/templates/storefront/src/modules/common/components/radio/index.tsx +27 -0
  224. package/templates/storefront/src/modules/common/icons/back.tsx +37 -0
  225. package/templates/storefront/src/modules/common/icons/bancontact.tsx +26 -0
  226. package/templates/storefront/src/modules/common/icons/chevron-down.tsx +30 -0
  227. package/templates/storefront/src/modules/common/icons/eye-off.tsx +37 -0
  228. package/templates/storefront/src/modules/common/icons/eye.tsx +37 -0
  229. package/templates/storefront/src/modules/common/icons/fast-delivery.tsx +65 -0
  230. package/templates/storefront/src/modules/common/icons/ideal.tsx +26 -0
  231. package/templates/storefront/src/modules/common/icons/map-pin.tsx +37 -0
  232. package/templates/storefront/src/modules/common/icons/package.tsx +44 -0
  233. package/templates/storefront/src/modules/common/icons/paypal.tsx +30 -0
  234. package/templates/storefront/src/modules/common/icons/placeholder-image.tsx +44 -0
  235. package/templates/storefront/src/modules/common/icons/refresh.tsx +51 -0
  236. package/templates/storefront/src/modules/common/icons/spinner.tsx +37 -0
  237. package/templates/storefront/src/modules/common/icons/trash.tsx +51 -0
  238. package/templates/storefront/src/modules/common/icons/user.tsx +37 -0
  239. package/templates/storefront/src/modules/common/icons/x.tsx +37 -0
  240. package/templates/storefront/src/modules/layout/components/cart-mismatch-banner/index.tsx +59 -0
  241. package/templates/storefront/src/modules/order/components/help/index.tsx +26 -0
  242. package/templates/storefront/src/modules/order/components/item/index.tsx +57 -0
  243. package/templates/storefront/src/modules/order/components/items/index.tsx +44 -0
  244. package/templates/storefront/src/modules/order/components/onboarding-cta/index.tsx +28 -0
  245. package/templates/storefront/src/modules/order/components/order-details/index.tsx +64 -0
  246. package/templates/storefront/src/modules/order/components/order-summary/index.tsx +61 -0
  247. package/templates/storefront/src/modules/order/components/payment-details/index.tsx +64 -0
  248. package/templates/storefront/src/modules/order/components/shipping-details/index.tsx +74 -0
  249. package/templates/storefront/src/modules/order/components/transfer-actions/index.tsx +83 -0
  250. package/templates/storefront/src/modules/order/components/transfer-image/index.tsx +275 -0
  251. package/templates/storefront/src/modules/order/templates/order-completed-template.tsx +53 -0
  252. package/templates/storefront/src/modules/order/templates/order-details-template.tsx +46 -0
  253. package/templates/storefront/src/modules/products/components/thumbnail/index.tsx +70 -0
  254. package/templates/storefront/src/modules/products/templates/index.tsx +118 -0
  255. package/templates/storefront/src/modules/shipping/components/free-shipping-price-nudge/index.tsx +285 -0
  256. package/templates/storefront/src/modules/skeletons/components/skeleton-button/index.tsx +5 -0
  257. package/templates/storefront/src/modules/skeletons/components/skeleton-card-details/index.tsx +10 -0
  258. package/templates/storefront/src/modules/skeletons/components/skeleton-cart-item/index.tsx +35 -0
  259. package/templates/storefront/src/modules/skeletons/components/skeleton-cart-totals/index.tsx +30 -0
  260. package/templates/storefront/src/modules/skeletons/components/skeleton-code-form/index.tsx +13 -0
  261. package/templates/storefront/src/modules/skeletons/components/skeleton-line-item/index.tsx +35 -0
  262. package/templates/storefront/src/modules/skeletons/components/skeleton-order-confirmed-header/index.tsx +14 -0
  263. package/templates/storefront/src/modules/skeletons/components/skeleton-order-information/index.tsx +36 -0
  264. package/templates/storefront/src/modules/skeletons/components/skeleton-order-items/index.tsx +43 -0
  265. package/templates/storefront/src/modules/skeletons/components/skeleton-order-summary/index.tsx +15 -0
  266. package/templates/storefront/src/modules/skeletons/components/skeleton-product-preview/index.tsx +15 -0
  267. package/templates/storefront/src/modules/skeletons/templates/skeleton-cart-page/index.tsx +65 -0
  268. package/templates/storefront/src/modules/skeletons/templates/skeleton-order-confirmed/index.tsx +21 -0
  269. package/templates/storefront/src/modules/skeletons/templates/skeleton-product-grid/index.tsx +23 -0
  270. package/templates/storefront/src/modules/store/components/pagination/index.tsx +114 -0
  271. package/templates/storefront/src/modules/store/components/refinement-list/index.tsx +41 -0
  272. package/templates/storefront/src/modules/store/components/refinement-list/sort-products/index.tsx +48 -0
  273. package/templates/storefront/src/modules/store/templates/index.tsx +42 -0
  274. package/templates/storefront/src/modules/store/templates/paginated-products.tsx +80 -0
  275. package/templates/storefront/src/modules/ub/button.tsx +41 -0
  276. package/templates/storefront/src/modules/ub/campaign-blocks.tsx +197 -0
  277. package/templates/storefront/src/modules/ub/campaign-ended.tsx +28 -0
  278. package/templates/storefront/src/modules/ub/category-tiles.tsx +41 -0
  279. package/templates/storefront/src/modules/ub/countdown.tsx +46 -0
  280. package/templates/storefront/src/modules/ub/footer.tsx +56 -0
  281. package/templates/storefront/src/modules/ub/icons.tsx +42 -0
  282. package/templates/storefront/src/modules/ub/nav.tsx +90 -0
  283. package/templates/storefront/src/modules/ub/pdp/buy-box.tsx +140 -0
  284. package/templates/storefront/src/modules/ub/pdp/gallery.tsx +40 -0
  285. package/templates/storefront/src/modules/ub/product-card.tsx +66 -0
  286. package/templates/storefront/src/modules/ub/top-bar.tsx +20 -0
  287. package/templates/storefront/src/modules/ub/track-form.tsx +92 -0
  288. package/templates/storefront/src/proxy.ts +89 -0
  289. package/templates/storefront/src/styles/globals.css +98 -0
  290. package/templates/storefront/src/styles/ub/bundle.css +372 -0
  291. package/templates/storefront/src/styles/ub/fonts.css +17 -0
  292. package/templates/storefront/src/styles/ub/medusa-ui.css +90 -0
  293. package/templates/storefront/src/styles/ub/overrides.css +12 -0
  294. package/templates/storefront/src/styles/ub/tokens.css +9 -0
  295. package/templates/storefront/src/types/global.ts +24 -0
  296. package/templates/storefront/src/types/icon.ts +4 -0
  297. package/templates/storefront/tailwind.config.js +164 -0
  298. package/templates/storefront/themes/black-friday/campaign.en.json +31 -0
  299. package/templates/storefront/themes/black-friday/campaign.fr.json +31 -0
  300. package/templates/storefront/themes/black-friday/theme.json +9 -0
  301. package/templates/storefront/themes/cyber-monday/campaign.en.json +31 -0
  302. package/templates/storefront/themes/cyber-monday/campaign.fr.json +31 -0
  303. package/templates/storefront/themes/cyber-monday/theme.json +9 -0
  304. package/templates/storefront/themes/halloween/campaign.en.json +31 -0
  305. package/templates/storefront/themes/halloween/campaign.fr.json +31 -0
  306. package/templates/storefront/themes/halloween/theme.json +9 -0
  307. package/templates/storefront/themes/noel/campaign.en.json +31 -0
  308. package/templates/storefront/themes/noel/campaign.fr.json +31 -0
  309. package/templates/storefront/themes/noel/theme.json +9 -0
  310. package/templates/storefront/themes/nouvel-an/campaign.en.json +31 -0
  311. package/templates/storefront/themes/nouvel-an/campaign.fr.json +31 -0
  312. package/templates/storefront/themes/nouvel-an/theme.json +9 -0
  313. package/templates/storefront/themes/thanksgiving/campaign.en.json +31 -0
  314. package/templates/storefront/themes/thanksgiving/campaign.fr.json +31 -0
  315. package/templates/storefront/themes/thanksgiving/theme.json +9 -0
  316. package/templates/storefront/tsconfig.json +53 -0
@@ -0,0 +1,434 @@
1
+ "use server"
2
+
3
+ import { sdk } from "@lib/config"
4
+ import medusaError from "@lib/util/medusa-error"
5
+ import { HttpTypes } from "@medusajs/types"
6
+ import { updateTag } from "next/cache"
7
+ import { redirect } from "next/navigation"
8
+ import {
9
+ getAuthHeaders,
10
+ getCacheOptions,
11
+ getCacheTag,
12
+ getCartId,
13
+ removeCartId,
14
+ setCartId,
15
+ } from "./cookies"
16
+ import { getRegion } from "./regions"
17
+
18
+ /**
19
+ * Retrieves a cart by its ID. If no ID is provided, it will use the cart ID from the cookies.
20
+ * @param cartId - optional - The ID of the cart to retrieve.
21
+ * @returns The cart object if found, or null if not found.
22
+ */
23
+ export async function retrieveCart(cartId?: string, fields?: string) {
24
+ const id = cartId || (await getCartId())
25
+ fields ??=
26
+ "*items, *region, *items.product, *items.variant, *items.thumbnail, *items.metadata, +items.total, *promotions, +shipping_methods.name"
27
+
28
+ if (!id) {
29
+ return null
30
+ }
31
+
32
+ const headers = {
33
+ ...(await getAuthHeaders()),
34
+ }
35
+
36
+ const next = {
37
+ ...(await getCacheOptions("carts")),
38
+ }
39
+
40
+ return await sdk.client
41
+ .fetch<HttpTypes.StoreCartResponse>(`/store/carts/${id}`, {
42
+ method: "GET",
43
+ query: {
44
+ fields,
45
+ },
46
+ headers,
47
+ next,
48
+ cache: "force-cache",
49
+ })
50
+ .then(({ cart }: { cart: HttpTypes.StoreCart }) => cart)
51
+ .catch(() => null)
52
+ }
53
+
54
+ export async function getOrSetCart() {
55
+ const region = await getRegion()
56
+
57
+ let cart = await retrieveCart(undefined, "id,region_id")
58
+
59
+ const headers = {
60
+ ...(await getAuthHeaders()),
61
+ }
62
+
63
+ if (!cart) {
64
+ const cartResp = await sdk.store.cart.create(
65
+ { region_id: region.id },
66
+ {},
67
+ headers
68
+ )
69
+ cart = cartResp.cart
70
+
71
+ await setCartId(cart.id)
72
+
73
+ const cartCacheTag = await getCacheTag("carts")
74
+ updateTag(cartCacheTag)
75
+ }
76
+
77
+ if (cart && cart?.region_id !== region.id) {
78
+ await sdk.store.cart.update(cart.id, { region_id: region.id }, {}, headers)
79
+ const cartCacheTag = await getCacheTag("carts")
80
+ updateTag(cartCacheTag)
81
+ }
82
+
83
+ return cart
84
+ }
85
+
86
+ export async function updateCart(data: HttpTypes.StoreUpdateCart) {
87
+ const cartId = await getCartId()
88
+
89
+ if (!cartId) {
90
+ throw new Error("No existing cart found, please create one before updating")
91
+ }
92
+
93
+ const headers = {
94
+ ...(await getAuthHeaders()),
95
+ }
96
+
97
+ return sdk.store.cart
98
+ .update(cartId, data, {}, headers)
99
+ .then(async ({ cart }: { cart: HttpTypes.StoreCart }) => {
100
+ const cartCacheTag = await getCacheTag("carts")
101
+ updateTag(cartCacheTag)
102
+
103
+ const fulfillmentCacheTag = await getCacheTag("fulfillment")
104
+ updateTag(fulfillmentCacheTag)
105
+
106
+ return cart
107
+ })
108
+ .catch(medusaError)
109
+ }
110
+
111
+ export async function addToCart({
112
+ variantId,
113
+ quantity,
114
+ }: {
115
+ variantId: string
116
+ quantity: number
117
+ }) {
118
+ if (!variantId) {
119
+ throw new Error("Missing variant ID when adding to cart")
120
+ }
121
+
122
+ const cart = await getOrSetCart()
123
+
124
+ if (!cart) {
125
+ throw new Error("Error retrieving or creating cart")
126
+ }
127
+
128
+ const headers = {
129
+ ...(await getAuthHeaders()),
130
+ }
131
+
132
+ await sdk.store.cart
133
+ .createLineItem(
134
+ cart.id,
135
+ {
136
+ variant_id: variantId,
137
+ quantity,
138
+ },
139
+ {},
140
+ headers
141
+ )
142
+ .then(async () => {
143
+ const cartCacheTag = await getCacheTag("carts")
144
+ updateTag(cartCacheTag)
145
+
146
+ const fulfillmentCacheTag = await getCacheTag("fulfillment")
147
+ updateTag(fulfillmentCacheTag)
148
+ })
149
+ .catch(medusaError)
150
+ }
151
+
152
+ export async function updateLineItem({
153
+ lineId,
154
+ quantity,
155
+ }: {
156
+ lineId: string
157
+ quantity: number
158
+ }) {
159
+ if (!lineId) {
160
+ throw new Error("Missing lineItem ID when updating line item")
161
+ }
162
+
163
+ const cartId = await getCartId()
164
+
165
+ if (!cartId) {
166
+ throw new Error("Missing cart ID when updating line item")
167
+ }
168
+
169
+ const headers = {
170
+ ...(await getAuthHeaders()),
171
+ }
172
+
173
+ await sdk.store.cart
174
+ .updateLineItem(cartId, lineId, { quantity }, {}, headers)
175
+ .then(async () => {
176
+ const cartCacheTag = await getCacheTag("carts")
177
+ updateTag(cartCacheTag)
178
+
179
+ const fulfillmentCacheTag = await getCacheTag("fulfillment")
180
+ updateTag(fulfillmentCacheTag)
181
+ })
182
+ .catch(medusaError)
183
+ }
184
+
185
+ export async function deleteLineItem(lineId: string) {
186
+ if (!lineId) {
187
+ throw new Error("Missing lineItem ID when deleting line item")
188
+ }
189
+
190
+ const cartId = await getCartId()
191
+
192
+ if (!cartId) {
193
+ throw new Error("Missing cart ID when deleting line item")
194
+ }
195
+
196
+ const headers = {
197
+ ...(await getAuthHeaders()),
198
+ }
199
+
200
+ await sdk.store.cart
201
+ .deleteLineItem(cartId, lineId, {}, headers)
202
+ .then(async () => {
203
+ const cartCacheTag = await getCacheTag("carts")
204
+ updateTag(cartCacheTag)
205
+
206
+ const fulfillmentCacheTag = await getCacheTag("fulfillment")
207
+ updateTag(fulfillmentCacheTag)
208
+ })
209
+ .catch(medusaError)
210
+ }
211
+
212
+ export async function setShippingMethod({
213
+ cartId,
214
+ shippingMethodId,
215
+ }: {
216
+ cartId: string
217
+ shippingMethodId: string
218
+ }) {
219
+ const headers = {
220
+ ...(await getAuthHeaders()),
221
+ }
222
+
223
+ return sdk.store.cart
224
+ .addShippingMethod(cartId, { option_id: shippingMethodId }, {}, headers)
225
+ .then(async () => {
226
+ const cartCacheTag = await getCacheTag("carts")
227
+ updateTag(cartCacheTag)
228
+ })
229
+ .catch(medusaError)
230
+ }
231
+
232
+ export async function initiatePaymentSession(
233
+ cart: HttpTypes.StoreCart,
234
+ data: HttpTypes.StoreInitializePaymentSession
235
+ ) {
236
+ const headers = {
237
+ ...(await getAuthHeaders()),
238
+ }
239
+
240
+ return sdk.store.payment
241
+ .initiatePaymentSession(cart, data, {}, headers)
242
+ .then(async (resp) => {
243
+ const cartCacheTag = await getCacheTag("carts")
244
+ updateTag(cartCacheTag)
245
+ return resp
246
+ })
247
+ .catch(medusaError)
248
+ }
249
+
250
+ export async function applyPromotions(codes: string[]) {
251
+ const cartId = await getCartId()
252
+
253
+ if (!cartId) {
254
+ throw new Error("No existing cart found")
255
+ }
256
+
257
+ const headers = {
258
+ ...(await getAuthHeaders()),
259
+ }
260
+
261
+ return sdk.store.cart
262
+ .update(cartId, { promo_codes: codes }, {}, headers)
263
+ .then(async () => {
264
+ const cartCacheTag = await getCacheTag("carts")
265
+ updateTag(cartCacheTag)
266
+
267
+ const fulfillmentCacheTag = await getCacheTag("fulfillment")
268
+ updateTag(fulfillmentCacheTag)
269
+ })
270
+ .catch(medusaError)
271
+ }
272
+
273
+ export async function applyGiftCard(code: string) {
274
+ // const cartId = getCartId()
275
+ // if (!cartId) return "No cartId cookie found"
276
+ // try {
277
+ // await updateCart(cartId, { gift_cards: [{ code }] }).then(() => {
278
+ // revalidateTag("cart")
279
+ // })
280
+ // } catch (error: any) {
281
+ // throw error
282
+ // }
283
+ }
284
+
285
+ export async function removeDiscount(code: string) {
286
+ // const cartId = getCartId()
287
+ // if (!cartId) return "No cartId cookie found"
288
+ // try {
289
+ // await deleteDiscount(cartId, code)
290
+ // revalidateTag("cart")
291
+ // } catch (error: any) {
292
+ // throw error
293
+ // }
294
+ }
295
+
296
+ export async function removeGiftCard(
297
+ codeToRemove: string,
298
+ giftCards: any[]
299
+ // giftCards: GiftCard[]
300
+ ) {
301
+ // const cartId = getCartId()
302
+ // if (!cartId) return "No cartId cookie found"
303
+ // try {
304
+ // await updateCart(cartId, {
305
+ // gift_cards: [...giftCards]
306
+ // .filter((gc) => gc.code !== codeToRemove)
307
+ // .map((gc) => ({ code: gc.code })),
308
+ // }).then(() => {
309
+ // revalidateTag("cart")
310
+ // })
311
+ // } catch (error: any) {
312
+ // throw error
313
+ // }
314
+ }
315
+
316
+ export async function submitPromotionForm(
317
+ currentState: unknown,
318
+ formData: FormData
319
+ ) {
320
+ const code = formData.get("code") as string
321
+ try {
322
+ await applyPromotions([code])
323
+ } catch (e: any) {
324
+ return e.message
325
+ }
326
+ }
327
+
328
+ // TODO: Pass a POJO instead of a form entity here
329
+ export async function setAddresses(currentState: unknown, formData: FormData) {
330
+ try {
331
+ if (!formData) {
332
+ throw new Error("No form data found when setting addresses")
333
+ }
334
+ const cartId = getCartId()
335
+ if (!cartId) {
336
+ throw new Error("No existing cart found when setting addresses")
337
+ }
338
+
339
+ const data = {
340
+ shipping_address: {
341
+ first_name: formData.get("shipping_address.first_name"),
342
+ last_name: formData.get("shipping_address.last_name"),
343
+ address_1: formData.get("shipping_address.address_1"),
344
+ address_2: "",
345
+ company: formData.get("shipping_address.company"),
346
+ postal_code: formData.get("shipping_address.postal_code"),
347
+ city: formData.get("shipping_address.city"),
348
+ country_code: formData.get("shipping_address.country_code"),
349
+ province: formData.get("shipping_address.province"),
350
+ phone: formData.get("shipping_address.phone"),
351
+ },
352
+ email: formData.get("email"),
353
+ } as any
354
+
355
+ const sameAsBilling = formData.get("same_as_billing")
356
+ if (sameAsBilling === "on") data.billing_address = data.shipping_address
357
+
358
+ if (sameAsBilling !== "on")
359
+ data.billing_address = {
360
+ first_name: formData.get("billing_address.first_name"),
361
+ last_name: formData.get("billing_address.last_name"),
362
+ address_1: formData.get("billing_address.address_1"),
363
+ address_2: "",
364
+ company: formData.get("billing_address.company"),
365
+ postal_code: formData.get("billing_address.postal_code"),
366
+ city: formData.get("billing_address.city"),
367
+ country_code: formData.get("billing_address.country_code"),
368
+ province: formData.get("billing_address.province"),
369
+ phone: formData.get("billing_address.phone"),
370
+ }
371
+ await updateCart(data)
372
+ } catch (e: any) {
373
+ return e.message
374
+ }
375
+
376
+ redirect(
377
+ `/checkout?step=delivery`
378
+ )
379
+ }
380
+
381
+ /**
382
+ * Places an order for a cart. If no cart ID is provided, it will use the cart ID from the cookies.
383
+ * @param cartId - optional - The ID of the cart to place an order for.
384
+ * @returns The cart object if the order was successful, or null if not.
385
+ */
386
+ export async function placeOrder(cartId?: string) {
387
+ const id = cartId || (await getCartId())
388
+
389
+ if (!id) {
390
+ throw new Error("No existing cart found when placing an order")
391
+ }
392
+
393
+ const headers = {
394
+ ...(await getAuthHeaders()),
395
+ }
396
+
397
+ const cartRes = await sdk.store.cart
398
+ .complete(id, {}, headers)
399
+ .then(async (cartRes) => {
400
+ const cartCacheTag = await getCacheTag("carts")
401
+ updateTag(cartCacheTag)
402
+ return cartRes
403
+ })
404
+ .catch(medusaError)
405
+
406
+ if (cartRes?.type === "order") {
407
+ const orderCacheTag = await getCacheTag("orders")
408
+ updateTag(orderCacheTag)
409
+
410
+ removeCartId()
411
+ redirect(`/order/${cartRes?.order.id}/confirmed`)
412
+ }
413
+
414
+ return cartRes.cart
415
+ }
416
+
417
+ export async function listCartOptions() {
418
+ const cartId = await getCartId()
419
+ const headers = {
420
+ ...(await getAuthHeaders()),
421
+ }
422
+ const next = {
423
+ ...(await getCacheOptions("shippingOptions")),
424
+ }
425
+
426
+ return await sdk.client.fetch<{
427
+ shipping_options: HttpTypes.StoreCartShippingOption[]
428
+ }>("/store/shipping-options", {
429
+ query: { cart_id: cartId },
430
+ next,
431
+ headers,
432
+ cache: "force-cache",
433
+ })
434
+ }
@@ -0,0 +1,49 @@
1
+ import { sdk } from "@lib/config"
2
+ import { HttpTypes } from "@medusajs/types"
3
+ import { getCacheOptions } from "./cookies"
4
+
5
+ export const listCategories = async (query?: Record<string, any>) => {
6
+ const next = {
7
+ ...(await getCacheOptions("categories")),
8
+ }
9
+
10
+ const limit = query?.limit || 100
11
+
12
+ return sdk.client
13
+ .fetch<{ product_categories: HttpTypes.StoreProductCategory[] }>(
14
+ "/store/product-categories",
15
+ {
16
+ query: {
17
+ fields:
18
+ "+metadata, *category_children, *products, *parent_category, *parent_category.parent_category",
19
+ limit,
20
+ ...query,
21
+ },
22
+ next,
23
+ cache: "force-cache",
24
+ }
25
+ )
26
+ .then(({ product_categories }) => product_categories)
27
+ }
28
+
29
+ export const getCategoryByHandle = async (categoryHandle: string[]) => {
30
+ const handle = `${categoryHandle.join("/")}`
31
+
32
+ const next = {
33
+ ...(await getCacheOptions("categories")),
34
+ }
35
+
36
+ return sdk.client
37
+ .fetch<HttpTypes.StoreProductCategoryListResponse>(
38
+ `/store/product-categories`,
39
+ {
40
+ query: {
41
+ fields: "*category_children, *products",
42
+ handle,
43
+ },
44
+ next,
45
+ cache: "force-cache",
46
+ }
47
+ )
48
+ .then(({ product_categories }) => product_categories[0])
49
+ }
@@ -0,0 +1,59 @@
1
+ "use server"
2
+
3
+ import { sdk } from "@lib/config"
4
+ import { HttpTypes } from "@medusajs/types"
5
+ import { getCacheOptions } from "./cookies"
6
+
7
+ export const retrieveCollection = async (id: string) => {
8
+ const next = {
9
+ ...(await getCacheOptions("collections")),
10
+ }
11
+
12
+ return sdk.client
13
+ .fetch<{ collection: HttpTypes.StoreCollection }>(
14
+ `/store/collections/${id}`,
15
+ {
16
+ next,
17
+ cache: "force-cache",
18
+ }
19
+ )
20
+ .then(({ collection }) => collection)
21
+ }
22
+
23
+ export const listCollections = async (
24
+ queryParams: Record<string, string> = {}
25
+ ): Promise<{ collections: HttpTypes.StoreCollection[]; count: number }> => {
26
+ const next = {
27
+ ...(await getCacheOptions("collections")),
28
+ }
29
+
30
+ queryParams.limit = queryParams.limit || "100"
31
+ queryParams.offset = queryParams.offset || "0"
32
+
33
+ return sdk.client
34
+ .fetch<{ collections: HttpTypes.StoreCollection[]; count: number }>(
35
+ "/store/collections",
36
+ {
37
+ query: queryParams,
38
+ next,
39
+ cache: "force-cache",
40
+ }
41
+ )
42
+ .then(({ collections }) => ({ collections, count: collections.length }))
43
+ }
44
+
45
+ export const getCollectionByHandle = async (
46
+ handle: string
47
+ ): Promise<HttpTypes.StoreCollection> => {
48
+ const next = {
49
+ ...(await getCacheOptions("collections")),
50
+ }
51
+
52
+ return sdk.client
53
+ .fetch<HttpTypes.StoreCollectionListResponse>(`/store/collections`, {
54
+ query: { handle, fields: "*products" },
55
+ next,
56
+ cache: "force-cache",
57
+ })
58
+ .then(({ collections }) => collections[0])
59
+ }
@@ -0,0 +1,103 @@
1
+ import "server-only"
2
+ import { getBoutique } from "@lib/boutique/config"
3
+ import { cookies as nextCookies } from "next/headers"
4
+
5
+ /**
6
+ * Les cookies ne dépendent pas du port : sur localhost (ou un même domaine),
7
+ * toutes les boutiques du projet les partagent. Chaque nom est donc suffixé
8
+ * par le slug, pour qu'un panier ou une session d'une boutique n'apparaisse
9
+ * jamais dans une autre.
10
+ */
11
+ export const cookieName = (base: "jwt" | "cart_id" | "cache_id" | "onboarding") =>
12
+ `_medusa_${base}_${getBoutique().slug}`
13
+
14
+ export const getAuthHeaders = async (): Promise<
15
+ { authorization: string } | {}
16
+ > => {
17
+ try {
18
+ const cookies = await nextCookies()
19
+ const token = cookies.get(cookieName("jwt"))?.value
20
+
21
+ if (!token) {
22
+ return {}
23
+ }
24
+
25
+ return { authorization: `Bearer ${token}` }
26
+ } catch {
27
+ return {}
28
+ }
29
+ }
30
+
31
+ export const getCacheTag = async (tag: string): Promise<string> => {
32
+ try {
33
+ const cookies = await nextCookies()
34
+ const cacheId = cookies.get(cookieName("cache_id"))?.value
35
+
36
+ if (!cacheId) {
37
+ return ""
38
+ }
39
+
40
+ return `${tag}-${cacheId}`
41
+ } catch (error) {
42
+ return ""
43
+ }
44
+ }
45
+
46
+ /**
47
+ * Cache des requêtes Medusa. Les tags (par visiteur) permettent aux server actions
48
+ * d'expirer panier / compte immédiatement ; `revalidate` fait apparaître en 60 s
49
+ * les changements faits dans l'admin (produits, prix, catégories) pour tout le monde.
50
+ * Sans lui, le starter gardait le catalogue en cache jusqu'au redémarrage.
51
+ */
52
+ export const getCacheOptions = async (
53
+ tag: string
54
+ ): Promise<{ tags?: string[]; revalidate: number }> => {
55
+ if (typeof window !== "undefined") {
56
+ return { revalidate: 60 }
57
+ }
58
+
59
+ const cacheTag = await getCacheTag(tag)
60
+
61
+ return cacheTag ? { tags: [cacheTag], revalidate: 60 } : { revalidate: 60 }
62
+ }
63
+
64
+ const secureCookie = {
65
+ httpOnly: true,
66
+ sameSite: "strict" as const,
67
+ secure: process.env.NODE_ENV === "production",
68
+ }
69
+
70
+ export const setAuthToken = async (token: string) => {
71
+ const cookies = await nextCookies()
72
+ cookies.set(cookieName("jwt"), token, {
73
+ ...secureCookie,
74
+ maxAge: 60 * 60 * 24 * 7,
75
+ })
76
+ }
77
+
78
+ export const removeAuthToken = async () => {
79
+ const cookies = await nextCookies()
80
+ cookies.set(cookieName("jwt"), "", {
81
+ maxAge: -1,
82
+ })
83
+ }
84
+
85
+ export const getCartId = async () => {
86
+ const cookies = await nextCookies()
87
+ return cookies.get(cookieName("cart_id"))?.value
88
+ }
89
+
90
+ export const setCartId = async (cartId: string) => {
91
+ const cookies = await nextCookies()
92
+ cookies.set(cookieName("cart_id"), cartId, {
93
+ ...secureCookie,
94
+ maxAge: 60 * 60 * 24 * 7,
95
+ })
96
+ }
97
+
98
+ export const removeCartId = async () => {
99
+ const cookies = await nextCookies()
100
+ cookies.set(cookieName("cart_id"), "", {
101
+ maxAge: -1,
102
+ })
103
+ }