@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,64 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useRouter, useSearchParams, usePathname } from "next/navigation";
|
|
4
|
+
import { useCallback } from "react";
|
|
5
|
+
import { ProductSortKeys } from "@doswiftly/commerce-sdk/graphql";
|
|
6
|
+
|
|
7
|
+
interface SortSelectProps {
|
|
8
|
+
currentSort?: string;
|
|
9
|
+
currentOrder?: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* SortSelect - Client Component for sorting products
|
|
14
|
+
*
|
|
15
|
+
* Uses URL params for sort state (Server Component compatible).
|
|
16
|
+
*/
|
|
17
|
+
export function SortSelect({ currentSort, currentOrder }: SortSelectProps) {
|
|
18
|
+
const router = useRouter();
|
|
19
|
+
const pathname = usePathname();
|
|
20
|
+
const searchParams = useSearchParams();
|
|
21
|
+
|
|
22
|
+
// Build combined value for select
|
|
23
|
+
const sortValue =
|
|
24
|
+
currentSort === ProductSortKeys.Price && currentOrder === "asc"
|
|
25
|
+
? "PRICE_asc"
|
|
26
|
+
: currentSort === ProductSortKeys.Price && currentOrder === "desc"
|
|
27
|
+
? "PRICE_desc"
|
|
28
|
+
: "RELEVANCE";
|
|
29
|
+
|
|
30
|
+
const handleSortChange = useCallback(
|
|
31
|
+
(e: React.ChangeEvent<HTMLSelectElement>) => {
|
|
32
|
+
const value = e.target.value;
|
|
33
|
+
const params = new URLSearchParams(searchParams.toString());
|
|
34
|
+
|
|
35
|
+
if (value === ProductSortKeys.Relevance) {
|
|
36
|
+
params.delete("sort");
|
|
37
|
+
params.delete("order");
|
|
38
|
+
} else {
|
|
39
|
+
// Parse combined sort value (e.g., "PRICE_asc")
|
|
40
|
+
const [sortKey, order] = value.split("_");
|
|
41
|
+
params.set("sort", sortKey);
|
|
42
|
+
params.set("order", order);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Reset pagination when sort changes
|
|
46
|
+
params.delete("after");
|
|
47
|
+
|
|
48
|
+
router.push(`${pathname}?${params.toString()}`);
|
|
49
|
+
},
|
|
50
|
+
[router, pathname, searchParams]
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
return (
|
|
54
|
+
<select
|
|
55
|
+
value={sortValue}
|
|
56
|
+
onChange={handleSortChange}
|
|
57
|
+
className="rounded border border-gray-200 px-3 py-2 text-sm focus:border-gray-900 focus:outline-none"
|
|
58
|
+
>
|
|
59
|
+
<option value={ProductSortKeys.Relevance}>Relevance</option>
|
|
60
|
+
<option value="PRICE_asc">Price: Low to High</option>
|
|
61
|
+
<option value="PRICE_desc">Price: High to Low</option>
|
|
62
|
+
</select>
|
|
63
|
+
);
|
|
64
|
+
}
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useState, useMemo, useEffect } from "react";
|
|
4
|
+
|
|
5
|
+
interface VariantOption {
|
|
6
|
+
name: string;
|
|
7
|
+
value: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
interface ProductVariant {
|
|
11
|
+
id: string;
|
|
12
|
+
title: string;
|
|
13
|
+
available: boolean;
|
|
14
|
+
selectedOptions: VariantOption[];
|
|
15
|
+
price: {
|
|
16
|
+
amount: string;
|
|
17
|
+
currencyCode: string;
|
|
18
|
+
};
|
|
19
|
+
compareAtPrice?: {
|
|
20
|
+
amount: string;
|
|
21
|
+
currencyCode: string;
|
|
22
|
+
} | null;
|
|
23
|
+
image?: {
|
|
24
|
+
url: string;
|
|
25
|
+
altText?: string | null;
|
|
26
|
+
} | null;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
interface VariantSelectorProps {
|
|
30
|
+
variants: ProductVariant[];
|
|
31
|
+
selectedVariantId?: string;
|
|
32
|
+
onVariantChange: (variant: ProductVariant) => void;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* VariantSelector - Select product options (size, color, etc.)
|
|
37
|
+
*
|
|
38
|
+
* Extracts unique options from variants and allows selection.
|
|
39
|
+
* Automatically finds matching variant when options change.
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* ```tsx
|
|
43
|
+
* <VariantSelector
|
|
44
|
+
* variants={product.variants}
|
|
45
|
+
* selectedVariantId={selectedVariant?.id}
|
|
46
|
+
* onVariantChange={setSelectedVariant}
|
|
47
|
+
* />
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
export function VariantSelector({
|
|
51
|
+
variants,
|
|
52
|
+
selectedVariantId,
|
|
53
|
+
onVariantChange,
|
|
54
|
+
}: VariantSelectorProps) {
|
|
55
|
+
// Extract unique option names and their values
|
|
56
|
+
const options = useMemo(() => {
|
|
57
|
+
const optionMap = new Map<string, Set<string>>();
|
|
58
|
+
|
|
59
|
+
variants.forEach((variant) => {
|
|
60
|
+
variant.selectedOptions.forEach((opt) => {
|
|
61
|
+
if (!optionMap.has(opt.name)) {
|
|
62
|
+
optionMap.set(opt.name, new Set());
|
|
63
|
+
}
|
|
64
|
+
optionMap.get(opt.name)!.add(opt.value);
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
return Array.from(optionMap.entries()).map(([name, values]) => ({
|
|
69
|
+
name,
|
|
70
|
+
values: Array.from(values),
|
|
71
|
+
}));
|
|
72
|
+
}, [variants]);
|
|
73
|
+
|
|
74
|
+
// Currently selected values for each option
|
|
75
|
+
const [selectedOptions, setSelectedOptions] = useState<
|
|
76
|
+
Record<string, string>
|
|
77
|
+
>(() => {
|
|
78
|
+
// Initialize from selected variant or first variant
|
|
79
|
+
const initialVariant = selectedVariantId
|
|
80
|
+
? variants.find((v) => v.id === selectedVariantId)
|
|
81
|
+
: variants[0];
|
|
82
|
+
|
|
83
|
+
if (!initialVariant) return {};
|
|
84
|
+
|
|
85
|
+
return initialVariant.selectedOptions.reduce(
|
|
86
|
+
(acc, opt) => ({
|
|
87
|
+
...acc,
|
|
88
|
+
[opt.name]: opt.value,
|
|
89
|
+
}),
|
|
90
|
+
{}
|
|
91
|
+
);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
// Find variant matching current selection
|
|
95
|
+
const findMatchingVariant = (
|
|
96
|
+
opts: Record<string, string>
|
|
97
|
+
): ProductVariant | undefined => {
|
|
98
|
+
return variants.find((variant) =>
|
|
99
|
+
variant.selectedOptions.every((opt) => opts[opt.name] === opt.value)
|
|
100
|
+
);
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
// Check if a specific option value is available
|
|
104
|
+
const isOptionAvailable = (
|
|
105
|
+
optionName: string,
|
|
106
|
+
optionValue: string
|
|
107
|
+
): boolean => {
|
|
108
|
+
const testOptions = { ...selectedOptions, [optionName]: optionValue };
|
|
109
|
+
const matchingVariant = findMatchingVariant(testOptions);
|
|
110
|
+
return !!matchingVariant;
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
// Check if option value leads to in-stock variant
|
|
114
|
+
const isOptionInStock = (
|
|
115
|
+
optionName: string,
|
|
116
|
+
optionValue: string
|
|
117
|
+
): boolean => {
|
|
118
|
+
const testOptions = { ...selectedOptions, [optionName]: optionValue };
|
|
119
|
+
const matchingVariant = findMatchingVariant(testOptions);
|
|
120
|
+
return matchingVariant?.available ?? false;
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
// Handle option selection
|
|
124
|
+
const handleOptionChange = (optionName: string, optionValue: string) => {
|
|
125
|
+
const newOptions = { ...selectedOptions, [optionName]: optionValue };
|
|
126
|
+
setSelectedOptions(newOptions);
|
|
127
|
+
|
|
128
|
+
const matchingVariant = findMatchingVariant(newOptions);
|
|
129
|
+
if (matchingVariant) {
|
|
130
|
+
onVariantChange(matchingVariant);
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
// Sync when selectedVariantId changes externally
|
|
135
|
+
useEffect(() => {
|
|
136
|
+
if (selectedVariantId) {
|
|
137
|
+
const variant = variants.find((v) => v.id === selectedVariantId);
|
|
138
|
+
if (variant) {
|
|
139
|
+
const opts = variant.selectedOptions.reduce(
|
|
140
|
+
(acc, opt) => ({ ...acc, [opt.name]: opt.value }),
|
|
141
|
+
{}
|
|
142
|
+
);
|
|
143
|
+
setSelectedOptions(opts);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}, [selectedVariantId, variants]);
|
|
147
|
+
|
|
148
|
+
// Sync parent when variants prop changes (e.g., after currency change)
|
|
149
|
+
// This ensures parent gets the updated variant object with new prices
|
|
150
|
+
useEffect(() => {
|
|
151
|
+
if (selectedVariantId && variants.length > 0) {
|
|
152
|
+
const updatedVariant = variants.find((v) => v.id === selectedVariantId);
|
|
153
|
+
if (updatedVariant) {
|
|
154
|
+
// Notify parent with updated variant (containing new prices)
|
|
155
|
+
onVariantChange(updatedVariant);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}, [variants]); // Only trigger when variants change, not on every render
|
|
159
|
+
|
|
160
|
+
// Don't render if only one variant with no meaningful options
|
|
161
|
+
if (variants.length <= 1 && options.every((o) => o.values.length <= 1)) {
|
|
162
|
+
return null;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return (
|
|
166
|
+
<div className="space-y-4">
|
|
167
|
+
{options.map((option) => (
|
|
168
|
+
<div key={option.name}>
|
|
169
|
+
<label className="mb-2 block text-sm font-medium text-gray-700">
|
|
170
|
+
{option.name}
|
|
171
|
+
</label>
|
|
172
|
+
<div className="flex flex-wrap gap-2">
|
|
173
|
+
{option.values.map((value) => {
|
|
174
|
+
const isSelected = selectedOptions[option.name] === value;
|
|
175
|
+
const available = isOptionAvailable(option.name, value);
|
|
176
|
+
const inStock = isOptionInStock(option.name, value);
|
|
177
|
+
|
|
178
|
+
return (
|
|
179
|
+
<button
|
|
180
|
+
key={value}
|
|
181
|
+
type="button"
|
|
182
|
+
onClick={() => handleOptionChange(option.name, value)}
|
|
183
|
+
disabled={!available}
|
|
184
|
+
className={`
|
|
185
|
+
relative min-w-[3rem] rounded-lg border px-4 py-2 text-sm font-medium
|
|
186
|
+
transition-all
|
|
187
|
+
${
|
|
188
|
+
isSelected
|
|
189
|
+
? "border-primary bg-primary text-white"
|
|
190
|
+
: available
|
|
191
|
+
? "border-gray-300 bg-white text-gray-900 hover:border-primary"
|
|
192
|
+
: "cursor-not-allowed border-gray-200 bg-gray-50 text-gray-400"
|
|
193
|
+
}
|
|
194
|
+
${!inStock && available ? "text-gray-500" : ""}
|
|
195
|
+
`}
|
|
196
|
+
>
|
|
197
|
+
{value}
|
|
198
|
+
{/* Out of stock indicator */}
|
|
199
|
+
{!inStock && available && (
|
|
200
|
+
<span className="absolute -right-1 -top-1 h-3 w-3 rounded-full border-2 border-white bg-gray-400" />
|
|
201
|
+
)}
|
|
202
|
+
</button>
|
|
203
|
+
);
|
|
204
|
+
})}
|
|
205
|
+
</div>
|
|
206
|
+
</div>
|
|
207
|
+
))}
|
|
208
|
+
</div>
|
|
209
|
+
);
|
|
210
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import Link from "next/link";
|
|
2
|
+
|
|
3
|
+
export function Footer() {
|
|
4
|
+
return (
|
|
5
|
+
<footer className="border-t border-gray-200 bg-gray-50">
|
|
6
|
+
<div className="container mx-auto px-4 py-12">
|
|
7
|
+
<div className="grid grid-cols-1 gap-8 md:grid-cols-4">
|
|
8
|
+
{/* Brand */}
|
|
9
|
+
<div>
|
|
10
|
+
<Link href="/" className="text-xl font-bold text-primary">
|
|
11
|
+
{process.env.NEXT_PUBLIC_SITE_NAME || "My Store"}
|
|
12
|
+
</Link>
|
|
13
|
+
<p className="mt-4 text-sm text-gray-600">
|
|
14
|
+
Quality products at affordable prices. Powered by DoSwiftly
|
|
15
|
+
Commerce.
|
|
16
|
+
</p>
|
|
17
|
+
</div>
|
|
18
|
+
|
|
19
|
+
{/* Shop */}
|
|
20
|
+
<div>
|
|
21
|
+
<h3 className="mb-4 font-semibold text-gray-900">Shop</h3>
|
|
22
|
+
<ul className="space-y-2 text-sm text-gray-600">
|
|
23
|
+
<li>
|
|
24
|
+
<Link href="/products" className="hover:text-primary">
|
|
25
|
+
All Products
|
|
26
|
+
</Link>
|
|
27
|
+
</li>
|
|
28
|
+
<li>
|
|
29
|
+
<Link href="/collections" className="hover:text-primary">
|
|
30
|
+
Collections
|
|
31
|
+
</Link>
|
|
32
|
+
</li>
|
|
33
|
+
<li>
|
|
34
|
+
<Link href="/products?sale=true" className="hover:text-primary">
|
|
35
|
+
Sale
|
|
36
|
+
</Link>
|
|
37
|
+
</li>
|
|
38
|
+
</ul>
|
|
39
|
+
</div>
|
|
40
|
+
|
|
41
|
+
{/* Account */}
|
|
42
|
+
<div>
|
|
43
|
+
<h3 className="mb-4 font-semibold text-gray-900">Account</h3>
|
|
44
|
+
<ul className="space-y-2 text-sm text-gray-600">
|
|
45
|
+
<li>
|
|
46
|
+
<Link href="/account" className="hover:text-primary">
|
|
47
|
+
My Account
|
|
48
|
+
</Link>
|
|
49
|
+
</li>
|
|
50
|
+
<li>
|
|
51
|
+
<Link href="/account/orders" className="hover:text-primary">
|
|
52
|
+
Order History
|
|
53
|
+
</Link>
|
|
54
|
+
</li>
|
|
55
|
+
<li>
|
|
56
|
+
<Link href="/cart" className="hover:text-primary">
|
|
57
|
+
Cart
|
|
58
|
+
</Link>
|
|
59
|
+
</li>
|
|
60
|
+
</ul>
|
|
61
|
+
</div>
|
|
62
|
+
|
|
63
|
+
{/* Support */}
|
|
64
|
+
<div>
|
|
65
|
+
<h3 className="mb-4 font-semibold text-gray-900">Support</h3>
|
|
66
|
+
<ul className="space-y-2 text-sm text-gray-600">
|
|
67
|
+
<li>
|
|
68
|
+
<Link href="/contact" className="hover:text-primary">
|
|
69
|
+
Contact Us
|
|
70
|
+
</Link>
|
|
71
|
+
</li>
|
|
72
|
+
<li>
|
|
73
|
+
<Link href="/shipping" className="hover:text-primary">
|
|
74
|
+
Shipping Info
|
|
75
|
+
</Link>
|
|
76
|
+
</li>
|
|
77
|
+
<li>
|
|
78
|
+
<Link href="/returns" className="hover:text-primary">
|
|
79
|
+
Returns & Refunds
|
|
80
|
+
</Link>
|
|
81
|
+
</li>
|
|
82
|
+
</ul>
|
|
83
|
+
</div>
|
|
84
|
+
</div>
|
|
85
|
+
|
|
86
|
+
<div className="mt-12 border-t border-gray-200 pt-8 text-center text-sm text-gray-600">
|
|
87
|
+
<p>
|
|
88
|
+
© {new Date().getFullYear()}{" "}
|
|
89
|
+
{process.env.NEXT_PUBLIC_SITE_NAME || "My Store"}. All rights
|
|
90
|
+
reserved.
|
|
91
|
+
</p>
|
|
92
|
+
<p className="mt-2">
|
|
93
|
+
Powered by{" "}
|
|
94
|
+
<a
|
|
95
|
+
href="https://doswiftly.pl"
|
|
96
|
+
target="_blank"
|
|
97
|
+
rel="noopener noreferrer"
|
|
98
|
+
className="text-primary hover:underline"
|
|
99
|
+
>
|
|
100
|
+
DoSwiftly Commerce
|
|
101
|
+
</a>
|
|
102
|
+
</p>
|
|
103
|
+
</div>
|
|
104
|
+
</div>
|
|
105
|
+
</footer>
|
|
106
|
+
);
|
|
107
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import Link from "next/link";
|
|
4
|
+
import { useState } from "react";
|
|
5
|
+
import { User, Menu, X } from "lucide-react";
|
|
6
|
+
import CurrencySelector from "@/components/commerce/currency-selector";
|
|
7
|
+
import { CartIcon } from "@/components/commerce/cart-icon";
|
|
8
|
+
import { SearchInput } from "@/components/commerce/search-input";
|
|
9
|
+
|
|
10
|
+
export function Header() {
|
|
11
|
+
const [isMenuOpen, setIsMenuOpen] = useState(false);
|
|
12
|
+
|
|
13
|
+
return (
|
|
14
|
+
<header className="sticky top-0 z-50 border-b border-gray-200 bg-white">
|
|
15
|
+
<div className="container mx-auto px-4">
|
|
16
|
+
<div className="flex h-16 items-center justify-between">
|
|
17
|
+
{/* Logo */}
|
|
18
|
+
<Link href="/" className="text-xl font-bold text-primary">
|
|
19
|
+
{process.env.NEXT_PUBLIC_SITE_NAME || "My Store"}
|
|
20
|
+
</Link>
|
|
21
|
+
|
|
22
|
+
{/* Desktop Navigation */}
|
|
23
|
+
<nav className="hidden items-center gap-6 md:flex">
|
|
24
|
+
<Link href="/products" className="text-gray-600 hover:text-primary">
|
|
25
|
+
Products
|
|
26
|
+
</Link>
|
|
27
|
+
<Link
|
|
28
|
+
href="/collections"
|
|
29
|
+
className="text-gray-600 hover:text-primary"
|
|
30
|
+
>
|
|
31
|
+
Collections
|
|
32
|
+
</Link>
|
|
33
|
+
<Link href="/about" className="text-gray-600 hover:text-primary">
|
|
34
|
+
About
|
|
35
|
+
</Link>
|
|
36
|
+
</nav>
|
|
37
|
+
|
|
38
|
+
{/* Search & Actions */}
|
|
39
|
+
<div className="flex items-center gap-4">
|
|
40
|
+
{/* Search */}
|
|
41
|
+
<div className="hidden w-64 lg:block">
|
|
42
|
+
<SearchInput placeholder="Search..." />
|
|
43
|
+
</div>
|
|
44
|
+
{/* Currency Selector */}
|
|
45
|
+
<div className="hidden md:block">
|
|
46
|
+
<CurrencySelector variant="compact" />
|
|
47
|
+
</div>
|
|
48
|
+
<Link
|
|
49
|
+
href="/account"
|
|
50
|
+
className="p-2 text-gray-600 hover:text-primary"
|
|
51
|
+
>
|
|
52
|
+
<User className="h-5 w-5" />
|
|
53
|
+
</Link>
|
|
54
|
+
<CartIcon />
|
|
55
|
+
<button
|
|
56
|
+
className="p-2 text-gray-600 md:hidden"
|
|
57
|
+
onClick={() => setIsMenuOpen(!isMenuOpen)}
|
|
58
|
+
>
|
|
59
|
+
{isMenuOpen ? (
|
|
60
|
+
<X className="h-5 w-5" />
|
|
61
|
+
) : (
|
|
62
|
+
<Menu className="h-5 w-5" />
|
|
63
|
+
)}
|
|
64
|
+
</button>
|
|
65
|
+
</div>
|
|
66
|
+
</div>
|
|
67
|
+
|
|
68
|
+
{/* Mobile Navigation */}
|
|
69
|
+
{isMenuOpen && (
|
|
70
|
+
<nav className="border-t border-gray-200 py-4 md:hidden">
|
|
71
|
+
<div className="flex flex-col gap-4">
|
|
72
|
+
{/* Mobile Currency Selector */}
|
|
73
|
+
<div className="flex items-center justify-between">
|
|
74
|
+
<span className="text-sm text-gray-500">Currency</span>
|
|
75
|
+
<CurrencySelector variant="compact" />
|
|
76
|
+
</div>
|
|
77
|
+
<Link
|
|
78
|
+
href="/products"
|
|
79
|
+
className="text-gray-600 hover:text-primary"
|
|
80
|
+
onClick={() => setIsMenuOpen(false)}
|
|
81
|
+
>
|
|
82
|
+
Products
|
|
83
|
+
</Link>
|
|
84
|
+
<Link
|
|
85
|
+
href="/collections"
|
|
86
|
+
className="text-gray-600 hover:text-primary"
|
|
87
|
+
onClick={() => setIsMenuOpen(false)}
|
|
88
|
+
>
|
|
89
|
+
Collections
|
|
90
|
+
</Link>
|
|
91
|
+
<Link
|
|
92
|
+
href="/about"
|
|
93
|
+
className="text-gray-600 hover:text-primary"
|
|
94
|
+
onClick={() => setIsMenuOpen(false)}
|
|
95
|
+
>
|
|
96
|
+
About
|
|
97
|
+
</Link>
|
|
98
|
+
</div>
|
|
99
|
+
</nav>
|
|
100
|
+
)}
|
|
101
|
+
</div>
|
|
102
|
+
</header>
|
|
103
|
+
);
|
|
104
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Providers - Client-side providers wrapper
|
|
5
|
+
*
|
|
6
|
+
* Uses StorefrontProvider from commerce-sdk which handles:
|
|
7
|
+
* - Currency management with persistence
|
|
8
|
+
* - Authentication state
|
|
9
|
+
* - React Query for data fetching
|
|
10
|
+
* - Dynamic SDK headers (currency changes trigger automatic data refetch)
|
|
11
|
+
*
|
|
12
|
+
* @module storefront-nextjs/components/providers
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { ReactNode } from "react";
|
|
16
|
+
import { StorefrontProvider } from "@doswiftly/commerce-sdk/graphql/react";
|
|
17
|
+
|
|
18
|
+
// ============================================================================
|
|
19
|
+
// TYPES
|
|
20
|
+
// ============================================================================
|
|
21
|
+
|
|
22
|
+
interface ProvidersProps {
|
|
23
|
+
children: ReactNode;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// ============================================================================
|
|
27
|
+
// COMPONENT
|
|
28
|
+
// ============================================================================
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Providers - Wraps the app with StorefrontProvider
|
|
32
|
+
*
|
|
33
|
+
* The StorefrontProvider handles:
|
|
34
|
+
* 1. Fetching shop configuration (currencies, etc.)
|
|
35
|
+
* 2. Managing currency state with cookie persistence
|
|
36
|
+
* 3. Managing auth token state
|
|
37
|
+
* 4. Providing React Query client for data caching
|
|
38
|
+
* 5. Dynamic SDK headers - when currency changes, all data refetches automatically
|
|
39
|
+
*
|
|
40
|
+
* NOTE: We must pass apiUrl and shopSlug explicitly because NEXT_PUBLIC_* env vars
|
|
41
|
+
* are only inlined in Next.js app code, not in external packages like commerce-sdk.
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```tsx
|
|
45
|
+
* // In layout.tsx
|
|
46
|
+
* <Providers>
|
|
47
|
+
* <Header />
|
|
48
|
+
* <main>{children}</main>
|
|
49
|
+
* <Footer />
|
|
50
|
+
* </Providers>
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
export function Providers({ children }: ProvidersProps) {
|
|
54
|
+
return (
|
|
55
|
+
<StorefrontProvider
|
|
56
|
+
apiUrl={process.env.NEXT_PUBLIC_API_URL!}
|
|
57
|
+
shopSlug={process.env.NEXT_PUBLIC_SHOP_SLUG!}
|
|
58
|
+
>
|
|
59
|
+
{children}
|
|
60
|
+
</StorefrontProvider>
|
|
61
|
+
);
|
|
62
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auth Routes Configuration (SSOT)
|
|
3
|
+
*
|
|
4
|
+
* This file is the single source of truth for authentication routes.
|
|
5
|
+
* Used by middleware.ts and can be imported by components if needed.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* // Add new protected route
|
|
9
|
+
* export const protectedRoutes = ['/account', '/checkout', '/wishlist'];
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* // Add new guest-only route
|
|
13
|
+
* export const guestOnlyRoutes = ['/auth/login', '/auth/register', '/auth/forgot-password'];
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Routes that require authentication.
|
|
18
|
+
* Unauthenticated users will be redirected to login.
|
|
19
|
+
*/
|
|
20
|
+
export const protectedRoutes = ["/account", "/checkout"];
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Routes only accessible to guests (unauthenticated users).
|
|
24
|
+
* Authenticated users will be redirected to account.
|
|
25
|
+
*/
|
|
26
|
+
export const guestOnlyRoutes = ["/auth/login", "/auth/register"];
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Cookie name for customer access token.
|
|
30
|
+
* Must match the cookie name used by commerce-sdk.
|
|
31
|
+
*/
|
|
32
|
+
export const AUTH_COOKIE_NAME = "customerAccessToken";
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Default redirect paths
|
|
36
|
+
*/
|
|
37
|
+
export const redirects = {
|
|
38
|
+
/** Where to redirect unauthenticated users trying to access protected routes */
|
|
39
|
+
unauthenticated: "/auth/login",
|
|
40
|
+
/** Where to redirect authenticated users trying to access guest-only routes */
|
|
41
|
+
authenticated: "/account",
|
|
42
|
+
} as const;
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Check if a pathname matches any route in the list.
|
|
46
|
+
* Supports both exact matches and prefix matches (e.g., /account matches /account/orders).
|
|
47
|
+
*/
|
|
48
|
+
export function matchesRoute(pathname: string, routes: string[]): boolean {
|
|
49
|
+
return routes.some(
|
|
50
|
+
(route) => pathname === route || pathname.startsWith(`${route}/`)
|
|
51
|
+
);
|
|
52
|
+
}
|