@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.
- package/README.md +1 -0
- package/cli/dist/commands.js +382 -0
- package/cli/dist/create.js +194 -0
- package/cli/dist/docker.js +19 -0
- package/cli/dist/generate.js +322 -0
- package/cli/dist/guide.js +72 -0
- package/cli/dist/index.js +156 -0
- package/cli/dist/paths.js +29 -0
- package/cli/dist/ports.js +54 -0
- package/cli/dist/project.js +119 -0
- package/cli/dist/themes.js +24 -0
- package/docs/fiche-client.en.html +137 -0
- package/docs/fiche-client.html +137 -0
- package/docs/guide-complet.en.html +259 -0
- package/docs/guide-complet.fr.html +259 -0
- package/package.json +51 -0
- package/templates/backend/.dockerignore +9 -0
- package/templates/backend/Dockerfile +30 -0
- package/templates/backend/README.md +78 -0
- package/templates/backend/TEMPLATE_VERSION +1 -0
- package/templates/backend/docker/entrypoint.sh +28 -0
- package/templates/backend/instrumentation.ts +24 -0
- package/templates/backend/medusa-config.ts +114 -0
- package/templates/backend/package-lock.json +16222 -0
- package/templates/backend/package.json +39 -0
- package/templates/backend/src/admin/README.md +33 -0
- package/templates/backend/src/admin/components/image-field.tsx +61 -0
- package/templates/backend/src/admin/i18n/README.md +58 -0
- package/templates/backend/src/admin/i18n/index.ts +8 -0
- package/templates/backend/src/admin/i18n/json/en.json +66 -0
- package/templates/backend/src/admin/i18n/json/fr.json +66 -0
- package/templates/backend/src/admin/lib/client.ts +9 -0
- package/templates/backend/src/admin/routes/boutique-campaigns/campaign-drawer.tsx +286 -0
- package/templates/backend/src/admin/routes/boutique-campaigns/page.tsx +113 -0
- package/templates/backend/src/admin/tsconfig.json +24 -0
- package/templates/backend/src/admin/vite-env.d.ts +1 -0
- package/templates/backend/src/admin/widgets/category-image.tsx +56 -0
- package/templates/backend/src/api/README.md +135 -0
- package/templates/backend/src/api/admin/boutique-campaigns/[salesChannelId]/route.ts +30 -0
- package/templates/backend/src/api/admin/boutique-campaigns/route.ts +24 -0
- package/templates/backend/src/api/middlewares.ts +28 -0
- package/templates/backend/src/api/rate-limit.ts +30 -0
- package/templates/backend/src/api/route.ts +6 -0
- package/templates/backend/src/api/store/campaign/route.ts +25 -0
- package/templates/backend/src/api/store/order-lookup/route.ts +74 -0
- package/templates/backend/src/emails/en.json +64 -0
- package/templates/backend/src/emails/fr.json +64 -0
- package/templates/backend/src/jobs/README.md +38 -0
- package/templates/backend/src/lib/emails.ts +94 -0
- package/templates/backend/src/lib/notify.ts +148 -0
- package/templates/backend/src/lib/project.ts +146 -0
- package/templates/backend/src/links/README.md +26 -0
- package/templates/backend/src/links/campaign-sales-channel.ts +9 -0
- package/templates/backend/src/modules/README.md +117 -0
- package/templates/backend/src/modules/campaign/index.ts +9 -0
- package/templates/backend/src/modules/campaign/migrations/.snapshot-boutique-campaign.json +272 -0
- package/templates/backend/src/modules/campaign/migrations/Migration20260928141440.ts +16 -0
- package/templates/backend/src/modules/campaign/migrations/Migration20260928145243.ts +13 -0
- package/templates/backend/src/modules/campaign/models/campaign.ts +28 -0
- package/templates/backend/src/modules/campaign/service.ts +6 -0
- package/templates/backend/src/modules/campaign/validators.ts +94 -0
- package/templates/backend/src/modules/resend/index.ts +6 -0
- package/templates/backend/src/modules/resend/service.ts +63 -0
- package/templates/backend/src/scripts/README.md +63 -0
- package/templates/backend/src/scripts/campaign-export.ts +15 -0
- package/templates/backend/src/scripts/campaign-import.ts +38 -0
- package/templates/backend/src/scripts/price-report.ts +34 -0
- package/templates/backend/src/scripts/seed.ts +418 -0
- package/templates/backend/src/scripts/storage.ts +63 -0
- package/templates/backend/src/subscribers/README.md +61 -0
- package/templates/backend/src/subscribers/account-emails.ts +27 -0
- package/templates/backend/src/subscribers/fulfillment-emails.ts +42 -0
- package/templates/backend/src/subscribers/order-emails.ts +12 -0
- package/templates/backend/src/subscribers/return-refund-emails.ts +50 -0
- package/templates/backend/src/workflows/README.md +81 -0
- package/templates/backend/src/workflows/steps/upsert-campaign.ts +53 -0
- package/templates/backend/src/workflows/upsert-campaign.ts +30 -0
- package/templates/backend/tsconfig.json +36 -0
- package/templates/storefront/.dockerignore +7 -0
- package/templates/storefront/.github/ISSUE_TEMPLATE/bug-report.yml +71 -0
- package/templates/storefront/.prettierrc +8 -0
- package/templates/storefront/Dockerfile +37 -0
- package/templates/storefront/LICENSE +21 -0
- package/templates/storefront/README.md +127 -0
- package/templates/storefront/locales/en.json +269 -0
- package/templates/storefront/locales/fr.json +269 -0
- package/templates/storefront/next-env.d.ts +7 -0
- package/templates/storefront/next-sitemap.js +19 -0
- package/templates/storefront/next.config.js +29 -0
- package/templates/storefront/package-lock.json +9031 -0
- package/templates/storefront/package.json +49 -0
- package/templates/storefront/postcss.config.js +6 -0
- package/templates/storefront/public/favicon.ico +0 -0
- package/templates/storefront/scripts/sync-design.mjs +30 -0
- package/templates/storefront/src/app/(checkout)/checkout/page.tsx +31 -0
- package/templates/storefront/src/app/(checkout)/layout.tsx +29 -0
- package/templates/storefront/src/app/(checkout)/not-found.tsx +20 -0
- package/templates/storefront/src/app/(main)/account/@dashboard/addresses/page.tsx +34 -0
- package/templates/storefront/src/app/(main)/account/@dashboard/loading.tsx +9 -0
- package/templates/storefront/src/app/(main)/account/@dashboard/orders/details/[id]/page.tsx +33 -0
- package/templates/storefront/src/app/(main)/account/@dashboard/orders/page.tsx +37 -0
- package/templates/storefront/src/app/(main)/account/@dashboard/page.tsx +22 -0
- package/templates/storefront/src/app/(main)/account/@dashboard/profile/page.tsx +53 -0
- package/templates/storefront/src/app/(main)/account/@login/page.tsx +12 -0
- package/templates/storefront/src/app/(main)/account/layout.tsx +20 -0
- package/templates/storefront/src/app/(main)/account/loading.tsx +9 -0
- package/templates/storefront/src/app/(main)/cart/loading.tsx +5 -0
- package/templates/storefront/src/app/(main)/cart/not-found.tsx +21 -0
- package/templates/storefront/src/app/(main)/cart/page.tsx +21 -0
- package/templates/storefront/src/app/(main)/categories/[...category]/page.tsx +55 -0
- package/templates/storefront/src/app/(main)/collections/[handle]/page.tsx +55 -0
- package/templates/storefront/src/app/(main)/layout.tsx +43 -0
- package/templates/storefront/src/app/(main)/legal/[page]/page.tsx +42 -0
- package/templates/storefront/src/app/(main)/not-found.tsx +21 -0
- package/templates/storefront/src/app/(main)/order/[id]/confirmed/loading.tsx +5 -0
- package/templates/storefront/src/app/(main)/order/[id]/confirmed/page.tsx +23 -0
- package/templates/storefront/src/app/(main)/order/[id]/transfer/[token]/accept/page.tsx +42 -0
- package/templates/storefront/src/app/(main)/order/[id]/transfer/[token]/decline/page.tsx +42 -0
- package/templates/storefront/src/app/(main)/order/[id]/transfer/[token]/page.tsx +35 -0
- package/templates/storefront/src/app/(main)/order/track/page.tsx +32 -0
- package/templates/storefront/src/app/(main)/page.tsx +68 -0
- package/templates/storefront/src/app/(main)/products/[handle]/page.tsx +86 -0
- package/templates/storefront/src/app/(main)/store/page.tsx +28 -0
- package/templates/storefront/src/app/api/health/route.ts +13 -0
- package/templates/storefront/src/app/layout.tsx +42 -0
- package/templates/storefront/src/app/not-found.tsx +21 -0
- package/templates/storefront/src/app/opengraph-image.jpg +0 -0
- package/templates/storefront/src/app/twitter-image.jpg +0 -0
- package/templates/storefront/src/instrumentation-node.ts +18 -0
- package/templates/storefront/src/instrumentation.ts +9 -0
- package/templates/storefront/src/lib/boutique/campaign.ts +116 -0
- package/templates/storefront/src/lib/boutique/config.ts +152 -0
- package/templates/storefront/src/lib/boutique/fonts.ts +29 -0
- package/templates/storefront/src/lib/boutique/i18n-client.tsx +34 -0
- package/templates/storefront/src/lib/boutique/i18n.ts +43 -0
- package/templates/storefront/src/lib/boutique/schema.ts +131 -0
- package/templates/storefront/src/lib/config.ts +39 -0
- package/templates/storefront/src/lib/constants.tsx +75 -0
- package/templates/storefront/src/lib/context/modal-context.tsx +34 -0
- package/templates/storefront/src/lib/data/cart.ts +434 -0
- package/templates/storefront/src/lib/data/categories.ts +49 -0
- package/templates/storefront/src/lib/data/collections.ts +59 -0
- package/templates/storefront/src/lib/data/cookies.ts +103 -0
- package/templates/storefront/src/lib/data/customer.ts +261 -0
- package/templates/storefront/src/lib/data/fulfillment.ts +68 -0
- package/templates/storefront/src/lib/data/onboarding.ts +9 -0
- package/templates/storefront/src/lib/data/order-lookup.ts +34 -0
- package/templates/storefront/src/lib/data/orders.ts +112 -0
- package/templates/storefront/src/lib/data/payment.ts +35 -0
- package/templates/storefront/src/lib/data/products.ts +127 -0
- package/templates/storefront/src/lib/data/regions.ts +70 -0
- package/templates/storefront/src/lib/data/variants.ts +38 -0
- package/templates/storefront/src/lib/hooks/use-in-view.tsx +29 -0
- package/templates/storefront/src/lib/hooks/use-toggle-state.tsx +46 -0
- package/templates/storefront/src/lib/util/compare-addresses.ts +28 -0
- package/templates/storefront/src/lib/util/get-percentage-diff.ts +6 -0
- package/templates/storefront/src/lib/util/get-product-price.ts +79 -0
- package/templates/storefront/src/lib/util/isEmpty.ts +11 -0
- package/templates/storefront/src/lib/util/medusa-error.ts +22 -0
- package/templates/storefront/src/lib/util/money.ts +35 -0
- package/templates/storefront/src/lib/util/product.ts +5 -0
- package/templates/storefront/src/lib/util/repeat.ts +5 -0
- package/templates/storefront/src/lib/util/sort-products.ts +50 -0
- package/templates/storefront/src/modules/account/components/account-info/index.tsx +140 -0
- package/templates/storefront/src/modules/account/components/account-nav/index.tsx +198 -0
- package/templates/storefront/src/modules/account/components/address-book/index.tsx +28 -0
- package/templates/storefront/src/modules/account/components/address-card/add-address.tsx +169 -0
- package/templates/storefront/src/modules/account/components/address-card/edit-address-modal.tsx +241 -0
- package/templates/storefront/src/modules/account/components/login/index.tsx +65 -0
- package/templates/storefront/src/modules/account/components/order-card/index.tsx +88 -0
- package/templates/storefront/src/modules/account/components/order-overview/index.tsx +47 -0
- package/templates/storefront/src/modules/account/components/overview/index.tsx +169 -0
- package/templates/storefront/src/modules/account/components/profile-billing-address/index.tsx +193 -0
- package/templates/storefront/src/modules/account/components/profile-email/index.tsx +75 -0
- package/templates/storefront/src/modules/account/components/profile-name/index.tsx +79 -0
- package/templates/storefront/src/modules/account/components/profile-password/index.tsx +72 -0
- package/templates/storefront/src/modules/account/components/profile-phone/index.tsx +74 -0
- package/templates/storefront/src/modules/account/components/register/index.tsx +107 -0
- package/templates/storefront/src/modules/account/components/transfer-request-form/index.tsx +83 -0
- package/templates/storefront/src/modules/account/templates/account-layout.tsx +43 -0
- package/templates/storefront/src/modules/account/templates/login-template.tsx +27 -0
- package/templates/storefront/src/modules/cart/components/cart-item-select/index.tsx +75 -0
- package/templates/storefront/src/modules/cart/components/empty-cart-message/index.tsx +25 -0
- package/templates/storefront/src/modules/cart/components/item/index.tsx +144 -0
- package/templates/storefront/src/modules/cart/components/sign-in-prompt/index.tsx +27 -0
- package/templates/storefront/src/modules/cart/templates/index.tsx +51 -0
- package/templates/storefront/src/modules/cart/templates/items.tsx +58 -0
- package/templates/storefront/src/modules/cart/templates/preview.tsx +51 -0
- package/templates/storefront/src/modules/cart/templates/summary.tsx +50 -0
- package/templates/storefront/src/modules/categories/templates/index.tsx +94 -0
- package/templates/storefront/src/modules/checkout/components/address-select/index.tsx +117 -0
- package/templates/storefront/src/modules/checkout/components/addresses/index.tsx +186 -0
- package/templates/storefront/src/modules/checkout/components/billing_address/index.tsx +114 -0
- package/templates/storefront/src/modules/checkout/components/country-select/index.tsx +50 -0
- package/templates/storefront/src/modules/checkout/components/discount-code/index.tsx +181 -0
- package/templates/storefront/src/modules/checkout/components/error-message/index.tsx +13 -0
- package/templates/storefront/src/modules/checkout/components/payment/index.tsx +261 -0
- package/templates/storefront/src/modules/checkout/components/payment-button/index.tsx +195 -0
- package/templates/storefront/src/modules/checkout/components/payment-container/index.tsx +130 -0
- package/templates/storefront/src/modules/checkout/components/payment-test/index.tsx +12 -0
- package/templates/storefront/src/modules/checkout/components/payment-wrapper/index.tsx +42 -0
- package/templates/storefront/src/modules/checkout/components/payment-wrapper/stripe-wrapper.tsx +54 -0
- package/templates/storefront/src/modules/checkout/components/review/index.tsx +54 -0
- package/templates/storefront/src/modules/checkout/components/shipping/index.tsx +417 -0
- package/templates/storefront/src/modules/checkout/components/shipping-address/index.tsx +219 -0
- package/templates/storefront/src/modules/checkout/components/submit-button/index.tsx +32 -0
- package/templates/storefront/src/modules/checkout/templates/checkout-form/index.tsx +38 -0
- package/templates/storefront/src/modules/checkout/templates/checkout-summary/index.tsx +31 -0
- package/templates/storefront/src/modules/collections/templates/index.tsx +44 -0
- package/templates/storefront/src/modules/common/components/cart-totals/index.tsx +84 -0
- package/templates/storefront/src/modules/common/components/checkbox/index.tsx +44 -0
- package/templates/storefront/src/modules/common/components/delete-button/index.tsx +42 -0
- package/templates/storefront/src/modules/common/components/divider/index.tsx +9 -0
- package/templates/storefront/src/modules/common/components/filter-radio-group/index.tsx +61 -0
- package/templates/storefront/src/modules/common/components/input/index.tsx +79 -0
- package/templates/storefront/src/modules/common/components/interactive-link/index.tsx +33 -0
- package/templates/storefront/src/modules/common/components/line-item-options/index.tsx +26 -0
- package/templates/storefront/src/modules/common/components/line-item-price/index.tsx +63 -0
- package/templates/storefront/src/modules/common/components/line-item-unit-price/index.tsx +62 -0
- package/templates/storefront/src/modules/common/components/localized-client-link/index.tsx +29 -0
- package/templates/storefront/src/modules/common/components/modal/index.tsx +118 -0
- package/templates/storefront/src/modules/common/components/native-select/index.tsx +76 -0
- package/templates/storefront/src/modules/common/components/radio/index.tsx +27 -0
- package/templates/storefront/src/modules/common/icons/back.tsx +37 -0
- package/templates/storefront/src/modules/common/icons/bancontact.tsx +26 -0
- package/templates/storefront/src/modules/common/icons/chevron-down.tsx +30 -0
- package/templates/storefront/src/modules/common/icons/eye-off.tsx +37 -0
- package/templates/storefront/src/modules/common/icons/eye.tsx +37 -0
- package/templates/storefront/src/modules/common/icons/fast-delivery.tsx +65 -0
- package/templates/storefront/src/modules/common/icons/ideal.tsx +26 -0
- package/templates/storefront/src/modules/common/icons/map-pin.tsx +37 -0
- package/templates/storefront/src/modules/common/icons/package.tsx +44 -0
- package/templates/storefront/src/modules/common/icons/paypal.tsx +30 -0
- package/templates/storefront/src/modules/common/icons/placeholder-image.tsx +44 -0
- package/templates/storefront/src/modules/common/icons/refresh.tsx +51 -0
- package/templates/storefront/src/modules/common/icons/spinner.tsx +37 -0
- package/templates/storefront/src/modules/common/icons/trash.tsx +51 -0
- package/templates/storefront/src/modules/common/icons/user.tsx +37 -0
- package/templates/storefront/src/modules/common/icons/x.tsx +37 -0
- package/templates/storefront/src/modules/layout/components/cart-mismatch-banner/index.tsx +59 -0
- package/templates/storefront/src/modules/order/components/help/index.tsx +26 -0
- package/templates/storefront/src/modules/order/components/item/index.tsx +57 -0
- package/templates/storefront/src/modules/order/components/items/index.tsx +44 -0
- package/templates/storefront/src/modules/order/components/onboarding-cta/index.tsx +28 -0
- package/templates/storefront/src/modules/order/components/order-details/index.tsx +64 -0
- package/templates/storefront/src/modules/order/components/order-summary/index.tsx +61 -0
- package/templates/storefront/src/modules/order/components/payment-details/index.tsx +64 -0
- package/templates/storefront/src/modules/order/components/shipping-details/index.tsx +74 -0
- package/templates/storefront/src/modules/order/components/transfer-actions/index.tsx +83 -0
- package/templates/storefront/src/modules/order/components/transfer-image/index.tsx +275 -0
- package/templates/storefront/src/modules/order/templates/order-completed-template.tsx +53 -0
- package/templates/storefront/src/modules/order/templates/order-details-template.tsx +46 -0
- package/templates/storefront/src/modules/products/components/thumbnail/index.tsx +70 -0
- package/templates/storefront/src/modules/products/templates/index.tsx +118 -0
- package/templates/storefront/src/modules/shipping/components/free-shipping-price-nudge/index.tsx +285 -0
- package/templates/storefront/src/modules/skeletons/components/skeleton-button/index.tsx +5 -0
- package/templates/storefront/src/modules/skeletons/components/skeleton-card-details/index.tsx +10 -0
- package/templates/storefront/src/modules/skeletons/components/skeleton-cart-item/index.tsx +35 -0
- package/templates/storefront/src/modules/skeletons/components/skeleton-cart-totals/index.tsx +30 -0
- package/templates/storefront/src/modules/skeletons/components/skeleton-code-form/index.tsx +13 -0
- package/templates/storefront/src/modules/skeletons/components/skeleton-line-item/index.tsx +35 -0
- package/templates/storefront/src/modules/skeletons/components/skeleton-order-confirmed-header/index.tsx +14 -0
- package/templates/storefront/src/modules/skeletons/components/skeleton-order-information/index.tsx +36 -0
- package/templates/storefront/src/modules/skeletons/components/skeleton-order-items/index.tsx +43 -0
- package/templates/storefront/src/modules/skeletons/components/skeleton-order-summary/index.tsx +15 -0
- package/templates/storefront/src/modules/skeletons/components/skeleton-product-preview/index.tsx +15 -0
- package/templates/storefront/src/modules/skeletons/templates/skeleton-cart-page/index.tsx +65 -0
- package/templates/storefront/src/modules/skeletons/templates/skeleton-order-confirmed/index.tsx +21 -0
- package/templates/storefront/src/modules/skeletons/templates/skeleton-product-grid/index.tsx +23 -0
- package/templates/storefront/src/modules/store/components/pagination/index.tsx +114 -0
- package/templates/storefront/src/modules/store/components/refinement-list/index.tsx +41 -0
- package/templates/storefront/src/modules/store/components/refinement-list/sort-products/index.tsx +48 -0
- package/templates/storefront/src/modules/store/templates/index.tsx +42 -0
- package/templates/storefront/src/modules/store/templates/paginated-products.tsx +80 -0
- package/templates/storefront/src/modules/ub/button.tsx +41 -0
- package/templates/storefront/src/modules/ub/campaign-blocks.tsx +197 -0
- package/templates/storefront/src/modules/ub/campaign-ended.tsx +28 -0
- package/templates/storefront/src/modules/ub/category-tiles.tsx +41 -0
- package/templates/storefront/src/modules/ub/countdown.tsx +46 -0
- package/templates/storefront/src/modules/ub/footer.tsx +56 -0
- package/templates/storefront/src/modules/ub/icons.tsx +42 -0
- package/templates/storefront/src/modules/ub/nav.tsx +90 -0
- package/templates/storefront/src/modules/ub/pdp/buy-box.tsx +140 -0
- package/templates/storefront/src/modules/ub/pdp/gallery.tsx +40 -0
- package/templates/storefront/src/modules/ub/product-card.tsx +66 -0
- package/templates/storefront/src/modules/ub/top-bar.tsx +20 -0
- package/templates/storefront/src/modules/ub/track-form.tsx +92 -0
- package/templates/storefront/src/proxy.ts +89 -0
- package/templates/storefront/src/styles/globals.css +98 -0
- package/templates/storefront/src/styles/ub/bundle.css +372 -0
- package/templates/storefront/src/styles/ub/fonts.css +17 -0
- package/templates/storefront/src/styles/ub/medusa-ui.css +90 -0
- package/templates/storefront/src/styles/ub/overrides.css +12 -0
- package/templates/storefront/src/styles/ub/tokens.css +9 -0
- package/templates/storefront/src/types/global.ts +24 -0
- package/templates/storefront/src/types/icon.ts +4 -0
- package/templates/storefront/tailwind.config.js +164 -0
- package/templates/storefront/themes/black-friday/campaign.en.json +31 -0
- package/templates/storefront/themes/black-friday/campaign.fr.json +31 -0
- package/templates/storefront/themes/black-friday/theme.json +9 -0
- package/templates/storefront/themes/cyber-monday/campaign.en.json +31 -0
- package/templates/storefront/themes/cyber-monday/campaign.fr.json +31 -0
- package/templates/storefront/themes/cyber-monday/theme.json +9 -0
- package/templates/storefront/themes/halloween/campaign.en.json +31 -0
- package/templates/storefront/themes/halloween/campaign.fr.json +31 -0
- package/templates/storefront/themes/halloween/theme.json +9 -0
- package/templates/storefront/themes/noel/campaign.en.json +31 -0
- package/templates/storefront/themes/noel/campaign.fr.json +31 -0
- package/templates/storefront/themes/noel/theme.json +9 -0
- package/templates/storefront/themes/nouvel-an/campaign.en.json +31 -0
- package/templates/storefront/themes/nouvel-an/campaign.fr.json +31 -0
- package/templates/storefront/themes/nouvel-an/theme.json +9 -0
- package/templates/storefront/themes/thanksgiving/campaign.en.json +31 -0
- package/templates/storefront/themes/thanksgiving/campaign.fr.json +31 -0
- package/templates/storefront/themes/thanksgiving/theme.json +9 -0
- package/templates/storefront/tsconfig.json +53 -0
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "usine-storefront",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"description": "Storefront Usine à Boutiques (fork de nextjs-starter-medusa) — une image, une instance par boutique (BOUTIQUE=<slug>)",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"sync-design": "node scripts/sync-design.mjs",
|
|
8
|
+
"dev": "next dev -p 8000",
|
|
9
|
+
"build": "next build",
|
|
10
|
+
"start": "next start -p 8000",
|
|
11
|
+
"typecheck": "tsc --noEmit"
|
|
12
|
+
},
|
|
13
|
+
"engines": {
|
|
14
|
+
"node": ">=20.9.0"
|
|
15
|
+
},
|
|
16
|
+
"dependencies": {
|
|
17
|
+
"@headlessui/react": "2.2.10",
|
|
18
|
+
"@medusajs/icons": "2.21.2",
|
|
19
|
+
"@medusajs/js-sdk": "2.21.2",
|
|
20
|
+
"@medusajs/ui": "4.2.6",
|
|
21
|
+
"@radix-ui/react-accordion": "1.2.20",
|
|
22
|
+
"@stripe/react-stripe-js": "5.6.1",
|
|
23
|
+
"@stripe/stripe-js": "8.11.0",
|
|
24
|
+
"lodash": "4.18.1",
|
|
25
|
+
"next": "16.3.6",
|
|
26
|
+
"qs": "6.16.0",
|
|
27
|
+
"react": "19.3.0",
|
|
28
|
+
"react-dom": "19.3.0",
|
|
29
|
+
"server-only": "0.0.1",
|
|
30
|
+
"tailwindcss-radix": "2.9.0",
|
|
31
|
+
"zod": "4.6.5"
|
|
32
|
+
},
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"@medusajs/types": "2.21.2",
|
|
35
|
+
"@medusajs/ui-preset": "2.21.2",
|
|
36
|
+
"@types/lodash": "4.17.25",
|
|
37
|
+
"@types/node": "24.19.0",
|
|
38
|
+
"@types/react": "19.3.0",
|
|
39
|
+
"@types/react-dom": "19.3.0",
|
|
40
|
+
"autoprefixer": "10.6.1",
|
|
41
|
+
"postcss": "8.5.28",
|
|
42
|
+
"tailwindcss": "3.4.19",
|
|
43
|
+
"typescript": "5.9.3"
|
|
44
|
+
},
|
|
45
|
+
"overrides": {
|
|
46
|
+
"react": "19.3.0",
|
|
47
|
+
"react-dom": "19.3.0"
|
|
48
|
+
}
|
|
49
|
+
}
|
|
Binary file
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// Copie design/tokens.css et design/bundle.css dans le template (src/styles/ub/).
|
|
2
|
+
// À lancer dans le repo du générateur après une modification du design : `npm run sync-design`.
|
|
3
|
+
// Les fichiers copiés sont versionnés : un projet généré n'a pas de dossier design/.
|
|
4
|
+
// Seule transformation : l'@import Google Fonts est retiré (polices servies par next/font,
|
|
5
|
+
// pas d'appel à fonts.googleapis.com depuis le navigateur ni d'exception CSP).
|
|
6
|
+
import fs from "node:fs"
|
|
7
|
+
import path from "node:path"
|
|
8
|
+
import { fileURLToPath } from "node:url"
|
|
9
|
+
|
|
10
|
+
const here = path.dirname(fileURLToPath(import.meta.url))
|
|
11
|
+
const designDir = path.resolve(here, "../../../design")
|
|
12
|
+
const outDir = path.resolve(here, "../src/styles/ub")
|
|
13
|
+
|
|
14
|
+
if (!fs.existsSync(designDir)) {
|
|
15
|
+
console.error(`design/ introuvable (${designDir}) : à lancer depuis le repo usine-a-boutiques.`)
|
|
16
|
+
process.exit(1)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
fs.mkdirSync(outDir, { recursive: true })
|
|
20
|
+
|
|
21
|
+
const header = "/* COPIE de design/ par scripts/sync-design.mjs — ne pas modifier ici. */\n"
|
|
22
|
+
|
|
23
|
+
fs.writeFileSync(path.join(outDir, "tokens.css"), header + fs.readFileSync(path.join(designDir, "tokens.css"), "utf8"))
|
|
24
|
+
|
|
25
|
+
const bundle = fs
|
|
26
|
+
.readFileSync(path.join(designDir, "bundle.css"), "utf8")
|
|
27
|
+
.replace(/^@import url\("https:\/\/fonts\.googleapis\.com[^\n]*\n/m, "")
|
|
28
|
+
fs.writeFileSync(path.join(outDir, "bundle.css"), header + bundle)
|
|
29
|
+
|
|
30
|
+
console.log(`design synchronisé → ${path.relative(process.cwd(), outDir)}`)
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { t } from "@lib/boutique/i18n"
|
|
2
|
+
import { retrieveCart } from "@lib/data/cart"
|
|
3
|
+
import { retrieveCustomer } from "@lib/data/customer"
|
|
4
|
+
import PaymentWrapper from "@modules/checkout/components/payment-wrapper"
|
|
5
|
+
import CheckoutForm from "@modules/checkout/templates/checkout-form"
|
|
6
|
+
import CheckoutSummary from "@modules/checkout/templates/checkout-summary"
|
|
7
|
+
import { Metadata } from "next"
|
|
8
|
+
import { notFound } from "next/navigation"
|
|
9
|
+
|
|
10
|
+
export async function generateMetadata(): Promise<Metadata> {
|
|
11
|
+
return { title: t("checkout.title") }
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export default async function Checkout() {
|
|
15
|
+
const cart = await retrieveCart()
|
|
16
|
+
|
|
17
|
+
if (!cart) {
|
|
18
|
+
return notFound()
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const customer = await retrieveCustomer()
|
|
22
|
+
|
|
23
|
+
return (
|
|
24
|
+
<div className="grid grid-cols-1 small:grid-cols-[1fr_416px] content-container gap-x-40 py-12">
|
|
25
|
+
<PaymentWrapper cart={cart} stripeKey={process.env.STRIPE_PUBLISHABLE_KEY || undefined}>
|
|
26
|
+
<CheckoutForm cart={cart} customer={customer} />
|
|
27
|
+
</PaymentWrapper>
|
|
28
|
+
<CheckoutSummary cart={cart} />
|
|
29
|
+
</div>
|
|
30
|
+
)
|
|
31
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import Link from "next/link"
|
|
2
|
+
import { t } from "@lib/boutique/i18n"
|
|
3
|
+
import { Icon } from "@modules/ub/icons"
|
|
4
|
+
import { Logo } from "@modules/ub/nav"
|
|
5
|
+
|
|
6
|
+
export default function CheckoutLayout({ children }: { children: React.ReactNode }) {
|
|
7
|
+
return (
|
|
8
|
+
<div className="w-full relative small:min-h-screen">
|
|
9
|
+
<header className="ub-nav">
|
|
10
|
+
<div className="ub-wrap">
|
|
11
|
+
<Link href="/cart" className="ub-more" data-testid="back-to-cart-link">
|
|
12
|
+
<Icon name="arrowRight" style={{ transform: "rotate(180deg)" }} />
|
|
13
|
+
{t("checkout.back")}
|
|
14
|
+
</Link>
|
|
15
|
+
<Logo />
|
|
16
|
+
<span style={{ display: "inline-flex", alignItems: "center", gap: 6, fontSize: 13 }}>
|
|
17
|
+
<Icon name="lock" style={{ width: 16, height: 16 }} />
|
|
18
|
+
</span>
|
|
19
|
+
</div>
|
|
20
|
+
</header>
|
|
21
|
+
<div className="relative" data-testid="checkout-container">
|
|
22
|
+
{children}
|
|
23
|
+
</div>
|
|
24
|
+
<p className="ub-wrap" style={{ padding: "24px", fontSize: 13, textAlign: "center" }}>
|
|
25
|
+
{t("checkout.secure")}
|
|
26
|
+
</p>
|
|
27
|
+
</div>
|
|
28
|
+
)
|
|
29
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { T } from "@lib/boutique/i18n-client"
|
|
2
|
+
import InteractiveLink from "@modules/common/components/interactive-link"
|
|
3
|
+
import { Metadata } from "next"
|
|
4
|
+
|
|
5
|
+
export const metadata: Metadata = {
|
|
6
|
+
title: "404",
|
|
7
|
+
description: "Something went wrong",
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export default async function NotFound() {
|
|
11
|
+
return (
|
|
12
|
+
<div className="flex flex-col gap-4 items-center justify-center min-h-[calc(100vh-64px)]">
|
|
13
|
+
<h1 className="text-2xl-semi text-ui-fg-base"><T k="notFound.title" /></h1>
|
|
14
|
+
<p className="text-small-regular text-ui-fg-base">
|
|
15
|
+
<T k="notFound.text" />
|
|
16
|
+
</p>
|
|
17
|
+
<InteractiveLink href="/"><T k="notFound.cta" /></InteractiveLink>
|
|
18
|
+
</div>
|
|
19
|
+
)
|
|
20
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { T } from "@lib/boutique/i18n-client"
|
|
2
|
+
import { t } from "@lib/boutique/i18n"
|
|
3
|
+
import { Metadata } from "next"
|
|
4
|
+
import { notFound } from "next/navigation"
|
|
5
|
+
|
|
6
|
+
import AddressBook from "@modules/account/components/address-book"
|
|
7
|
+
|
|
8
|
+
import { getRegion } from "@lib/data/regions"
|
|
9
|
+
import { retrieveCustomer } from "@lib/data/customer"
|
|
10
|
+
|
|
11
|
+
export async function generateMetadata(): Promise<Metadata> {
|
|
12
|
+
return { title: t("account.addresses") }
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export default async function Addresses() {
|
|
16
|
+
const customer = await retrieveCustomer()
|
|
17
|
+
const region = await getRegion()
|
|
18
|
+
|
|
19
|
+
if (!customer || !region) {
|
|
20
|
+
notFound()
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return (
|
|
24
|
+
<div className="w-full" data-testid="addresses-page-wrapper">
|
|
25
|
+
<div className="mb-8 flex flex-col gap-y-4">
|
|
26
|
+
<h1 className="text-2xl-semi"><T k="account.shippingAddresses" /></h1>
|
|
27
|
+
<p className="text-base-regular">
|
|
28
|
+
<T k="account.addressesText" />
|
|
29
|
+
</p>
|
|
30
|
+
</div>
|
|
31
|
+
<AddressBook customer={customer} region={region} />
|
|
32
|
+
</div>
|
|
33
|
+
)
|
|
34
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { retrieveOrder } from "@lib/data/orders"
|
|
2
|
+
import OrderDetailsTemplate from "@modules/order/templates/order-details-template"
|
|
3
|
+
import { Metadata } from "next"
|
|
4
|
+
import { notFound } from "next/navigation"
|
|
5
|
+
|
|
6
|
+
type Props = {
|
|
7
|
+
params: Promise<{ id: string }>
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export async function generateMetadata(props: Props): Promise<Metadata> {
|
|
11
|
+
const params = await props.params
|
|
12
|
+
const order = await retrieveOrder(params.id).catch(() => null)
|
|
13
|
+
|
|
14
|
+
if (!order) {
|
|
15
|
+
notFound()
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return {
|
|
19
|
+
title: `Order #${order.display_id}`,
|
|
20
|
+
description: `View your order`,
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export default async function OrderDetailPage(props: Props) {
|
|
25
|
+
const params = await props.params
|
|
26
|
+
const order = await retrieveOrder(params.id).catch(() => null)
|
|
27
|
+
|
|
28
|
+
if (!order) {
|
|
29
|
+
notFound()
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return <OrderDetailsTemplate order={order} />
|
|
33
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { T } from "@lib/boutique/i18n-client"
|
|
2
|
+
import { t } from "@lib/boutique/i18n"
|
|
3
|
+
import { Metadata } from "next"
|
|
4
|
+
|
|
5
|
+
import OrderOverview from "@modules/account/components/order-overview"
|
|
6
|
+
import { notFound } from "next/navigation"
|
|
7
|
+
import { listOrders } from "@lib/data/orders"
|
|
8
|
+
import Divider from "@modules/common/components/divider"
|
|
9
|
+
import TransferRequestForm from "@modules/account/components/transfer-request-form"
|
|
10
|
+
|
|
11
|
+
export async function generateMetadata(): Promise<Metadata> {
|
|
12
|
+
return { title: t("account.orders") }
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export default async function Orders() {
|
|
16
|
+
const orders = await listOrders()
|
|
17
|
+
|
|
18
|
+
if (!orders) {
|
|
19
|
+
notFound()
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return (
|
|
23
|
+
<div className="w-full" data-testid="orders-page-wrapper">
|
|
24
|
+
<div className="mb-8 flex flex-col gap-y-4">
|
|
25
|
+
<h1 className="text-2xl-semi"><T k="account.orders" /></h1>
|
|
26
|
+
<p className="text-base-regular">
|
|
27
|
+
<T k="account.ordersText" />
|
|
28
|
+
</p>
|
|
29
|
+
</div>
|
|
30
|
+
<div>
|
|
31
|
+
<OrderOverview orders={orders} />
|
|
32
|
+
<Divider className="my-16" />
|
|
33
|
+
<TransferRequestForm />
|
|
34
|
+
</div>
|
|
35
|
+
</div>
|
|
36
|
+
)
|
|
37
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { t } from "@lib/boutique/i18n"
|
|
2
|
+
import { Metadata } from "next"
|
|
3
|
+
|
|
4
|
+
import Overview from "@modules/account/components/overview"
|
|
5
|
+
import { notFound } from "next/navigation"
|
|
6
|
+
import { retrieveCustomer } from "@lib/data/customer"
|
|
7
|
+
import { listOrders } from "@lib/data/orders"
|
|
8
|
+
|
|
9
|
+
export async function generateMetadata(): Promise<Metadata> {
|
|
10
|
+
return { title: t("account.title") }
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export default async function OverviewTemplate() {
|
|
14
|
+
const customer = await retrieveCustomer().catch(() => null)
|
|
15
|
+
const orders = (await listOrders().catch(() => null)) || null
|
|
16
|
+
|
|
17
|
+
if (!customer) {
|
|
18
|
+
notFound()
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return <Overview customer={customer} orders={orders} />
|
|
22
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { T } from "@lib/boutique/i18n-client"
|
|
2
|
+
import { t } from "@lib/boutique/i18n"
|
|
3
|
+
import { Metadata } from "next"
|
|
4
|
+
|
|
5
|
+
import ProfilePhone from "@modules/account//components/profile-phone"
|
|
6
|
+
import ProfileBillingAddress from "@modules/account/components/profile-billing-address"
|
|
7
|
+
import ProfileEmail from "@modules/account/components/profile-email"
|
|
8
|
+
import ProfileName from "@modules/account/components/profile-name"
|
|
9
|
+
import ProfilePassword from "@modules/account/components/profile-password"
|
|
10
|
+
|
|
11
|
+
import { notFound } from "next/navigation"
|
|
12
|
+
import { listRegions } from "@lib/data/regions"
|
|
13
|
+
import { retrieveCustomer } from "@lib/data/customer"
|
|
14
|
+
|
|
15
|
+
export async function generateMetadata(): Promise<Metadata> {
|
|
16
|
+
return { title: t("account.profile") }
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export default async function Profile() {
|
|
20
|
+
const customer = await retrieveCustomer()
|
|
21
|
+
const regions = await listRegions()
|
|
22
|
+
|
|
23
|
+
if (!customer || !regions) {
|
|
24
|
+
notFound()
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return (
|
|
28
|
+
<div className="w-full" data-testid="profile-page-wrapper">
|
|
29
|
+
<div className="mb-8 flex flex-col gap-y-4">
|
|
30
|
+
<h1 className="text-2xl-semi"><T k="account.profile" /></h1>
|
|
31
|
+
<p className="text-base-regular">
|
|
32
|
+
<T k="account.profileText" />
|
|
33
|
+
</p>
|
|
34
|
+
</div>
|
|
35
|
+
<div className="flex flex-col gap-y-8 w-full">
|
|
36
|
+
<ProfileName customer={customer} />
|
|
37
|
+
<Divider />
|
|
38
|
+
<ProfileEmail customer={customer} />
|
|
39
|
+
<Divider />
|
|
40
|
+
<ProfilePhone customer={customer} />
|
|
41
|
+
<Divider />
|
|
42
|
+
{/* <ProfilePassword customer={customer} />
|
|
43
|
+
<Divider /> */}
|
|
44
|
+
<ProfileBillingAddress customer={customer} regions={regions} />
|
|
45
|
+
</div>
|
|
46
|
+
</div>
|
|
47
|
+
)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const Divider = () => {
|
|
51
|
+
return <div className="w-full h-px bg-gray-200" />
|
|
52
|
+
}
|
|
53
|
+
;``
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { t } from "@lib/boutique/i18n"
|
|
2
|
+
import { Metadata } from "next"
|
|
3
|
+
|
|
4
|
+
import LoginTemplate from "@modules/account/templates/login-template"
|
|
5
|
+
|
|
6
|
+
export async function generateMetadata(): Promise<Metadata> {
|
|
7
|
+
return { title: t("account.signIn") }
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export default function Login() {
|
|
11
|
+
return <LoginTemplate />
|
|
12
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { retrieveCustomer } from "@lib/data/customer"
|
|
2
|
+
import { Toaster } from "@medusajs/ui"
|
|
3
|
+
import AccountLayout from "@modules/account/templates/account-layout"
|
|
4
|
+
|
|
5
|
+
export default async function AccountPageLayout({
|
|
6
|
+
dashboard,
|
|
7
|
+
login,
|
|
8
|
+
}: {
|
|
9
|
+
dashboard?: React.ReactNode
|
|
10
|
+
login?: React.ReactNode
|
|
11
|
+
}) {
|
|
12
|
+
const customer = await retrieveCustomer().catch(() => null)
|
|
13
|
+
|
|
14
|
+
return (
|
|
15
|
+
<AccountLayout customer={customer}>
|
|
16
|
+
{customer ? dashboard : login}
|
|
17
|
+
<Toaster />
|
|
18
|
+
</AccountLayout>
|
|
19
|
+
)
|
|
20
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { T } from "@lib/boutique/i18n-client"
|
|
2
|
+
import { Metadata } from "next"
|
|
3
|
+
|
|
4
|
+
import InteractiveLink from "@modules/common/components/interactive-link"
|
|
5
|
+
|
|
6
|
+
export const metadata: Metadata = {
|
|
7
|
+
title: "404",
|
|
8
|
+
description: "Something went wrong",
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export default function NotFound() {
|
|
12
|
+
return (
|
|
13
|
+
<div className="flex flex-col items-center justify-center min-h-[calc(100vh-64px)]">
|
|
14
|
+
<h1 className="text-2xl-semi text-ui-fg-base"><T k="notFound.title" /></h1>
|
|
15
|
+
<p className="text-small-regular text-ui-fg-base">
|
|
16
|
+
<T k="cart.notFound" />
|
|
17
|
+
</p>
|
|
18
|
+
<InteractiveLink href="/"><T k="notFound.cta" /></InteractiveLink>
|
|
19
|
+
</div>
|
|
20
|
+
)
|
|
21
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { t } from "@lib/boutique/i18n"
|
|
2
|
+
import { retrieveCart } from "@lib/data/cart"
|
|
3
|
+
import { retrieveCustomer } from "@lib/data/customer"
|
|
4
|
+
import CartTemplate from "@modules/cart/templates"
|
|
5
|
+
import { Metadata } from "next"
|
|
6
|
+
import { notFound } from "next/navigation"
|
|
7
|
+
|
|
8
|
+
export async function generateMetadata(): Promise<Metadata> {
|
|
9
|
+
return { title: t("cart.title") }
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export default async function Cart() {
|
|
13
|
+
const cart = await retrieveCart().catch((error) => {
|
|
14
|
+
console.error(error)
|
|
15
|
+
return notFound()
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
const customer = await retrieveCustomer()
|
|
19
|
+
|
|
20
|
+
return <CartTemplate cart={cart} customer={customer} />
|
|
21
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { Metadata } from "next"
|
|
2
|
+
import { notFound } from "next/navigation"
|
|
3
|
+
|
|
4
|
+
import { getCategoryByHandle } from "@lib/data/categories"
|
|
5
|
+
import CategoryTemplate from "@modules/categories/templates"
|
|
6
|
+
import { SortOptions } from "@modules/store/components/refinement-list/sort-products"
|
|
7
|
+
|
|
8
|
+
type Props = {
|
|
9
|
+
params: Promise<{ category: string[] }>
|
|
10
|
+
searchParams: Promise<{
|
|
11
|
+
sortBy?: SortOptions
|
|
12
|
+
page?: string
|
|
13
|
+
}>
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export async function generateMetadata(props: Props): Promise<Metadata> {
|
|
17
|
+
const params = await props.params
|
|
18
|
+
try {
|
|
19
|
+
const productCategory = await getCategoryByHandle(params.category)
|
|
20
|
+
|
|
21
|
+
const title = productCategory.name
|
|
22
|
+
|
|
23
|
+
const description = productCategory.description ?? `${title} category.`
|
|
24
|
+
|
|
25
|
+
return {
|
|
26
|
+
title,
|
|
27
|
+
description,
|
|
28
|
+
alternates: {
|
|
29
|
+
canonical: `${params.category.join("/")}`,
|
|
30
|
+
},
|
|
31
|
+
}
|
|
32
|
+
} catch (error) {
|
|
33
|
+
notFound()
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export default async function CategoryPage(props: Props) {
|
|
38
|
+
const searchParams = await props.searchParams
|
|
39
|
+
const params = await props.params
|
|
40
|
+
const { sortBy, page } = searchParams
|
|
41
|
+
|
|
42
|
+
const productCategory = await getCategoryByHandle(params.category)
|
|
43
|
+
|
|
44
|
+
if (!productCategory) {
|
|
45
|
+
notFound()
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return (
|
|
49
|
+
<CategoryTemplate
|
|
50
|
+
category={productCategory}
|
|
51
|
+
sortBy={sortBy}
|
|
52
|
+
page={page}
|
|
53
|
+
/>
|
|
54
|
+
)
|
|
55
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { Metadata } from "next"
|
|
2
|
+
import { notFound } from "next/navigation"
|
|
3
|
+
|
|
4
|
+
import { getCollectionByHandle } from "@lib/data/collections"
|
|
5
|
+
import { StoreCollection } from "@medusajs/types"
|
|
6
|
+
import CollectionTemplate from "@modules/collections/templates"
|
|
7
|
+
import { SortOptions } from "@modules/store/components/refinement-list/sort-products"
|
|
8
|
+
|
|
9
|
+
type Props = {
|
|
10
|
+
params: Promise<{ handle: string }>
|
|
11
|
+
searchParams: Promise<{
|
|
12
|
+
page?: string
|
|
13
|
+
sortBy?: SortOptions
|
|
14
|
+
}>
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export const PRODUCT_LIMIT = 12
|
|
18
|
+
|
|
19
|
+
export async function generateMetadata(props: Props): Promise<Metadata> {
|
|
20
|
+
const params = await props.params
|
|
21
|
+
const collection = await getCollectionByHandle(params.handle)
|
|
22
|
+
|
|
23
|
+
if (!collection) {
|
|
24
|
+
notFound()
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const metadata = {
|
|
28
|
+
title: collection.title,
|
|
29
|
+
description: `${collection.title} collection`,
|
|
30
|
+
} as Metadata
|
|
31
|
+
|
|
32
|
+
return metadata
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export default async function CollectionPage(props: Props) {
|
|
36
|
+
const searchParams = await props.searchParams
|
|
37
|
+
const params = await props.params
|
|
38
|
+
const { sortBy, page } = searchParams
|
|
39
|
+
|
|
40
|
+
const collection = await getCollectionByHandle(params.handle).then(
|
|
41
|
+
(collection: StoreCollection) => collection
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
if (!collection) {
|
|
45
|
+
notFound()
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return (
|
|
49
|
+
<CollectionTemplate
|
|
50
|
+
collection={collection}
|
|
51
|
+
page={page}
|
|
52
|
+
sortBy={sortBy}
|
|
53
|
+
/>
|
|
54
|
+
)
|
|
55
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { Suspense } from "react"
|
|
2
|
+
|
|
3
|
+
import { getCampaign } from "@lib/boutique/campaign"
|
|
4
|
+
import { listCartOptions, retrieveCart } from "@lib/data/cart"
|
|
5
|
+
import { retrieveCustomer } from "@lib/data/customer"
|
|
6
|
+
import { StoreCartShippingOption } from "@medusajs/types"
|
|
7
|
+
import CartMismatchBanner from "@modules/layout/components/cart-mismatch-banner"
|
|
8
|
+
import FreeShippingPriceNudge from "@modules/shipping/components/free-shipping-price-nudge"
|
|
9
|
+
import Footer from "@modules/ub/footer"
|
|
10
|
+
import Nav from "@modules/ub/nav"
|
|
11
|
+
import TopBar from "@modules/ub/top-bar"
|
|
12
|
+
|
|
13
|
+
async function CartNotices() {
|
|
14
|
+
const [customer, cart] = await Promise.all([retrieveCustomer(), retrieveCart()])
|
|
15
|
+
if (!cart) return null
|
|
16
|
+
|
|
17
|
+
let shippingOptions: StoreCartShippingOption[] = []
|
|
18
|
+
const { shipping_options } = await listCartOptions()
|
|
19
|
+
shippingOptions = shipping_options
|
|
20
|
+
|
|
21
|
+
return (
|
|
22
|
+
<>
|
|
23
|
+
{customer && <CartMismatchBanner customer={customer} cart={cart} />}
|
|
24
|
+
<FreeShippingPriceNudge variant="popup" cart={cart} shippingOptions={shippingOptions} />
|
|
25
|
+
</>
|
|
26
|
+
)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export default async function PageLayout(props: { children: React.ReactNode }) {
|
|
30
|
+
const campaign = await getCampaign()
|
|
31
|
+
|
|
32
|
+
return (
|
|
33
|
+
<>
|
|
34
|
+
<TopBar messages={campaign.topbar} />
|
|
35
|
+
<Nav />
|
|
36
|
+
<Suspense fallback={null}>
|
|
37
|
+
<CartNotices />
|
|
38
|
+
</Suspense>
|
|
39
|
+
{props.children}
|
|
40
|
+
<Footer />
|
|
41
|
+
</>
|
|
42
|
+
)
|
|
43
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { Metadata } from "next"
|
|
2
|
+
import { notFound } from "next/navigation"
|
|
3
|
+
import { getBoutique } from "@lib/boutique/config"
|
|
4
|
+
import { t } from "@lib/boutique/i18n"
|
|
5
|
+
|
|
6
|
+
const PAGES = ["shipping", "returns", "privacy", "terms", "contact"] as const
|
|
7
|
+
type Page = (typeof PAGES)[number]
|
|
8
|
+
|
|
9
|
+
type Props = { params: Promise<{ page: string }> }
|
|
10
|
+
|
|
11
|
+
const isPage = (p: string): p is Page => (PAGES as readonly string[]).includes(p)
|
|
12
|
+
|
|
13
|
+
export async function generateMetadata(props: Props): Promise<Metadata> {
|
|
14
|
+
const { page } = await props.params
|
|
15
|
+
return isPage(page) ? { title: t(`legal.${page}`) } : {}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export default async function LegalPage(props: Props) {
|
|
19
|
+
const { page } = await props.params
|
|
20
|
+
if (!isPage(page)) notFound()
|
|
21
|
+
|
|
22
|
+
const { storeName, merchantEmail } = getBoutique()
|
|
23
|
+
|
|
24
|
+
return (
|
|
25
|
+
<section className="ub-section">
|
|
26
|
+
<div className="ub-wrap" style={{ maxWidth: 760 }}>
|
|
27
|
+
<h1 className="ub-head" style={{ fontSize: 36, lineHeight: "44px", marginBottom: 24 }}>
|
|
28
|
+
{t(`legal.${page}`)}
|
|
29
|
+
</h1>
|
|
30
|
+
<p>{t(`legal.${page}.body`, { storeName })}</p>
|
|
31
|
+
{page === "contact" && merchantEmail && (
|
|
32
|
+
<p style={{ marginTop: 16 }}>
|
|
33
|
+
{t("legal.contact.email", { email: "" })}
|
|
34
|
+
<a href={`mailto:${merchantEmail}`} style={{ textDecoration: "underline" }}>
|
|
35
|
+
{merchantEmail}
|
|
36
|
+
</a>
|
|
37
|
+
</p>
|
|
38
|
+
)}
|
|
39
|
+
</div>
|
|
40
|
+
</section>
|
|
41
|
+
)
|
|
42
|
+
}
|