@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,186 @@
1
+ "use client"
2
+
3
+
4
+ import { T } from "@lib/boutique/i18n-client"
5
+ import { setAddresses } from "@lib/data/cart"
6
+ import compareAddresses from "@lib/util/compare-addresses"
7
+ import { CheckCircleSolid } from "@medusajs/icons"
8
+ import { HttpTypes } from "@medusajs/types"
9
+ import { Heading, Text, useToggleState } from "@medusajs/ui"
10
+ import Divider from "@modules/common/components/divider"
11
+ import Spinner from "@modules/common/icons/spinner"
12
+ import { usePathname, useRouter, useSearchParams } from "next/navigation"
13
+ import { useActionState } from "react"
14
+ import BillingAddress from "../billing_address"
15
+ import ErrorMessage from "../error-message"
16
+ import ShippingAddress from "../shipping-address"
17
+ import { SubmitButton } from "../submit-button"
18
+
19
+ const Addresses = ({
20
+ cart,
21
+ customer,
22
+ }: {
23
+ cart: HttpTypes.StoreCart | null
24
+ customer: HttpTypes.StoreCustomer | null
25
+ }) => {
26
+ const searchParams = useSearchParams()
27
+ const router = useRouter()
28
+ const pathname = usePathname()
29
+
30
+ const isOpen = searchParams.get("step") === "address"
31
+
32
+ const { state: sameAsBilling, toggle: toggleSameAsBilling } = useToggleState(
33
+ cart?.shipping_address && cart?.billing_address
34
+ ? compareAddresses(cart?.shipping_address, cart?.billing_address)
35
+ : true
36
+ )
37
+
38
+ const handleEdit = () => {
39
+ router.push(pathname + "?step=address")
40
+ }
41
+
42
+ const [message, formAction] = useActionState(setAddresses, null)
43
+
44
+ return (
45
+ <div className="bg-white">
46
+ <div className="flex flex-row items-center justify-between mb-6">
47
+ <Heading
48
+ level="h2"
49
+ className="flex flex-row text-3xl-regular gap-x-2 items-baseline"
50
+ >
51
+ <T k="checkout.shippingAddress" />
52
+ {!isOpen && <CheckCircleSolid />}
53
+ </Heading>
54
+ {!isOpen && cart?.shipping_address && (
55
+ <Text>
56
+ <button
57
+ onClick={handleEdit}
58
+ className="text-ui-fg-interactive hover:text-ui-fg-interactive-hover"
59
+ data-testid="edit-address-button"
60
+ >
61
+ <T k="form.edit" />
62
+ </button>
63
+ </Text>
64
+ )}
65
+ </div>
66
+ {isOpen ? (
67
+ <form action={formAction}>
68
+ <div className="pb-8">
69
+ <ShippingAddress
70
+ customer={customer}
71
+ checked={sameAsBilling}
72
+ onChange={toggleSameAsBilling}
73
+ cart={cart}
74
+ />
75
+
76
+ {!sameAsBilling && (
77
+ <div>
78
+ <Heading
79
+ level="h2"
80
+ className="text-3xl-regular gap-x-4 pb-6 pt-8"
81
+ >
82
+ <T k="form.billingAddress" />
83
+ </Heading>
84
+
85
+ <BillingAddress cart={cart} />
86
+ </div>
87
+ )}
88
+ <SubmitButton className="mt-6" data-testid="submit-address-button">
89
+ <T k="checkout.continueDelivery" />
90
+ </SubmitButton>
91
+ <ErrorMessage error={message} data-testid="address-error-message" />
92
+ </div>
93
+ </form>
94
+ ) : (
95
+ <div>
96
+ <div className="text-small-regular">
97
+ {cart && cart.shipping_address ? (
98
+ <div className="flex items-start gap-x-8">
99
+ <div className="flex items-start gap-x-1 w-full">
100
+ <div
101
+ className="flex flex-col w-1/3"
102
+ data-testid="shipping-address-summary"
103
+ >
104
+ <Text className="txt-medium-plus text-ui-fg-base mb-1">
105
+ <T k="checkout.shippingAddress" />
106
+ </Text>
107
+ <Text className="txt-medium text-ui-fg-subtle">
108
+ {cart.shipping_address.first_name}{" "}
109
+ {cart.shipping_address.last_name}
110
+ </Text>
111
+ <Text className="txt-medium text-ui-fg-subtle">
112
+ {cart.shipping_address.address_1}{" "}
113
+ {cart.shipping_address.address_2}
114
+ </Text>
115
+ <Text className="txt-medium text-ui-fg-subtle">
116
+ {cart.shipping_address.postal_code},{" "}
117
+ {cart.shipping_address.city}
118
+ </Text>
119
+ <Text className="txt-medium text-ui-fg-subtle">
120
+ {cart.shipping_address.country_code?.toUpperCase()}
121
+ </Text>
122
+ </div>
123
+
124
+ <div
125
+ className="flex flex-col w-1/3 "
126
+ data-testid="shipping-contact-summary"
127
+ >
128
+ <Text className="txt-medium-plus text-ui-fg-base mb-1">
129
+ <T k="checkout.contact" />
130
+ </Text>
131
+ <Text className="txt-medium text-ui-fg-subtle">
132
+ {cart.shipping_address.phone}
133
+ </Text>
134
+ <Text className="txt-medium text-ui-fg-subtle">
135
+ {cart.email}
136
+ </Text>
137
+ </div>
138
+
139
+ <div
140
+ className="flex flex-col w-1/3"
141
+ data-testid="billing-address-summary"
142
+ >
143
+ <Text className="txt-medium-plus text-ui-fg-base mb-1">
144
+ <T k="checkout.billingAddress" />
145
+ </Text>
146
+
147
+ {sameAsBilling ? (
148
+ <Text className="txt-medium text-ui-fg-subtle">
149
+ <T k="checkout.sameAddress" />
150
+ </Text>
151
+ ) : (
152
+ <>
153
+ <Text className="txt-medium text-ui-fg-subtle">
154
+ {cart.billing_address?.first_name}{" "}
155
+ {cart.billing_address?.last_name}
156
+ </Text>
157
+ <Text className="txt-medium text-ui-fg-subtle">
158
+ {cart.billing_address?.address_1}{" "}
159
+ {cart.billing_address?.address_2}
160
+ </Text>
161
+ <Text className="txt-medium text-ui-fg-subtle">
162
+ {cart.billing_address?.postal_code},{" "}
163
+ {cart.billing_address?.city}
164
+ </Text>
165
+ <Text className="txt-medium text-ui-fg-subtle">
166
+ {cart.billing_address?.country_code?.toUpperCase()}
167
+ </Text>
168
+ </>
169
+ )}
170
+ </div>
171
+ </div>
172
+ </div>
173
+ ) : (
174
+ <div>
175
+ <Spinner />
176
+ </div>
177
+ )}
178
+ </div>
179
+ </div>
180
+ )}
181
+ <Divider className="mt-8" />
182
+ </div>
183
+ )
184
+ }
185
+
186
+ export default Addresses
@@ -0,0 +1,114 @@
1
+ import { HttpTypes } from "@medusajs/types"
2
+ import Input from "@modules/common/components/input"
3
+ import React, { useState } from "react"
4
+ import CountrySelect from "../country-select"
5
+
6
+ const BillingAddress = ({ cart }: { cart: HttpTypes.StoreCart | null }) => {
7
+ const [formData, setFormData] = useState<any>({
8
+ "billing_address.first_name": cart?.billing_address?.first_name || "",
9
+ "billing_address.last_name": cart?.billing_address?.last_name || "",
10
+ "billing_address.address_1": cart?.billing_address?.address_1 || "",
11
+ "billing_address.company": cart?.billing_address?.company || "",
12
+ "billing_address.postal_code": cart?.billing_address?.postal_code || "",
13
+ "billing_address.city": cart?.billing_address?.city || "",
14
+ "billing_address.country_code": cart?.billing_address?.country_code || "",
15
+ "billing_address.province": cart?.billing_address?.province || "",
16
+ "billing_address.phone": cart?.billing_address?.phone || "",
17
+ })
18
+
19
+ const handleChange = (
20
+ e: React.ChangeEvent<
21
+ HTMLInputElement | HTMLInputElement | HTMLSelectElement
22
+ >
23
+ ) => {
24
+ setFormData({
25
+ ...formData,
26
+ [e.target.name]: e.target.value,
27
+ })
28
+ }
29
+
30
+ return (
31
+ <>
32
+ <div className="grid grid-cols-2 gap-4">
33
+ <Input
34
+ label="form.firstName"
35
+ name="billing_address.first_name"
36
+ autoComplete="given-name"
37
+ value={formData["billing_address.first_name"]}
38
+ onChange={handleChange}
39
+ required
40
+ data-testid="billing-first-name-input"
41
+ />
42
+ <Input
43
+ label="form.lastName"
44
+ name="billing_address.last_name"
45
+ autoComplete="family-name"
46
+ value={formData["billing_address.last_name"]}
47
+ onChange={handleChange}
48
+ required
49
+ data-testid="billing-last-name-input"
50
+ />
51
+ <Input
52
+ label="form.address"
53
+ name="billing_address.address_1"
54
+ autoComplete="address-line1"
55
+ value={formData["billing_address.address_1"]}
56
+ onChange={handleChange}
57
+ required
58
+ data-testid="billing-address-input"
59
+ />
60
+ <Input
61
+ label="form.company"
62
+ name="billing_address.company"
63
+ value={formData["billing_address.company"]}
64
+ onChange={handleChange}
65
+ autoComplete="organization"
66
+ data-testid="billing-company-input"
67
+ />
68
+ <Input
69
+ label="form.postalCode"
70
+ name="billing_address.postal_code"
71
+ autoComplete="postal-code"
72
+ value={formData["billing_address.postal_code"]}
73
+ onChange={handleChange}
74
+ required
75
+ data-testid="billing-postal-input"
76
+ />
77
+ <Input
78
+ label="form.city"
79
+ name="billing_address.city"
80
+ autoComplete="address-level2"
81
+ value={formData["billing_address.city"]}
82
+ onChange={handleChange}
83
+ />
84
+ <CountrySelect
85
+ name="billing_address.country_code"
86
+ autoComplete="country"
87
+ region={cart?.region}
88
+ value={formData["billing_address.country_code"]}
89
+ onChange={handleChange}
90
+ required
91
+ data-testid="billing-country-select"
92
+ />
93
+ <Input
94
+ label="form.province"
95
+ name="billing_address.province"
96
+ autoComplete="address-level1"
97
+ value={formData["billing_address.province"]}
98
+ onChange={handleChange}
99
+ data-testid="billing-province-input"
100
+ />
101
+ <Input
102
+ label="form.phone"
103
+ name="billing_address.phone"
104
+ autoComplete="tel"
105
+ value={formData["billing_address.phone"]}
106
+ onChange={handleChange}
107
+ data-testid="billing-phone-input"
108
+ />
109
+ </div>
110
+ </>
111
+ )
112
+ }
113
+
114
+ export default BillingAddress
@@ -0,0 +1,50 @@
1
+ import { forwardRef, useImperativeHandle, useMemo, useRef } from "react"
2
+
3
+ import NativeSelect, {
4
+ NativeSelectProps,
5
+ } from "@modules/common/components/native-select"
6
+ import { HttpTypes } from "@medusajs/types"
7
+
8
+ const CountrySelect = forwardRef<
9
+ HTMLSelectElement,
10
+ NativeSelectProps & {
11
+ region?: HttpTypes.StoreRegion
12
+ }
13
+ >(({ placeholder = "Country", region, defaultValue, ...props }, ref) => {
14
+ const innerRef = useRef<HTMLSelectElement>(null)
15
+
16
+ useImperativeHandle<HTMLSelectElement | null, HTMLSelectElement | null>(
17
+ ref,
18
+ () => innerRef.current
19
+ )
20
+
21
+ const countryOptions = useMemo(() => {
22
+ if (!region) {
23
+ return []
24
+ }
25
+
26
+ return region.countries?.map((country) => ({
27
+ value: country.iso_2,
28
+ label: country.display_name,
29
+ }))
30
+ }, [region])
31
+
32
+ return (
33
+ <NativeSelect
34
+ ref={innerRef}
35
+ placeholder={placeholder}
36
+ defaultValue={defaultValue}
37
+ {...props}
38
+ >
39
+ {countryOptions?.map(({ value, label }, index) => (
40
+ <option key={index} value={value}>
41
+ {label}
42
+ </option>
43
+ ))}
44
+ </NativeSelect>
45
+ )
46
+ })
47
+
48
+ CountrySelect.displayName = "CountrySelect"
49
+
50
+ export default CountrySelect
@@ -0,0 +1,181 @@
1
+ "use client"
2
+
3
+
4
+ import { T } from "@lib/boutique/i18n-client"
5
+ import { Badge, Heading, Input, Label, Text } from "@medusajs/ui"
6
+ import React from "react"
7
+
8
+ import { applyPromotions } from "@lib/data/cart"
9
+ import { convertToLocale } from "@lib/util/money"
10
+ import { HttpTypes } from "@medusajs/types"
11
+ import Trash from "@modules/common/icons/trash"
12
+ import ErrorMessage from "../error-message"
13
+ import { SubmitButton } from "../submit-button"
14
+
15
+ type DiscountCodeProps = {
16
+ cart: HttpTypes.StoreCart & {
17
+ promotions: HttpTypes.StorePromotion[]
18
+ }
19
+ }
20
+
21
+ const DiscountCode: React.FC<DiscountCodeProps> = ({ cart }) => {
22
+ const [isOpen, setIsOpen] = React.useState(false)
23
+ const [errorMessage, setErrorMessage] = React.useState("")
24
+
25
+ const { promotions = [] } = cart
26
+ const removePromotionCode = async (code: string) => {
27
+ const validPromotions = promotions.filter(
28
+ (promotion) => promotion.code !== code
29
+ )
30
+
31
+ await applyPromotions(
32
+ validPromotions.filter((p) => p.code !== undefined).map((p) => p.code!)
33
+ )
34
+ }
35
+
36
+ const addPromotionCode = async (formData: FormData) => {
37
+ setErrorMessage("")
38
+
39
+ const code = formData.get("code")
40
+ if (!code) {
41
+ return
42
+ }
43
+ const input = document.getElementById("promotion-input") as HTMLInputElement
44
+ const codes = promotions
45
+ .filter((p) => p.code !== undefined)
46
+ .map((p) => p.code!)
47
+ codes.push(code.toString())
48
+
49
+ try {
50
+ await applyPromotions(codes)
51
+ } catch (e: any) {
52
+ setErrorMessage(e.message)
53
+ }
54
+
55
+ if (input) {
56
+ input.value = ""
57
+ }
58
+ }
59
+
60
+ return (
61
+ <div className="w-full bg-white flex flex-col">
62
+ <div className="txt-medium">
63
+ <form action={(a) => addPromotionCode(a)} className="w-full mb-5">
64
+ <Label className="flex gap-x-1 my-2 items-center">
65
+ <button
66
+ onClick={() => setIsOpen(!isOpen)}
67
+ type="button"
68
+ className="txt-medium text-ui-fg-interactive hover:text-ui-fg-interactive-hover"
69
+ data-testid="add-discount-button"
70
+ >
71
+ <T k="checkout.addPromo" />
72
+ </button>
73
+
74
+ {/* <Tooltip content="You can add multiple promotion codes">
75
+ <InformationCircleSolid color="var(--fg-muted)" />
76
+ </Tooltip> */}
77
+ </Label>
78
+
79
+ {isOpen && (
80
+ <>
81
+ <div className="flex w-full gap-x-2">
82
+ <Input
83
+ className="size-full"
84
+ id="promotion-input"
85
+ name="code"
86
+ type="text"
87
+ autoFocus={false}
88
+ data-testid="discount-input"
89
+ />
90
+ <SubmitButton
91
+ variant="secondary"
92
+ data-testid="discount-apply-button"
93
+ >
94
+ <T k="checkout.apply" />
95
+ </SubmitButton>
96
+ </div>
97
+
98
+ <ErrorMessage
99
+ error={errorMessage}
100
+ data-testid="discount-error-message"
101
+ />
102
+ </>
103
+ )}
104
+ </form>
105
+
106
+ {promotions.length > 0 && (
107
+ <div className="w-full flex items-center">
108
+ <div className="flex flex-col w-full">
109
+ <Heading className="txt-medium mb-2">
110
+ <T k="checkout.promosApplied" />
111
+ </Heading>
112
+
113
+ {promotions.map((promotion) => {
114
+ return (
115
+ <div
116
+ key={promotion.id}
117
+ className="flex items-center justify-between w-full max-w-full mb-2"
118
+ data-testid="discount-row"
119
+ >
120
+ <Text className="flex gap-x-1 items-baseline txt-small-plus w-4/5 pr-1">
121
+ <span className="truncate" data-testid="discount-code">
122
+ <Badge
123
+ color={promotion.is_automatic ? "green" : "grey"}
124
+ size="small"
125
+ >
126
+ {promotion.code}
127
+ </Badge>{" "}
128
+ (
129
+ {promotion.application_method?.value !== undefined &&
130
+ promotion.application_method.currency_code !==
131
+ undefined && (
132
+ <>
133
+ {promotion.application_method.type ===
134
+ "percentage"
135
+ ? `${promotion.application_method.value}%`
136
+ : convertToLocale({
137
+ amount: +promotion.application_method.value,
138
+ currency_code:
139
+ promotion.application_method
140
+ .currency_code,
141
+ })}
142
+ </>
143
+ )}
144
+ )
145
+ {/* {promotion.is_automatic && (
146
+ <Tooltip content="This promotion is automatically applied">
147
+ <InformationCircleSolid className="inline text-zinc-400" />
148
+ </Tooltip>
149
+ )} */}
150
+ </span>
151
+ </Text>
152
+ {!promotion.is_automatic && (
153
+ <button
154
+ className="flex items-center"
155
+ onClick={() => {
156
+ if (!promotion.code) {
157
+ return
158
+ }
159
+
160
+ removePromotionCode(promotion.code)
161
+ }}
162
+ data-testid="remove-discount-button"
163
+ >
164
+ <Trash size={14} />
165
+ <span className="sr-only">
166
+ <T k="checkout.removePromo" />
167
+ </span>
168
+ </button>
169
+ )}
170
+ </div>
171
+ )
172
+ })}
173
+ </div>
174
+ </div>
175
+ )}
176
+ </div>
177
+ </div>
178
+ )
179
+ }
180
+
181
+ export default DiscountCode
@@ -0,0 +1,13 @@
1
+ const ErrorMessage = ({ error, 'data-testid': dataTestid }: { error?: string | null, 'data-testid'?: string }) => {
2
+ if (!error) {
3
+ return null
4
+ }
5
+
6
+ return (
7
+ <div className="pt-2 text-rose-500 text-small-regular" data-testid={dataTestid}>
8
+ <span>{error}</span>
9
+ </div>
10
+ )
11
+ }
12
+
13
+ export default ErrorMessage