@doswiftly/cli 0.1.18 → 0.1.20
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 +23 -323
- package/dist/commands/check.js +1 -1
- package/dist/commands/check.js.map +1 -1
- package/dist/commands/deploy.d.ts +20 -0
- package/dist/commands/deploy.d.ts.map +1 -1
- package/dist/commands/deploy.js +249 -17
- package/dist/commands/deploy.js.map +1 -1
- package/dist/commands/doctor.js +3 -3
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/init.js +4 -4
- package/dist/commands/sdk.js +5 -5
- package/dist/commands/sdk.js.map +1 -1
- package/dist/commands/template.js +4 -4
- package/dist/commands/template.js.map +1 -1
- package/dist/commands/types.js +5 -5
- package/dist/commands/types.js.map +1 -1
- package/dist/commands/verify.js +2 -2
- package/dist/commands/verify.js.map +1 -1
- package/dist/lib/package-manager.d.ts +1 -1
- package/dist/lib/package-manager.js +1 -1
- package/package.json +4 -4
- package/templates/storefront-minimal/.github/workflows/build-template.yml +10 -0
- package/templates/storefront-minimal/wrangler.toml +11 -0
- package/templates/storefront-nextjs/.github/workflows/build-template.yml +10 -0
- package/templates/storefront-nextjs/README.md +16 -12
- package/templates/storefront-nextjs/app/account/orders/page.tsx +2 -2
- package/templates/storefront-nextjs/app/account/page.tsx +2 -2
- package/templates/storefront-nextjs/app/auth/login/page.tsx +1 -1
- package/templates/storefront-nextjs/app/auth/register/page.tsx +1 -1
- package/templates/storefront-nextjs/app/cart/page.tsx +1 -1
- package/templates/storefront-nextjs/app/categories/[slug]/page.tsx +2 -2
- package/templates/storefront-nextjs/app/categories/page.tsx +1 -1
- package/templates/storefront-nextjs/app/collections/[slug]/page.tsx +1 -1
- package/templates/storefront-nextjs/app/collections/page.tsx +1 -1
- package/templates/storefront-nextjs/app/page.tsx +1 -1
- package/templates/storefront-nextjs/app/products/[slug]/page.tsx +1 -1
- package/templates/storefront-nextjs/app/products/page.tsx +2 -2
- package/templates/storefront-nextjs/app/search/page.tsx +1 -1
- package/templates/storefront-nextjs/components/auth/auth-guard.tsx +1 -1
- package/templates/storefront-nextjs/components/commerce/add-to-cart-button.tsx +1 -1
- package/templates/storefront-nextjs/components/commerce/cart-icon.tsx +1 -1
- package/templates/storefront-nextjs/components/commerce/currency-selector.tsx +2 -2
- package/templates/storefront-nextjs/components/commerce/product-filters.tsx +1 -1
- package/templates/storefront-nextjs/components/commerce/product-price.tsx +1 -1
- package/templates/storefront-nextjs/components/commerce/search-input.tsx +1 -1
- package/templates/storefront-nextjs/components/commerce/sort-select.tsx +1 -1
- package/templates/storefront-nextjs/components/providers.tsx +1 -1
- package/templates/storefront-nextjs/lib/currency.tsx +3 -3
- package/templates/storefront-nextjs/lib/format.ts +1 -1
- package/templates/storefront-nextjs/lib/graphql-queries.ts +3 -3
- package/templates/storefront-nextjs/package.dev.json +1 -1
- package/templates/storefront-nextjs/package.json +1 -1
- package/templates/storefront-nextjs/package.json.template +1 -1
- package/templates/storefront-nextjs/wrangler.toml +11 -0
- package/templates/storefront-nextjs-shadcn/.github/workflows/build-template.yml +10 -0
- package/templates/storefront-nextjs-shadcn/.github/workflows/deploy.yml +47 -0
- package/templates/storefront-nextjs-shadcn/.github/workflows/preview.yml +47 -0
- package/templates/storefront-nextjs-shadcn/CLAUDE.md +172 -35
- package/templates/storefront-nextjs-shadcn/README.md +29 -162
- package/templates/storefront-nextjs-shadcn/app/{about → [locale]/about}/page.tsx +17 -14
- package/templates/storefront-nextjs-shadcn/app/[locale]/account/addresses/page.tsx +226 -0
- package/templates/storefront-nextjs-shadcn/app/[locale]/account/error.tsx +46 -0
- package/templates/storefront-nextjs-shadcn/app/[locale]/account/loading.tsx +19 -0
- package/templates/storefront-nextjs-shadcn/app/{account → [locale]/account}/loyalty/page.tsx +89 -193
- package/templates/storefront-nextjs-shadcn/app/[locale]/account/orders/[id]/loading.tsx +60 -0
- package/templates/storefront-nextjs-shadcn/app/[locale]/account/orders/[id]/page.tsx +119 -0
- package/templates/storefront-nextjs-shadcn/app/{account → [locale]/account}/orders/[id]/tracking/page.tsx +27 -25
- package/templates/storefront-nextjs-shadcn/app/[locale]/account/orders/page.tsx +101 -0
- package/templates/storefront-nextjs-shadcn/app/{account → [locale]/account}/page.tsx +9 -7
- package/templates/storefront-nextjs-shadcn/app/[locale]/account/settings/page.tsx +208 -0
- package/templates/storefront-nextjs-shadcn/app/{auth → [locale]/auth}/forgot-password/page.tsx +24 -17
- package/templates/storefront-nextjs-shadcn/app/{auth → [locale]/auth}/login/page.tsx +5 -2
- package/templates/storefront-nextjs-shadcn/app/{auth → [locale]/auth}/register/page.tsx +5 -2
- package/templates/storefront-nextjs-shadcn/app/[locale]/blog/[slug]/loading.tsx +17 -0
- package/templates/storefront-nextjs-shadcn/app/{blog → [locale]/blog}/[slug]/page.tsx +44 -3
- package/templates/storefront-nextjs-shadcn/app/[locale]/blog/loading.tsx +19 -0
- package/templates/storefront-nextjs-shadcn/app/{brands → [locale]/brands}/page.tsx +2 -1
- package/templates/storefront-nextjs-shadcn/app/[locale]/cart/loading.tsx +26 -0
- package/templates/storefront-nextjs-shadcn/app/{cart → [locale]/cart}/page.tsx +20 -13
- package/templates/storefront-nextjs-shadcn/app/[locale]/categories/[slug]/category-products-client.tsx +58 -0
- package/templates/storefront-nextjs-shadcn/app/[locale]/categories/[slug]/loading.tsx +32 -0
- package/templates/storefront-nextjs-shadcn/app/[locale]/categories/[slug]/page.tsx +95 -0
- package/templates/storefront-nextjs-shadcn/app/{categories → [locale]/categories}/page.tsx +21 -12
- package/templates/storefront-nextjs-shadcn/app/[locale]/checkout/error.tsx +43 -0
- package/templates/storefront-nextjs-shadcn/app/[locale]/checkout/loading.tsx +31 -0
- package/templates/storefront-nextjs-shadcn/app/{checkout → [locale]/checkout}/page.tsx +334 -253
- package/templates/storefront-nextjs-shadcn/app/{checkout → [locale]/checkout}/success/[orderId]/page.tsx +36 -34
- package/templates/storefront-nextjs-shadcn/app/[locale]/collections/[handle]/loading.tsx +19 -0
- package/templates/storefront-nextjs-shadcn/app/{collections → [locale]/collections}/[handle]/page.tsx +6 -4
- package/templates/storefront-nextjs-shadcn/app/[locale]/collections/loading.tsx +18 -0
- package/templates/storefront-nextjs-shadcn/app/{collections → [locale]/collections}/page.tsx +20 -12
- package/templates/storefront-nextjs-shadcn/app/{contact → [locale]/contact}/page.tsx +24 -21
- package/templates/storefront-nextjs-shadcn/app/{error.tsx → [locale]/error.tsx} +13 -8
- package/templates/storefront-nextjs-shadcn/app/[locale]/layout.tsx +92 -0
- package/templates/storefront-nextjs-shadcn/app/{not-found.tsx → [locale]/not-found.tsx} +13 -18
- package/templates/storefront-nextjs-shadcn/app/{page.tsx → [locale]/page.tsx} +8 -4
- package/templates/storefront-nextjs-shadcn/app/[locale]/products/[slug]/error.tsx +43 -0
- package/templates/storefront-nextjs-shadcn/app/[locale]/products/[slug]/loading.tsx +29 -0
- package/templates/storefront-nextjs-shadcn/app/{products → [locale]/products}/[slug]/page.tsx +17 -14
- package/templates/storefront-nextjs-shadcn/app/{products → [locale]/products}/[slug]/product-client.tsx +18 -62
- package/templates/storefront-nextjs-shadcn/app/[locale]/products/loading.tsx +32 -0
- package/templates/storefront-nextjs-shadcn/app/{products → [locale]/products}/page.tsx +6 -3
- package/templates/storefront-nextjs-shadcn/app/[locale]/products/products-client.tsx +450 -0
- package/templates/storefront-nextjs-shadcn/app/[locale]/search/loading.tsx +18 -0
- package/templates/storefront-nextjs-shadcn/app/{wishlist → [locale]/wishlist}/page.tsx +27 -28
- package/templates/storefront-nextjs-shadcn/app/api/auth/clear-token/route.ts +2 -86
- package/templates/storefront-nextjs-shadcn/app/api/auth/set-token/route.ts +2 -124
- package/templates/storefront-nextjs-shadcn/app/global-error.tsx +117 -0
- package/templates/storefront-nextjs-shadcn/app/globals.css +8 -0
- package/templates/storefront-nextjs-shadcn/app/layout.tsx +8 -35
- package/templates/storefront-nextjs-shadcn/codegen.ts +48 -31
- package/templates/storefront-nextjs-shadcn/components/account/address-form.tsx +25 -20
- package/templates/storefront-nextjs-shadcn/components/account/address-list.tsx +11 -10
- package/templates/storefront-nextjs-shadcn/components/account/customer-info.fragment.graphql +36 -0
- package/templates/storefront-nextjs-shadcn/components/account/order-details.tsx +17 -13
- package/templates/storefront-nextjs-shadcn/components/account/order-history.tsx +42 -30
- package/templates/storefront-nextjs-shadcn/components/account/order-summary.fragment.graphql +36 -0
- package/templates/storefront-nextjs-shadcn/components/auth/account-menu.tsx +18 -16
- package/templates/storefront-nextjs-shadcn/components/auth/login-form.tsx +37 -58
- package/templates/storefront-nextjs-shadcn/components/auth/register-form.tsx +85 -66
- package/templates/storefront-nextjs-shadcn/components/blog/blog-card.tsx +1 -1
- package/templates/storefront-nextjs-shadcn/components/blog/blog-sidebar.tsx +1 -1
- package/templates/storefront-nextjs-shadcn/components/brand/brand-card.tsx +1 -1
- package/templates/storefront-nextjs-shadcn/components/cart/cart-drawer.tsx +10 -6
- package/templates/storefront-nextjs-shadcn/components/cart/cart-icon.tsx +9 -6
- package/templates/storefront-nextjs-shadcn/components/cart/cart-item.tsx +8 -6
- package/templates/storefront-nextjs-shadcn/components/cart/cart-line.fragment.graphql +53 -0
- package/templates/storefront-nextjs-shadcn/components/cart/cart-summary.tsx +10 -8
- package/templates/storefront-nextjs-shadcn/components/cart/promo-code-input.tsx +8 -5
- package/templates/storefront-nextjs-shadcn/components/cart/shipping-estimator.tsx +38 -20
- package/templates/storefront-nextjs-shadcn/components/checkout/payment-method-card.tsx +15 -25
- package/templates/storefront-nextjs-shadcn/components/checkout/payment-step.tsx +10 -8
- package/templates/storefront-nextjs-shadcn/components/checkout/tax-breakdown.tsx +9 -6
- package/templates/storefront-nextjs-shadcn/components/commerce/currency-selector.tsx +7 -5
- package/templates/storefront-nextjs-shadcn/components/commerce/pagination.tsx +8 -5
- package/templates/storefront-nextjs-shadcn/components/commerce/product-actions.tsx +6 -4
- package/templates/storefront-nextjs-shadcn/components/commerce/search-input.tsx +10 -9
- package/templates/storefront-nextjs-shadcn/components/common/category-card.tsx +1 -1
- package/templates/storefront-nextjs-shadcn/components/common/collection-card.tsx +1 -1
- package/templates/storefront-nextjs-shadcn/components/common/price-display.tsx +35 -11
- package/templates/storefront-nextjs-shadcn/components/common/social-share.tsx +9 -6
- package/templates/storefront-nextjs-shadcn/components/discount/discount-breakdown.tsx +22 -12
- package/templates/storefront-nextjs-shadcn/components/discount/discount-code-input.tsx +18 -15
- package/templates/storefront-nextjs-shadcn/components/error/error-boundary.tsx +53 -28
- package/templates/storefront-nextjs-shadcn/components/filters/dynamic-attribute-filters.tsx +7 -5
- package/templates/storefront-nextjs-shadcn/components/filters/range-slider-filter.tsx +5 -5
- package/templates/storefront-nextjs-shadcn/components/gift-card/gift-card-balance.tsx +19 -15
- package/templates/storefront-nextjs-shadcn/components/gift-card/gift-card-input.tsx +13 -10
- package/templates/storefront-nextjs-shadcn/components/home/category-grid.tsx +10 -6
- package/templates/storefront-nextjs-shadcn/components/home/collection-card.fragment.graphql +21 -0
- package/templates/storefront-nextjs-shadcn/components/home/featured-collections.tsx +3 -13
- package/templates/storefront-nextjs-shadcn/components/home/featured-products.tsx +12 -8
- package/templates/storefront-nextjs-shadcn/components/home/hero-section.tsx +13 -8
- package/templates/storefront-nextjs-shadcn/components/home/index.ts +0 -1
- package/templates/storefront-nextjs-shadcn/components/home/newsletter-signup.tsx +10 -8
- package/templates/storefront-nextjs-shadcn/components/hydrated.tsx +24 -0
- package/templates/storefront-nextjs-shadcn/components/layout/breadcrumbs.tsx +41 -16
- package/templates/storefront-nextjs-shadcn/components/layout/category-node.fragment.graphql +22 -0
- package/templates/storefront-nextjs-shadcn/components/layout/currency-selector.tsx +7 -4
- package/templates/storefront-nextjs-shadcn/components/layout/footer.tsx +24 -23
- package/templates/storefront-nextjs-shadcn/components/layout/header.tsx +52 -34
- package/templates/storefront-nextjs-shadcn/components/layout/language-switcher.tsx +54 -0
- package/templates/storefront-nextjs-shadcn/components/layout/mobile-menu.tsx +33 -30
- package/templates/storefront-nextjs-shadcn/components/layout/navigation.tsx +27 -24
- package/templates/storefront-nextjs-shadcn/components/loyalty/points-balance.tsx +2 -11
- package/templates/storefront-nextjs-shadcn/components/loyalty/points-history.tsx +8 -25
- package/templates/storefront-nextjs-shadcn/components/loyalty/referral-section.tsx +32 -42
- package/templates/storefront-nextjs-shadcn/components/loyalty/rewards-catalog.tsx +17 -41
- package/templates/storefront-nextjs-shadcn/components/loyalty/tier-progress.tsx +2 -29
- package/templates/storefront-nextjs-shadcn/components/order/index.ts +6 -1
- package/templates/storefront-nextjs-shadcn/components/product/add-to-cart-button.tsx +6 -14
- package/templates/storefront-nextjs-shadcn/components/product/b2b-price-display.tsx +4 -2
- package/templates/storefront-nextjs-shadcn/components/product/filter-active-pills.tsx +72 -0
- package/templates/storefront-nextjs-shadcn/components/product/filter-mobile-sheet.tsx +87 -0
- package/templates/storefront-nextjs-shadcn/components/product/filter-price-range.tsx +140 -0
- package/templates/storefront-nextjs-shadcn/components/product/index.ts +9 -2
- package/templates/storefront-nextjs-shadcn/components/product/product-card.fragment.graphql +49 -0
- package/templates/storefront-nextjs-shadcn/components/product/product-card.tsx +11 -37
- package/templates/storefront-nextjs-shadcn/components/product/product-detail.fragment.graphql +52 -0
- package/templates/storefront-nextjs-shadcn/components/product/product-filters.tsx +179 -124
- package/templates/storefront-nextjs-shadcn/components/product/product-grid.tsx +3 -5
- package/templates/storefront-nextjs-shadcn/components/product/product-image.tsx +3 -7
- package/templates/storefront-nextjs-shadcn/components/product/product-price.tsx +2 -2
- package/templates/storefront-nextjs-shadcn/components/product/product-reviews.tsx +5 -4
- package/templates/storefront-nextjs-shadcn/components/product/product-sort.tsx +44 -19
- package/templates/storefront-nextjs-shadcn/components/product/product-variant-selector.tsx +8 -23
- package/templates/storefront-nextjs-shadcn/components/product/product-variant.fragment.graphql +51 -0
- package/templates/storefront-nextjs-shadcn/components/product/review-card.tsx +1 -1
- package/templates/storefront-nextjs-shadcn/components/product/review-form.tsx +26 -34
- package/templates/storefront-nextjs-shadcn/components/product/savings-display.tsx +17 -2
- package/templates/storefront-nextjs-shadcn/components/product/similar-products.tsx +3 -2
- package/templates/storefront-nextjs-shadcn/components/providers/index.ts +1 -1
- package/templates/storefront-nextjs-shadcn/components/providers/language-sync-provider.tsx +27 -0
- package/templates/storefront-nextjs-shadcn/components/providers/stores-provider.tsx +63 -0
- package/templates/storefront-nextjs-shadcn/components/providers/theme-provider.tsx +1 -1
- package/templates/storefront-nextjs-shadcn/components/returns/index.ts +2 -2
- package/templates/storefront-nextjs-shadcn/components/returns/return-request-form.tsx +59 -72
- package/templates/storefront-nextjs-shadcn/components/search/search-bar.tsx +7 -4
- package/templates/storefront-nextjs-shadcn/components/search/search-results.tsx +3 -2
- package/templates/storefront-nextjs-shadcn/components/shipping/shipping-method-selector.tsx +12 -9
- package/templates/storefront-nextjs-shadcn/components/ui/empty-state.tsx +23 -12
- package/templates/storefront-nextjs-shadcn/components/ui/form.tsx +174 -0
- package/templates/storefront-nextjs-shadcn/components/ui/index.ts +30 -2
- package/templates/storefront-nextjs-shadcn/components/ui/progress.tsx +40 -0
- package/templates/storefront-nextjs-shadcn/components/ui/sheet.tsx +107 -0
- package/templates/storefront-nextjs-shadcn/components/ui/slider.tsx +33 -0
- package/templates/storefront-nextjs-shadcn/components/ui/textarea.tsx +24 -0
- package/templates/storefront-nextjs-shadcn/components/wishlist/wishlist-button.tsx +7 -4
- package/templates/storefront-nextjs-shadcn/components/wishlist/wishlist-icon.tsx +4 -2
- package/templates/storefront-nextjs-shadcn/components/wishlist/wishlist-item.tsx +2 -10
- package/templates/storefront-nextjs-shadcn/generated/graphql.ts +13387 -0
- package/templates/storefront-nextjs-shadcn/graphql/custom.example.graphql +159 -0
- package/templates/storefront-nextjs-shadcn/hooks/index.ts +3 -0
- package/templates/storefront-nextjs-shadcn/hooks/use-auth-sync.ts +42 -0
- package/templates/storefront-nextjs-shadcn/hooks/use-auth.ts +17 -295
- package/templates/storefront-nextjs-shadcn/hooks/use-cart-actions.ts +34 -229
- package/templates/storefront-nextjs-shadcn/hooks/use-cart-di.ts +67 -0
- package/templates/storefront-nextjs-shadcn/hooks/use-cart-sync.ts +16 -12
- package/templates/storefront-nextjs-shadcn/i18n/navigation.ts +12 -0
- package/templates/storefront-nextjs-shadcn/i18n/request.ts +17 -0
- package/templates/storefront-nextjs-shadcn/i18n/routing.ts +17 -0
- package/templates/storefront-nextjs-shadcn/lib/auth/routes.ts +4 -17
- package/templates/storefront-nextjs-shadcn/lib/graphql/client.ts +22 -99
- package/templates/storefront-nextjs-shadcn/lib/graphql/config.ts +33 -0
- package/templates/storefront-nextjs-shadcn/lib/graphql/fragments.ts +34 -0
- package/templates/storefront-nextjs-shadcn/lib/graphql/hooks.ts +720 -632
- package/templates/storefront-nextjs-shadcn/lib/graphql/query-keys.ts +88 -0
- package/templates/storefront-nextjs-shadcn/lib/graphql/server.ts +132 -182
- package/templates/storefront-nextjs-shadcn/lib/graphql/types.ts +62 -0
- package/templates/storefront-nextjs-shadcn/lib/theme/theme-config.ts +0 -17
- package/templates/storefront-nextjs-shadcn/messages/en.json +869 -0
- package/templates/storefront-nextjs-shadcn/messages/pl.json +869 -0
- package/templates/storefront-nextjs-shadcn/next-env.d.ts +6 -0
- package/templates/storefront-nextjs-shadcn/next.config.ts +6 -5
- package/templates/storefront-nextjs-shadcn/package.dev.json +1 -3
- package/templates/storefront-nextjs-shadcn/package.json +14 -14
- package/templates/storefront-nextjs-shadcn/package.json.template +6 -7
- package/templates/storefront-nextjs-shadcn/proxy.ts +115 -47
- package/templates/storefront-nextjs-shadcn/stores/cart-store.ts +24 -56
- package/templates/storefront-nextjs-shadcn/stores/checkout-store.ts +64 -75
- package/templates/storefront-nextjs-shadcn/stores/wishlist-store.ts +178 -177
- package/templates/storefront-nextjs-shadcn/tsconfig.json +23 -5
- package/templates/storefront-nextjs-shadcn/wrangler.toml +11 -0
- package/templates/storefront-nextjs-shadcn/CART_INTEGRATION.md +0 -282
- package/templates/storefront-nextjs-shadcn/GRAPHQL_DOCUMENT_NAMES.md +0 -190
- package/templates/storefront-nextjs-shadcn/GRAPHQL_ERROR_HANDLING.md +0 -263
- package/templates/storefront-nextjs-shadcn/GRAPHQL_FIXES_SUMMARY.md +0 -135
- package/templates/storefront-nextjs-shadcn/GRAPHQL_INTEGRATION_COMPLETE.md +0 -142
- package/templates/storefront-nextjs-shadcn/INTEGRATION_CHECKLIST.md +0 -448
- package/templates/storefront-nextjs-shadcn/PRODUCT_DETAIL_PAGE_IMPLEMENTATION.md +0 -307
- package/templates/storefront-nextjs-shadcn/THEME_CUSTOMIZATION.md +0 -245
- package/templates/storefront-nextjs-shadcn/app/account/addresses/page.tsx +0 -215
- package/templates/storefront-nextjs-shadcn/app/account/orders/[id]/page.tsx +0 -128
- package/templates/storefront-nextjs-shadcn/app/account/orders/page.tsx +0 -80
- package/templates/storefront-nextjs-shadcn/app/account/settings/page.tsx +0 -171
- package/templates/storefront-nextjs-shadcn/app/categories/[slug]/page.tsx +0 -78
- package/templates/storefront-nextjs-shadcn/app/products/products-client.tsx +0 -192
- package/templates/storefront-nextjs-shadcn/components/providers/currency-provider.tsx +0 -103
- package/templates/storefront-nextjs-shadcn/graphql/collections.example.ts +0 -168
- package/templates/storefront-nextjs-shadcn/graphql/products.example.ts +0 -160
- package/templates/storefront-nextjs-shadcn/lib/auth/cookies.ts +0 -220
- package/templates/storefront-nextjs-shadcn/lib/config.ts +0 -46
- package/templates/storefront-nextjs-shadcn/lib/currency/IMPLEMENTATION_SUMMARY.md +0 -254
- package/templates/storefront-nextjs-shadcn/lib/currency/README.md +0 -464
- package/templates/storefront-nextjs-shadcn/lib/currency/cookie-manager.test.ts +0 -328
- package/templates/storefront-nextjs-shadcn/lib/currency/cookie-manager.ts +0 -295
- package/templates/storefront-nextjs-shadcn/lib/currency/index.ts +0 -27
- package/templates/storefront-nextjs-shadcn/lib/format.ts +0 -226
- package/templates/storefront-nextjs-shadcn/lib/hooks.ts +0 -30
- package/templates/storefront-nextjs-shadcn/stores/auth-store.ts +0 -66
- package/templates/storefront-nextjs-shadcn/stores/currency-store.ts +0 -103
- /package/templates/storefront-nextjs-shadcn/app/{blog → [locale]/blog}/page.tsx +0 -0
- /package/templates/storefront-nextjs-shadcn/app/{brands → [locale]/brands}/[slug]/page.tsx +0 -0
- /package/templates/storefront-nextjs-shadcn/app/{returns → [locale]/returns}/page.tsx +0 -0
- /package/templates/storefront-nextjs-shadcn/app/{search → [locale]/search}/page.tsx +0 -0
- /package/templates/storefront-nextjs-shadcn/app/{search → [locale]/search}/search-client.tsx +0 -0
- /package/templates/storefront-nextjs-shadcn/app/{shipping → [locale]/shipping}/page.tsx +0 -0
|
@@ -1,87 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
* API Route: Clear Authentication Token
|
|
3
|
-
*
|
|
4
|
-
* Clears the customer access token cookie by setting it to expire immediately.
|
|
5
|
-
* This is used during logout to ensure the user is fully signed out.
|
|
6
|
-
*
|
|
7
|
-
* Security Features:
|
|
8
|
-
* 1. Origin validation - Only accepts requests from same origin (CSRF protection)
|
|
9
|
-
* 2. Immediate expiration - Sets maxAge to 0 to delete cookie
|
|
10
|
-
* 3. Same cookie attributes - Ensures proper deletion across all contexts
|
|
11
|
-
*
|
|
12
|
-
* @see lib/auth/cookies.ts - Cookie configuration
|
|
13
|
-
* @see hooks/use-auth.ts - Client-side usage
|
|
14
|
-
*
|
|
15
|
-
* @example
|
|
16
|
-
* ```tsx
|
|
17
|
-
* // Client-side usage (via clearAuthToken helper)
|
|
18
|
-
* await clearAuthToken();
|
|
19
|
-
* ```
|
|
20
|
-
*/
|
|
1
|
+
import { createClearTokenHandler } from '@doswiftly/storefront-sdk';
|
|
21
2
|
|
|
22
|
-
|
|
23
|
-
import { AUTH_COOKIE_CONFIG } from "@/lib/auth/cookies";
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* POST /api/auth/clear-token
|
|
27
|
-
*
|
|
28
|
-
* Clears the authentication token cookie.
|
|
29
|
-
*
|
|
30
|
-
* @param request - Next.js request object
|
|
31
|
-
* @returns Response confirming token was cleared
|
|
32
|
-
*/
|
|
33
|
-
export async function POST(request: NextRequest) {
|
|
34
|
-
try {
|
|
35
|
-
// 1. CSRF Protection: Validate origin
|
|
36
|
-
const origin = request.headers.get("origin");
|
|
37
|
-
const host = request.headers.get("host");
|
|
38
|
-
|
|
39
|
-
// Only allow requests from same origin
|
|
40
|
-
if (origin && !origin.includes(host || "")) {
|
|
41
|
-
return NextResponse.json(
|
|
42
|
-
{ error: "Invalid origin" },
|
|
43
|
-
{ status: 403 }
|
|
44
|
-
);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
// 2. Create response
|
|
48
|
-
const response = NextResponse.json(
|
|
49
|
-
{ success: true, message: "Token cleared successfully" },
|
|
50
|
-
{ status: 200 }
|
|
51
|
-
);
|
|
52
|
-
|
|
53
|
-
// 3. Clear cookie by setting maxAge to 0
|
|
54
|
-
response.cookies.set({
|
|
55
|
-
name: AUTH_COOKIE_CONFIG.name,
|
|
56
|
-
value: "",
|
|
57
|
-
maxAge: 0, // Expire immediately
|
|
58
|
-
path: AUTH_COOKIE_CONFIG.path,
|
|
59
|
-
sameSite: AUTH_COOKIE_CONFIG.sameSite,
|
|
60
|
-
secure: AUTH_COOKIE_CONFIG.secure,
|
|
61
|
-
httpOnly: AUTH_COOKIE_CONFIG.httpOnly,
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
return response;
|
|
65
|
-
} catch (error) {
|
|
66
|
-
console.error("Error clearing auth token:", error);
|
|
67
|
-
return NextResponse.json(
|
|
68
|
-
{ error: "Internal server error" },
|
|
69
|
-
{ status: 500 }
|
|
70
|
-
);
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* OPTIONS /api/auth/clear-token
|
|
76
|
-
*
|
|
77
|
-
* Handle preflight requests for CORS.
|
|
78
|
-
*/
|
|
79
|
-
export async function OPTIONS() {
|
|
80
|
-
return new NextResponse(null, {
|
|
81
|
-
status: 204,
|
|
82
|
-
headers: {
|
|
83
|
-
"Access-Control-Allow-Methods": "POST, OPTIONS",
|
|
84
|
-
"Access-Control-Allow-Headers": "Content-Type",
|
|
85
|
-
},
|
|
86
|
-
});
|
|
87
|
-
}
|
|
3
|
+
export const POST = createClearTokenHandler();
|
|
@@ -1,125 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
* API Route: Set Authentication Token
|
|
3
|
-
*
|
|
4
|
-
* Sets the customer access token in an httpOnly cookie.
|
|
5
|
-
* This provides security by preventing client-side JavaScript from accessing the token.
|
|
6
|
-
*
|
|
7
|
-
* Security Features:
|
|
8
|
-
* 1. httpOnly cookie - Cannot be accessed via JavaScript (XSS protection)
|
|
9
|
-
* 2. Secure flag - Only sent over HTTPS in production
|
|
10
|
-
* 3. SameSite=Lax - CSRF protection
|
|
11
|
-
* 4. Origin validation - Only accepts requests from same origin
|
|
12
|
-
* 5. Content-Type validation - Only accepts JSON
|
|
13
|
-
*
|
|
14
|
-
* @see lib/auth/cookies.ts - Cookie configuration
|
|
15
|
-
* @see hooks/use-auth.ts - Client-side usage
|
|
16
|
-
*
|
|
17
|
-
* @example
|
|
18
|
-
* ```tsx
|
|
19
|
-
* // Client-side usage (via setAuthToken helper)
|
|
20
|
-
* await setAuthToken(customerAccessToken.accessToken);
|
|
21
|
-
* ```
|
|
22
|
-
*/
|
|
1
|
+
import { createSetTokenHandler } from '@doswiftly/storefront-sdk';
|
|
23
2
|
|
|
24
|
-
|
|
25
|
-
import { AUTH_COOKIE_CONFIG } from "@/lib/auth/cookies";
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Request body schema
|
|
29
|
-
*/
|
|
30
|
-
interface SetTokenRequest {
|
|
31
|
-
token: string;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* POST /api/auth/set-token
|
|
36
|
-
*
|
|
37
|
-
* Sets the authentication token in an httpOnly cookie.
|
|
38
|
-
*
|
|
39
|
-
* @param request - Next.js request object
|
|
40
|
-
* @returns Response with Set-Cookie header
|
|
41
|
-
*/
|
|
42
|
-
export async function POST(request: NextRequest) {
|
|
43
|
-
try {
|
|
44
|
-
// 1. CSRF Protection: Validate origin
|
|
45
|
-
const origin = request.headers.get("origin");
|
|
46
|
-
const host = request.headers.get("host");
|
|
47
|
-
|
|
48
|
-
// Only allow requests from same origin
|
|
49
|
-
if (origin && !origin.includes(host || "")) {
|
|
50
|
-
return NextResponse.json(
|
|
51
|
-
{ error: "Invalid origin" },
|
|
52
|
-
{ status: 403 }
|
|
53
|
-
);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
// 2. Validate Content-Type
|
|
57
|
-
const contentType = request.headers.get("content-type");
|
|
58
|
-
if (!contentType?.includes("application/json")) {
|
|
59
|
-
return NextResponse.json(
|
|
60
|
-
{ error: "Content-Type must be application/json" },
|
|
61
|
-
{ status: 400 }
|
|
62
|
-
);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
// 3. Parse and validate request body
|
|
66
|
-
let body: SetTokenRequest;
|
|
67
|
-
try {
|
|
68
|
-
body = await request.json();
|
|
69
|
-
} catch {
|
|
70
|
-
return NextResponse.json(
|
|
71
|
-
{ error: "Invalid JSON body" },
|
|
72
|
-
{ status: 400 }
|
|
73
|
-
);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
const { token } = body;
|
|
77
|
-
|
|
78
|
-
if (!token || typeof token !== "string" || token.trim() === "") {
|
|
79
|
-
return NextResponse.json(
|
|
80
|
-
{ error: "Token is required and must be a non-empty string" },
|
|
81
|
-
{ status: 400 }
|
|
82
|
-
);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
// 4. Create response with Set-Cookie header
|
|
86
|
-
const response = NextResponse.json(
|
|
87
|
-
{ success: true, message: "Token set successfully" },
|
|
88
|
-
{ status: 200 }
|
|
89
|
-
);
|
|
90
|
-
|
|
91
|
-
// 5. Set httpOnly cookie
|
|
92
|
-
response.cookies.set({
|
|
93
|
-
name: AUTH_COOKIE_CONFIG.name,
|
|
94
|
-
value: token,
|
|
95
|
-
maxAge: AUTH_COOKIE_CONFIG.maxAge,
|
|
96
|
-
path: AUTH_COOKIE_CONFIG.path,
|
|
97
|
-
sameSite: AUTH_COOKIE_CONFIG.sameSite,
|
|
98
|
-
secure: AUTH_COOKIE_CONFIG.secure,
|
|
99
|
-
httpOnly: AUTH_COOKIE_CONFIG.httpOnly,
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
return response;
|
|
103
|
-
} catch (error) {
|
|
104
|
-
console.error("Error setting auth token:", error);
|
|
105
|
-
return NextResponse.json(
|
|
106
|
-
{ error: "Internal server error" },
|
|
107
|
-
{ status: 500 }
|
|
108
|
-
);
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
/**
|
|
113
|
-
* OPTIONS /api/auth/set-token
|
|
114
|
-
*
|
|
115
|
-
* Handle preflight requests for CORS.
|
|
116
|
-
*/
|
|
117
|
-
export async function OPTIONS() {
|
|
118
|
-
return new NextResponse(null, {
|
|
119
|
-
status: 204,
|
|
120
|
-
headers: {
|
|
121
|
-
"Access-Control-Allow-Methods": "POST, OPTIONS",
|
|
122
|
-
"Access-Control-Allow-Headers": "Content-Type",
|
|
123
|
-
},
|
|
124
|
-
});
|
|
125
|
-
}
|
|
3
|
+
export const POST = createSetTokenHandler();
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* GlobalError — catches errors from root layout (where error.tsx cannot reach).
|
|
5
|
+
*
|
|
6
|
+
* This replaces the entire <html> document, so it must include its own
|
|
7
|
+
* <html> and <body> tags. No providers, no Header/Footer — just a
|
|
8
|
+
* self-contained error page.
|
|
9
|
+
*
|
|
10
|
+
* Next.js docs: https://nextjs.org/docs/app/api-reference/file-conventions/error#global-errorjs
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { useEffect } from 'react';
|
|
14
|
+
|
|
15
|
+
interface GlobalErrorProps {
|
|
16
|
+
error: Error & { digest?: string };
|
|
17
|
+
reset: () => void;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export default function GlobalError({ error, reset }: GlobalErrorProps) {
|
|
21
|
+
useEffect(() => {
|
|
22
|
+
console.error('[GlobalError]', error);
|
|
23
|
+
}, [error]);
|
|
24
|
+
|
|
25
|
+
return (
|
|
26
|
+
<html lang="pl">
|
|
27
|
+
<body
|
|
28
|
+
style={{
|
|
29
|
+
margin: 0,
|
|
30
|
+
fontFamily:
|
|
31
|
+
'-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
|
|
32
|
+
backgroundColor: '#fafafa',
|
|
33
|
+
color: '#1e293b',
|
|
34
|
+
display: 'flex',
|
|
35
|
+
alignItems: 'center',
|
|
36
|
+
justifyContent: 'center',
|
|
37
|
+
minHeight: '100vh',
|
|
38
|
+
}}
|
|
39
|
+
>
|
|
40
|
+
<div
|
|
41
|
+
style={{
|
|
42
|
+
maxWidth: '28rem',
|
|
43
|
+
width: '100%',
|
|
44
|
+
padding: '2rem',
|
|
45
|
+
textAlign: 'center',
|
|
46
|
+
}}
|
|
47
|
+
>
|
|
48
|
+
<div
|
|
49
|
+
style={{
|
|
50
|
+
width: '4rem',
|
|
51
|
+
height: '4rem',
|
|
52
|
+
margin: '0 auto 1.5rem',
|
|
53
|
+
borderRadius: '50%',
|
|
54
|
+
backgroundColor: '#fef2f2',
|
|
55
|
+
display: 'flex',
|
|
56
|
+
alignItems: 'center',
|
|
57
|
+
justifyContent: 'center',
|
|
58
|
+
fontSize: '1.5rem',
|
|
59
|
+
}}
|
|
60
|
+
>
|
|
61
|
+
!
|
|
62
|
+
</div>
|
|
63
|
+
|
|
64
|
+
<h1 style={{ fontSize: '1.5rem', fontWeight: 600, margin: '0 0 0.5rem' }}>
|
|
65
|
+
Serwer tymczasowo niedostępny
|
|
66
|
+
</h1>
|
|
67
|
+
|
|
68
|
+
<p style={{ color: '#64748b', margin: '0 0 2rem', lineHeight: 1.6 }}>
|
|
69
|
+
Nie udało się załadować strony. Serwer może być tymczasowo niedostępny.
|
|
70
|
+
Spróbuj odświeżyć stronę za chwilę.
|
|
71
|
+
</p>
|
|
72
|
+
|
|
73
|
+
{process.env.NODE_ENV === 'development' && (
|
|
74
|
+
<div
|
|
75
|
+
style={{
|
|
76
|
+
backgroundColor: '#f1f5f9',
|
|
77
|
+
borderRadius: '0.5rem',
|
|
78
|
+
padding: '0.75rem 1rem',
|
|
79
|
+
marginBottom: '1.5rem',
|
|
80
|
+
textAlign: 'left',
|
|
81
|
+
fontSize: '0.75rem',
|
|
82
|
+
wordBreak: 'break-word',
|
|
83
|
+
}}
|
|
84
|
+
>
|
|
85
|
+
<strong style={{ color: '#ef4444' }}>{error.message}</strong>
|
|
86
|
+
{error.digest && (
|
|
87
|
+
<p style={{ color: '#64748b', margin: '0.25rem 0 0' }}>
|
|
88
|
+
Digest: {error.digest}
|
|
89
|
+
</p>
|
|
90
|
+
)}
|
|
91
|
+
</div>
|
|
92
|
+
)}
|
|
93
|
+
|
|
94
|
+
<button
|
|
95
|
+
onClick={reset}
|
|
96
|
+
style={{
|
|
97
|
+
display: 'inline-flex',
|
|
98
|
+
alignItems: 'center',
|
|
99
|
+
justifyContent: 'center',
|
|
100
|
+
width: '100%',
|
|
101
|
+
padding: '0.625rem 1.25rem',
|
|
102
|
+
fontSize: '0.875rem',
|
|
103
|
+
fontWeight: 500,
|
|
104
|
+
color: '#fff',
|
|
105
|
+
backgroundColor: '#3b82f6',
|
|
106
|
+
border: 'none',
|
|
107
|
+
borderRadius: '0.5rem',
|
|
108
|
+
cursor: 'pointer',
|
|
109
|
+
}}
|
|
110
|
+
>
|
|
111
|
+
Spróbuj ponownie
|
|
112
|
+
</button>
|
|
113
|
+
</div>
|
|
114
|
+
</body>
|
|
115
|
+
</html>
|
|
116
|
+
);
|
|
117
|
+
}
|
|
@@ -1,57 +1,30 @@
|
|
|
1
1
|
import type { Metadata } from "next";
|
|
2
2
|
import { Inter } from "next/font/google";
|
|
3
3
|
import "./globals.css";
|
|
4
|
-
import {
|
|
5
|
-
import { Footer } from "@/components/layout/footer";
|
|
6
|
-
import { QueryProvider } from "@/components/providers/query-provider";
|
|
7
|
-
import { CurrencyProvider } from "@/components/providers/currency-provider";
|
|
8
|
-
import { ThemeProvider } from "@/components/providers/theme-provider";
|
|
9
|
-
import { Toaster } from "sonner";
|
|
10
|
-
import { fetchShop } from "@/lib/graphql/server";
|
|
11
|
-
import { themeConfig } from "@/lib/theme/theme-config";
|
|
4
|
+
import { defaultLocale } from "@/i18n/routing";
|
|
12
5
|
|
|
13
6
|
const inter = Inter({ subsets: ["latin"] });
|
|
14
7
|
|
|
15
8
|
const siteName = process.env.NEXT_PUBLIC_SITE_NAME || "My Store";
|
|
9
|
+
const siteUrl = process.env.NEXT_PUBLIC_SITE_URL || "http://localhost:3001";
|
|
16
10
|
|
|
17
11
|
export const metadata: Metadata = {
|
|
12
|
+
metadataBase: new URL(siteUrl),
|
|
18
13
|
title: `${siteName} - E-commerce Store`,
|
|
19
14
|
description: "Welcome to our online store powered by DoSwiftly Commerce",
|
|
20
15
|
};
|
|
21
16
|
|
|
22
|
-
// Enable ISR with 60 second revalidation for shop data (currencies)
|
|
23
|
-
export const revalidate = 60;
|
|
24
|
-
|
|
25
17
|
export default async function RootLayout({
|
|
26
18
|
children,
|
|
19
|
+
params,
|
|
27
20
|
}: {
|
|
28
21
|
children: React.ReactNode;
|
|
22
|
+
params: Promise<{ locale?: string }>;
|
|
29
23
|
}) {
|
|
30
|
-
|
|
31
|
-
const shopData = await fetchShop();
|
|
32
|
-
|
|
24
|
+
const { locale } = await params;
|
|
33
25
|
return (
|
|
34
|
-
<html lang=
|
|
35
|
-
<body className={inter.className}>
|
|
36
|
-
<ThemeProvider
|
|
37
|
-
attribute={themeConfig.attribute}
|
|
38
|
-
defaultTheme={themeConfig.defaultTheme}
|
|
39
|
-
enableSystem={themeConfig.enableSystem}
|
|
40
|
-
disableTransitionOnChange={themeConfig.disableTransitionOnChange}
|
|
41
|
-
storageKey={themeConfig.storageKey}
|
|
42
|
-
>
|
|
43
|
-
<QueryProvider>
|
|
44
|
-
<CurrencyProvider shopData={shopData.shop}>
|
|
45
|
-
<div className="flex min-h-screen flex-col">
|
|
46
|
-
<Header />
|
|
47
|
-
<main className="flex-1">{children}</main>
|
|
48
|
-
<Footer />
|
|
49
|
-
</div>
|
|
50
|
-
<Toaster position="bottom-right" richColors />
|
|
51
|
-
</CurrencyProvider>
|
|
52
|
-
</QueryProvider>
|
|
53
|
-
</ThemeProvider>
|
|
54
|
-
</body>
|
|
26
|
+
<html lang={locale || defaultLocale} suppressHydrationWarning>
|
|
27
|
+
<body className={inter.className}>{children}</body>
|
|
55
28
|
</html>
|
|
56
29
|
);
|
|
57
30
|
}
|
|
@@ -1,45 +1,62 @@
|
|
|
1
|
-
import { CodegenConfig } from '@graphql-codegen/cli';
|
|
2
|
-
import { loadEnvConfig } from '@next/env';
|
|
3
|
-
|
|
4
|
-
// Load environment variables from .env.local
|
|
5
|
-
loadEnvConfig(process.cwd());
|
|
6
|
-
|
|
7
|
-
const apiUrl = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:8000';
|
|
8
|
-
const shopSlug = process.env.NEXT_PUBLIC_SHOP_SLUG || 'test-shop';
|
|
1
|
+
import type { CodegenConfig } from '@graphql-codegen/cli';
|
|
9
2
|
|
|
3
|
+
/**
|
|
4
|
+
* GraphQL Code Generator Configuration
|
|
5
|
+
*
|
|
6
|
+
* Uses `client-preset` with `documentMode: 'string'` (TypedDocumentString).
|
|
7
|
+
* This generates lightweight string-based documents instead of parsed AST objects,
|
|
8
|
+
* eliminating the need for the `graphql` package at runtime.
|
|
9
|
+
*
|
|
10
|
+
* Schema and operations come from @doswiftly/storefront-operations (SSOT).
|
|
11
|
+
* No running backend needed — schema is synced as a file.
|
|
12
|
+
*
|
|
13
|
+
* Architecture decision: https://github.com/dotansimha/graphql-typed-document-node
|
|
14
|
+
* Inspired by: Saleor Storefront (client-preset + TypedDocumentString)
|
|
15
|
+
*
|
|
16
|
+
* To update schema after backend changes:
|
|
17
|
+
* cd packages/@doswiftly/storefront-operations && pnpm run sync
|
|
18
|
+
*/
|
|
10
19
|
const config: CodegenConfig = {
|
|
11
|
-
// Schema from
|
|
12
|
-
schema:
|
|
13
|
-
{
|
|
14
|
-
[`${apiUrl}/storefront/graphql`]: {
|
|
15
|
-
headers: {
|
|
16
|
-
'X-Shop-Slug': shopSlug,
|
|
17
|
-
},
|
|
18
|
-
},
|
|
19
|
-
},
|
|
20
|
-
],
|
|
20
|
+
// Schema from storefront-operations package (no introspection needed!)
|
|
21
|
+
schema: 'node_modules/@doswiftly/storefront-operations/schema.graphql',
|
|
21
22
|
|
|
22
|
-
// Operations: Backend SSOT + Developer Custom Queries
|
|
23
|
+
// Operations: Backend SSOT + Developer Custom Queries + Colocated Component Fragments
|
|
23
24
|
documents: [
|
|
24
|
-
'node_modules/@doswiftly/storefront-operations/**/*.graphql',
|
|
25
|
-
'graphql/**/*.
|
|
25
|
+
'node_modules/@doswiftly/storefront-operations/**/*.graphql',
|
|
26
|
+
'graphql/**/*.graphql',
|
|
27
|
+
'components/**/*.fragment.graphql',
|
|
26
28
|
],
|
|
27
29
|
|
|
28
|
-
// Output configuration
|
|
29
30
|
generates: {
|
|
30
|
-
'generated/
|
|
31
|
-
|
|
32
|
-
'typescript', // Generate TS types
|
|
33
|
-
'typescript-operations', // Generate operation types
|
|
34
|
-
'typed-document-node', // Generate TypedDocumentNode
|
|
35
|
-
],
|
|
31
|
+
'generated/': {
|
|
32
|
+
preset: 'client',
|
|
36
33
|
config: {
|
|
37
|
-
|
|
38
|
-
|
|
34
|
+
// TypedDocumentString: lightweight string wrapper instead of parsed AST
|
|
35
|
+
// Eliminates `graphql` package from runtime bundle (~40kb savings)
|
|
36
|
+
documentMode: 'string',
|
|
37
|
+
|
|
38
|
+
// Scalar mappings
|
|
39
39
|
scalars: {
|
|
40
40
|
DateTime: 'string',
|
|
41
|
-
|
|
41
|
+
Decimal: 'string',
|
|
42
|
+
JSON: 'Record<string, unknown>',
|
|
42
43
|
},
|
|
44
|
+
|
|
45
|
+
// Keep __typename for connection normalization and cache keys
|
|
46
|
+
skipTypename: false,
|
|
47
|
+
|
|
48
|
+
// Readable enum types (union of string literals)
|
|
49
|
+
enumsAsTypes: true,
|
|
50
|
+
|
|
51
|
+
// Deduplicate fragments shared across queries
|
|
52
|
+
dedupeFragments: true,
|
|
53
|
+
|
|
54
|
+
// Use `import type` for cleaner output
|
|
55
|
+
useTypeImports: true,
|
|
56
|
+
},
|
|
57
|
+
presetConfig: {
|
|
58
|
+
// Disable fragment masking — simpler DX, developer sees all fields
|
|
59
|
+
fragmentMasking: false,
|
|
43
60
|
},
|
|
44
61
|
},
|
|
45
62
|
},
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
3
|
import { useState } from "react";
|
|
4
|
+
import { useTranslations } from "next-intl";
|
|
4
5
|
import { Button } from "@/components/ui/button";
|
|
5
6
|
import { Input } from "@/components/ui/input";
|
|
6
7
|
import { Card } from "@/components/ui/card";
|
|
@@ -38,6 +39,10 @@ export function AddressForm({
|
|
|
38
39
|
isLoading = false,
|
|
39
40
|
className,
|
|
40
41
|
}: AddressFormProps) {
|
|
42
|
+
const t = useTranslations("checkout");
|
|
43
|
+
const tc = useTranslations("common");
|
|
44
|
+
const tAccount = useTranslations("account");
|
|
45
|
+
|
|
41
46
|
const [formData, setFormData] = useState<AddressFormData>(
|
|
42
47
|
address || {
|
|
43
48
|
firstName: "",
|
|
@@ -68,25 +73,25 @@ export function AddressForm({
|
|
|
68
73
|
const newErrors: Partial<Record<keyof AddressFormData, string>> = {};
|
|
69
74
|
|
|
70
75
|
if (!formData.firstName.trim()) {
|
|
71
|
-
newErrors.firstName = "
|
|
76
|
+
newErrors.firstName = t("validation.firstNameRequired");
|
|
72
77
|
}
|
|
73
78
|
if (!formData.lastName.trim()) {
|
|
74
|
-
newErrors.lastName = "
|
|
79
|
+
newErrors.lastName = t("validation.lastNameRequired");
|
|
75
80
|
}
|
|
76
81
|
if (!formData.address1.trim()) {
|
|
77
|
-
newErrors.address1 = "
|
|
82
|
+
newErrors.address1 = t("validation.addressRequired");
|
|
78
83
|
}
|
|
79
84
|
if (!formData.city.trim()) {
|
|
80
|
-
newErrors.city = "
|
|
85
|
+
newErrors.city = t("validation.cityRequired");
|
|
81
86
|
}
|
|
82
87
|
if (!formData.province.trim()) {
|
|
83
|
-
newErrors.province = "
|
|
88
|
+
newErrors.province = t("validation.provinceRequired");
|
|
84
89
|
}
|
|
85
90
|
if (!formData.zip.trim()) {
|
|
86
|
-
newErrors.zip = "
|
|
91
|
+
newErrors.zip = t("validation.zipRequired");
|
|
87
92
|
}
|
|
88
93
|
if (!formData.country.trim()) {
|
|
89
|
-
newErrors.country = "
|
|
94
|
+
newErrors.country = t("validation.countryRequired");
|
|
90
95
|
}
|
|
91
96
|
|
|
92
97
|
setErrors(newErrors);
|
|
@@ -113,7 +118,7 @@ export function AddressForm({
|
|
|
113
118
|
htmlFor="firstName"
|
|
114
119
|
className="block text-sm font-medium text-foreground mb-1"
|
|
115
120
|
>
|
|
116
|
-
|
|
121
|
+
{t("address.firstName")} *
|
|
117
122
|
</label>
|
|
118
123
|
<Input
|
|
119
124
|
id="firstName"
|
|
@@ -134,7 +139,7 @@ export function AddressForm({
|
|
|
134
139
|
htmlFor="lastName"
|
|
135
140
|
className="block text-sm font-medium text-foreground mb-1"
|
|
136
141
|
>
|
|
137
|
-
|
|
142
|
+
{t("address.lastName")} *
|
|
138
143
|
</label>
|
|
139
144
|
<Input
|
|
140
145
|
id="lastName"
|
|
@@ -156,7 +161,7 @@ export function AddressForm({
|
|
|
156
161
|
htmlFor="company"
|
|
157
162
|
className="block text-sm font-medium text-foreground mb-1"
|
|
158
163
|
>
|
|
159
|
-
|
|
164
|
+
{`${t("address.company")} (${tc("optional")})`}
|
|
160
165
|
</label>
|
|
161
166
|
<Input
|
|
162
167
|
id="company"
|
|
@@ -173,7 +178,7 @@ export function AddressForm({
|
|
|
173
178
|
htmlFor="address1"
|
|
174
179
|
className="block text-sm font-medium text-foreground mb-1"
|
|
175
180
|
>
|
|
176
|
-
|
|
181
|
+
{t("address.address1")} *
|
|
177
182
|
</label>
|
|
178
183
|
<Input
|
|
179
184
|
id="address1"
|
|
@@ -194,7 +199,7 @@ export function AddressForm({
|
|
|
194
199
|
htmlFor="address2"
|
|
195
200
|
className="block text-sm font-medium text-foreground mb-1"
|
|
196
201
|
>
|
|
197
|
-
|
|
202
|
+
{`${t("address.address2")} (${tc("optional")})`}
|
|
198
203
|
</label>
|
|
199
204
|
<Input
|
|
200
205
|
id="address2"
|
|
@@ -212,7 +217,7 @@ export function AddressForm({
|
|
|
212
217
|
htmlFor="city"
|
|
213
218
|
className="block text-sm font-medium text-foreground mb-1"
|
|
214
219
|
>
|
|
215
|
-
|
|
220
|
+
{t("address.city")} *
|
|
216
221
|
</label>
|
|
217
222
|
<Input
|
|
218
223
|
id="city"
|
|
@@ -233,7 +238,7 @@ export function AddressForm({
|
|
|
233
238
|
htmlFor="province"
|
|
234
239
|
className="block text-sm font-medium text-foreground mb-1"
|
|
235
240
|
>
|
|
236
|
-
|
|
241
|
+
{t("address.province")} *
|
|
237
242
|
</label>
|
|
238
243
|
<Input
|
|
239
244
|
id="province"
|
|
@@ -254,7 +259,7 @@ export function AddressForm({
|
|
|
254
259
|
htmlFor="zip"
|
|
255
260
|
className="block text-sm font-medium text-foreground mb-1"
|
|
256
261
|
>
|
|
257
|
-
|
|
262
|
+
{t("address.zip")} *
|
|
258
263
|
</label>
|
|
259
264
|
<Input
|
|
260
265
|
id="zip"
|
|
@@ -276,7 +281,7 @@ export function AddressForm({
|
|
|
276
281
|
htmlFor="country"
|
|
277
282
|
className="block text-sm font-medium text-foreground mb-1"
|
|
278
283
|
>
|
|
279
|
-
|
|
284
|
+
{t("address.country")} *
|
|
280
285
|
</label>
|
|
281
286
|
<Input
|
|
282
287
|
id="country"
|
|
@@ -297,7 +302,7 @@ export function AddressForm({
|
|
|
297
302
|
htmlFor="phone"
|
|
298
303
|
className="block text-sm font-medium text-foreground mb-1"
|
|
299
304
|
>
|
|
300
|
-
|
|
305
|
+
{`${t("address.phone")} (${tc("optional")})`}
|
|
301
306
|
</label>
|
|
302
307
|
<Input
|
|
303
308
|
id="phone"
|
|
@@ -322,14 +327,14 @@ export function AddressForm({
|
|
|
322
327
|
htmlFor="isDefault"
|
|
323
328
|
className="text-sm font-medium text-foreground"
|
|
324
329
|
>
|
|
325
|
-
|
|
330
|
+
{tAccount("setAsDefault")}
|
|
326
331
|
</label>
|
|
327
332
|
</div>
|
|
328
333
|
|
|
329
334
|
{/* Form Actions */}
|
|
330
335
|
<div className="flex gap-3 pt-4">
|
|
331
336
|
<Button type="submit" disabled={isLoading} className="flex-1">
|
|
332
|
-
{isLoading ? "
|
|
337
|
+
{isLoading ? tc("saving") : address ? tAccount("editAddress") : tAccount("addAddress")}
|
|
333
338
|
</Button>
|
|
334
339
|
{onCancel && (
|
|
335
340
|
<Button
|
|
@@ -338,7 +343,7 @@ export function AddressForm({
|
|
|
338
343
|
onClick={onCancel}
|
|
339
344
|
disabled={isLoading}
|
|
340
345
|
>
|
|
341
|
-
|
|
346
|
+
{tc("cancel")}
|
|
342
347
|
</Button>
|
|
343
348
|
)}
|
|
344
349
|
</div>
|