@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,267 @@
|
|
|
1
|
+
import { cache } from 'react';
|
|
2
|
+
import { GraphQLClient } from 'graphql-request';
|
|
3
|
+
import type { TypedDocumentNode } from '@graphql-typed-document-node/core';
|
|
4
|
+
import { getCurrencyFromCookieAsync } from '@/lib/currency/';
|
|
5
|
+
|
|
6
|
+
// Import config - will be injected by CLI during template generation
|
|
7
|
+
let config: {
|
|
8
|
+
shop: { slug: string };
|
|
9
|
+
api: { url: string };
|
|
10
|
+
} | null = null;
|
|
11
|
+
|
|
12
|
+
try {
|
|
13
|
+
// Dynamic import to handle cases where config doesn't exist yet
|
|
14
|
+
const configModule = require('@/doswiftly.config');
|
|
15
|
+
config = configModule.default || configModule;
|
|
16
|
+
} catch (error) {
|
|
17
|
+
// Fallback to environment variables if config file doesn't exist
|
|
18
|
+
config = {
|
|
19
|
+
shop: {
|
|
20
|
+
slug: process.env.NEXT_PUBLIC_SHOP_SLUG || 'demo-shop',
|
|
21
|
+
},
|
|
22
|
+
api: {
|
|
23
|
+
url: process.env.NEXT_PUBLIC_API_URL || 'http://localhost:8000',
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Cached GraphQL client factory for Server Components
|
|
30
|
+
*
|
|
31
|
+
* Uses React cache() to deduplicate requests within a single render pass.
|
|
32
|
+
* Server-side requests now include X-Preferred-Currency header from cookie
|
|
33
|
+
* for SSR currency consistency.
|
|
34
|
+
*
|
|
35
|
+
* Note: This is an async function in Next.js 15+ because cookies() is async.
|
|
36
|
+
*
|
|
37
|
+
* @returns GraphQL client configured for server-side usage with currency support
|
|
38
|
+
*/
|
|
39
|
+
export const getClient = cache(async () => {
|
|
40
|
+
// Read currency from cookie (SSR-safe, async in Next.js 15+)
|
|
41
|
+
const currency = await getCurrencyFromCookieAsync();
|
|
42
|
+
|
|
43
|
+
return new GraphQLClient(`${config!.api.url}/storefront/graphql`, {
|
|
44
|
+
headers: {
|
|
45
|
+
'X-Shop-Slug': config!.shop.slug,
|
|
46
|
+
// Include X-Preferred-Currency from cookie for SSR consistency
|
|
47
|
+
...(currency && { 'X-Preferred-Currency': currency }),
|
|
48
|
+
},
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Generic request helper with React cache
|
|
54
|
+
*
|
|
55
|
+
* @param document - TypedDocumentNode from codegen
|
|
56
|
+
* @param variables - Query variables
|
|
57
|
+
* @returns Query result
|
|
58
|
+
*/
|
|
59
|
+
export const request = cache(async <TResult, TVariables>(
|
|
60
|
+
document: TypedDocumentNode<TResult, TVariables>,
|
|
61
|
+
variables?: TVariables
|
|
62
|
+
): Promise<TResult> => {
|
|
63
|
+
const client = await getClient();
|
|
64
|
+
return client.request(document, variables as any);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
// ============================================================================
|
|
68
|
+
// HELPER FUNCTIONS
|
|
69
|
+
// ============================================================================
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Fetch shop data with currency configuration
|
|
73
|
+
*
|
|
74
|
+
* Used in root layout to initialize currency store.
|
|
75
|
+
* Cached per render to avoid duplicate requests.
|
|
76
|
+
*
|
|
77
|
+
* @returns Shop query result
|
|
78
|
+
*
|
|
79
|
+
* @example
|
|
80
|
+
* ```typescript
|
|
81
|
+
* // app/layout.tsx
|
|
82
|
+
* import { fetchShop } from '@/lib/graphql/server';
|
|
83
|
+
*
|
|
84
|
+
* export default async function RootLayout() {
|
|
85
|
+
* const data = await fetchShop();
|
|
86
|
+
* return <CurrencyProvider shopData={data.shop}>...</CurrencyProvider>;
|
|
87
|
+
* }
|
|
88
|
+
* ```
|
|
89
|
+
*/
|
|
90
|
+
export const fetchShop = cache(async () => {
|
|
91
|
+
// Import generated types dynamically to avoid circular dependencies
|
|
92
|
+
const { ShopDocument } = await import('@/generated/graphql');
|
|
93
|
+
return request(ShopDocument, {});
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Fetch single product by handle or ID
|
|
98
|
+
*
|
|
99
|
+
* Returns product in base currency for SSG compatibility.
|
|
100
|
+
* Client components should refetch with preferred currency if needed.
|
|
101
|
+
*
|
|
102
|
+
* @param handleOrId - Product handle (string) or ID
|
|
103
|
+
* @returns Product query result
|
|
104
|
+
*
|
|
105
|
+
* @example
|
|
106
|
+
* ```typescript
|
|
107
|
+
* // app/products/[handle]/page.tsx
|
|
108
|
+
* import { fetchProduct } from '@/lib/graphql/server';
|
|
109
|
+
*
|
|
110
|
+
* export default async function ProductPage({ params }) {
|
|
111
|
+
* const data = await fetchProduct(params.handle);
|
|
112
|
+
* return <ProductClient initialProduct={data.product} />;
|
|
113
|
+
* }
|
|
114
|
+
* ```
|
|
115
|
+
*/
|
|
116
|
+
export const fetchProduct = cache(async (handleOrId: string) => {
|
|
117
|
+
if (!handleOrId) {
|
|
118
|
+
throw new Error('Product handle or ID is required');
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const { ProductDocument } = await import('@/generated/graphql');
|
|
122
|
+
|
|
123
|
+
// Determine if it's an ID or handle
|
|
124
|
+
const isId = handleOrId.startsWith('gid://');
|
|
125
|
+
|
|
126
|
+
return request(ProductDocument, {
|
|
127
|
+
...(isId ? { id: handleOrId } : { handle: handleOrId }),
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Fetch products with pagination and normalization
|
|
133
|
+
*
|
|
134
|
+
* Automatically normalizes GraphQL edges/nodes structure to flat arrays
|
|
135
|
+
* for easier consumption in components.
|
|
136
|
+
*
|
|
137
|
+
* @param variables - Query variables (first, after, query, sortKey, reverse)
|
|
138
|
+
* @returns Normalized products response
|
|
139
|
+
*
|
|
140
|
+
* @example
|
|
141
|
+
* ```typescript
|
|
142
|
+
* // app/products/page.tsx
|
|
143
|
+
* import { fetchProducts } from '@/lib/graphql/server';
|
|
144
|
+
*
|
|
145
|
+
* export default async function ProductsPage() {
|
|
146
|
+
* const { products, pageInfo } = await fetchProducts({ first: 20 });
|
|
147
|
+
* return products.map(product => <ProductCard key={product.id} product={product} />);
|
|
148
|
+
* }
|
|
149
|
+
* ```
|
|
150
|
+
*/
|
|
151
|
+
export const fetchProducts = cache(async (variables?: {
|
|
152
|
+
first?: number;
|
|
153
|
+
after?: string;
|
|
154
|
+
query?: string;
|
|
155
|
+
sortKey?: string;
|
|
156
|
+
reverse?: boolean;
|
|
157
|
+
}) => {
|
|
158
|
+
const { ProductsDocument } = await import('@/generated/graphql');
|
|
159
|
+
|
|
160
|
+
const data = await request(ProductsDocument, {
|
|
161
|
+
first: variables?.first ?? 20,
|
|
162
|
+
after: variables?.after,
|
|
163
|
+
query: variables?.query,
|
|
164
|
+
sortKey: variables?.sortKey as any,
|
|
165
|
+
reverse: variables?.reverse,
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
// Normalize: edges/nodes → flat array
|
|
169
|
+
return {
|
|
170
|
+
products: data.products.edges.map((edge: any) => edge.node),
|
|
171
|
+
pageInfo: data.products.pageInfo,
|
|
172
|
+
totalCount: data.products.totalCount,
|
|
173
|
+
};
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Fetch collections with pagination and normalization
|
|
178
|
+
*
|
|
179
|
+
* @param variables - Query variables
|
|
180
|
+
* @returns Normalized collections response
|
|
181
|
+
*
|
|
182
|
+
* @example
|
|
183
|
+
* ```typescript
|
|
184
|
+
* import { fetchCollections } from '@/lib/graphql/server';
|
|
185
|
+
*
|
|
186
|
+
* const { collections } = await fetchCollections({ first: 10 });
|
|
187
|
+
* ```
|
|
188
|
+
*/
|
|
189
|
+
export const fetchCollections = cache(async (variables?: {
|
|
190
|
+
first?: number;
|
|
191
|
+
after?: string;
|
|
192
|
+
query?: string;
|
|
193
|
+
sortKey?: string;
|
|
194
|
+
reverse?: boolean;
|
|
195
|
+
}) => {
|
|
196
|
+
const { CollectionsDocument } = await import('@/generated/graphql');
|
|
197
|
+
|
|
198
|
+
const data = await request(CollectionsDocument, {
|
|
199
|
+
first: variables?.first ?? 20,
|
|
200
|
+
after: variables?.after,
|
|
201
|
+
query: variables?.query,
|
|
202
|
+
sortKey: variables?.sortKey as any,
|
|
203
|
+
reverse: variables?.reverse,
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
// Normalize: edges/nodes → flat array
|
|
207
|
+
return {
|
|
208
|
+
collections: data.collections.edges.map((edge: any) => edge.node),
|
|
209
|
+
pageInfo: data.collections.pageInfo,
|
|
210
|
+
totalCount: data.collections.totalCount,
|
|
211
|
+
};
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Fetch single collection by handle or ID
|
|
216
|
+
*
|
|
217
|
+
* @param handleOrId - Collection handle or ID
|
|
218
|
+
* @returns Collection query result
|
|
219
|
+
*
|
|
220
|
+
* @example
|
|
221
|
+
* ```typescript
|
|
222
|
+
* import { fetchCollection } from '@/lib/graphql/server';
|
|
223
|
+
*
|
|
224
|
+
* const data = await fetchCollection('featured-products');
|
|
225
|
+
* ```
|
|
226
|
+
*/
|
|
227
|
+
export const fetchCollection = cache(async (handleOrId: string) => {
|
|
228
|
+
const { CollectionDocument } = await import('@/generated/graphql');
|
|
229
|
+
|
|
230
|
+
const isId = handleOrId.startsWith('gid://');
|
|
231
|
+
|
|
232
|
+
return request(CollectionDocument, {
|
|
233
|
+
...(isId ? { id: handleOrId } : { handle: handleOrId }),
|
|
234
|
+
});
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Fetch categories from GraphQL API
|
|
239
|
+
*
|
|
240
|
+
* @returns Categories query result with tree structure
|
|
241
|
+
*/
|
|
242
|
+
export const fetchCategories = cache(async () => {
|
|
243
|
+
const { CategoriesDocument } = await import('@/generated/graphql');
|
|
244
|
+
return request(CategoriesDocument, {});
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Fetch customer data (requires access token)
|
|
249
|
+
*
|
|
250
|
+
* @param accessToken - Customer access token
|
|
251
|
+
* @returns Customer query result with addresses and orders
|
|
252
|
+
*/
|
|
253
|
+
export const fetchCustomer = cache(async (accessToken: string) => {
|
|
254
|
+
const { CustomerDocument } = await import('@/generated/graphql');
|
|
255
|
+
return request(CustomerDocument, { customerAccessToken: accessToken });
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
// ============================================================================
|
|
259
|
+
// TYPE EXPORTS
|
|
260
|
+
// ============================================================================
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Normalized response types for helper functions
|
|
264
|
+
* These types will be inferred from generated GraphQL types
|
|
265
|
+
*/
|
|
266
|
+
export type NormalizedProductsResponse = Awaited<ReturnType<typeof fetchProducts>>;
|
|
267
|
+
export type NormalizedCollectionsResponse = Awaited<ReturnType<typeof fetchCollections>>;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { useState, useEffect } from "react";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* useDebouncedValue - Debounce a value
|
|
5
|
+
*
|
|
6
|
+
* @param value - Value to debounce
|
|
7
|
+
* @param delay - Delay in ms (default: 300)
|
|
8
|
+
* @returns Debounced value
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```tsx
|
|
12
|
+
* const [query, setQuery] = useState("");
|
|
13
|
+
* const debouncedQuery = useDebouncedValue(query, 300);
|
|
14
|
+
*
|
|
15
|
+
* // debouncedQuery updates 300ms after query stops changing
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
export function useDebouncedValue<T>(value: T, delay = 300): T {
|
|
19
|
+
const [debouncedValue, setDebouncedValue] = useState(value);
|
|
20
|
+
|
|
21
|
+
useEffect(() => {
|
|
22
|
+
const timer = setTimeout(() => {
|
|
23
|
+
setDebouncedValue(value);
|
|
24
|
+
}, delay);
|
|
25
|
+
|
|
26
|
+
return () => clearTimeout(timer);
|
|
27
|
+
}, [value, delay]);
|
|
28
|
+
|
|
29
|
+
return debouncedValue;
|
|
30
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Theme Configuration
|
|
3
|
+
* Design tokens and theme settings for the storefront
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export const themeConfig = {
|
|
7
|
+
// Default theme
|
|
8
|
+
defaultTheme: "system" as const,
|
|
9
|
+
|
|
10
|
+
// Available themes
|
|
11
|
+
themes: ["light", "dark", "system"] as const,
|
|
12
|
+
|
|
13
|
+
// Enable system theme detection
|
|
14
|
+
enableSystem: true,
|
|
15
|
+
|
|
16
|
+
// Disable theme transition on page load
|
|
17
|
+
disableTransitionOnChange: false,
|
|
18
|
+
|
|
19
|
+
// Storage key for theme preference
|
|
20
|
+
storageKey: "doswiftly-theme",
|
|
21
|
+
|
|
22
|
+
// Attribute to set on document element
|
|
23
|
+
attribute: "class",
|
|
24
|
+
|
|
25
|
+
// CSS variables for theme colors
|
|
26
|
+
colors: {
|
|
27
|
+
light: {
|
|
28
|
+
background: "0 0% 100%",
|
|
29
|
+
foreground: "222.2 84% 4.9%",
|
|
30
|
+
card: "0 0% 100%",
|
|
31
|
+
"card-foreground": "222.2 84% 4.9%",
|
|
32
|
+
popover: "0 0% 100%",
|
|
33
|
+
"popover-foreground": "222.2 84% 4.9%",
|
|
34
|
+
primary: "222.2 47.4% 11.2%",
|
|
35
|
+
"primary-foreground": "210 40% 98%",
|
|
36
|
+
secondary: "210 40% 96.1%",
|
|
37
|
+
"secondary-foreground": "222.2 47.4% 11.2%",
|
|
38
|
+
muted: "210 40% 96.1%",
|
|
39
|
+
"muted-foreground": "215.4 16.3% 46.9%",
|
|
40
|
+
accent: "210 40% 96.1%",
|
|
41
|
+
"accent-foreground": "222.2 47.4% 11.2%",
|
|
42
|
+
destructive: "0 84.2% 60.2%",
|
|
43
|
+
"destructive-foreground": "210 40% 98%",
|
|
44
|
+
border: "214.3 31.8% 91.4%",
|
|
45
|
+
input: "214.3 31.8% 91.4%",
|
|
46
|
+
ring: "222.2 84% 4.9%",
|
|
47
|
+
},
|
|
48
|
+
dark: {
|
|
49
|
+
background: "222.2 84% 4.9%",
|
|
50
|
+
foreground: "210 40% 98%",
|
|
51
|
+
card: "222.2 84% 4.9%",
|
|
52
|
+
"card-foreground": "210 40% 98%",
|
|
53
|
+
popover: "222.2 84% 4.9%",
|
|
54
|
+
"popover-foreground": "210 40% 98%",
|
|
55
|
+
primary: "210 40% 98%",
|
|
56
|
+
"primary-foreground": "222.2 47.4% 11.2%",
|
|
57
|
+
secondary: "217.2 32.6% 17.5%",
|
|
58
|
+
"secondary-foreground": "210 40% 98%",
|
|
59
|
+
muted: "217.2 32.6% 17.5%",
|
|
60
|
+
"muted-foreground": "215 20.2% 65.1%",
|
|
61
|
+
accent: "217.2 32.6% 17.5%",
|
|
62
|
+
"accent-foreground": "210 40% 98%",
|
|
63
|
+
destructive: "0 62.8% 30.6%",
|
|
64
|
+
"destructive-foreground": "210 40% 98%",
|
|
65
|
+
border: "217.2 32.6% 17.5%",
|
|
66
|
+
input: "217.2 32.6% 17.5%",
|
|
67
|
+
ring: "212.7 26.8% 83.9%",
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
} as const;
|
|
71
|
+
|
|
72
|
+
export type Theme = (typeof themeConfig.themes)[number];
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Get theme colors for a specific theme
|
|
76
|
+
*/
|
|
77
|
+
export function getThemeColors(theme: "light" | "dark") {
|
|
78
|
+
return themeConfig.colors[theme];
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Generate CSS variables for theme
|
|
83
|
+
*/
|
|
84
|
+
export function generateThemeVariables(theme: "light" | "dark") {
|
|
85
|
+
const colors = getThemeColors(theme);
|
|
86
|
+
return Object.entries(colors)
|
|
87
|
+
.map(([key, value]) => `--${key}: ${value};`)
|
|
88
|
+
.join("\n ");
|
|
89
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { NextConfig } from 'next';
|
|
2
|
+
|
|
3
|
+
const nextConfig: NextConfig = {
|
|
4
|
+
// Enable React strict mode for better development experience
|
|
5
|
+
reactStrictMode: true,
|
|
6
|
+
|
|
7
|
+
// Image optimization configuration
|
|
8
|
+
images: {
|
|
9
|
+
remotePatterns: [
|
|
10
|
+
{
|
|
11
|
+
protocol: 'https',
|
|
12
|
+
hostname: '**.doswiftly.pl',
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
protocol: 'https',
|
|
16
|
+
hostname: 'images.unsplash.com',
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
protocol: 'http',
|
|
20
|
+
hostname: 'app.localhost',
|
|
21
|
+
port: '8000',
|
|
22
|
+
},
|
|
23
|
+
],
|
|
24
|
+
// Allow dangerous URLs for local development
|
|
25
|
+
dangerouslyAllowSVG: true,
|
|
26
|
+
contentDispositionType: 'attachment',
|
|
27
|
+
// Disable image optimization for local development if needed
|
|
28
|
+
unoptimized: process.env.NODE_ENV === 'development',
|
|
29
|
+
},
|
|
30
|
+
|
|
31
|
+
// Experimental features
|
|
32
|
+
experimental: {
|
|
33
|
+
// Enable server actions
|
|
34
|
+
serverActions: {
|
|
35
|
+
bodySizeLimit: '2mb',
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
|
|
39
|
+
// Environment variables validation
|
|
40
|
+
env: {
|
|
41
|
+
NEXT_PUBLIC_API_URL: process.env.NEXT_PUBLIC_API_URL,
|
|
42
|
+
NEXT_PUBLIC_PROJECT_ID: process.env.NEXT_PUBLIC_PROJECT_ID,
|
|
43
|
+
NEXT_PUBLIC_SHOP_SLUG: process.env.NEXT_PUBLIC_SHOP_SLUG,
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export default nextConfig;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "test-storefront",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"scripts": {
|
|
6
|
+
"dev": "next dev",
|
|
7
|
+
"build": "next build",
|
|
8
|
+
"start": "next start",
|
|
9
|
+
"lint": "next lint"
|
|
10
|
+
},
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"@doswiftly/commerce-sdk": "file:../../../commerce-sdk",
|
|
13
|
+
"graphql-request": "^7.1.2",
|
|
14
|
+
"graphql": "^16.10.0",
|
|
15
|
+
"next": "latest",
|
|
16
|
+
"react": "^19",
|
|
17
|
+
"react-dom": "^19",
|
|
18
|
+
"lucide-react": "latest"
|
|
19
|
+
},
|
|
20
|
+
"devDependencies": {
|
|
21
|
+
"@types/node": "latest",
|
|
22
|
+
"@types/react": "latest",
|
|
23
|
+
"@types/react-dom": "latest",
|
|
24
|
+
"typescript": "latest",
|
|
25
|
+
"@tailwindcss/postcss": "latest",
|
|
26
|
+
"tailwindcss": "latest",
|
|
27
|
+
"eslint": "latest",
|
|
28
|
+
"eslint-config-next": "latest"
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "{{PROJECT_NAME}}",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"scripts": {
|
|
6
|
+
"dev": "next dev",
|
|
7
|
+
"build": "next build",
|
|
8
|
+
"build:cf": "opennextjs-cloudflare build",
|
|
9
|
+
"start": "next start",
|
|
10
|
+
"lint": "next lint",
|
|
11
|
+
"codegen": "graphql-codegen --config codegen.ts",
|
|
12
|
+
"codegen:watch": "graphql-codegen --config codegen.ts --watch"
|
|
13
|
+
},
|
|
14
|
+
"dependencies": {
|
|
15
|
+
"@doswiftly/storefront-operations": "{{STOREFRONT_OPS_VERSION}}",
|
|
16
|
+
"@graphql-typed-document-node/core": "^3.2.0",
|
|
17
|
+
"@tanstack/react-query": "^5.62.0",
|
|
18
|
+
"graphql-request": "^7.1.2",
|
|
19
|
+
"graphql": "^16.10.0",
|
|
20
|
+
"graphql-tag": "^2.12.6",
|
|
21
|
+
"js-cookie": "^3.0.5",
|
|
22
|
+
"next": "^15.1.9",
|
|
23
|
+
"react": "^19",
|
|
24
|
+
"react-dom": "^19",
|
|
25
|
+
"lucide-react": "latest",
|
|
26
|
+
"@radix-ui/react-accordion": "^1.2.0",
|
|
27
|
+
"@radix-ui/react-checkbox": "^1.1.0",
|
|
28
|
+
"@radix-ui/react-dialog": "^1.1.0",
|
|
29
|
+
"@radix-ui/react-label": "^2.1.0",
|
|
30
|
+
"@radix-ui/react-radio-group": "^1.2.0",
|
|
31
|
+
"@radix-ui/react-select": "^2.1.0",
|
|
32
|
+
"@radix-ui/react-slot": "^1.1.0",
|
|
33
|
+
"@radix-ui/react-tabs": "^1.1.0",
|
|
34
|
+
"class-variance-authority": "^0.7.0",
|
|
35
|
+
"clsx": "^2.1.0",
|
|
36
|
+
"tailwind-merge": "^2.5.0",
|
|
37
|
+
"zustand": "^5.0.2",
|
|
38
|
+
"zod": "^3.23.8",
|
|
39
|
+
"sonner": "^1.7.1",
|
|
40
|
+
"next-themes": "^0.4.4"
|
|
41
|
+
},
|
|
42
|
+
"devDependencies": {
|
|
43
|
+
"@graphql-codegen/cli": "^5.0.3",
|
|
44
|
+
"@graphql-codegen/typescript": "^4.1.2",
|
|
45
|
+
"@graphql-codegen/typescript-operations": "^4.4.2",
|
|
46
|
+
"@graphql-codegen/typed-document-node": "^5.0.12",
|
|
47
|
+
"@next/env": "^15.1.9",
|
|
48
|
+
"@opennextjs/cloudflare": "^1.0.0",
|
|
49
|
+
"@types/js-cookie": "^3.0.6",
|
|
50
|
+
"@types/node": "latest",
|
|
51
|
+
"@types/react": "latest",
|
|
52
|
+
"@types/react-dom": "latest",
|
|
53
|
+
"fast-check": "^3.15.0",
|
|
54
|
+
"typescript": "latest",
|
|
55
|
+
"@tailwindcss/postcss": "latest",
|
|
56
|
+
"tailwindcss": "latest",
|
|
57
|
+
"eslint": "latest",
|
|
58
|
+
"eslint-config-next": "^15.1.9"
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "{{PROJECT_NAME}}",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"scripts": {
|
|
6
|
+
"dev": "next dev",
|
|
7
|
+
"build": "next build",
|
|
8
|
+
"start": "next start",
|
|
9
|
+
"lint": "next lint",
|
|
10
|
+
"codegen": "graphql-codegen --config codegen.ts",
|
|
11
|
+
"codegen:watch": "graphql-codegen --config codegen.ts --watch"
|
|
12
|
+
},
|
|
13
|
+
"dependencies": {
|
|
14
|
+
"@doswiftly/storefront-operations": "{{STOREFRONT_OPS_VERSION}}",
|
|
15
|
+
"@graphql-typed-document-node/core": "^3.2.0",
|
|
16
|
+
"@tanstack/react-query": "^5.62.0",
|
|
17
|
+
"graphql-request": "^7.1.2",
|
|
18
|
+
"graphql": "^16.10.0",
|
|
19
|
+
"graphql-tag": "^2.12.6",
|
|
20
|
+
"next": "latest",
|
|
21
|
+
"react": "^19",
|
|
22
|
+
"react-dom": "^19",
|
|
23
|
+
"lucide-react": "latest",
|
|
24
|
+
"@radix-ui/react-slot": "^1.1.0",
|
|
25
|
+
"class-variance-authority": "^0.7.0",
|
|
26
|
+
"clsx": "^2.1.0",
|
|
27
|
+
"tailwind-merge": "^2.5.0",
|
|
28
|
+
"zustand": "^5.0.2",
|
|
29
|
+
"zod": "^3.23.8"
|
|
30
|
+
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"@graphql-codegen/cli": "^5.0.3",
|
|
33
|
+
"@graphql-codegen/typescript": "^4.1.2",
|
|
34
|
+
"@graphql-codegen/typescript-operations": "^4.4.2",
|
|
35
|
+
"@graphql-codegen/typed-document-node": "^5.0.12",
|
|
36
|
+
"@next/env": "latest",
|
|
37
|
+
"@types/node": "latest",
|
|
38
|
+
"@types/react": "latest",
|
|
39
|
+
"@types/react-dom": "latest",
|
|
40
|
+
"typescript": "latest",
|
|
41
|
+
"@tailwindcss/postcss": "latest",
|
|
42
|
+
"tailwindcss": "latest",
|
|
43
|
+
"eslint": "latest",
|
|
44
|
+
"eslint-config-next": "latest"
|
|
45
|
+
}
|
|
46
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { NextResponse } from "next/server";
|
|
2
|
+
import type { NextRequest } from "next/server";
|
|
3
|
+
import {
|
|
4
|
+
protectedRoutes,
|
|
5
|
+
guestOnlyRoutes,
|
|
6
|
+
AUTH_COOKIE_NAME,
|
|
7
|
+
redirects,
|
|
8
|
+
matchesRoute,
|
|
9
|
+
} from "@/lib/auth/routes";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Authentication Proxy Function (Next.js 15+)
|
|
13
|
+
*
|
|
14
|
+
* Security Model (3 layers):
|
|
15
|
+
* 1. Proxy function (this file) - Fast redirect based on cookie existence (UX layer)
|
|
16
|
+
* 2. AuthGuard component - Client-side validation via useAuth hook
|
|
17
|
+
* 3. GraphQL Backend - Ultimate security (validates token on every request)
|
|
18
|
+
*
|
|
19
|
+
* IMPORTANT: This proxy checks cookie EXISTENCE, not VALIDITY.
|
|
20
|
+
* Token validation happens in:
|
|
21
|
+
* - AuthGuard (client-side via useAuth hook)
|
|
22
|
+
* - GraphQL API (server-side, ultimate security)
|
|
23
|
+
*
|
|
24
|
+
* Why this approach?
|
|
25
|
+
* - Proxy runs on Edge Runtime (fast, but limited capabilities)
|
|
26
|
+
* - Cannot make GraphQL requests to validate token
|
|
27
|
+
* - Provides instant redirect without waiting for client hydration
|
|
28
|
+
* - Prevents flash of protected content for unauthenticated users
|
|
29
|
+
*
|
|
30
|
+
* @see lib/auth/routes.ts - SSOT for route configuration
|
|
31
|
+
* @see components/auth/auth-guard.tsx - Client-side auth protection
|
|
32
|
+
*/
|
|
33
|
+
export function proxy(request: NextRequest) {
|
|
34
|
+
const { pathname } = request.nextUrl;
|
|
35
|
+
const token = request.cookies.get(AUTH_COOKIE_NAME)?.value;
|
|
36
|
+
const hasToken = Boolean(token);
|
|
37
|
+
|
|
38
|
+
// Protected routes - redirect to login if no token
|
|
39
|
+
if (matchesRoute(pathname, protectedRoutes)) {
|
|
40
|
+
if (!hasToken) {
|
|
41
|
+
const loginUrl = new URL(redirects.unauthenticated, request.url);
|
|
42
|
+
// Preserve the original URL for redirect after login
|
|
43
|
+
loginUrl.searchParams.set("redirect", pathname);
|
|
44
|
+
return NextResponse.redirect(loginUrl);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Guest-only routes - redirect to account if has token
|
|
49
|
+
if (matchesRoute(pathname, guestOnlyRoutes)) {
|
|
50
|
+
if (hasToken) {
|
|
51
|
+
return NextResponse.redirect(
|
|
52
|
+
new URL(redirects.authenticated, request.url)
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return NextResponse.next();
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Matcher configuration
|
|
62
|
+
*
|
|
63
|
+
* Only run proxy on routes that need auth checks.
|
|
64
|
+
* This improves performance by skipping static assets, API routes, etc.
|
|
65
|
+
*
|
|
66
|
+
* Update this when adding new protected or guest-only route groups.
|
|
67
|
+
*/
|
|
68
|
+
export const config = {
|
|
69
|
+
matcher: [
|
|
70
|
+
/*
|
|
71
|
+
* Match all request paths except:
|
|
72
|
+
* - _next/static (static files)
|
|
73
|
+
* - _next/image (image optimization files)
|
|
74
|
+
* - favicon.ico (favicon file)
|
|
75
|
+
* - public folder files (images, etc.)
|
|
76
|
+
* - API routes (handled separately)
|
|
77
|
+
*/
|
|
78
|
+
"/((?!_next/static|_next/image|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp)$).*)",
|
|
79
|
+
],
|
|
80
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 32" fill="none">
|
|
2
|
+
<rect width="48" height="32" rx="4" fill="#000"/>
|
|
3
|
+
<path d="M14.5 11.5c.5-.7.9-1.6.8-2.5-.8 0-1.8.5-2.3 1.2-.5.6-.9 1.5-.8 2.4.9.1 1.8-.4 2.3-1.1z" fill="#fff"/>
|
|
4
|
+
<path d="M15.3 12.8c-1.3-.1-2.4.7-3 .7-.6 0-1.6-.7-2.6-.7-1.3 0-2.6.8-3.3 2-.7 1.2-.9 3.2.1 5 .5.9 1.1 1.8 1.9 1.8s1.2-.5 2.3-.5c1.1 0 1.4.5 2.4.5s1.4-.9 1.9-1.8c.3-.5.5-.9.6-1.2-1.4-.5-2-2.2-1.4-3.5.3-.7.8-1.2 1.4-1.5-.5-.8-1.3-1.3-2.3-1.3v.5z" fill="#fff"/>
|
|
5
|
+
<path d="M22 21.5V11h2.9c2 0 3.4 1.4 3.4 3.4s-1.4 3.4-3.4 3.4h-1.5v3.7H22zm1.4-4.9h1.2c1.4 0 2.1-.7 2.1-2s-.7-2-2.1-2h-1.2v4z" fill="#fff"/>
|
|
6
|
+
<path d="M29 18.3c0-2 1.3-3.2 3.2-3.2 2 0 3.2 1.2 3.2 3.2v.3h-5.1c.1 1.2.8 1.9 2 1.9.8 0 1.4-.3 1.6-.9h1.4c-.2 1.2-1.4 2-3 2-2 0-3.3-1.3-3.3-3.3zm1.3-.4h3.8c-.1-1.1-.8-1.8-1.9-1.8s-1.8.7-1.9 1.8z" fill="#fff"/>
|
|
7
|
+
<path d="M36.5 24v-1.2c.1 0 .3.1.5.1.6 0 1-.3 1.2-.9l.1-.4-2.6-6.4h1.5l1.9 5.2 1.9-5.2H42l-2.7 6.9c-.6 1.5-1.3 2-2.5 2-.1 0-.2 0-.3-.1z" fill="#fff"/>
|
|
8
|
+
</svg>
|