@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,144 @@
1
+ "use client"
2
+
3
+ import { Table, Text, clx } from "@medusajs/ui"
4
+ import { updateLineItem } from "@lib/data/cart"
5
+ import { HttpTypes } from "@medusajs/types"
6
+ import CartItemSelect from "@modules/cart/components/cart-item-select"
7
+ import ErrorMessage from "@modules/checkout/components/error-message"
8
+ import DeleteButton from "@modules/common/components/delete-button"
9
+ import LineItemOptions from "@modules/common/components/line-item-options"
10
+ import LineItemPrice from "@modules/common/components/line-item-price"
11
+ import LineItemUnitPrice from "@modules/common/components/line-item-unit-price"
12
+ import LocalizedClientLink from "@modules/common/components/localized-client-link"
13
+ import Spinner from "@modules/common/icons/spinner"
14
+ import Thumbnail from "@modules/products/components/thumbnail"
15
+ import { useState } from "react"
16
+
17
+ type ItemProps = {
18
+ item: HttpTypes.StoreCartLineItem
19
+ type?: "full" | "preview"
20
+ currencyCode: string
21
+ }
22
+
23
+ const Item = ({ item, type = "full", currencyCode }: ItemProps) => {
24
+ const [updating, setUpdating] = useState(false)
25
+ const [error, setError] = useState<string | null>(null)
26
+
27
+ const changeQuantity = async (quantity: number) => {
28
+ setError(null)
29
+ setUpdating(true)
30
+
31
+ await updateLineItem({
32
+ lineId: item.id,
33
+ quantity,
34
+ })
35
+ .catch((err) => {
36
+ setError(err.message)
37
+ })
38
+ .finally(() => {
39
+ setUpdating(false)
40
+ })
41
+ }
42
+
43
+ // TODO: Update this to grab the actual max inventory
44
+ const maxQtyFromInventory = 10
45
+ const maxQuantity = item.variant?.manage_inventory ? 10 : maxQtyFromInventory
46
+
47
+ return (
48
+ <Table.Row className="w-full" data-testid="product-row">
49
+ <Table.Cell className="!pl-0 p-4 w-24">
50
+ <LocalizedClientLink
51
+ href={`/products/${item.product_handle}`}
52
+ className={clx("flex", {
53
+ "w-16": type === "preview",
54
+ "small:w-24 w-12": type === "full",
55
+ })}
56
+ >
57
+ <Thumbnail
58
+ thumbnail={item.thumbnail}
59
+ images={item.variant?.product?.images}
60
+ size="square"
61
+ />
62
+ </LocalizedClientLink>
63
+ </Table.Cell>
64
+
65
+ <Table.Cell className="text-left">
66
+ <Text
67
+ className="txt-medium-plus text-ui-fg-base"
68
+ data-testid="product-title"
69
+ >
70
+ {item.product_title}
71
+ </Text>
72
+ <LineItemOptions variant={item.variant} data-testid="product-variant" />
73
+ </Table.Cell>
74
+
75
+ {type === "full" && (
76
+ <Table.Cell>
77
+ <div className="flex gap-2 items-center w-28">
78
+ <DeleteButton id={item.id} data-testid="product-delete-button" />
79
+ <CartItemSelect
80
+ value={item.quantity}
81
+ onChange={(value) => changeQuantity(parseInt(value.target.value))}
82
+ className="w-14 h-10 p-4"
83
+ data-testid="product-select-button"
84
+ >
85
+ {/* TODO: Update this with the v2 way of managing inventory */}
86
+ {Array.from(
87
+ {
88
+ length: Math.min(maxQuantity, 10),
89
+ },
90
+ (_, i) => (
91
+ <option value={i + 1} key={i}>
92
+ {i + 1}
93
+ </option>
94
+ )
95
+ )}
96
+
97
+ <option value={1} key={1}>
98
+ 1
99
+ </option>
100
+ </CartItemSelect>
101
+ {updating && <Spinner />}
102
+ </div>
103
+ <ErrorMessage error={error} data-testid="product-error-message" />
104
+ </Table.Cell>
105
+ )}
106
+
107
+ {type === "full" && (
108
+ <Table.Cell className="hidden small:table-cell">
109
+ <LineItemUnitPrice
110
+ item={item}
111
+ style="tight"
112
+ currencyCode={currencyCode}
113
+ />
114
+ </Table.Cell>
115
+ )}
116
+
117
+ <Table.Cell className="!pr-0">
118
+ <span
119
+ className={clx("!pr-0", {
120
+ "flex flex-col items-end h-full justify-center": type === "preview",
121
+ })}
122
+ >
123
+ {type === "preview" && (
124
+ <span className="flex gap-x-1 ">
125
+ <Text className="text-ui-fg-muted">{item.quantity}x </Text>
126
+ <LineItemUnitPrice
127
+ item={item}
128
+ style="tight"
129
+ currencyCode={currencyCode}
130
+ />
131
+ </span>
132
+ )}
133
+ <LineItemPrice
134
+ item={item}
135
+ style="tight"
136
+ currencyCode={currencyCode}
137
+ />
138
+ </span>
139
+ </Table.Cell>
140
+ </Table.Row>
141
+ )
142
+ }
143
+
144
+ export default Item
@@ -0,0 +1,27 @@
1
+ import { T } from "@lib/boutique/i18n-client"
2
+ import { Button, Heading, Text } from "@medusajs/ui"
3
+ import LocalizedClientLink from "@modules/common/components/localized-client-link"
4
+
5
+ const SignInPrompt = () => {
6
+ return (
7
+ <div className="flex items-center justify-between">
8
+ <div>
9
+ <Heading level="h2" className="txt-xlarge">
10
+ <T k="cart.signInTitle" />
11
+ </Heading>
12
+ <Text className="txt-medium text-ui-fg-subtle mt-2">
13
+ <T k="cart.signInText" />
14
+ </Text>
15
+ </div>
16
+ <div>
17
+ <LocalizedClientLink href="/account">
18
+ <Button variant="secondary" className="h-10" data-testid="sign-in-button">
19
+ <T k="cart.signIn" />
20
+ </Button>
21
+ </LocalizedClientLink>
22
+ </div>
23
+ </div>
24
+ )
25
+ }
26
+
27
+ export default SignInPrompt
@@ -0,0 +1,51 @@
1
+ import ItemsTemplate from "./items"
2
+ import Summary from "./summary"
3
+ import EmptyCartMessage from "../components/empty-cart-message"
4
+ import SignInPrompt from "../components/sign-in-prompt"
5
+ import Divider from "@modules/common/components/divider"
6
+ import { HttpTypes } from "@medusajs/types"
7
+
8
+ const CartTemplate = ({
9
+ cart,
10
+ customer,
11
+ }: {
12
+ cart: HttpTypes.StoreCart | null
13
+ customer: HttpTypes.StoreCustomer | null
14
+ }) => {
15
+ return (
16
+ <div className="py-12">
17
+ <div className="content-container" data-testid="cart-container">
18
+ {cart?.items?.length ? (
19
+ <div className="grid grid-cols-1 small:grid-cols-[1fr_360px] gap-x-40">
20
+ <div className="flex flex-col py-6 gap-y-6">
21
+ {!customer && (
22
+ <>
23
+ <SignInPrompt />
24
+ <Divider />
25
+ </>
26
+ )}
27
+ <ItemsTemplate cart={cart} />
28
+ </div>
29
+ <div className="relative">
30
+ <div className="flex flex-col gap-y-8 sticky top-12">
31
+ {cart && cart.region && (
32
+ <>
33
+ <div className="py-6">
34
+ <Summary cart={cart as any} />
35
+ </div>
36
+ </>
37
+ )}
38
+ </div>
39
+ </div>
40
+ </div>
41
+ ) : (
42
+ <div>
43
+ <EmptyCartMessage />
44
+ </div>
45
+ )}
46
+ </div>
47
+ </div>
48
+ )
49
+ }
50
+
51
+ export default CartTemplate
@@ -0,0 +1,58 @@
1
+ import { T } from "@lib/boutique/i18n-client"
2
+ import repeat from "@lib/util/repeat"
3
+ import { HttpTypes } from "@medusajs/types"
4
+ import { Heading, Table } from "@medusajs/ui"
5
+
6
+ import Item from "@modules/cart/components/item"
7
+ import SkeletonLineItem from "@modules/skeletons/components/skeleton-line-item"
8
+
9
+ type ItemsTemplateProps = {
10
+ cart?: HttpTypes.StoreCart
11
+ }
12
+
13
+ const ItemsTemplate = ({ cart }: ItemsTemplateProps) => {
14
+ const items = cart?.items
15
+ return (
16
+ <div>
17
+ <div className="pb-3 flex items-center">
18
+ <Heading className="text-[2rem] leading-[2.75rem]"><T k="cart.title" /></Heading>
19
+ </div>
20
+ <Table>
21
+ <Table.Header className="border-t-0">
22
+ <Table.Row className="text-ui-fg-subtle txt-medium-plus">
23
+ <Table.HeaderCell className="!pl-0"><T k="cart.item" /></Table.HeaderCell>
24
+ <Table.HeaderCell></Table.HeaderCell>
25
+ <Table.HeaderCell><T k="cart.quantity" /></Table.HeaderCell>
26
+ <Table.HeaderCell className="hidden small:table-cell">
27
+ <T k="cart.price" />
28
+ </Table.HeaderCell>
29
+ <Table.HeaderCell className="!pr-0 text-right">
30
+ <T k="cart.total" />
31
+ </Table.HeaderCell>
32
+ </Table.Row>
33
+ </Table.Header>
34
+ <Table.Body>
35
+ {items
36
+ ? items
37
+ .sort((a, b) => {
38
+ return (a.created_at ?? "") > (b.created_at ?? "") ? -1 : 1
39
+ })
40
+ .map((item) => {
41
+ return (
42
+ <Item
43
+ key={item.id}
44
+ item={item}
45
+ currencyCode={cart?.currency_code}
46
+ />
47
+ )
48
+ })
49
+ : repeat(5).map((i) => {
50
+ return <SkeletonLineItem key={i} />
51
+ })}
52
+ </Table.Body>
53
+ </Table>
54
+ </div>
55
+ )
56
+ }
57
+
58
+ export default ItemsTemplate
@@ -0,0 +1,51 @@
1
+ "use client"
2
+
3
+ import repeat from "@lib/util/repeat"
4
+ import { HttpTypes } from "@medusajs/types"
5
+ import { Table, clx } from "@medusajs/ui"
6
+
7
+ import Item from "@modules/cart/components/item"
8
+ import SkeletonLineItem from "@modules/skeletons/components/skeleton-line-item"
9
+
10
+ type ItemsTemplateProps = {
11
+ cart: HttpTypes.StoreCart
12
+ }
13
+
14
+ const ItemsPreviewTemplate = ({ cart }: ItemsTemplateProps) => {
15
+ const items = cart.items
16
+ const hasOverflow = items && items.length > 4
17
+
18
+ return (
19
+ <div
20
+ className={clx({
21
+ "pl-[1px] overflow-y-scroll overflow-x-hidden no-scrollbar max-h-[420px]":
22
+ hasOverflow,
23
+ })}
24
+ >
25
+ <Table>
26
+ <Table.Body data-testid="items-table">
27
+ {items
28
+ ? items
29
+ .sort((a, b) => {
30
+ return (a.created_at ?? "") > (b.created_at ?? "") ? -1 : 1
31
+ })
32
+ .map((item) => {
33
+ return (
34
+ <Item
35
+ key={item.id}
36
+ item={item}
37
+ type="preview"
38
+ currencyCode={cart.currency_code}
39
+ />
40
+ )
41
+ })
42
+ : repeat(5).map((i) => {
43
+ return <SkeletonLineItem key={i} />
44
+ })}
45
+ </Table.Body>
46
+ </Table>
47
+ </div>
48
+ )
49
+ }
50
+
51
+ export default ItemsPreviewTemplate
@@ -0,0 +1,50 @@
1
+ "use client"
2
+
3
+
4
+ import { T } from "@lib/boutique/i18n-client"
5
+ import { Button, Heading } from "@medusajs/ui"
6
+
7
+ import CartTotals from "@modules/common/components/cart-totals"
8
+ import Divider from "@modules/common/components/divider"
9
+ import DiscountCode from "@modules/checkout/components/discount-code"
10
+ import LocalizedClientLink from "@modules/common/components/localized-client-link"
11
+ import { HttpTypes } from "@medusajs/types"
12
+
13
+ type SummaryProps = {
14
+ cart: HttpTypes.StoreCart & {
15
+ promotions: HttpTypes.StorePromotion[]
16
+ }
17
+ }
18
+
19
+ function getCheckoutStep(cart: HttpTypes.StoreCart) {
20
+ if (!cart?.shipping_address?.address_1 || !cart.email) {
21
+ return "address"
22
+ } else if (cart?.shipping_methods?.length === 0) {
23
+ return "delivery"
24
+ } else {
25
+ return "payment"
26
+ }
27
+ }
28
+
29
+ const Summary = ({ cart }: SummaryProps) => {
30
+ const step = getCheckoutStep(cart)
31
+
32
+ return (
33
+ <div className="flex flex-col gap-y-4">
34
+ <Heading level="h2" className="text-[2rem] leading-[2.75rem]">
35
+ <T k="cart.summary" />
36
+ </Heading>
37
+ <DiscountCode cart={cart} />
38
+ <Divider />
39
+ <CartTotals totals={cart} />
40
+ <LocalizedClientLink
41
+ href={"/checkout?step=" + step}
42
+ data-testid="checkout-button"
43
+ >
44
+ <Button className="w-full h-10"><T k="cart.goToCheckout" /></Button>
45
+ </LocalizedClientLink>
46
+ </div>
47
+ )
48
+ }
49
+
50
+ export default Summary
@@ -0,0 +1,94 @@
1
+ import { notFound } from "next/navigation"
2
+ import { Suspense } from "react"
3
+
4
+ import InteractiveLink from "@modules/common/components/interactive-link"
5
+ import SkeletonProductGrid from "@modules/skeletons/templates/skeleton-product-grid"
6
+ import RefinementList from "@modules/store/components/refinement-list"
7
+ import { SortOptions } from "@modules/store/components/refinement-list/sort-products"
8
+ import PaginatedProducts from "@modules/store/templates/paginated-products"
9
+ import LocalizedClientLink from "@modules/common/components/localized-client-link"
10
+ import { HttpTypes } from "@medusajs/types"
11
+
12
+ export default function CategoryTemplate({
13
+ category,
14
+ sortBy,
15
+ page,
16
+ }: {
17
+ category: HttpTypes.StoreProductCategory
18
+ sortBy?: SortOptions
19
+ page?: string
20
+ }) {
21
+ const pageNumber = page ? parseInt(page) : 1
22
+ const sort = sortBy || "created_at"
23
+
24
+ if (!category) notFound()
25
+
26
+ const parents = [] as HttpTypes.StoreProductCategory[]
27
+
28
+ const getParents = (category: HttpTypes.StoreProductCategory) => {
29
+ if (category.parent_category) {
30
+ parents.push(category.parent_category)
31
+ getParents(category.parent_category)
32
+ }
33
+ }
34
+
35
+ getParents(category)
36
+
37
+ return (
38
+ <div
39
+ className="flex flex-col small:flex-row small:items-start py-6 content-container"
40
+ data-testid="category-container"
41
+ >
42
+ <RefinementList sortBy={sort} data-testid="sort-by-container" />
43
+ <div className="w-full">
44
+ <div className="flex flex-row mb-8 text-2xl-semi gap-4">
45
+ {parents &&
46
+ parents.map((parent) => (
47
+ <span key={parent.id} className="text-ui-fg-subtle">
48
+ <LocalizedClientLink
49
+ className="mr-4 hover:text-black"
50
+ href={`/categories/${parent.handle}`}
51
+ data-testid="sort-by-link"
52
+ >
53
+ {parent.name}
54
+ </LocalizedClientLink>
55
+ /
56
+ </span>
57
+ ))}
58
+ <h1 data-testid="category-page-title">{category.name}</h1>
59
+ </div>
60
+ {category.description && (
61
+ <div className="mb-8 text-base-regular">
62
+ <p>{category.description}</p>
63
+ </div>
64
+ )}
65
+ {category.category_children && (
66
+ <div className="mb-8 text-base-large">
67
+ <ul className="grid grid-cols-1 gap-2">
68
+ {category.category_children?.map((c) => (
69
+ <li key={c.id}>
70
+ <InteractiveLink href={`/categories/${c.handle}`}>
71
+ {c.name}
72
+ </InteractiveLink>
73
+ </li>
74
+ ))}
75
+ </ul>
76
+ </div>
77
+ )}
78
+ <Suspense
79
+ fallback={
80
+ <SkeletonProductGrid
81
+ numberOfProducts={category.products?.length ?? 8}
82
+ />
83
+ }
84
+ >
85
+ <PaginatedProducts
86
+ sortBy={sort}
87
+ page={pageNumber}
88
+ categoryId={category.id}
89
+ />
90
+ </Suspense>
91
+ </div>
92
+ </div>
93
+ )
94
+ }
@@ -0,0 +1,117 @@
1
+ import { T } from "@lib/boutique/i18n-client"
2
+ import { Listbox, Transition } from "@headlessui/react"
3
+ import { ChevronUpDown } from "@medusajs/icons"
4
+ import { clx } from "@medusajs/ui"
5
+ import { Fragment, useMemo } from "react"
6
+
7
+ import Radio from "@modules/common/components/radio"
8
+ import compareAddresses from "@lib/util/compare-addresses"
9
+ import { HttpTypes } from "@medusajs/types"
10
+
11
+ type AddressSelectProps = {
12
+ addresses: HttpTypes.StoreCustomerAddress[]
13
+ addressInput: HttpTypes.StoreCartAddress | null
14
+ onSelect: (
15
+ address: HttpTypes.StoreCartAddress | undefined,
16
+ email?: string
17
+ ) => void
18
+ }
19
+
20
+ const AddressSelect = ({
21
+ addresses,
22
+ addressInput,
23
+ onSelect,
24
+ }: AddressSelectProps) => {
25
+ const handleSelect = (id: string) => {
26
+ const savedAddress = addresses.find((a) => a.id === id)
27
+ if (savedAddress) {
28
+ onSelect(savedAddress as HttpTypes.StoreCartAddress)
29
+ }
30
+ }
31
+
32
+ const selectedAddress = useMemo(() => {
33
+ return addresses.find((a) => compareAddresses(a, addressInput))
34
+ }, [addresses, addressInput])
35
+
36
+ return (
37
+ <Listbox onChange={handleSelect} value={selectedAddress?.id}>
38
+ <div className="relative">
39
+ <Listbox.Button
40
+ className="relative w-full flex justify-between items-center px-4 py-[10px] text-left bg-white cursor-default focus:outline-none border rounded-rounded focus-visible:ring-2 focus-visible:ring-opacity-75 focus-visible:ring-white focus-visible:ring-offset-gray-300 focus-visible:ring-offset-2 focus-visible:border-gray-300 text-base-regular"
41
+ data-testid="shipping-address-select"
42
+ >
43
+ {({ open }) => (
44
+ <>
45
+ <span className="block truncate">
46
+ {selectedAddress
47
+ ? selectedAddress.address_1
48
+ : <T k="form.chooseAddress" />}
49
+ </span>
50
+ <ChevronUpDown
51
+ className={clx("transition-rotate duration-200", {
52
+ "transform rotate-180": open,
53
+ })}
54
+ />
55
+ </>
56
+ )}
57
+ </Listbox.Button>
58
+ <Transition
59
+ as={Fragment}
60
+ leave="transition ease-in duration-100"
61
+ leaveFrom="opacity-100"
62
+ leaveTo="opacity-0"
63
+ >
64
+ <Listbox.Options
65
+ className="absolute z-20 w-full overflow-auto text-small-regular bg-white border border-top-0 max-h-60 focus:outline-none sm:text-sm"
66
+ data-testid="shipping-address-options"
67
+ >
68
+ {addresses.map((address) => {
69
+ return (
70
+ <Listbox.Option
71
+ key={address.id}
72
+ value={address.id}
73
+ className="cursor-default select-none relative pl-6 pr-10 hover:bg-gray-50 py-4"
74
+ data-testid="shipping-address-option"
75
+ >
76
+ <div className="flex gap-x-4 items-start">
77
+ <Radio
78
+ checked={selectedAddress?.id === address.id}
79
+ data-testid="shipping-address-radio"
80
+ />
81
+ <div className="flex flex-col">
82
+ <span className="text-left text-base-semi">
83
+ {address.first_name} {address.last_name}
84
+ </span>
85
+ {address.company && (
86
+ <span className="text-small-regular text-ui-fg-base">
87
+ {address.company}
88
+ </span>
89
+ )}
90
+ <div className="flex flex-col text-left text-base-regular mt-2">
91
+ <span>
92
+ {address.address_1}
93
+ {address.address_2 && (
94
+ <span>, {address.address_2}</span>
95
+ )}
96
+ </span>
97
+ <span>
98
+ {address.postal_code}, {address.city}
99
+ </span>
100
+ <span>
101
+ {address.province && `${address.province}, `}
102
+ {address.country_code?.toUpperCase()}
103
+ </span>
104
+ </div>
105
+ </div>
106
+ </div>
107
+ </Listbox.Option>
108
+ )
109
+ })}
110
+ </Listbox.Options>
111
+ </Transition>
112
+ </div>
113
+ </Listbox>
114
+ )
115
+ }
116
+
117
+ export default AddressSelect