@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,118 @@
|
|
|
1
|
+
import { Suspense } from "react"
|
|
2
|
+
import { notFound } from "next/navigation"
|
|
3
|
+
import { HttpTypes } from "@medusajs/types"
|
|
4
|
+
|
|
5
|
+
import { t } from "@lib/boutique/i18n"
|
|
6
|
+
import { listProducts } from "@lib/data/products"
|
|
7
|
+
import { SectionHead } from "@modules/ub/campaign-blocks"
|
|
8
|
+
import { Icon, type IconName } from "@modules/ub/icons"
|
|
9
|
+
import BuyBox, { type BuyBoxLabels } from "@modules/ub/pdp/buy-box"
|
|
10
|
+
import Gallery from "@modules/ub/pdp/gallery"
|
|
11
|
+
import { ProductGrid } from "@modules/ub/product-card"
|
|
12
|
+
|
|
13
|
+
type ProductTemplateProps = {
|
|
14
|
+
product: HttpTypes.StoreProduct
|
|
15
|
+
region: HttpTypes.StoreRegion
|
|
16
|
+
images: HttpTypes.StoreProductImage[]
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function labels(): BuyBoxLabels {
|
|
20
|
+
return {
|
|
21
|
+
addToCart: t("pdp.addToCart"),
|
|
22
|
+
buyNow: t("pdp.buyNow"),
|
|
23
|
+
adding: t("pdp.adding"),
|
|
24
|
+
selectVariant: t("pdp.selectVariant"),
|
|
25
|
+
outOfStock: t("pdp.outOfStock"),
|
|
26
|
+
save: t("pdp.save"),
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** Prix et stock à jour (non mis en cache avec la page). */
|
|
31
|
+
async function LiveBuyBox({ product, region }: { product: HttpTypes.StoreProduct; region: HttpTypes.StoreRegion }) {
|
|
32
|
+
const live = await listProducts({ queryParams: { id: [product.id] }, regionId: region.id }).then(
|
|
33
|
+
({ response }) => response.products[0]
|
|
34
|
+
)
|
|
35
|
+
if (!live) return null
|
|
36
|
+
return <BuyBox product={live} labels={labels()} />
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
async function Related({ product }: { product: HttpTypes.StoreProduct }) {
|
|
40
|
+
const queryParams: HttpTypes.StoreProductListParams = { limit: 5, is_giftcard: false }
|
|
41
|
+
if (product.collection_id) queryParams.collection_id = [product.collection_id]
|
|
42
|
+
|
|
43
|
+
const products = await listProducts({ queryParams }).then(({ response }) =>
|
|
44
|
+
response.products.filter((p) => p.id !== product.id).slice(0, 4)
|
|
45
|
+
)
|
|
46
|
+
if (!products.length) return null
|
|
47
|
+
|
|
48
|
+
return (
|
|
49
|
+
<section className="ub-section" data-testid="related-products-container">
|
|
50
|
+
<div className="ub-wrap">
|
|
51
|
+
<SectionHead title={t("section.related")} href="/store" />
|
|
52
|
+
<ProductGrid products={products} />
|
|
53
|
+
</div>
|
|
54
|
+
</section>
|
|
55
|
+
)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const TRUST: [IconName, string][] = [
|
|
59
|
+
["lock", "pdp.trust.secure"],
|
|
60
|
+
["truck", "pdp.trust.fast"],
|
|
61
|
+
["returns", "pdp.trust.money"],
|
|
62
|
+
["shield", "pdp.trust.warranty"],
|
|
63
|
+
]
|
|
64
|
+
|
|
65
|
+
export default function ProductTemplate({ product, region, images }: ProductTemplateProps) {
|
|
66
|
+
if (!product?.id) notFound()
|
|
67
|
+
|
|
68
|
+
const gallery = images.filter((i) => !!i.url).map((i) => ({ id: i.id, url: i.url }))
|
|
69
|
+
if (!gallery.length && product.thumbnail) gallery.push({ id: "thumbnail", url: product.thumbnail })
|
|
70
|
+
|
|
71
|
+
return (
|
|
72
|
+
<>
|
|
73
|
+
<section className="ub-section" data-testid="product-container">
|
|
74
|
+
<div className="ub-wrap">
|
|
75
|
+
<div className="ub-pdp">
|
|
76
|
+
<Gallery images={gallery} alt={product.title ?? ""} />
|
|
77
|
+
<div className="ub-pdp__info">
|
|
78
|
+
<h1 className="ub-pdp__title ub-head" data-testid="product-title">
|
|
79
|
+
{product.title}
|
|
80
|
+
</h1>
|
|
81
|
+
{product.subtitle && <p className="ub-pdp__subtitle">{product.subtitle}</p>}
|
|
82
|
+
<Suspense fallback={<BuyBox product={product} labels={labels()} disabled />}>
|
|
83
|
+
<LiveBuyBox product={product} region={region} />
|
|
84
|
+
</Suspense>
|
|
85
|
+
{product.description && <p className="ub-pdp__desc">{product.description}</p>}
|
|
86
|
+
<ul className="ub-pdp__trust">
|
|
87
|
+
{TRUST.map(([icon, key]) => (
|
|
88
|
+
<li key={key}>
|
|
89
|
+
<Icon name={icon} />
|
|
90
|
+
{t(key)}
|
|
91
|
+
</li>
|
|
92
|
+
))}
|
|
93
|
+
</ul>
|
|
94
|
+
</div>
|
|
95
|
+
</div>
|
|
96
|
+
</div>
|
|
97
|
+
</section>
|
|
98
|
+
|
|
99
|
+
<section className="ub-section" style={{ paddingTop: 0 }}>
|
|
100
|
+
<div className="ub-wrap">
|
|
101
|
+
<SectionHead title={t("pdp.faq")} />
|
|
102
|
+
<div className="ub-faq">
|
|
103
|
+
{[1, 2, 3].map((n) => (
|
|
104
|
+
<details key={n} open={n === 1}>
|
|
105
|
+
<summary>{t(`pdp.faq.q${n}`)}</summary>
|
|
106
|
+
<p>{t(`pdp.faq.a${n}`)}</p>
|
|
107
|
+
</details>
|
|
108
|
+
))}
|
|
109
|
+
</div>
|
|
110
|
+
</div>
|
|
111
|
+
</section>
|
|
112
|
+
|
|
113
|
+
<Suspense fallback={null}>
|
|
114
|
+
<Related product={product} />
|
|
115
|
+
</Suspense>
|
|
116
|
+
</>
|
|
117
|
+
)
|
|
118
|
+
}
|
package/templates/storefront/src/modules/shipping/components/free-shipping-price-nudge/index.tsx
ADDED
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
import { T } from "@lib/boutique/i18n-client"
|
|
5
|
+
import { convertToLocale } from "@lib/util/money"
|
|
6
|
+
import { CheckCircleSolid, XMark } from "@medusajs/icons"
|
|
7
|
+
import {
|
|
8
|
+
HttpTypes,
|
|
9
|
+
StoreCart,
|
|
10
|
+
StoreCartShippingOption,
|
|
11
|
+
StorePrice,
|
|
12
|
+
} from "@medusajs/types"
|
|
13
|
+
import { Button, clx } from "@medusajs/ui"
|
|
14
|
+
import LocalizedClientLink from "@modules/common/components/localized-client-link"
|
|
15
|
+
import { useState } from "react"
|
|
16
|
+
import { StoreFreeShippingPrice } from "types/global"
|
|
17
|
+
|
|
18
|
+
const computeTarget = (
|
|
19
|
+
cart: HttpTypes.StoreCart,
|
|
20
|
+
price: HttpTypes.StorePrice
|
|
21
|
+
) => {
|
|
22
|
+
const priceRule = (price.price_rules || []).find(
|
|
23
|
+
(pr) => pr.attribute === "item_total"
|
|
24
|
+
)!
|
|
25
|
+
|
|
26
|
+
const currentAmount = cart.item_total
|
|
27
|
+
const targetAmount = parseFloat(priceRule.value)
|
|
28
|
+
|
|
29
|
+
if (priceRule.operator === "gt") {
|
|
30
|
+
return {
|
|
31
|
+
current_amount: currentAmount,
|
|
32
|
+
target_amount: targetAmount,
|
|
33
|
+
target_reached: currentAmount > targetAmount,
|
|
34
|
+
target_remaining:
|
|
35
|
+
currentAmount > targetAmount ? 0 : targetAmount + 1 - currentAmount,
|
|
36
|
+
remaining_percentage: (currentAmount / targetAmount) * 100,
|
|
37
|
+
}
|
|
38
|
+
} else if (priceRule.operator === "gte") {
|
|
39
|
+
return {
|
|
40
|
+
current_amount: currentAmount,
|
|
41
|
+
target_amount: targetAmount,
|
|
42
|
+
target_reached: currentAmount > targetAmount,
|
|
43
|
+
target_remaining:
|
|
44
|
+
currentAmount > targetAmount ? 0 : targetAmount - currentAmount,
|
|
45
|
+
remaining_percentage: (currentAmount / targetAmount) * 100,
|
|
46
|
+
}
|
|
47
|
+
} else if (priceRule.operator === "lt") {
|
|
48
|
+
return {
|
|
49
|
+
current_amount: currentAmount,
|
|
50
|
+
target_amount: targetAmount,
|
|
51
|
+
target_reached: targetAmount > currentAmount,
|
|
52
|
+
target_remaining:
|
|
53
|
+
targetAmount > currentAmount ? 0 : currentAmount + 1 - targetAmount,
|
|
54
|
+
remaining_percentage: (currentAmount / targetAmount) * 100,
|
|
55
|
+
}
|
|
56
|
+
} else if (priceRule.operator === "lte") {
|
|
57
|
+
return {
|
|
58
|
+
current_amount: currentAmount,
|
|
59
|
+
target_amount: targetAmount,
|
|
60
|
+
target_reached: targetAmount > currentAmount,
|
|
61
|
+
target_remaining:
|
|
62
|
+
targetAmount > currentAmount ? 0 : currentAmount - targetAmount,
|
|
63
|
+
remaining_percentage: (currentAmount / targetAmount) * 100,
|
|
64
|
+
}
|
|
65
|
+
} else {
|
|
66
|
+
return {
|
|
67
|
+
current_amount: currentAmount,
|
|
68
|
+
target_amount: targetAmount,
|
|
69
|
+
target_reached: currentAmount === targetAmount,
|
|
70
|
+
target_remaining:
|
|
71
|
+
targetAmount > currentAmount ? 0 : targetAmount - currentAmount,
|
|
72
|
+
remaining_percentage: (currentAmount / targetAmount) * 100,
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export default function ShippingPriceNudge({
|
|
78
|
+
variant = "inline",
|
|
79
|
+
cart,
|
|
80
|
+
shippingOptions,
|
|
81
|
+
}: {
|
|
82
|
+
variant?: "popup" | "inline"
|
|
83
|
+
cart: StoreCart
|
|
84
|
+
shippingOptions: StoreCartShippingOption[]
|
|
85
|
+
}) {
|
|
86
|
+
if (!cart || !shippingOptions?.length) {
|
|
87
|
+
return
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Check if any shipping options have a conditional price based on item_total
|
|
91
|
+
const freeShippingPrice = shippingOptions
|
|
92
|
+
.map((shippingOption) => {
|
|
93
|
+
const calculatedPrice = shippingOption.calculated_price
|
|
94
|
+
|
|
95
|
+
if (!calculatedPrice) {
|
|
96
|
+
return
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Get all prices that are:
|
|
100
|
+
// 1. Currency code is same as the cart's
|
|
101
|
+
// 2. Have a rule that is set on item_total
|
|
102
|
+
const validCurrencyPrices = shippingOption.prices.filter(
|
|
103
|
+
(price) =>
|
|
104
|
+
price.currency_code === cart.currency_code &&
|
|
105
|
+
(price.price_rules || []).some(
|
|
106
|
+
(priceRule) => priceRule.attribute === "item_total"
|
|
107
|
+
)
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
return validCurrencyPrices.map((price) => {
|
|
111
|
+
return {
|
|
112
|
+
...price,
|
|
113
|
+
shipping_option_id: shippingOption.id,
|
|
114
|
+
...computeTarget(cart, price),
|
|
115
|
+
}
|
|
116
|
+
})
|
|
117
|
+
})
|
|
118
|
+
.flat(1)
|
|
119
|
+
.filter(Boolean)
|
|
120
|
+
// We focus here entirely on free shipping, but this can be edited to handle multiple layers
|
|
121
|
+
// of reduced shipping prices.
|
|
122
|
+
.find((price) => price?.amount === 0)
|
|
123
|
+
|
|
124
|
+
if (!freeShippingPrice) {
|
|
125
|
+
return
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if (variant === "popup") {
|
|
129
|
+
return <FreeShippingPopup cart={cart} price={freeShippingPrice} />
|
|
130
|
+
} else {
|
|
131
|
+
return <FreeShippingInline cart={cart} price={freeShippingPrice} />
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function FreeShippingInline({
|
|
136
|
+
cart,
|
|
137
|
+
price,
|
|
138
|
+
}: {
|
|
139
|
+
cart: StoreCart
|
|
140
|
+
price: StorePrice & {
|
|
141
|
+
target_reached: boolean
|
|
142
|
+
target_remaining: number
|
|
143
|
+
remaining_percentage: number
|
|
144
|
+
}
|
|
145
|
+
}) {
|
|
146
|
+
return (
|
|
147
|
+
<div className="bg-neutral-100 p-2 rounded-lg border">
|
|
148
|
+
<div className="space-y-1.5">
|
|
149
|
+
<div className="flex justify-between text-xs text-neutral-600">
|
|
150
|
+
<div>
|
|
151
|
+
{price.target_reached ? (
|
|
152
|
+
<div className="flex items-center gap-1.5">
|
|
153
|
+
<CheckCircleSolid className="text-green-500 inline-block" />{" "}
|
|
154
|
+
<T k="cart.freeShippingUnlocked" />
|
|
155
|
+
</div>
|
|
156
|
+
) : (
|
|
157
|
+
`Unlock Free Shipping`
|
|
158
|
+
)}
|
|
159
|
+
</div>
|
|
160
|
+
|
|
161
|
+
<div
|
|
162
|
+
className={clx("visible", {
|
|
163
|
+
"opacity-0 invisible": price.target_reached,
|
|
164
|
+
})}
|
|
165
|
+
>
|
|
166
|
+
Only{" "}
|
|
167
|
+
<span className="text-neutral-950">
|
|
168
|
+
{convertToLocale({
|
|
169
|
+
amount: price.target_remaining,
|
|
170
|
+
currency_code: cart.currency_code,
|
|
171
|
+
})}
|
|
172
|
+
</span>{" "}
|
|
173
|
+
away
|
|
174
|
+
</div>
|
|
175
|
+
</div>
|
|
176
|
+
<div className="flex justify-between gap-1">
|
|
177
|
+
<div
|
|
178
|
+
className={clx(
|
|
179
|
+
"bg-gradient-to-r from-zinc-400 to-zinc-500 h-1 rounded-full max-w-full duration-500 ease-in-out",
|
|
180
|
+
{
|
|
181
|
+
"from-green-400 to-green-500": price.target_reached,
|
|
182
|
+
}
|
|
183
|
+
)}
|
|
184
|
+
style={{ width: `${price.remaining_percentage}%` }}
|
|
185
|
+
></div>
|
|
186
|
+
<div className="bg-neutral-300 h-1 rounded-full w-fit flex-grow"></div>
|
|
187
|
+
</div>
|
|
188
|
+
</div>
|
|
189
|
+
</div>
|
|
190
|
+
)
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
function FreeShippingPopup({
|
|
194
|
+
cart,
|
|
195
|
+
price,
|
|
196
|
+
}: {
|
|
197
|
+
cart: StoreCart
|
|
198
|
+
price: StoreFreeShippingPrice
|
|
199
|
+
}) {
|
|
200
|
+
const [isClosed, setIsClosed] = useState(false)
|
|
201
|
+
|
|
202
|
+
return (
|
|
203
|
+
<div
|
|
204
|
+
className={clx(
|
|
205
|
+
"fixed bottom-5 right-5 flex flex-col items-end gap-2 transition-all duration-500 ease-in-out z-10",
|
|
206
|
+
{
|
|
207
|
+
"opacity-0 invisible delay-1000": price.target_reached,
|
|
208
|
+
"opacity-0 invisible": isClosed,
|
|
209
|
+
"opacity-100 visible": !price.target_reached && !isClosed,
|
|
210
|
+
}
|
|
211
|
+
)}
|
|
212
|
+
>
|
|
213
|
+
<div>
|
|
214
|
+
<Button
|
|
215
|
+
className="rounded-full bg-neutral-900 shadow-none outline-none border-none text-[15px] p-2"
|
|
216
|
+
onClick={() => setIsClosed(true)}
|
|
217
|
+
>
|
|
218
|
+
<XMark />
|
|
219
|
+
</Button>
|
|
220
|
+
</div>
|
|
221
|
+
|
|
222
|
+
<div className="w-[400px] bg-[var(--ink)] text-[var(--bg)] p-6 rounded-lg ">
|
|
223
|
+
<div className="pb-4">
|
|
224
|
+
<div className="space-y-3">
|
|
225
|
+
<div className="flex justify-between text-[15px] text-neutral-400">
|
|
226
|
+
<div>
|
|
227
|
+
{price.target_reached ? (
|
|
228
|
+
<div className="flex items-center gap-1.5">
|
|
229
|
+
<CheckCircleSolid className="text-green-500 inline-block" />{" "}
|
|
230
|
+
<T k="cart.freeShippingUnlocked" />
|
|
231
|
+
</div>
|
|
232
|
+
) : (
|
|
233
|
+
`Unlock Free Shipping`
|
|
234
|
+
)}
|
|
235
|
+
</div>
|
|
236
|
+
|
|
237
|
+
<div
|
|
238
|
+
className={clx("visible", {
|
|
239
|
+
"opacity-0 invisible": price.target_reached,
|
|
240
|
+
})}
|
|
241
|
+
>
|
|
242
|
+
Only{" "}
|
|
243
|
+
<span className="text-white">
|
|
244
|
+
{convertToLocale({
|
|
245
|
+
amount: price.target_remaining,
|
|
246
|
+
currency_code: cart.currency_code,
|
|
247
|
+
})}
|
|
248
|
+
</span>{" "}
|
|
249
|
+
away
|
|
250
|
+
</div>
|
|
251
|
+
</div>
|
|
252
|
+
<div className="flex justify-between gap-1">
|
|
253
|
+
<div
|
|
254
|
+
className={clx(
|
|
255
|
+
"bg-gradient-to-r from-zinc-400 to-zinc-500 h-1.5 rounded-full max-w-full duration-500 ease-in-out",
|
|
256
|
+
{
|
|
257
|
+
"from-green-400 to-green-500": price.target_reached,
|
|
258
|
+
}
|
|
259
|
+
)}
|
|
260
|
+
style={{ width: `${price.remaining_percentage}%` }}
|
|
261
|
+
></div>
|
|
262
|
+
<div className="bg-zinc-600 h-1.5 rounded-full w-fit flex-grow"></div>
|
|
263
|
+
</div>
|
|
264
|
+
</div>
|
|
265
|
+
</div>
|
|
266
|
+
|
|
267
|
+
<div className="flex gap-3">
|
|
268
|
+
<LocalizedClientLink
|
|
269
|
+
className="rounded-2xl bg-transparent shadow-none outline-none border-[1px] border-white text-[15px] py-2.5 px-4"
|
|
270
|
+
href="/cart"
|
|
271
|
+
>
|
|
272
|
+
<T k="cart.viewCart" />
|
|
273
|
+
</LocalizedClientLink>
|
|
274
|
+
|
|
275
|
+
<LocalizedClientLink
|
|
276
|
+
className="flex-grow rounded-2xl bg-white text-neutral-950 shadow-none outline-none border-[1px] border-white text-[15px] py-2.5 px-4 text-center"
|
|
277
|
+
href="/store"
|
|
278
|
+
>
|
|
279
|
+
<T k="cart.viewProducts" />
|
|
280
|
+
</LocalizedClientLink>
|
|
281
|
+
</div>
|
|
282
|
+
</div>
|
|
283
|
+
</div>
|
|
284
|
+
)
|
|
285
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
const SkeletonCardDetails = () => {
|
|
2
|
+
return (
|
|
3
|
+
<div className="flex flex-col gap-1 my-4 transition-all duration-150 ease-in-out">
|
|
4
|
+
<div className="h-4 bg-ui-bg-component-pressed rounded-md w-1/4 animate-pulse mb-1"></div>
|
|
5
|
+
<div className="pt-3 pb-1 block w-full h-11 px-4 mt-0 bg-ui-bg-field border rounded-md appearance-none border-ui-border-base animate-pulse" />
|
|
6
|
+
</div>
|
|
7
|
+
)
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export default SkeletonCardDetails
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { Table } from "@medusajs/ui"
|
|
2
|
+
|
|
3
|
+
const SkeletonCartItem = () => {
|
|
4
|
+
return (
|
|
5
|
+
<Table.Row className="w-full m-4">
|
|
6
|
+
<Table.Cell className="!pl-0 p-4 w-24">
|
|
7
|
+
<div className="flex w-24 h-24 p-4 bg-gray-200 rounded-large animate-pulse" />
|
|
8
|
+
</Table.Cell>
|
|
9
|
+
<Table.Cell className="text-left">
|
|
10
|
+
<div className="flex flex-col gap-y-2">
|
|
11
|
+
<div className="w-32 h-4 bg-gray-200 animate-pulse" />
|
|
12
|
+
<div className="w-24 h-4 bg-gray-200 animate-pulse" />
|
|
13
|
+
</div>
|
|
14
|
+
</Table.Cell>
|
|
15
|
+
<Table.Cell>
|
|
16
|
+
<div className="flex gap-2 items-center">
|
|
17
|
+
<div className="w-6 h-8 bg-gray-200 animate-pulse" />
|
|
18
|
+
<div className="w-14 h-10 bg-gray-200 animate-pulse" />
|
|
19
|
+
</div>
|
|
20
|
+
</Table.Cell>
|
|
21
|
+
<Table.Cell>
|
|
22
|
+
<div className="flex gap-2">
|
|
23
|
+
<div className="w-12 h-6 bg-gray-200 animate-pulse" />
|
|
24
|
+
</div>
|
|
25
|
+
</Table.Cell>
|
|
26
|
+
<Table.Cell className="!pr-0 text-right">
|
|
27
|
+
<div className="flex gap-2 justify-end">
|
|
28
|
+
<div className="w-12 h-6 bg-gray-200 animate-pulse" />
|
|
29
|
+
</div>
|
|
30
|
+
</Table.Cell>
|
|
31
|
+
</Table.Row>
|
|
32
|
+
)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export default SkeletonCartItem
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
const SkeletonCartTotals = ({ header = true }) => {
|
|
2
|
+
return (
|
|
3
|
+
<div className="flex flex-col">
|
|
4
|
+
{header && <div className="w-32 h-4 bg-gray-100 mb-4"></div>}
|
|
5
|
+
<div className="flex items-center justify-between">
|
|
6
|
+
<div className="w-32 h-3 bg-gray-100"></div>
|
|
7
|
+
<div className="w-32 h-3 bg-gray-100"></div>
|
|
8
|
+
</div>
|
|
9
|
+
|
|
10
|
+
<div className="flex items-center justify-between my-4">
|
|
11
|
+
<div className="w-24 h-3 bg-gray-100"></div>
|
|
12
|
+
<div className="w-24 h-3 bg-gray-100"></div>
|
|
13
|
+
</div>
|
|
14
|
+
|
|
15
|
+
<div className="flex items-center justify-between">
|
|
16
|
+
<div className="w-28 h-3 bg-gray-100 "></div>
|
|
17
|
+
<div className="w-20 h-3 bg-gray-100"></div>
|
|
18
|
+
</div>
|
|
19
|
+
|
|
20
|
+
<div className="w-full border-b border-gray-200 border-dashed my-4"></div>
|
|
21
|
+
|
|
22
|
+
<div className="flex items-center justify-between">
|
|
23
|
+
<div className="w-32 h-6 bg-gray-100 mb-4"></div>
|
|
24
|
+
<div className="w-24 h-6 bg-gray-100 mb-4"></div>
|
|
25
|
+
</div>
|
|
26
|
+
</div>
|
|
27
|
+
)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export default SkeletonCartTotals
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
const SkeletonCodeForm = () => {
|
|
2
|
+
return (
|
|
3
|
+
<div className="w-full flex flex-col">
|
|
4
|
+
<div className="bg-gray-100 h-7 w-24 mb-4"></div>
|
|
5
|
+
<div className="grid grid-cols-[1fr_80px] gap-x-2">
|
|
6
|
+
<div className="bg-gray-100 h-12"></div>
|
|
7
|
+
<div className="bg-gray-100 h-12"></div>
|
|
8
|
+
</div>
|
|
9
|
+
</div>
|
|
10
|
+
)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export default SkeletonCodeForm
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { Table } from "@medusajs/ui"
|
|
2
|
+
|
|
3
|
+
const SkeletonLineItem = () => {
|
|
4
|
+
return (
|
|
5
|
+
<Table.Row className="w-full m-4">
|
|
6
|
+
<Table.Cell className="p-4 w-24">
|
|
7
|
+
<div className="flex w-24 h-24 p-4 bg-gray-200 animate-pulse" />
|
|
8
|
+
</Table.Cell>
|
|
9
|
+
<Table.Cell className="text-left">
|
|
10
|
+
<div className="flex flex-col gap-y-2">
|
|
11
|
+
<div className="w-32 h-4 bg-gray-200 animate-pulse" />
|
|
12
|
+
<div className="w-24 h-4 bg-gray-200 animate-pulse" />
|
|
13
|
+
</div>
|
|
14
|
+
</Table.Cell>
|
|
15
|
+
<Table.Cell>
|
|
16
|
+
<div className="flex gap-2 items-center">
|
|
17
|
+
<div className="w-6 h-8 bg-gray-200 animate-pulse" />
|
|
18
|
+
<div className="w-14 h-10 bg-gray-200 animate-pulse" />
|
|
19
|
+
</div>
|
|
20
|
+
</Table.Cell>
|
|
21
|
+
<Table.Cell>
|
|
22
|
+
<div className="flex gap-2">
|
|
23
|
+
<div className="w-12 h-6 bg-gray-200 animate-pulse" />
|
|
24
|
+
</div>
|
|
25
|
+
</Table.Cell>
|
|
26
|
+
<Table.Cell>
|
|
27
|
+
<div className="flex gap-2 justify-end">
|
|
28
|
+
<div className="w-12 h-6 bg-gray-200 animate-pulse" />
|
|
29
|
+
</div>
|
|
30
|
+
</Table.Cell>
|
|
31
|
+
</Table.Row>
|
|
32
|
+
)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export default SkeletonLineItem
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
const SkeletonOrderConfirmedHeader = () => {
|
|
2
|
+
return (
|
|
3
|
+
<div className="flex flex-col gap-y-2 pb-10 animate-pulse">
|
|
4
|
+
<div className="w-2/5 h-4 bg-gray-100"></div>
|
|
5
|
+
<div className="w-3/6 h-6 bg-gray-100"></div>
|
|
6
|
+
<div className="flex gap-x-4">
|
|
7
|
+
<div className="w-16 h-4 bg-gray-100"></div>
|
|
8
|
+
<div className="w-12 h-4 bg-gray-100"></div>
|
|
9
|
+
</div>
|
|
10
|
+
</div>
|
|
11
|
+
)
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export default SkeletonOrderConfirmedHeader
|
package/templates/storefront/src/modules/skeletons/components/skeleton-order-information/index.tsx
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import SkeletonCartTotals from "@modules/skeletons/components/skeleton-cart-totals"
|
|
2
|
+
|
|
3
|
+
const SkeletonOrderInformation = () => {
|
|
4
|
+
return (
|
|
5
|
+
<div>
|
|
6
|
+
<div className="grid grid-cols-1 lg:grid-cols-2 gap-4 py-10 border-b border-gray-200">
|
|
7
|
+
<div className="flex flex-col">
|
|
8
|
+
<div className="w-32 h-4 bg-gray-100 mb-4"></div>
|
|
9
|
+
<div className="w-2/6 h-3 bg-gray-100"></div>
|
|
10
|
+
<div className="w-3/6 h-3 bg-gray-100 my-2"></div>
|
|
11
|
+
<div className="w-1/6 h-3 bg-gray-100"></div>
|
|
12
|
+
</div>
|
|
13
|
+
<div className="flex flex-col">
|
|
14
|
+
<div className="w-32 h-4 bg-gray-100 mb-4"></div>
|
|
15
|
+
<div className="w-2/6 h-3 bg-gray-100"></div>
|
|
16
|
+
<div className="w-3/6 h-3 bg-gray-100 my-2"></div>
|
|
17
|
+
<div className="w-2/6 h-3 bg-gray-100"></div>
|
|
18
|
+
<div className="w-1/6 h-3 bg-gray-100 mt-2"></div>
|
|
19
|
+
<div className="w-32 h-4 bg-gray-100 my-4"></div>
|
|
20
|
+
<div className="w-1/6 h-3 bg-gray-100"></div>
|
|
21
|
+
</div>
|
|
22
|
+
</div>
|
|
23
|
+
<div className="grid grid-cols-1 lg:grid-cols-2 gap-4 py-10">
|
|
24
|
+
<div className="flex flex-col">
|
|
25
|
+
<div className="w-32 h-4 bg-gray-100 mb-4"></div>
|
|
26
|
+
<div className="w-2/6 h-3 bg-gray-100"></div>
|
|
27
|
+
<div className="w-3/6 h-3 bg-gray-100 my-4"></div>
|
|
28
|
+
</div>
|
|
29
|
+
|
|
30
|
+
<SkeletonCartTotals />
|
|
31
|
+
</div>
|
|
32
|
+
</div>
|
|
33
|
+
)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export default SkeletonOrderInformation
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
const SkeletonOrderItems = () => {
|
|
2
|
+
return (
|
|
3
|
+
<div className="flex flex-col gap-y-4 py-10 border-y border-gray-200">
|
|
4
|
+
<div className="grid grid-cols-[122px_1fr] gap-x-4">
|
|
5
|
+
<div className="w-full aspect-[29/34] bg-gray-100"></div>
|
|
6
|
+
<div className="flex items-start justify-between">
|
|
7
|
+
<div className="flex flex-col gap-y-2">
|
|
8
|
+
<div className="w-48 h-6 bg-gray-100"></div>
|
|
9
|
+
<div className="w-24 h-4 bg-gray-100"></div>
|
|
10
|
+
<div className="w-32 h-4 bg-gray-100"></div>
|
|
11
|
+
</div>
|
|
12
|
+
<div className="w-32 h-6 bg-gray-100"></div>
|
|
13
|
+
</div>
|
|
14
|
+
</div>
|
|
15
|
+
|
|
16
|
+
<div className="grid grid-cols-[122px_1fr] gap-x-4">
|
|
17
|
+
<div className="w-full aspect-[29/34] bg-gray-100"></div>
|
|
18
|
+
<div className="flex items-start justify-between">
|
|
19
|
+
<div className="flex flex-col gap-y-2">
|
|
20
|
+
<div className="w-48 h-6 bg-gray-100"></div>
|
|
21
|
+
<div className="w-24 h-4 bg-gray-100"></div>
|
|
22
|
+
<div className="w-32 h-4 bg-gray-100"></div>
|
|
23
|
+
</div>
|
|
24
|
+
<div className="w-32 h-6 bg-gray-100"></div>
|
|
25
|
+
</div>
|
|
26
|
+
</div>
|
|
27
|
+
|
|
28
|
+
<div className="grid grid-cols-[122px_1fr] gap-x-4">
|
|
29
|
+
<div className="w-full aspect-[29/34] bg-gray-100"></div>
|
|
30
|
+
<div className="flex items-start justify-between">
|
|
31
|
+
<div className="flex flex-col gap-y-2">
|
|
32
|
+
<div className="w-48 h-6 bg-gray-100"></div>
|
|
33
|
+
<div className="w-24 h-4 bg-gray-100"></div>
|
|
34
|
+
<div className="w-32 h-4 bg-gray-100"></div>
|
|
35
|
+
</div>
|
|
36
|
+
<div className="w-32 h-6 bg-gray-100"></div>
|
|
37
|
+
</div>
|
|
38
|
+
</div>
|
|
39
|
+
</div>
|
|
40
|
+
)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export default SkeletonOrderItems
|
package/templates/storefront/src/modules/skeletons/components/skeleton-order-summary/index.tsx
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import SkeletonButton from "@modules/skeletons/components/skeleton-button"
|
|
2
|
+
import SkeletonCartTotals from "@modules/skeletons/components/skeleton-cart-totals"
|
|
3
|
+
|
|
4
|
+
const SkeletonOrderSummary = () => {
|
|
5
|
+
return (
|
|
6
|
+
<div className="grid-cols-1">
|
|
7
|
+
<SkeletonCartTotals header={false} />
|
|
8
|
+
<div className="mt-4">
|
|
9
|
+
<SkeletonButton />
|
|
10
|
+
</div>
|
|
11
|
+
</div>
|
|
12
|
+
)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export default SkeletonOrderSummary
|
package/templates/storefront/src/modules/skeletons/components/skeleton-product-preview/index.tsx
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Container } from "@medusajs/ui"
|
|
2
|
+
|
|
3
|
+
const SkeletonProductPreview = () => {
|
|
4
|
+
return (
|
|
5
|
+
<div className="animate-pulse">
|
|
6
|
+
<Container className="aspect-[9/16] w-full bg-gray-100 bg-ui-bg-subtle" />
|
|
7
|
+
<div className="flex justify-between text-base-regular mt-2">
|
|
8
|
+
<div className="w-2/5 h-6 bg-gray-100"></div>
|
|
9
|
+
<div className="w-1/5 h-6 bg-gray-100"></div>
|
|
10
|
+
</div>
|
|
11
|
+
</div>
|
|
12
|
+
)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export default SkeletonProductPreview
|