@doswiftly/cli 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 +357 -0
- package/bin/doswiftly.js +2 -0
- package/dist/commands/auth-github.d.ts +6 -0
- package/dist/commands/auth-github.d.ts.map +1 -0
- package/dist/commands/auth-github.js +89 -0
- package/dist/commands/auth-github.js.map +1 -0
- package/dist/commands/auth-token.d.ts +12 -0
- package/dist/commands/auth-token.d.ts.map +1 -0
- package/dist/commands/auth-token.js +43 -0
- package/dist/commands/auth-token.js.map +1 -0
- package/dist/commands/auth.d.ts +22 -0
- package/dist/commands/auth.d.ts.map +1 -0
- package/dist/commands/auth.js +348 -0
- package/dist/commands/auth.js.map +1 -0
- package/dist/commands/check.d.ts +5 -0
- package/dist/commands/check.d.ts.map +1 -0
- package/dist/commands/check.js +234 -0
- package/dist/commands/check.js.map +1 -0
- package/dist/commands/config.d.ts +3 -0
- package/dist/commands/config.d.ts.map +1 -0
- package/dist/commands/config.js +104 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/deploy.d.ts +37 -0
- package/dist/commands/deploy.d.ts.map +1 -0
- package/dist/commands/deploy.js +580 -0
- package/dist/commands/deploy.js.map +1 -0
- package/dist/commands/dev.d.ts +8 -0
- package/dist/commands/dev.d.ts.map +1 -0
- package/dist/commands/dev.js +83 -0
- package/dist/commands/dev.js.map +1 -0
- package/dist/commands/doctor.d.ts +5 -0
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/commands/doctor.js +363 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/domain.d.ts +13 -0
- package/dist/commands/domain.d.ts.map +1 -0
- package/dist/commands/domain.js +128 -0
- package/dist/commands/domain.js.map +1 -0
- package/dist/commands/env.d.ts +25 -0
- package/dist/commands/env.d.ts.map +1 -0
- package/dist/commands/env.js +228 -0
- package/dist/commands/env.js.map +1 -0
- package/dist/commands/init.d.ts +11 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +1028 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/inspect.d.ts +12 -0
- package/dist/commands/inspect.d.ts.map +1 -0
- package/dist/commands/inspect.js +162 -0
- package/dist/commands/inspect.js.map +1 -0
- package/dist/commands/migrate.d.ts +18 -0
- package/dist/commands/migrate.d.ts.map +1 -0
- package/dist/commands/migrate.js +355 -0
- package/dist/commands/migrate.js.map +1 -0
- package/dist/commands/preview.d.ts +29 -0
- package/dist/commands/preview.d.ts.map +1 -0
- package/dist/commands/preview.js +199 -0
- package/dist/commands/preview.js.map +1 -0
- package/dist/commands/proxy.d.ts +9 -0
- package/dist/commands/proxy.d.ts.map +1 -0
- package/dist/commands/proxy.js +37 -0
- package/dist/commands/proxy.js.map +1 -0
- package/dist/commands/sdk.d.ts +5 -0
- package/dist/commands/sdk.d.ts.map +1 -0
- package/dist/commands/sdk.js +82 -0
- package/dist/commands/sdk.js.map +1 -0
- package/dist/commands/template.d.ts +107 -0
- package/dist/commands/template.d.ts.map +1 -0
- package/dist/commands/template.js +1309 -0
- package/dist/commands/template.js.map +1 -0
- package/dist/commands/types.d.ts +5 -0
- package/dist/commands/types.d.ts.map +1 -0
- package/dist/commands/types.js +82 -0
- package/dist/commands/types.js.map +1 -0
- package/dist/commands/update.d.ts +2 -0
- package/dist/commands/update.d.ts.map +1 -0
- package/dist/commands/update.js +103 -0
- package/dist/commands/update.js.map +1 -0
- package/dist/commands/upgrade.d.ts +18 -0
- package/dist/commands/upgrade.d.ts.map +1 -0
- package/dist/commands/upgrade.js +55 -0
- package/dist/commands/upgrade.js.map +1 -0
- package/dist/commands/verify.d.ts +5 -0
- package/dist/commands/verify.d.ts.map +1 -0
- package/dist/commands/verify.js +232 -0
- package/dist/commands/verify.js.map +1 -0
- package/dist/commands/whoami.d.ts +5 -0
- package/dist/commands/whoami.d.ts.map +1 -0
- package/dist/commands/whoami.js +60 -0
- package/dist/commands/whoami.js.map +1 -0
- package/dist/config/types.d.ts +173 -0
- package/dist/config/types.d.ts.map +1 -0
- package/dist/config/types.js +48 -0
- package/dist/config/types.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +416 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/api-url.d.ts +14 -0
- package/dist/lib/api-url.d.ts.map +1 -0
- package/dist/lib/api-url.js +24 -0
- package/dist/lib/api-url.js.map +1 -0
- package/dist/lib/api.d.ts +67 -0
- package/dist/lib/api.d.ts.map +1 -0
- package/dist/lib/api.js +36 -0
- package/dist/lib/api.js.map +1 -0
- package/dist/lib/config.d.ts +39 -0
- package/dist/lib/config.d.ts.map +1 -0
- package/dist/lib/config.js +195 -0
- package/dist/lib/config.js.map +1 -0
- package/dist/lib/env-storage.d.ts +140 -0
- package/dist/lib/env-storage.d.ts.map +1 -0
- package/dist/lib/env-storage.js +464 -0
- package/dist/lib/env-storage.js.map +1 -0
- package/dist/lib/errors.d.ts +61 -0
- package/dist/lib/errors.d.ts.map +1 -0
- package/dist/lib/errors.js +204 -0
- package/dist/lib/errors.js.map +1 -0
- package/dist/lib/i18n.d.ts +99 -0
- package/dist/lib/i18n.d.ts.map +1 -0
- package/dist/lib/i18n.js +184 -0
- package/dist/lib/i18n.js.map +1 -0
- package/dist/lib/logger.d.ts +95 -0
- package/dist/lib/logger.d.ts.map +1 -0
- package/dist/lib/logger.js +168 -0
- package/dist/lib/logger.js.map +1 -0
- package/dist/lib/package-manager.d.ts +91 -0
- package/dist/lib/package-manager.d.ts.map +1 -0
- package/dist/lib/package-manager.js +205 -0
- package/dist/lib/package-manager.js.map +1 -0
- package/dist/lib/proxy-server.d.ts +24 -0
- package/dist/lib/proxy-server.d.ts.map +1 -0
- package/dist/lib/proxy-server.js +173 -0
- package/dist/lib/proxy-server.js.map +1 -0
- package/dist/lib/select-with-back.d.ts +34 -0
- package/dist/lib/select-with-back.d.ts.map +1 -0
- package/dist/lib/select-with-back.js +94 -0
- package/dist/lib/select-with-back.js.map +1 -0
- package/dist/lib/shared-api-client.d.ts +40 -0
- package/dist/lib/shared-api-client.d.ts.map +1 -0
- package/dist/lib/shared-api-client.js +92 -0
- package/dist/lib/shared-api-client.js.map +1 -0
- package/dist/lib/wizard-engine.d.ts +128 -0
- package/dist/lib/wizard-engine.d.ts.map +1 -0
- package/dist/lib/wizard-engine.js +168 -0
- package/dist/lib/wizard-engine.js.map +1 -0
- package/package.json +85 -0
- package/templates/storefront-minimal/.env.example +10 -0
- package/templates/storefront-minimal/.github/workflows/build-template.yml +109 -0
- package/templates/storefront-minimal/app/globals.css +18 -0
- package/templates/storefront-minimal/app/layout.tsx +26 -0
- package/templates/storefront-minimal/app/page.tsx +93 -0
- package/templates/storefront-minimal/lib/graphql-client.ts +23 -0
- package/templates/storefront-minimal/next.config.ts +15 -0
- package/templates/storefront-minimal/open-next.config.ts +3 -0
- package/templates/storefront-minimal/package.json +30 -0
- package/templates/storefront-minimal/postcss.config.mjs +5 -0
- package/templates/storefront-minimal/tailwind.config.ts +14 -0
- package/templates/storefront-minimal/tsconfig.json +27 -0
- package/templates/storefront-minimal/wrangler.toml +9 -0
- package/templates/storefront-nextjs/.env.example +68 -0
- package/templates/storefront-nextjs/.github/workflows/build-template.yml +109 -0
- package/templates/storefront-nextjs/.github/workflows/deploy.yml +25 -0
- package/templates/storefront-nextjs/.github/workflows/preview.yml +22 -0
- package/templates/storefront-nextjs/README.md +520 -0
- package/templates/storefront-nextjs/app/account/orders/page.tsx +216 -0
- package/templates/storefront-nextjs/app/account/page.tsx +167 -0
- package/templates/storefront-nextjs/app/auth/login/page.tsx +135 -0
- package/templates/storefront-nextjs/app/auth/register/page.tsx +228 -0
- package/templates/storefront-nextjs/app/cart/page.tsx +263 -0
- package/templates/storefront-nextjs/app/categories/[slug]/page.tsx +200 -0
- package/templates/storefront-nextjs/app/categories/page.tsx +58 -0
- package/templates/storefront-nextjs/app/checkout/page.tsx +351 -0
- package/templates/storefront-nextjs/app/collections/[slug]/page.tsx +158 -0
- package/templates/storefront-nextjs/app/collections/page.tsx +61 -0
- package/templates/storefront-nextjs/app/globals.css +98 -0
- package/templates/storefront-nextjs/app/layout.tsx +39 -0
- package/templates/storefront-nextjs/app/page.tsx +136 -0
- package/templates/storefront-nextjs/app/products/[slug]/page.tsx +119 -0
- package/templates/storefront-nextjs/app/products/page.tsx +107 -0
- package/templates/storefront-nextjs/app/search/page.tsx +127 -0
- package/templates/storefront-nextjs/components/auth/auth-guard.tsx +94 -0
- package/templates/storefront-nextjs/components/commerce/add-to-cart-button.tsx +77 -0
- package/templates/storefront-nextjs/components/commerce/cart-icon.tsx +29 -0
- package/templates/storefront-nextjs/components/commerce/currency-selector.tsx +217 -0
- package/templates/storefront-nextjs/components/commerce/pagination.tsx +62 -0
- package/templates/storefront-nextjs/components/commerce/product-actions.tsx +135 -0
- package/templates/storefront-nextjs/components/commerce/product-filters.tsx +109 -0
- package/templates/storefront-nextjs/components/commerce/product-price.tsx +375 -0
- package/templates/storefront-nextjs/components/commerce/search-input.tsx +178 -0
- package/templates/storefront-nextjs/components/commerce/sort-select.tsx +64 -0
- package/templates/storefront-nextjs/components/commerce/variant-selector.tsx +210 -0
- package/templates/storefront-nextjs/components/layout/footer.tsx +107 -0
- package/templates/storefront-nextjs/components/layout/header.tsx +104 -0
- package/templates/storefront-nextjs/components/providers.tsx +62 -0
- package/templates/storefront-nextjs/lib/auth/routes.ts +52 -0
- package/templates/storefront-nextjs/lib/currency.tsx +140 -0
- package/templates/storefront-nextjs/lib/format.ts +159 -0
- package/templates/storefront-nextjs/lib/graphql-queries.ts +629 -0
- package/templates/storefront-nextjs/lib/hooks.ts +30 -0
- package/templates/storefront-nextjs/middleware.ts +80 -0
- package/templates/storefront-nextjs/next.config.ts +37 -0
- package/templates/storefront-nextjs/open-next.config.ts +3 -0
- package/templates/storefront-nextjs/package.dev.json +30 -0
- package/templates/storefront-nextjs/package.json +32 -0
- package/templates/storefront-nextjs/package.json.template +32 -0
- package/templates/storefront-nextjs/postcss.config.mjs +8 -0
- package/templates/storefront-nextjs/tailwind.config.ts +111 -0
- package/templates/storefront-nextjs/tsconfig.json +27 -0
- package/templates/storefront-nextjs/wrangler.toml +9 -0
- package/templates/storefront-nextjs-shadcn/.env.example +68 -0
- package/templates/storefront-nextjs-shadcn/.github/workflows/build-template.yml +109 -0
- package/templates/storefront-nextjs-shadcn/.github/workflows/deploy.yml +25 -0
- package/templates/storefront-nextjs-shadcn/.github/workflows/preview.yml +22 -0
- package/templates/storefront-nextjs-shadcn/CART_INTEGRATION.md +282 -0
- package/templates/storefront-nextjs-shadcn/CLAUDE.md +96 -0
- package/templates/storefront-nextjs-shadcn/GRAPHQL_DOCUMENT_NAMES.md +190 -0
- package/templates/storefront-nextjs-shadcn/GRAPHQL_ERROR_HANDLING.md +263 -0
- package/templates/storefront-nextjs-shadcn/GRAPHQL_FIXES_SUMMARY.md +135 -0
- package/templates/storefront-nextjs-shadcn/GRAPHQL_INTEGRATION_COMPLETE.md +142 -0
- package/templates/storefront-nextjs-shadcn/INTEGRATION_CHECKLIST.md +448 -0
- package/templates/storefront-nextjs-shadcn/PRODUCT_DETAIL_PAGE_IMPLEMENTATION.md +307 -0
- package/templates/storefront-nextjs-shadcn/README.md +195 -0
- package/templates/storefront-nextjs-shadcn/THEME_CUSTOMIZATION.md +245 -0
- package/templates/storefront-nextjs-shadcn/app/about/page.tsx +34 -0
- package/templates/storefront-nextjs-shadcn/app/account/addresses/page.tsx +215 -0
- package/templates/storefront-nextjs-shadcn/app/account/loyalty/page.tsx +484 -0
- package/templates/storefront-nextjs-shadcn/app/account/orders/[id]/page.tsx +128 -0
- package/templates/storefront-nextjs-shadcn/app/account/orders/[id]/tracking/page.tsx +206 -0
- package/templates/storefront-nextjs-shadcn/app/account/orders/page.tsx +80 -0
- package/templates/storefront-nextjs-shadcn/app/account/page.tsx +107 -0
- package/templates/storefront-nextjs-shadcn/app/account/settings/page.tsx +195 -0
- package/templates/storefront-nextjs-shadcn/app/api/auth/clear-token/route.ts +87 -0
- package/templates/storefront-nextjs-shadcn/app/api/auth/set-token/route.ts +125 -0
- package/templates/storefront-nextjs-shadcn/app/auth/forgot-password/page.tsx +131 -0
- package/templates/storefront-nextjs-shadcn/app/auth/login/page.tsx +24 -0
- package/templates/storefront-nextjs-shadcn/app/auth/register/page.tsx +20 -0
- package/templates/storefront-nextjs-shadcn/app/blog/[slug]/page.tsx +323 -0
- package/templates/storefront-nextjs-shadcn/app/blog/page.tsx +159 -0
- package/templates/storefront-nextjs-shadcn/app/brands/[slug]/page.tsx +170 -0
- package/templates/storefront-nextjs-shadcn/app/brands/page.tsx +73 -0
- package/templates/storefront-nextjs-shadcn/app/cart/page.tsx +165 -0
- package/templates/storefront-nextjs-shadcn/app/categories/[slug]/page.tsx +78 -0
- package/templates/storefront-nextjs-shadcn/app/categories/page.tsx +75 -0
- package/templates/storefront-nextjs-shadcn/app/checkout/page.tsx +1752 -0
- package/templates/storefront-nextjs-shadcn/app/checkout/success/[orderId]/page.tsx +256 -0
- package/templates/storefront-nextjs-shadcn/app/collections/[handle]/page.tsx +74 -0
- package/templates/storefront-nextjs-shadcn/app/collections/page.tsx +75 -0
- package/templates/storefront-nextjs-shadcn/app/contact/page.tsx +114 -0
- package/templates/storefront-nextjs-shadcn/app/error.tsx +90 -0
- package/templates/storefront-nextjs-shadcn/app/globals.css +125 -0
- package/templates/storefront-nextjs-shadcn/app/layout.tsx +57 -0
- package/templates/storefront-nextjs-shadcn/app/not-found.tsx +68 -0
- package/templates/storefront-nextjs-shadcn/app/page.tsx +21 -0
- package/templates/storefront-nextjs-shadcn/app/products/[slug]/page.tsx +246 -0
- package/templates/storefront-nextjs-shadcn/app/products/[slug]/product-client.tsx +343 -0
- package/templates/storefront-nextjs-shadcn/app/products/page.tsx +25 -0
- package/templates/storefront-nextjs-shadcn/app/products/products-client.tsx +192 -0
- package/templates/storefront-nextjs-shadcn/app/returns/page.tsx +77 -0
- package/templates/storefront-nextjs-shadcn/app/robots.ts +53 -0
- package/templates/storefront-nextjs-shadcn/app/search/page.tsx +16 -0
- package/templates/storefront-nextjs-shadcn/app/search/search-client.tsx +47 -0
- package/templates/storefront-nextjs-shadcn/app/shipping/page.tsx +62 -0
- package/templates/storefront-nextjs-shadcn/app/sitemap.ts +144 -0
- package/templates/storefront-nextjs-shadcn/app/wishlist/page.tsx +179 -0
- package/templates/storefront-nextjs-shadcn/codegen.ts +51 -0
- package/templates/storefront-nextjs-shadcn/components/account/address-form.tsx +348 -0
- package/templates/storefront-nextjs-shadcn/components/account/address-list.tsx +144 -0
- package/templates/storefront-nextjs-shadcn/components/account/order-details.tsx +258 -0
- package/templates/storefront-nextjs-shadcn/components/account/order-history.tsx +107 -0
- package/templates/storefront-nextjs-shadcn/components/auth/account-menu.tsx +132 -0
- package/templates/storefront-nextjs-shadcn/components/auth/login-form.tsx +188 -0
- package/templates/storefront-nextjs-shadcn/components/auth/register-form.tsx +305 -0
- package/templates/storefront-nextjs-shadcn/components/blog/blog-card.tsx +240 -0
- package/templates/storefront-nextjs-shadcn/components/blog/blog-sidebar.tsx +177 -0
- package/templates/storefront-nextjs-shadcn/components/blog/index.ts +8 -0
- package/templates/storefront-nextjs-shadcn/components/brand/brand-card.tsx +119 -0
- package/templates/storefront-nextjs-shadcn/components/brand/brand-grid.tsx +64 -0
- package/templates/storefront-nextjs-shadcn/components/cart/cart-drawer.tsx +140 -0
- package/templates/storefront-nextjs-shadcn/components/cart/cart-icon.tsx +48 -0
- package/templates/storefront-nextjs-shadcn/components/cart/cart-item.tsx +112 -0
- package/templates/storefront-nextjs-shadcn/components/cart/cart-summary.tsx +84 -0
- package/templates/storefront-nextjs-shadcn/components/cart/index.ts +17 -0
- package/templates/storefront-nextjs-shadcn/components/cart/promo-code-input.tsx +121 -0
- package/templates/storefront-nextjs-shadcn/components/cart/shipping-estimator.tsx +162 -0
- package/templates/storefront-nextjs-shadcn/components/checkout/index.ts +25 -0
- package/templates/storefront-nextjs-shadcn/components/checkout/payment-method-card.tsx +187 -0
- package/templates/storefront-nextjs-shadcn/components/checkout/payment-step.tsx +160 -0
- package/templates/storefront-nextjs-shadcn/components/checkout/tax-breakdown.tsx +154 -0
- package/templates/storefront-nextjs-shadcn/components/commerce/currency-selector.tsx +225 -0
- package/templates/storefront-nextjs-shadcn/components/commerce/pagination.tsx +62 -0
- package/templates/storefront-nextjs-shadcn/components/commerce/product-actions.tsx +158 -0
- package/templates/storefront-nextjs-shadcn/components/commerce/search-input.tsx +174 -0
- package/templates/storefront-nextjs-shadcn/components/commerce/variant-selector.tsx +210 -0
- package/templates/storefront-nextjs-shadcn/components/common/category-card.tsx +97 -0
- package/templates/storefront-nextjs-shadcn/components/common/collection-card.tsx +187 -0
- package/templates/storefront-nextjs-shadcn/components/common/price-display.tsx +151 -0
- package/templates/storefront-nextjs-shadcn/components/common/social-share.tsx +166 -0
- package/templates/storefront-nextjs-shadcn/components/discount/discount-breakdown.tsx +245 -0
- package/templates/storefront-nextjs-shadcn/components/discount/discount-code-input.tsx +246 -0
- package/templates/storefront-nextjs-shadcn/components/discount/index.ts +19 -0
- package/templates/storefront-nextjs-shadcn/components/error/error-boundary.tsx +113 -0
- package/templates/storefront-nextjs-shadcn/components/error/index.ts +7 -0
- package/templates/storefront-nextjs-shadcn/components/filters/attribute-filter.tsx +153 -0
- package/templates/storefront-nextjs-shadcn/components/filters/checkbox-group-filter.tsx +167 -0
- package/templates/storefront-nextjs-shadcn/components/filters/color-swatch-filter.tsx +176 -0
- package/templates/storefront-nextjs-shadcn/components/filters/dynamic-attribute-filters.tsx +220 -0
- package/templates/storefront-nextjs-shadcn/components/filters/index.ts +36 -0
- package/templates/storefront-nextjs-shadcn/components/filters/range-slider-filter.tsx +193 -0
- package/templates/storefront-nextjs-shadcn/components/filters/toggle-filter.tsx +132 -0
- package/templates/storefront-nextjs-shadcn/components/gift-card/gift-card-balance.tsx +321 -0
- package/templates/storefront-nextjs-shadcn/components/gift-card/gift-card-input.tsx +309 -0
- package/templates/storefront-nextjs-shadcn/components/gift-card/index.ts +24 -0
- package/templates/storefront-nextjs-shadcn/components/home/category-grid.tsx +72 -0
- package/templates/storefront-nextjs-shadcn/components/home/featured-collections.tsx +107 -0
- package/templates/storefront-nextjs-shadcn/components/home/featured-products.tsx +85 -0
- package/templates/storefront-nextjs-shadcn/components/home/hero-section.tsx +34 -0
- package/templates/storefront-nextjs-shadcn/components/home/index.ts +8 -0
- package/templates/storefront-nextjs-shadcn/components/home/newsletter-signup.tsx +108 -0
- package/templates/storefront-nextjs-shadcn/components/layout/breadcrumbs.tsx +133 -0
- package/templates/storefront-nextjs-shadcn/components/layout/currency-selector.tsx +341 -0
- package/templates/storefront-nextjs-shadcn/components/layout/footer.tsx +128 -0
- package/templates/storefront-nextjs-shadcn/components/layout/header.tsx +147 -0
- package/templates/storefront-nextjs-shadcn/components/layout/index.ts +9 -0
- package/templates/storefront-nextjs-shadcn/components/layout/mobile-menu.tsx +211 -0
- package/templates/storefront-nextjs-shadcn/components/layout/navigation.tsx +95 -0
- package/templates/storefront-nextjs-shadcn/components/layout/theme-switcher.tsx +192 -0
- package/templates/storefront-nextjs-shadcn/components/loyalty/index.ts +11 -0
- package/templates/storefront-nextjs-shadcn/components/loyalty/points-balance.tsx +93 -0
- package/templates/storefront-nextjs-shadcn/components/loyalty/points-history.tsx +177 -0
- package/templates/storefront-nextjs-shadcn/components/loyalty/referral-section.tsx +250 -0
- package/templates/storefront-nextjs-shadcn/components/loyalty/rewards-catalog.tsx +217 -0
- package/templates/storefront-nextjs-shadcn/components/loyalty/tier-badge.tsx +106 -0
- package/templates/storefront-nextjs-shadcn/components/loyalty/tier-progress.tsx +131 -0
- package/templates/storefront-nextjs-shadcn/components/order/delivery-estimate.tsx +196 -0
- package/templates/storefront-nextjs-shadcn/components/order/index.ts +11 -0
- package/templates/storefront-nextjs-shadcn/components/order/order-tracking.tsx +200 -0
- package/templates/storefront-nextjs-shadcn/components/order/shipment-card.tsx +407 -0
- package/templates/storefront-nextjs-shadcn/components/order/tracking-status.tsx +222 -0
- package/templates/storefront-nextjs-shadcn/components/order/tracking-timeline.tsx +205 -0
- package/templates/storefront-nextjs-shadcn/components/product/add-to-cart-button.tsx +161 -0
- package/templates/storefront-nextjs-shadcn/components/product/b2b-price-display.tsx +250 -0
- package/templates/storefront-nextjs-shadcn/components/product/discount-badge.tsx +196 -0
- package/templates/storefront-nextjs-shadcn/components/product/index.ts +41 -0
- package/templates/storefront-nextjs-shadcn/components/product/product-card.tsx +147 -0
- package/templates/storefront-nextjs-shadcn/components/product/product-filters.tsx +217 -0
- package/templates/storefront-nextjs-shadcn/components/product/product-gallery.tsx +143 -0
- package/templates/storefront-nextjs-shadcn/components/product/product-grid.tsx +83 -0
- package/templates/storefront-nextjs-shadcn/components/product/product-image.tsx +155 -0
- package/templates/storefront-nextjs-shadcn/components/product/product-price.tsx +158 -0
- package/templates/storefront-nextjs-shadcn/components/product/product-quantity-selector.tsx +111 -0
- package/templates/storefront-nextjs-shadcn/components/product/product-reviews.tsx +238 -0
- package/templates/storefront-nextjs-shadcn/components/product/product-sort.tsx +58 -0
- package/templates/storefront-nextjs-shadcn/components/product/product-variant-selector.tsx +169 -0
- package/templates/storefront-nextjs-shadcn/components/product/review-card.tsx +220 -0
- package/templates/storefront-nextjs-shadcn/components/product/review-form.tsx +338 -0
- package/templates/storefront-nextjs-shadcn/components/product/review-summary.tsx +143 -0
- package/templates/storefront-nextjs-shadcn/components/product/sale-countdown.tsx +166 -0
- package/templates/storefront-nextjs-shadcn/components/product/savings-display.tsx +213 -0
- package/templates/storefront-nextjs-shadcn/components/product/similar-products.tsx +57 -0
- package/templates/storefront-nextjs-shadcn/components/product/stock-indicator.tsx +91 -0
- package/templates/storefront-nextjs-shadcn/components/providers/currency-provider.tsx +103 -0
- package/templates/storefront-nextjs-shadcn/components/providers/index.ts +8 -0
- package/templates/storefront-nextjs-shadcn/components/providers/query-provider.tsx +260 -0
- package/templates/storefront-nextjs-shadcn/components/providers/theme-provider.tsx +13 -0
- package/templates/storefront-nextjs-shadcn/components/returns/index.ts +26 -0
- package/templates/storefront-nextjs-shadcn/components/returns/return-request-form.tsx +608 -0
- package/templates/storefront-nextjs-shadcn/components/returns/return-status-card.tsx +554 -0
- package/templates/storefront-nextjs-shadcn/components/search/index.ts +8 -0
- package/templates/storefront-nextjs-shadcn/components/search/search-bar.tsx +140 -0
- package/templates/storefront-nextjs-shadcn/components/search/search-results.tsx +58 -0
- package/templates/storefront-nextjs-shadcn/components/search/search-suggestions.tsx +43 -0
- package/templates/storefront-nextjs-shadcn/components/seo/index.ts +12 -0
- package/templates/storefront-nextjs-shadcn/components/seo/json-ld.tsx +56 -0
- package/templates/storefront-nextjs-shadcn/components/seo/product-json-ld.ts +167 -0
- package/templates/storefront-nextjs-shadcn/components/shipping/index.ts +16 -0
- package/templates/storefront-nextjs-shadcn/components/shipping/shipping-method-selector.tsx +337 -0
- package/templates/storefront-nextjs-shadcn/components/ui/accordion.tsx +153 -0
- package/templates/storefront-nextjs-shadcn/components/ui/alert.tsx +59 -0
- package/templates/storefront-nextjs-shadcn/components/ui/badge.tsx +34 -0
- package/templates/storefront-nextjs-shadcn/components/ui/button.tsx +51 -0
- package/templates/storefront-nextjs-shadcn/components/ui/card.tsx +77 -0
- package/templates/storefront-nextjs-shadcn/components/ui/checkbox.tsx +30 -0
- package/templates/storefront-nextjs-shadcn/components/ui/dialog.tsx +137 -0
- package/templates/storefront-nextjs-shadcn/components/ui/empty-state.tsx +207 -0
- package/templates/storefront-nextjs-shadcn/components/ui/index.ts +67 -0
- package/templates/storefront-nextjs-shadcn/components/ui/input.tsx +65 -0
- package/templates/storefront-nextjs-shadcn/components/ui/label.tsx +26 -0
- package/templates/storefront-nextjs-shadcn/components/ui/pagination.tsx +205 -0
- package/templates/storefront-nextjs-shadcn/components/ui/radio-group.tsx +44 -0
- package/templates/storefront-nextjs-shadcn/components/ui/select.tsx +160 -0
- package/templates/storefront-nextjs-shadcn/components/ui/separator.tsx +28 -0
- package/templates/storefront-nextjs-shadcn/components/ui/skeleton.tsx +20 -0
- package/templates/storefront-nextjs-shadcn/components/ui/spinner.tsx +82 -0
- package/templates/storefront-nextjs-shadcn/components/ui/tabs.tsx +119 -0
- package/templates/storefront-nextjs-shadcn/components/ui/toast.tsx +96 -0
- package/templates/storefront-nextjs-shadcn/components/wishlist/index.ts +9 -0
- package/templates/storefront-nextjs-shadcn/components/wishlist/wishlist-button.tsx +148 -0
- package/templates/storefront-nextjs-shadcn/components/wishlist/wishlist-icon.tsx +47 -0
- package/templates/storefront-nextjs-shadcn/components/wishlist/wishlist-item.tsx +165 -0
- package/templates/storefront-nextjs-shadcn/components.json +19 -0
- package/templates/storefront-nextjs-shadcn/generated/.gitkeep +2 -0
- package/templates/storefront-nextjs-shadcn/graphql/.gitkeep +31 -0
- package/templates/storefront-nextjs-shadcn/graphql/collections.example.ts +168 -0
- package/templates/storefront-nextjs-shadcn/graphql/products.example.ts +160 -0
- package/templates/storefront-nextjs-shadcn/hooks/index.ts +9 -0
- package/templates/storefront-nextjs-shadcn/hooks/use-auth.ts +310 -0
- package/templates/storefront-nextjs-shadcn/hooks/use-cart-actions.ts +286 -0
- package/templates/storefront-nextjs-shadcn/hooks/use-cart-sync.ts +110 -0
- package/templates/storefront-nextjs-shadcn/hooks/use-filter-params.test.ts +173 -0
- package/templates/storefront-nextjs-shadcn/hooks/use-filter-params.ts +298 -0
- package/templates/storefront-nextjs-shadcn/lib/auth/cookies.ts +220 -0
- package/templates/storefront-nextjs-shadcn/lib/auth/routes.ts +57 -0
- package/templates/storefront-nextjs-shadcn/lib/config.ts +46 -0
- package/templates/storefront-nextjs-shadcn/lib/currency/IMPLEMENTATION_SUMMARY.md +254 -0
- package/templates/storefront-nextjs-shadcn/lib/currency/README.md +464 -0
- package/templates/storefront-nextjs-shadcn/lib/currency/cookie-manager.test.ts +328 -0
- package/templates/storefront-nextjs-shadcn/lib/currency/cookie-manager.ts +295 -0
- package/templates/storefront-nextjs-shadcn/lib/currency/index.ts +27 -0
- package/templates/storefront-nextjs-shadcn/lib/format.test.ts +397 -0
- package/templates/storefront-nextjs-shadcn/lib/format.ts +226 -0
- package/templates/storefront-nextjs-shadcn/lib/graphql/client.ts +109 -0
- package/templates/storefront-nextjs-shadcn/lib/graphql/hooks.ts +1183 -0
- package/templates/storefront-nextjs-shadcn/lib/graphql/server.ts +267 -0
- package/templates/storefront-nextjs-shadcn/lib/hooks.ts +30 -0
- package/templates/storefront-nextjs-shadcn/lib/theme/theme-config.ts +89 -0
- package/templates/storefront-nextjs-shadcn/lib/utils.ts +6 -0
- package/templates/storefront-nextjs-shadcn/next.config.ts +47 -0
- package/templates/storefront-nextjs-shadcn/open-next.config.ts +3 -0
- package/templates/storefront-nextjs-shadcn/package.dev.json +30 -0
- package/templates/storefront-nextjs-shadcn/package.json +60 -0
- package/templates/storefront-nextjs-shadcn/package.json.template +46 -0
- package/templates/storefront-nextjs-shadcn/postcss.config.mjs +8 -0
- package/templates/storefront-nextjs-shadcn/proxy.ts +80 -0
- package/templates/storefront-nextjs-shadcn/public/icons/payment/apple-pay.svg +8 -0
- package/templates/storefront-nextjs-shadcn/public/icons/payment/bank-transfer.svg +10 -0
- package/templates/storefront-nextjs-shadcn/public/icons/payment/blik.svg +6 -0
- package/templates/storefront-nextjs-shadcn/public/icons/payment/cash-on-delivery.svg +11 -0
- package/templates/storefront-nextjs-shadcn/public/icons/payment/google-pay.svg +11 -0
- package/templates/storefront-nextjs-shadcn/public/icons/payment/mastercard.svg +7 -0
- package/templates/storefront-nextjs-shadcn/public/icons/payment/paypal.svg +7 -0
- package/templates/storefront-nextjs-shadcn/public/icons/payment/payu.svg +7 -0
- package/templates/storefront-nextjs-shadcn/public/icons/payment/przelewy24.svg +7 -0
- package/templates/storefront-nextjs-shadcn/public/icons/payment/stripe.svg +4 -0
- package/templates/storefront-nextjs-shadcn/public/icons/payment/visa.svg +5 -0
- package/templates/storefront-nextjs-shadcn/stores/auth-store.ts +66 -0
- package/templates/storefront-nextjs-shadcn/stores/cart-store.ts +56 -0
- package/templates/storefront-nextjs-shadcn/stores/checkout-store.ts +184 -0
- package/templates/storefront-nextjs-shadcn/stores/currency-store.ts +103 -0
- package/templates/storefront-nextjs-shadcn/stores/wishlist-store.ts +291 -0
- package/templates/storefront-nextjs-shadcn/tailwind.config.ts +111 -0
- package/templates/storefront-nextjs-shadcn/tsconfig.json +27 -0
- package/templates/storefront-nextjs-shadcn/wrangler.toml +9 -0
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useState, useCallback } from "react";
|
|
4
|
+
import { cn } from "@/lib/utils";
|
|
5
|
+
import { CreditCard, AlertCircle, Loader2 } from "lucide-react";
|
|
6
|
+
import { PaymentMethodCard, PaymentMethod } from "./payment-method-card";
|
|
7
|
+
import { Alert, AlertDescription } from "@/components/ui/alert";
|
|
8
|
+
import { Button } from "@/components/ui/button";
|
|
9
|
+
|
|
10
|
+
export interface PaymentStepProps {
|
|
11
|
+
/** Available payment methods from checkout */
|
|
12
|
+
availablePaymentMethods: PaymentMethod[];
|
|
13
|
+
/** Currently selected payment method ID */
|
|
14
|
+
selectedPaymentMethodId?: string | null;
|
|
15
|
+
/** Callback when payment method is selected */
|
|
16
|
+
onPaymentMethodSelect: (paymentMethodId: string) => void | Promise<void>;
|
|
17
|
+
/** Whether the mutation is loading */
|
|
18
|
+
isLoading?: boolean;
|
|
19
|
+
/** Error message to display */
|
|
20
|
+
error?: string | null;
|
|
21
|
+
/** Whether checkout is ready for payment */
|
|
22
|
+
checkoutReady?: boolean;
|
|
23
|
+
/** Callback to proceed to next step */
|
|
24
|
+
onContinue?: () => void;
|
|
25
|
+
className?: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* PaymentStep - Checkout step for selecting payment method
|
|
30
|
+
*
|
|
31
|
+
* Features:
|
|
32
|
+
* - Lists available payment methods with icons
|
|
33
|
+
* - Pre-selects default or previously selected method
|
|
34
|
+
* - Shows loading state during mutation
|
|
35
|
+
* - Error handling with user feedback
|
|
36
|
+
*
|
|
37
|
+
* Requirements: R23.1, R23.2, R23.5
|
|
38
|
+
*/
|
|
39
|
+
export function PaymentStep({
|
|
40
|
+
availablePaymentMethods,
|
|
41
|
+
selectedPaymentMethodId,
|
|
42
|
+
onPaymentMethodSelect,
|
|
43
|
+
isLoading = false,
|
|
44
|
+
error,
|
|
45
|
+
checkoutReady = false,
|
|
46
|
+
onContinue,
|
|
47
|
+
className,
|
|
48
|
+
}: PaymentStepProps) {
|
|
49
|
+
const [localSelectedId, setLocalSelectedId] = useState<string | null>(
|
|
50
|
+
selectedPaymentMethodId ||
|
|
51
|
+
availablePaymentMethods.find((m) => m.isDefault)?.id ||
|
|
52
|
+
availablePaymentMethods[0]?.id ||
|
|
53
|
+
null
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
const handleSelect = useCallback(
|
|
57
|
+
async (method: PaymentMethod) => {
|
|
58
|
+
setLocalSelectedId(method.id);
|
|
59
|
+
await onPaymentMethodSelect(method.id);
|
|
60
|
+
},
|
|
61
|
+
[onPaymentMethodSelect]
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
// No payment methods available
|
|
65
|
+
if (availablePaymentMethods.length === 0) {
|
|
66
|
+
return (
|
|
67
|
+
<div className={cn("space-y-4", className)}>
|
|
68
|
+
<div className="flex items-center gap-2">
|
|
69
|
+
<CreditCard className="h-5 w-5 text-muted-foreground" />
|
|
70
|
+
<h3 className="text-lg font-semibold text-foreground">Payment Method</h3>
|
|
71
|
+
</div>
|
|
72
|
+
|
|
73
|
+
<Alert variant="destructive">
|
|
74
|
+
<AlertCircle className="h-4 w-4" />
|
|
75
|
+
<AlertDescription>
|
|
76
|
+
No payment methods are available. Please contact support.
|
|
77
|
+
</AlertDescription>
|
|
78
|
+
</Alert>
|
|
79
|
+
</div>
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const selectedMethod = availablePaymentMethods.find(
|
|
84
|
+
(m) => m.id === (selectedPaymentMethodId || localSelectedId)
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
return (
|
|
88
|
+
<div className={cn("space-y-4", className)}>
|
|
89
|
+
{/* Header */}
|
|
90
|
+
<div className="flex items-center gap-2">
|
|
91
|
+
<CreditCard className="h-5 w-5 text-muted-foreground" />
|
|
92
|
+
<h3 className="text-lg font-semibold text-foreground">Payment Method</h3>
|
|
93
|
+
</div>
|
|
94
|
+
|
|
95
|
+
{/* Description */}
|
|
96
|
+
<p className="text-sm text-muted-foreground">
|
|
97
|
+
Choose how you'd like to pay for your order.
|
|
98
|
+
</p>
|
|
99
|
+
|
|
100
|
+
{/* Error Alert */}
|
|
101
|
+
{error && (
|
|
102
|
+
<Alert variant="destructive">
|
|
103
|
+
<AlertCircle className="h-4 w-4" />
|
|
104
|
+
<AlertDescription>{error}</AlertDescription>
|
|
105
|
+
</Alert>
|
|
106
|
+
)}
|
|
107
|
+
|
|
108
|
+
{/* Payment Methods List */}
|
|
109
|
+
<div className="space-y-3">
|
|
110
|
+
{availablePaymentMethods.map((method) => (
|
|
111
|
+
<PaymentMethodCard
|
|
112
|
+
key={method.id}
|
|
113
|
+
method={method}
|
|
114
|
+
selected={
|
|
115
|
+
method.id === (selectedPaymentMethodId || localSelectedId)
|
|
116
|
+
}
|
|
117
|
+
onSelect={handleSelect}
|
|
118
|
+
disabled={isLoading}
|
|
119
|
+
/>
|
|
120
|
+
))}
|
|
121
|
+
</div>
|
|
122
|
+
|
|
123
|
+
{/* Loading Indicator */}
|
|
124
|
+
{isLoading && (
|
|
125
|
+
<div className="flex items-center justify-center gap-2 text-sm text-muted-foreground">
|
|
126
|
+
<Loader2 className="h-4 w-4 animate-spin" />
|
|
127
|
+
<span>Updating payment method...</span>
|
|
128
|
+
</div>
|
|
129
|
+
)}
|
|
130
|
+
|
|
131
|
+
{/* Continue Button */}
|
|
132
|
+
{onContinue && (
|
|
133
|
+
<Button
|
|
134
|
+
onClick={onContinue}
|
|
135
|
+
disabled={!selectedMethod || isLoading || !checkoutReady}
|
|
136
|
+
className="w-full"
|
|
137
|
+
>
|
|
138
|
+
{isLoading ? (
|
|
139
|
+
<>
|
|
140
|
+
<Loader2 className="h-4 w-4 animate-spin mr-2" />
|
|
141
|
+
Processing...
|
|
142
|
+
</>
|
|
143
|
+
) : (
|
|
144
|
+
"Continue to Review"
|
|
145
|
+
)}
|
|
146
|
+
</Button>
|
|
147
|
+
)}
|
|
148
|
+
|
|
149
|
+
{/* Selected Method Info */}
|
|
150
|
+
{selectedMethod && (
|
|
151
|
+
<p className="text-xs text-muted-foreground text-center">
|
|
152
|
+
Selected: {selectedMethod.name}
|
|
153
|
+
{selectedMethod.description && ` - ${selectedMethod.description}`}
|
|
154
|
+
</p>
|
|
155
|
+
)}
|
|
156
|
+
</div>
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export default PaymentStep;
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { cn } from "@/lib/utils";
|
|
4
|
+
import { Receipt } from "lucide-react";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Types matching GraphQL schema
|
|
8
|
+
*/
|
|
9
|
+
export interface Money {
|
|
10
|
+
amount: string;
|
|
11
|
+
currencyCode: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface TaxLine {
|
|
15
|
+
title: string;
|
|
16
|
+
rate: number;
|
|
17
|
+
price: Money;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface TaxBreakdownProps {
|
|
21
|
+
taxLines: TaxLine[];
|
|
22
|
+
totalTax: Money;
|
|
23
|
+
className?: string;
|
|
24
|
+
/** Whether to show the header */
|
|
25
|
+
showHeader?: boolean;
|
|
26
|
+
/** Compact mode for smaller displays */
|
|
27
|
+
compact?: boolean;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* TaxBreakdown - Display tax line items with rates and amounts
|
|
32
|
+
*
|
|
33
|
+
* Features:
|
|
34
|
+
* - Shows each tax line with name, rate, and amount
|
|
35
|
+
* - Shows total tax
|
|
36
|
+
* - Supports compact mode for checkout summary
|
|
37
|
+
*
|
|
38
|
+
* Requirements: R36.1, R36.2, R36.3
|
|
39
|
+
*/
|
|
40
|
+
export function TaxBreakdown({
|
|
41
|
+
taxLines,
|
|
42
|
+
totalTax,
|
|
43
|
+
className,
|
|
44
|
+
showHeader = true,
|
|
45
|
+
compact = false,
|
|
46
|
+
}: TaxBreakdownProps) {
|
|
47
|
+
const formatPrice = (money: Money) => {
|
|
48
|
+
const amount = parseFloat(money.amount);
|
|
49
|
+
return new Intl.NumberFormat("pl-PL", {
|
|
50
|
+
style: "currency",
|
|
51
|
+
currency: money.currencyCode,
|
|
52
|
+
}).format(amount);
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const formatRate = (rate: number) => {
|
|
56
|
+
return `${(rate * 100).toFixed(0)}%`;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
// No tax lines to show
|
|
60
|
+
if (taxLines.length === 0) {
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Compact mode - just show total
|
|
65
|
+
if (compact) {
|
|
66
|
+
return (
|
|
67
|
+
<div className={cn("flex items-center justify-between", className)}>
|
|
68
|
+
<span className="text-sm text-muted-foreground">Tax</span>
|
|
69
|
+
<span className="text-sm font-medium text-foreground">
|
|
70
|
+
{formatPrice(totalTax)}
|
|
71
|
+
</span>
|
|
72
|
+
</div>
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Full breakdown
|
|
77
|
+
return (
|
|
78
|
+
<div className={cn("space-y-2", className)}>
|
|
79
|
+
{showHeader && (
|
|
80
|
+
<div className="flex items-center gap-2">
|
|
81
|
+
<Receipt className="h-4 w-4 text-muted-foreground" />
|
|
82
|
+
<h4 className="text-sm font-medium text-foreground">Tax Breakdown</h4>
|
|
83
|
+
</div>
|
|
84
|
+
)}
|
|
85
|
+
|
|
86
|
+
<div className="space-y-1.5 rounded-lg border border-border bg-muted/30 p-3">
|
|
87
|
+
{taxLines.map((taxLine, index) => (
|
|
88
|
+
<div
|
|
89
|
+
key={`${taxLine.title}-${index}`}
|
|
90
|
+
className="flex items-center justify-between text-sm"
|
|
91
|
+
>
|
|
92
|
+
<span className="text-muted-foreground">
|
|
93
|
+
{taxLine.title}
|
|
94
|
+
<span className="ml-1 text-xs">({formatRate(taxLine.rate)})</span>
|
|
95
|
+
</span>
|
|
96
|
+
<span className="font-medium text-foreground">
|
|
97
|
+
{formatPrice(taxLine.price)}
|
|
98
|
+
</span>
|
|
99
|
+
</div>
|
|
100
|
+
))}
|
|
101
|
+
|
|
102
|
+
{/* Total if multiple tax lines */}
|
|
103
|
+
{taxLines.length > 1 && (
|
|
104
|
+
<>
|
|
105
|
+
<div className="border-t border-border my-2" />
|
|
106
|
+
<div className="flex items-center justify-between text-sm">
|
|
107
|
+
<span className="font-medium text-foreground">Total Tax</span>
|
|
108
|
+
<span className="font-semibold text-foreground">
|
|
109
|
+
{formatPrice(totalTax)}
|
|
110
|
+
</span>
|
|
111
|
+
</div>
|
|
112
|
+
</>
|
|
113
|
+
)}
|
|
114
|
+
</div>
|
|
115
|
+
|
|
116
|
+
{/* Tax exemption note (for B2B) */}
|
|
117
|
+
{parseFloat(totalTax.amount) === 0 && taxLines.length === 0 && (
|
|
118
|
+
<p className="text-xs text-muted-foreground">
|
|
119
|
+
Tax exempt order
|
|
120
|
+
</p>
|
|
121
|
+
)}
|
|
122
|
+
</div>
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* TaxSummaryLine - Simple tax line for order summary
|
|
128
|
+
*/
|
|
129
|
+
export function TaxSummaryLine({
|
|
130
|
+
totalTax,
|
|
131
|
+
label = "Tax",
|
|
132
|
+
className,
|
|
133
|
+
}: {
|
|
134
|
+
totalTax: Money;
|
|
135
|
+
label?: string;
|
|
136
|
+
className?: string;
|
|
137
|
+
}) {
|
|
138
|
+
const formatPrice = (money: Money) => {
|
|
139
|
+
const amount = parseFloat(money.amount);
|
|
140
|
+
return new Intl.NumberFormat("pl-PL", {
|
|
141
|
+
style: "currency",
|
|
142
|
+
currency: money.currencyCode,
|
|
143
|
+
}).format(amount);
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
return (
|
|
147
|
+
<div className={cn("flex items-center justify-between text-sm", className)}>
|
|
148
|
+
<span className="text-muted-foreground">{label}</span>
|
|
149
|
+
<span className="text-foreground">{formatPrice(totalTax)}</span>
|
|
150
|
+
</div>
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export default TaxBreakdown;
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useState, useRef, useEffect } from "react";
|
|
4
|
+
import { ChevronDown, Check, Globe } from "lucide-react";
|
|
5
|
+
import { useCurrencyStore } from "@/stores/currency-store";
|
|
6
|
+
import { useQueryClient } from "@tanstack/react-query";
|
|
7
|
+
|
|
8
|
+
// ============================================================================
|
|
9
|
+
// CURRENCY DATA
|
|
10
|
+
// ============================================================================
|
|
11
|
+
|
|
12
|
+
const CURRENCY_SYMBOLS: Record<string, string> = {
|
|
13
|
+
PLN: "zł",
|
|
14
|
+
EUR: "€",
|
|
15
|
+
USD: "$",
|
|
16
|
+
GBP: "£",
|
|
17
|
+
CHF: "CHF",
|
|
18
|
+
CZK: "Kč",
|
|
19
|
+
SEK: "kr",
|
|
20
|
+
NOK: "kr",
|
|
21
|
+
DKK: "kr",
|
|
22
|
+
JPY: "¥",
|
|
23
|
+
CNY: "¥",
|
|
24
|
+
AUD: "A$",
|
|
25
|
+
CAD: "C$",
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const CURRENCY_NAMES: Record<string, string> = {
|
|
29
|
+
PLN: "Polski złoty",
|
|
30
|
+
EUR: "Euro",
|
|
31
|
+
USD: "US Dollar",
|
|
32
|
+
GBP: "British Pound",
|
|
33
|
+
CHF: "Swiss Franc",
|
|
34
|
+
CZK: "Czech Koruna",
|
|
35
|
+
SEK: "Swedish Krona",
|
|
36
|
+
NOK: "Norwegian Krone",
|
|
37
|
+
DKK: "Danish Krone",
|
|
38
|
+
JPY: "Japanese Yen",
|
|
39
|
+
CNY: "Chinese Yuan",
|
|
40
|
+
AUD: "Australian Dollar",
|
|
41
|
+
CAD: "Canadian Dollar",
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
// ============================================================================
|
|
45
|
+
// TYPES
|
|
46
|
+
// ============================================================================
|
|
47
|
+
|
|
48
|
+
interface CurrencySelectorProps {
|
|
49
|
+
className?: string;
|
|
50
|
+
variant?: "default" | "compact";
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// ============================================================================
|
|
54
|
+
// COMPONENT
|
|
55
|
+
// ============================================================================
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* CurrencySelector - Dropdown for selecting preferred currency
|
|
59
|
+
*
|
|
60
|
+
* Features:
|
|
61
|
+
* - Shows current currency with symbol
|
|
62
|
+
* - Lists all supported currencies from Shop
|
|
63
|
+
* - Persists selection to HTTP cookie (SSR-safe)
|
|
64
|
+
* - Invalidates React Query cache on change (refetches prices)
|
|
65
|
+
* - Handles hydration properly (no flash)
|
|
66
|
+
* - Works seamlessly with Server-Side Rendering
|
|
67
|
+
*
|
|
68
|
+
* Technical Details:
|
|
69
|
+
* - Currency stored in cookie (not localStorage)
|
|
70
|
+
* - Cookie accessible by both client and server
|
|
71
|
+
* - GraphQL requests automatically include X-Preferred-Currency header
|
|
72
|
+
* - Cache invalidation ensures immediate price updates
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* ```tsx
|
|
76
|
+
* <CurrencySelector />
|
|
77
|
+
* <CurrencySelector variant="compact" />
|
|
78
|
+
* ```
|
|
79
|
+
*/
|
|
80
|
+
export function CurrencySelector({
|
|
81
|
+
className = "",
|
|
82
|
+
variant = "default",
|
|
83
|
+
}: CurrencySelectorProps) {
|
|
84
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
85
|
+
const dropdownRef = useRef<HTMLDivElement>(null);
|
|
86
|
+
const queryClient = useQueryClient();
|
|
87
|
+
|
|
88
|
+
// Get currency state from store
|
|
89
|
+
const currency = useCurrencyStore((state) => state.currency);
|
|
90
|
+
const supportedCurrencies = useCurrencyStore((state) => state.supportedCurrencies);
|
|
91
|
+
const setCurrency = useCurrencyStore((state) => state.setCurrency);
|
|
92
|
+
const isHydrated = useCurrencyStore((state) => state.isHydrated);
|
|
93
|
+
|
|
94
|
+
// Handle currency change
|
|
95
|
+
const handleCurrencyChange = (newCurrency: string) => {
|
|
96
|
+
// Update Zustand store (which automatically writes to cookie)
|
|
97
|
+
setCurrency(newCurrency);
|
|
98
|
+
|
|
99
|
+
// Close dropdown
|
|
100
|
+
setIsOpen(false);
|
|
101
|
+
|
|
102
|
+
// Invalidate all React Query cache to refetch with new currency
|
|
103
|
+
// This ensures prices are immediately updated across the app
|
|
104
|
+
queryClient.invalidateQueries();
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
// Close dropdown when clicking outside
|
|
108
|
+
useEffect(() => {
|
|
109
|
+
const handleClickOutside = (event: MouseEvent) => {
|
|
110
|
+
if (
|
|
111
|
+
dropdownRef.current &&
|
|
112
|
+
!dropdownRef.current.contains(event.target as Node)
|
|
113
|
+
) {
|
|
114
|
+
setIsOpen(false);
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
if (isOpen) {
|
|
119
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
120
|
+
return () =>
|
|
121
|
+
document.removeEventListener("mousedown", handleClickOutside);
|
|
122
|
+
}
|
|
123
|
+
}, [isOpen]);
|
|
124
|
+
|
|
125
|
+
// Don't render until hydrated (prevents flash)
|
|
126
|
+
if (!isHydrated) {
|
|
127
|
+
return (
|
|
128
|
+
<div className={`flex items-center gap-2 ${className}`}>
|
|
129
|
+
<Globe className="h-4 w-4 text-muted-foreground" />
|
|
130
|
+
<span className="text-sm text-muted-foreground">Loading...</span>
|
|
131
|
+
</div>
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const currentSymbol = currency ? (CURRENCY_SYMBOLS[currency] || currency) : "USD";
|
|
136
|
+
const currentName = currency ? (CURRENCY_NAMES[currency] || currency) : "US Dollar";
|
|
137
|
+
|
|
138
|
+
if (variant === "compact") {
|
|
139
|
+
return (
|
|
140
|
+
<div ref={dropdownRef} className={`relative ${className}`}>
|
|
141
|
+
<button
|
|
142
|
+
onClick={() => setIsOpen(!isOpen)}
|
|
143
|
+
className="flex items-center gap-1 rounded-md px-2 py-1 text-sm hover:bg-muted"
|
|
144
|
+
aria-label="Select currency"
|
|
145
|
+
>
|
|
146
|
+
<span className="font-medium">{currentSymbol}</span>
|
|
147
|
+
<ChevronDown className="h-3 w-3" />
|
|
148
|
+
</button>
|
|
149
|
+
|
|
150
|
+
{isOpen && (
|
|
151
|
+
<div className="absolute right-0 top-full z-50 mt-2 w-48 rounded-md border border-border bg-background shadow-lg">
|
|
152
|
+
<div className="max-h-64 overflow-y-auto p-1">
|
|
153
|
+
{supportedCurrencies.map((code) => (
|
|
154
|
+
<button
|
|
155
|
+
key={code}
|
|
156
|
+
onClick={() => handleCurrencyChange(code)}
|
|
157
|
+
className="flex w-full items-center justify-between rounded-sm px-3 py-2 text-sm hover:bg-muted"
|
|
158
|
+
>
|
|
159
|
+
<span className="flex items-center gap-2">
|
|
160
|
+
<span className="font-medium">
|
|
161
|
+
{CURRENCY_SYMBOLS[code] || code}
|
|
162
|
+
</span>
|
|
163
|
+
<span className="text-muted-foreground">{code}</span>
|
|
164
|
+
</span>
|
|
165
|
+
{currency === code && (
|
|
166
|
+
<Check className="h-4 w-4 text-primary" />
|
|
167
|
+
)}
|
|
168
|
+
</button>
|
|
169
|
+
))}
|
|
170
|
+
</div>
|
|
171
|
+
</div>
|
|
172
|
+
)}
|
|
173
|
+
</div>
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
return (
|
|
178
|
+
<div ref={dropdownRef} className={`relative ${className}`}>
|
|
179
|
+
<button
|
|
180
|
+
onClick={() => setIsOpen(!isOpen)}
|
|
181
|
+
className="flex items-center gap-2 rounded-md border border-border bg-background px-3 py-2 text-sm hover:bg-muted"
|
|
182
|
+
aria-label="Select currency"
|
|
183
|
+
>
|
|
184
|
+
<Globe className="h-4 w-4 text-muted-foreground" />
|
|
185
|
+
<span className="font-medium">{currentSymbol}</span>
|
|
186
|
+
<span className="text-muted-foreground">{currency}</span>
|
|
187
|
+
<ChevronDown className="h-4 w-4 text-muted-foreground" />
|
|
188
|
+
</button>
|
|
189
|
+
|
|
190
|
+
{isOpen && (
|
|
191
|
+
<div className="absolute right-0 top-full z-50 mt-2 w-64 rounded-md border border-border bg-background shadow-lg">
|
|
192
|
+
<div className="border-b border-border p-3">
|
|
193
|
+
<p className="text-sm font-medium text-foreground">
|
|
194
|
+
Select Currency
|
|
195
|
+
</p>
|
|
196
|
+
<p className="text-xs text-muted-foreground">
|
|
197
|
+
Prices will be displayed in your selected currency
|
|
198
|
+
</p>
|
|
199
|
+
</div>
|
|
200
|
+
<div className="max-h-64 overflow-y-auto p-1">
|
|
201
|
+
{supportedCurrencies.map((code) => (
|
|
202
|
+
<button
|
|
203
|
+
key={code}
|
|
204
|
+
onClick={() => handleCurrencyChange(code)}
|
|
205
|
+
className="flex w-full items-center justify-between rounded-sm px-3 py-2 text-sm hover:bg-muted"
|
|
206
|
+
>
|
|
207
|
+
<span className="flex items-center gap-2">
|
|
208
|
+
<span className="font-medium">
|
|
209
|
+
{CURRENCY_SYMBOLS[code] || code}
|
|
210
|
+
</span>
|
|
211
|
+
<span className="text-muted-foreground">
|
|
212
|
+
{CURRENCY_NAMES[code] || code}
|
|
213
|
+
</span>
|
|
214
|
+
</span>
|
|
215
|
+
{currency === code && (
|
|
216
|
+
<Check className="h-4 w-4 text-primary" />
|
|
217
|
+
)}
|
|
218
|
+
</button>
|
|
219
|
+
))}
|
|
220
|
+
</div>
|
|
221
|
+
</div>
|
|
222
|
+
)}
|
|
223
|
+
</div>
|
|
224
|
+
);
|
|
225
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useSearchParams, usePathname } from "next/navigation";
|
|
4
|
+
import Link from "next/link";
|
|
5
|
+
|
|
6
|
+
interface PaginationProps {
|
|
7
|
+
hasMore: boolean;
|
|
8
|
+
endCursor?: string | null;
|
|
9
|
+
currentCursor?: string;
|
|
10
|
+
totalShown: number;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Pagination - URL-based pagination that preserves filters
|
|
15
|
+
*/
|
|
16
|
+
export function Pagination({
|
|
17
|
+
hasMore,
|
|
18
|
+
endCursor,
|
|
19
|
+
currentCursor,
|
|
20
|
+
totalShown,
|
|
21
|
+
}: PaginationProps) {
|
|
22
|
+
const pathname = usePathname();
|
|
23
|
+
const searchParams = useSearchParams();
|
|
24
|
+
|
|
25
|
+
// Build URL preserving current filters
|
|
26
|
+
const buildUrl = (cursor?: string | null) => {
|
|
27
|
+
const params = new URLSearchParams(searchParams.toString());
|
|
28
|
+
|
|
29
|
+
if (cursor) {
|
|
30
|
+
params.set("after", cursor);
|
|
31
|
+
} else {
|
|
32
|
+
params.delete("after");
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const queryString = params.toString();
|
|
36
|
+
return queryString ? `${pathname}?${queryString}` : pathname;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
return (
|
|
40
|
+
<div className="mt-12 flex justify-center gap-2">
|
|
41
|
+
<Link
|
|
42
|
+
href={buildUrl()}
|
|
43
|
+
className={`btn btn-outline ${
|
|
44
|
+
!currentCursor ? "pointer-events-none opacity-50" : ""
|
|
45
|
+
}`}
|
|
46
|
+
>
|
|
47
|
+
First Page
|
|
48
|
+
</Link>
|
|
49
|
+
<span className="flex items-center px-4 text-gray-600">
|
|
50
|
+
Showing {totalShown} products
|
|
51
|
+
</span>
|
|
52
|
+
<Link
|
|
53
|
+
href={hasMore && endCursor ? buildUrl(endCursor) : "#"}
|
|
54
|
+
className={`btn btn-outline ${
|
|
55
|
+
!hasMore ? "pointer-events-none opacity-50" : ""
|
|
56
|
+
}`}
|
|
57
|
+
>
|
|
58
|
+
Next
|
|
59
|
+
</Link>
|
|
60
|
+
</div>
|
|
61
|
+
);
|
|
62
|
+
}
|