@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,32 @@
1
+ "use client"
2
+
3
+ import { Button } from "@medusajs/ui"
4
+ import React from "react"
5
+ import { useFormStatus } from "react-dom"
6
+
7
+ export function SubmitButton({
8
+ children,
9
+ variant = "primary",
10
+ className,
11
+ "data-testid": dataTestId,
12
+ }: {
13
+ children: React.ReactNode
14
+ variant?: "primary" | "secondary" | "transparent" | "danger" | null
15
+ className?: string
16
+ "data-testid"?: string
17
+ }) {
18
+ const { pending } = useFormStatus()
19
+
20
+ return (
21
+ <Button
22
+ size="large"
23
+ className={className}
24
+ type="submit"
25
+ isLoading={pending}
26
+ variant={variant || "primary"}
27
+ data-testid={dataTestId}
28
+ >
29
+ {children}
30
+ </Button>
31
+ )
32
+ }
@@ -0,0 +1,38 @@
1
+ import { listCartShippingMethods } from "@lib/data/fulfillment"
2
+ import { listCartPaymentMethods } from "@lib/data/payment"
3
+ import { HttpTypes } from "@medusajs/types"
4
+ import Addresses from "@modules/checkout/components/addresses"
5
+ import Payment from "@modules/checkout/components/payment"
6
+ import Review from "@modules/checkout/components/review"
7
+ import Shipping from "@modules/checkout/components/shipping"
8
+
9
+ export default async function CheckoutForm({
10
+ cart,
11
+ customer,
12
+ }: {
13
+ cart: HttpTypes.StoreCart | null
14
+ customer: HttpTypes.StoreCustomer | null
15
+ }) {
16
+ if (!cart) {
17
+ return null
18
+ }
19
+
20
+ const shippingMethods = await listCartShippingMethods(cart.id)
21
+ const paymentMethods = await listCartPaymentMethods(cart.region?.id ?? "")
22
+
23
+ if (!shippingMethods || !paymentMethods) {
24
+ return null
25
+ }
26
+
27
+ return (
28
+ <div className="w-full grid grid-cols-1 gap-y-8">
29
+ <Addresses cart={cart} customer={customer} />
30
+
31
+ <Shipping cart={cart} availableShippingMethods={shippingMethods} />
32
+
33
+ <Payment cart={cart} availablePaymentMethods={paymentMethods} />
34
+
35
+ <Review cart={cart} />
36
+ </div>
37
+ )
38
+ }
@@ -0,0 +1,31 @@
1
+ import { T } from "@lib/boutique/i18n-client"
2
+ import { Heading } from "@medusajs/ui"
3
+
4
+ import ItemsPreviewTemplate from "@modules/cart/templates/preview"
5
+ import DiscountCode from "@modules/checkout/components/discount-code"
6
+ import CartTotals from "@modules/common/components/cart-totals"
7
+ import Divider from "@modules/common/components/divider"
8
+
9
+ const CheckoutSummary = ({ cart }: { cart: any }) => {
10
+ return (
11
+ <div className="sticky top-0 flex flex-col-reverse small:flex-col gap-y-8 py-8 small:py-0 ">
12
+ <div className="w-full bg-white flex flex-col">
13
+ <Divider className="my-6 small:hidden" />
14
+ <Heading
15
+ level="h2"
16
+ className="flex flex-row text-3xl-regular items-baseline"
17
+ >
18
+ <T k="checkout.inYourCart" />
19
+ </Heading>
20
+ <Divider className="my-6" />
21
+ <CartTotals totals={cart} />
22
+ <ItemsPreviewTemplate cart={cart} />
23
+ <div className="my-6">
24
+ <DiscountCode cart={cart} />
25
+ </div>
26
+ </div>
27
+ </div>
28
+ )
29
+ }
30
+
31
+ export default CheckoutSummary
@@ -0,0 +1,44 @@
1
+ import { Suspense } from "react"
2
+
3
+ import SkeletonProductGrid from "@modules/skeletons/templates/skeleton-product-grid"
4
+ import RefinementList from "@modules/store/components/refinement-list"
5
+ import { SortOptions } from "@modules/store/components/refinement-list/sort-products"
6
+ import PaginatedProducts from "@modules/store/templates/paginated-products"
7
+ import { HttpTypes } from "@medusajs/types"
8
+
9
+ export default function CollectionTemplate({
10
+ sortBy,
11
+ collection,
12
+ page,
13
+ }: {
14
+ sortBy?: SortOptions
15
+ collection: HttpTypes.StoreCollection
16
+ page?: string
17
+ }) {
18
+ const pageNumber = page ? parseInt(page) : 1
19
+ const sort = sortBy || "created_at"
20
+
21
+ return (
22
+ <div className="flex flex-col small:flex-row small:items-start py-6 content-container">
23
+ <RefinementList sortBy={sort} />
24
+ <div className="w-full">
25
+ <div className="mb-8 text-2xl-semi">
26
+ <h1>{collection.title}</h1>
27
+ </div>
28
+ <Suspense
29
+ fallback={
30
+ <SkeletonProductGrid
31
+ numberOfProducts={collection.products?.length}
32
+ />
33
+ }
34
+ >
35
+ <PaginatedProducts
36
+ sortBy={sort}
37
+ page={pageNumber}
38
+ collectionId={collection.id}
39
+ />
40
+ </Suspense>
41
+ </div>
42
+ </div>
43
+ )
44
+ }
@@ -0,0 +1,84 @@
1
+ "use client"
2
+
3
+
4
+ import { T } from "@lib/boutique/i18n-client"
5
+ import { convertToLocale } from "@lib/util/money"
6
+ import React from "react"
7
+
8
+ type CartTotalsProps = {
9
+ totals: {
10
+ total?: number | null
11
+ subtotal?: number | null
12
+ tax_total?: number | null
13
+ currency_code: string
14
+ item_subtotal?: number | null
15
+ shipping_subtotal?: number | null
16
+ discount_subtotal?: number | null
17
+ }
18
+ }
19
+
20
+ const CartTotals: React.FC<CartTotalsProps> = ({ totals }) => {
21
+ const {
22
+ currency_code,
23
+ total,
24
+ tax_total,
25
+ item_subtotal,
26
+ shipping_subtotal,
27
+ discount_subtotal,
28
+ } = totals
29
+
30
+ return (
31
+ <div>
32
+ <div className="flex flex-col gap-y-2 txt-medium text-ui-fg-subtle ">
33
+ <div className="flex items-center justify-between">
34
+ <span><T k="cart.subtotalExcl" /></span>
35
+ <span data-testid="cart-subtotal" data-value={item_subtotal || 0}>
36
+ {convertToLocale({ amount: item_subtotal ?? 0, currency_code })}
37
+ </span>
38
+ </div>
39
+ <div className="flex items-center justify-between">
40
+ <span><T k="cart.shipping" /></span>
41
+ <span data-testid="cart-shipping" data-value={shipping_subtotal || 0}>
42
+ {convertToLocale({ amount: shipping_subtotal ?? 0, currency_code })}
43
+ </span>
44
+ </div>
45
+ {!!discount_subtotal && (
46
+ <div className="flex items-center justify-between">
47
+ <span><T k="cart.discount" /></span>
48
+ <span
49
+ className="text-ui-fg-interactive"
50
+ data-testid="cart-discount"
51
+ data-value={discount_subtotal || 0}
52
+ >
53
+ -{" "}
54
+ {convertToLocale({
55
+ amount: discount_subtotal ?? 0,
56
+ currency_code,
57
+ })}
58
+ </span>
59
+ </div>
60
+ )}
61
+ <div className="flex justify-between">
62
+ <span className="flex gap-x-1 items-center ">Taxes</span>
63
+ <span data-testid="cart-taxes" data-value={tax_total || 0}>
64
+ {convertToLocale({ amount: tax_total ?? 0, currency_code })}
65
+ </span>
66
+ </div>
67
+ </div>
68
+ <div className="h-px w-full border-b border-gray-200 my-4" />
69
+ <div className="flex items-center justify-between text-ui-fg-base mb-2 txt-medium ">
70
+ <span><T k="cart.total" /></span>
71
+ <span
72
+ className="txt-xlarge-plus"
73
+ data-testid="cart-total"
74
+ data-value={total || 0}
75
+ >
76
+ {convertToLocale({ amount: total ?? 0, currency_code })}
77
+ </span>
78
+ </div>
79
+ <div className="h-px w-full border-b border-gray-200 mt-4" />
80
+ </div>
81
+ )
82
+ }
83
+
84
+ export default CartTotals
@@ -0,0 +1,44 @@
1
+ import { T } from "@lib/boutique/i18n-client"
2
+ import { Checkbox, Label } from "@medusajs/ui"
3
+ import React from "react"
4
+
5
+ type CheckboxProps = {
6
+ checked?: boolean
7
+ onChange?: () => void
8
+ label: string
9
+ name?: string
10
+ 'data-testid'?: string
11
+ }
12
+
13
+ const CheckboxWithLabel: React.FC<CheckboxProps> = ({
14
+ checked = true,
15
+ onChange,
16
+ label,
17
+ name,
18
+ 'data-testid': dataTestId
19
+ }) => {
20
+ return (
21
+ <div className="flex items-center space-x-2 ">
22
+ <Checkbox
23
+ className="text-base-regular flex items-center gap-x-2"
24
+ id="checkbox"
25
+ role="checkbox"
26
+ type="button"
27
+ checked={checked}
28
+ aria-checked={checked}
29
+ onClick={onChange}
30
+ name={name}
31
+ data-testid={dataTestId}
32
+ />
33
+ <Label
34
+ htmlFor="checkbox"
35
+ className="!transform-none !txt-medium"
36
+ size="large"
37
+ >
38
+ <T k={label} />
39
+ </Label>
40
+ </div>
41
+ )
42
+ }
43
+
44
+ export default CheckboxWithLabel
@@ -0,0 +1,42 @@
1
+ import { deleteLineItem } from "@lib/data/cart"
2
+ import { Spinner, Trash } from "@medusajs/icons"
3
+ import { clx } from "@medusajs/ui"
4
+ import { useState } from "react"
5
+
6
+ const DeleteButton = ({
7
+ id,
8
+ children,
9
+ className,
10
+ }: {
11
+ id: string
12
+ children?: React.ReactNode
13
+ className?: string
14
+ }) => {
15
+ const [isDeleting, setIsDeleting] = useState(false)
16
+
17
+ const handleDelete = async (id: string) => {
18
+ setIsDeleting(true)
19
+ await deleteLineItem(id).catch((err) => {
20
+ setIsDeleting(false)
21
+ })
22
+ }
23
+
24
+ return (
25
+ <div
26
+ className={clx(
27
+ "flex items-center justify-between text-small-regular",
28
+ className
29
+ )}
30
+ >
31
+ <button
32
+ className="flex gap-x-1 text-ui-fg-subtle hover:text-ui-fg-base cursor-pointer"
33
+ onClick={() => handleDelete(id)}
34
+ >
35
+ {isDeleting ? <Spinner className="animate-spin" /> : <Trash />}
36
+ <span>{children}</span>
37
+ </button>
38
+ </div>
39
+ )
40
+ }
41
+
42
+ export default DeleteButton
@@ -0,0 +1,9 @@
1
+ import { clx } from "@medusajs/ui"
2
+
3
+ const Divider = ({ className }: { className?: string }) => (
4
+ <div
5
+ className={clx("h-px w-full border-b border-gray-200 mt-1", className)}
6
+ />
7
+ )
8
+
9
+ export default Divider
@@ -0,0 +1,61 @@
1
+ import { EllipseMiniSolid } from "@medusajs/icons"
2
+ import { Label, RadioGroup, Text, clx } from "@medusajs/ui"
3
+ import { T } from "@lib/boutique/i18n-client"
4
+
5
+ type FilterRadioGroupProps = {
6
+ title: string
7
+ items: {
8
+ value: string
9
+ label: string
10
+ }[]
11
+ value: any
12
+ handleChange: (...args: any[]) => void
13
+ "data-testid"?: string
14
+ }
15
+
16
+ const FilterRadioGroup = ({
17
+ title,
18
+ items,
19
+ value,
20
+ handleChange,
21
+ "data-testid": dataTestId,
22
+ }: FilterRadioGroupProps) => {
23
+ return (
24
+ <div className="flex gap-x-3 flex-col gap-y-3">
25
+ <Text className="txt-compact-small-plus text-ui-fg-muted"><T k={title} /></Text>
26
+ <RadioGroup data-testid={dataTestId} onValueChange={handleChange}>
27
+ {items?.map((i) => (
28
+ <div
29
+ key={i.value}
30
+ className={clx("flex gap-x-2 items-center", {
31
+ "ml-[-23px]": i.value === value,
32
+ })}
33
+ >
34
+ {i.value === value && <EllipseMiniSolid />}
35
+ <RadioGroup.Item
36
+ checked={i.value === value}
37
+ className="hidden peer"
38
+ id={i.value}
39
+ value={i.value}
40
+ />
41
+ <Label
42
+ htmlFor={i.value}
43
+ className={clx(
44
+ "!txt-compact-small !transform-none text-ui-fg-subtle hover:cursor-pointer",
45
+ {
46
+ "text-ui-fg-base": i.value === value,
47
+ }
48
+ )}
49
+ data-testid="radio-label"
50
+ data-active={i.value === value}
51
+ >
52
+ <T k={i.label} />
53
+ </Label>
54
+ </div>
55
+ ))}
56
+ </RadioGroup>
57
+ </div>
58
+ )
59
+ }
60
+
61
+ export default FilterRadioGroup
@@ -0,0 +1,79 @@
1
+ import { Label } from "@medusajs/ui"
2
+ import React, { useEffect, useImperativeHandle, useState } from "react"
3
+ import { useT } from "@lib/boutique/i18n-client"
4
+
5
+ import Eye from "@modules/common/icons/eye"
6
+ import EyeOff from "@modules/common/icons/eye-off"
7
+
8
+ type InputProps = Omit<
9
+ Omit<React.InputHTMLAttributes<HTMLInputElement>, "size">,
10
+ "placeholder"
11
+ > & {
12
+ label: string
13
+ errors?: Record<string, unknown>
14
+ touched?: Record<string, unknown>
15
+ name: string
16
+ topLabel?: string
17
+ }
18
+
19
+ const Input = React.forwardRef<HTMLInputElement, InputProps>(
20
+ ({ type, name, label, touched, required, topLabel, title, ...props }, ref) => {
21
+ const t = useT()
22
+ const inputRef = React.useRef<HTMLInputElement>(null)
23
+ const [showPassword, setShowPassword] = useState(false)
24
+ const [inputType, setInputType] = useState(type)
25
+
26
+ useEffect(() => {
27
+ if (type === "password" && showPassword) {
28
+ setInputType("text")
29
+ }
30
+
31
+ if (type === "password" && !showPassword) {
32
+ setInputType("password")
33
+ }
34
+ }, [type, showPassword])
35
+
36
+ useImperativeHandle(ref, () => inputRef.current!)
37
+
38
+ return (
39
+ <div className="flex flex-col w-full">
40
+ {topLabel && (
41
+ <Label className="mb-2 txt-compact-medium-plus">{t(topLabel)}</Label>
42
+ )}
43
+ <div className="flex relative z-0 w-full txt-compact-medium">
44
+ <input
45
+ type={inputType}
46
+ name={name}
47
+ placeholder=" "
48
+ required={required}
49
+ className="pt-4 pb-1 block w-full h-11 px-4 mt-0 bg-ui-bg-field border rounded-md appearance-none focus:outline-none focus:ring-0 focus:shadow-borders-interactive-with-active border-ui-border-base hover:bg-ui-bg-field-hover"
50
+ title={title ? t(title) : undefined}
51
+ {...props}
52
+ ref={inputRef}
53
+ />
54
+ <label
55
+ htmlFor={name}
56
+ onClick={() => inputRef.current?.focus()}
57
+ className="flex items-center justify-center mx-3 px-1 transition-all absolute duration-300 top-3 -z-1 origin-0 text-ui-fg-subtle"
58
+ >
59
+ {t(label)}
60
+ {required && <span className="text-rose-500">*</span>}
61
+ </label>
62
+ {type === "password" && (
63
+ <button
64
+ type="button"
65
+ onClick={() => setShowPassword(!showPassword)}
66
+ className="text-ui-fg-subtle px-4 focus:outline-none transition-all duration-150 outline-none focus:text-ui-fg-base absolute right-0 top-3"
67
+ >
68
+ {showPassword ? <Eye /> : <EyeOff />}
69
+ </button>
70
+ )}
71
+ </div>
72
+ </div>
73
+ )
74
+ }
75
+ )
76
+
77
+ Input.displayName = "Input"
78
+
79
+ export default Input
@@ -0,0 +1,33 @@
1
+ import { ArrowUpRightMini } from "@medusajs/icons"
2
+ import { Text } from "@medusajs/ui"
3
+ import LocalizedClientLink from "../localized-client-link"
4
+
5
+ type InteractiveLinkProps = {
6
+ href: string
7
+ children?: React.ReactNode
8
+ onClick?: () => void
9
+ }
10
+
11
+ const InteractiveLink = ({
12
+ href,
13
+ children,
14
+ onClick,
15
+ ...props
16
+ }: InteractiveLinkProps) => {
17
+ return (
18
+ <LocalizedClientLink
19
+ className="flex gap-x-1 items-center group"
20
+ href={href}
21
+ onClick={onClick}
22
+ {...props}
23
+ >
24
+ <Text className="text-ui-fg-interactive">{children}</Text>
25
+ <ArrowUpRightMini
26
+ className="group-hover:rotate-45 ease-in-out duration-150"
27
+ color="var(--fg-interactive)"
28
+ />
29
+ </LocalizedClientLink>
30
+ )
31
+ }
32
+
33
+ export default InteractiveLink
@@ -0,0 +1,26 @@
1
+ import { HttpTypes } from "@medusajs/types"
2
+ import { Text } from "@medusajs/ui"
3
+
4
+ type LineItemOptionsProps = {
5
+ variant: HttpTypes.StoreProductVariant | undefined
6
+ "data-testid"?: string
7
+ "data-value"?: HttpTypes.StoreProductVariant
8
+ }
9
+
10
+ const LineItemOptions = ({
11
+ variant,
12
+ "data-testid": dataTestid,
13
+ "data-value": dataValue,
14
+ }: LineItemOptionsProps) => {
15
+ return (
16
+ <Text
17
+ data-testid={dataTestid}
18
+ data-value={dataValue}
19
+ className="inline-block txt-medium text-ui-fg-subtle w-full overflow-hidden text-ellipsis"
20
+ >
21
+ Variant: {variant?.title}
22
+ </Text>
23
+ )
24
+ }
25
+
26
+ export default LineItemOptions
@@ -0,0 +1,63 @@
1
+ import { getPercentageDiff } from "@lib/util/get-percentage-diff"
2
+ import { convertToLocale } from "@lib/util/money"
3
+ import { HttpTypes } from "@medusajs/types"
4
+ import { clx } from "@medusajs/ui"
5
+
6
+ type LineItemPriceProps = {
7
+ item: HttpTypes.StoreCartLineItem | HttpTypes.StoreOrderLineItem
8
+ style?: "default" | "tight"
9
+ currencyCode: string
10
+ }
11
+
12
+ const LineItemPrice = ({
13
+ item,
14
+ style = "default",
15
+ currencyCode,
16
+ }: LineItemPriceProps) => {
17
+ const originalPrice = item.original_total ?? 0
18
+ const currentPrice = item.total ?? 0
19
+ const hasReducedPrice = currentPrice < originalPrice
20
+
21
+ return (
22
+ <div className="flex flex-col gap-x-2 text-ui-fg-subtle items-end">
23
+ <div className="text-left">
24
+ {hasReducedPrice && (
25
+ <>
26
+ <p>
27
+ {style === "default" && (
28
+ <span className="text-ui-fg-subtle">Original: </span>
29
+ )}
30
+ <span
31
+ className="line-through text-ui-fg-muted"
32
+ data-testid="product-original-price"
33
+ >
34
+ {convertToLocale({
35
+ amount: originalPrice,
36
+ currency_code: currencyCode,
37
+ })}
38
+ </span>
39
+ </p>
40
+ {style === "default" && (
41
+ <span className="text-ui-fg-interactive">
42
+ -{getPercentageDiff(originalPrice, currentPrice || 0)}%
43
+ </span>
44
+ )}
45
+ </>
46
+ )}
47
+ <span
48
+ className={clx("text-base-regular", {
49
+ "text-ui-fg-interactive": hasReducedPrice,
50
+ })}
51
+ data-testid="product-price"
52
+ >
53
+ {convertToLocale({
54
+ amount: currentPrice,
55
+ currency_code: currencyCode,
56
+ })}
57
+ </span>
58
+ </div>
59
+ </div>
60
+ )
61
+ }
62
+
63
+ export default LineItemPrice
@@ -0,0 +1,62 @@
1
+ import { convertToLocale } from "@lib/util/money"
2
+ import { HttpTypes } from "@medusajs/types"
3
+ import { clx } from "@medusajs/ui"
4
+
5
+ type LineItemUnitPriceProps = {
6
+ item: HttpTypes.StoreCartLineItem | HttpTypes.StoreOrderLineItem
7
+ style?: "default" | "tight"
8
+ currencyCode: string
9
+ }
10
+
11
+ const LineItemUnitPrice = ({
12
+ item,
13
+ style = "default",
14
+ currencyCode,
15
+ }: LineItemUnitPriceProps) => {
16
+ const total = item.total ?? 0
17
+ const original_total = item.original_total ?? 0
18
+ const hasReducedPrice = total < original_total
19
+
20
+ const percentage_diff = Math.round(
21
+ ((original_total - total) / original_total) * 100
22
+ )
23
+
24
+ return (
25
+ <div className="flex flex-col text-ui-fg-muted justify-center h-full">
26
+ {hasReducedPrice && (
27
+ <>
28
+ <p>
29
+ {style === "default" && (
30
+ <span className="text-ui-fg-muted">Original: </span>
31
+ )}
32
+ <span
33
+ className="line-through"
34
+ data-testid="product-unit-original-price"
35
+ >
36
+ {convertToLocale({
37
+ amount: original_total / item.quantity,
38
+ currency_code: currencyCode,
39
+ })}
40
+ </span>
41
+ </p>
42
+ {style === "default" && (
43
+ <span className="text-ui-fg-interactive">-{percentage_diff}%</span>
44
+ )}
45
+ </>
46
+ )}
47
+ <span
48
+ className={clx("text-base-regular", {
49
+ "text-ui-fg-interactive": hasReducedPrice,
50
+ })}
51
+ data-testid="product-unit-price"
52
+ >
53
+ {convertToLocale({
54
+ amount: total / item.quantity,
55
+ currency_code: currencyCode,
56
+ })}
57
+ </span>
58
+ </div>
59
+ )
60
+ }
61
+
62
+ export default LineItemUnitPrice
@@ -0,0 +1,29 @@
1
+ "use client"
2
+
3
+ import Link from "next/link"
4
+ import React from "react"
5
+
6
+ /**
7
+ * Lien interne. Les URL n'ont plus de préfixe pays (/products/<handle>) :
8
+ * la région est fixée par l'instance. Gardé pour ne pas toucher tous les appels du starter.
9
+ */
10
+ const LocalizedClientLink = ({
11
+ children,
12
+ href,
13
+ ...props
14
+ }: {
15
+ children?: React.ReactNode
16
+ href: string
17
+ className?: string
18
+ onClick?: () => void
19
+ passHref?: true
20
+ [x: string]: any
21
+ }) => {
22
+ return (
23
+ <Link href={href} {...props}>
24
+ {children}
25
+ </Link>
26
+ )
27
+ }
28
+
29
+ export default LocalizedClientLink