@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,241 +1,54 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
import { useCallback, useRef } from 'react';
|
|
4
|
-
import { useCartStore } from '@/stores/cart-store';
|
|
5
|
-
import { useCartCreate, useCartLinesAdd, useCartLinesUpdate, useCartLinesRemove } from '@/lib/graphql/hooks';
|
|
6
|
-
import { toast } from 'sonner';
|
|
3
|
+
import { useCallback, useEffect, useRef } from 'react';
|
|
4
|
+
import { useCartStore, useCartStoreApi } from '@/stores/cart-store';
|
|
7
5
|
|
|
8
6
|
// Debounce delay for quantity updates (prevents rate limiting)
|
|
9
7
|
const QUANTITY_UPDATE_DEBOUNCE_MS = 500;
|
|
10
8
|
|
|
11
9
|
/**
|
|
12
|
-
* Hook for cart mutations —
|
|
10
|
+
* Hook for cart mutations — delegates orchestration to SDK cart store.
|
|
13
11
|
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
12
|
+
* SDK handles: cart init, DI actions, error state, callbacks.
|
|
13
|
+
* Template handles: debounce, openCart UX.
|
|
16
14
|
*
|
|
17
15
|
* @example
|
|
18
16
|
* ```typescript
|
|
19
17
|
* const { addToCart, updateQuantity, removeFromCart } = useCartActions();
|
|
20
|
-
*
|
|
21
|
-
* await addToCart({
|
|
22
|
-
* variantId: 'variant-123',
|
|
23
|
-
* productId: 'product-456',
|
|
24
|
-
* productTitle: 'T-Shirt',
|
|
25
|
-
* variantTitle: 'Large / Blue',
|
|
26
|
-
* price: { amount: '29.99', currencyCode: 'USD' },
|
|
27
|
-
* quantity: 1
|
|
28
|
-
* });
|
|
29
|
-
*
|
|
30
|
-
* // updateQuantity and removeFromCart take lineId (not variantId)
|
|
31
|
-
* updateQuantity('line-abc', 3);
|
|
32
|
-
* removeFromCart('line-abc');
|
|
18
|
+
* await addToCart('variant-123', 1);
|
|
33
19
|
* ```
|
|
34
20
|
*/
|
|
35
21
|
export function useCartActions() {
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
clearCart,
|
|
39
|
-
openCart,
|
|
40
|
-
} = useCartStore();
|
|
22
|
+
const api = useCartStoreApi();
|
|
23
|
+
const isLoading = useCartStore((s) => s.isLoading);
|
|
41
24
|
|
|
42
|
-
//
|
|
43
|
-
const createCartMutation = useCartCreate();
|
|
44
|
-
const addLinesMutation = useCartLinesAdd();
|
|
45
|
-
const updateLinesMutation = useCartLinesUpdate();
|
|
46
|
-
const removeLinesMutation = useCartLinesRemove();
|
|
47
|
-
|
|
48
|
-
// Debounce refs for quantity updates (prevents ThrottlerException on rapid clicks)
|
|
25
|
+
// Debounce refs for quantity updates
|
|
49
26
|
const updateTimeoutRef = useRef<Map<string, NodeJS.Timeout>>(new Map());
|
|
50
|
-
const pendingUpdatesRef = useRef<Map<string, { lineId: string; quantity: number }>>(new Map());
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* Get or create cart ID.
|
|
54
|
-
* Reads cartId from store (fresh, not stale closure) or creates a new cart.
|
|
55
|
-
*/
|
|
56
|
-
const getOrCreateCartId = useCallback(async (forceNew: boolean = false): Promise<string> => {
|
|
57
|
-
const currentCartId = useCartStore.getState().cartId;
|
|
58
|
-
if (currentCartId && !forceNew) {
|
|
59
|
-
return currentCartId;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
try {
|
|
63
|
-
const result = await createCartMutation.mutateAsync({ input: {} });
|
|
64
|
-
|
|
65
|
-
if (result.cartCreate.cart) {
|
|
66
|
-
const newCartId = result.cartCreate.cart.id;
|
|
67
|
-
setCartId(newCartId);
|
|
68
|
-
return newCartId;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
if (result.cartCreate.userErrors?.length > 0) {
|
|
72
|
-
throw new Error(result.cartCreate.userErrors[0].message);
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
throw new Error('Failed to create cart');
|
|
76
|
-
} catch (error: any) {
|
|
77
|
-
console.error('Cart creation failed:', error);
|
|
78
|
-
throw error;
|
|
79
|
-
}
|
|
80
|
-
}, [setCartId, createCartMutation]);
|
|
81
27
|
|
|
82
28
|
/**
|
|
83
|
-
*
|
|
29
|
+
* Add item to cart by variant ID, delegates to SDK store.
|
|
84
30
|
*/
|
|
85
|
-
const
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
};
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* Add item to cart (server-only).
|
|
93
|
-
*
|
|
94
|
-
* Creates cart if needed. On "cart not found", clears cartId, creates new cart, retries once.
|
|
95
|
-
* React Query cache invalidation in hooks.ts updates all useCartSync consumers.
|
|
96
|
-
*/
|
|
97
|
-
const addToCart = useCallback(async (item: {
|
|
98
|
-
variantId: string;
|
|
99
|
-
productId: string;
|
|
100
|
-
productHandle?: string;
|
|
101
|
-
productTitle: string;
|
|
102
|
-
variantTitle: string;
|
|
103
|
-
price: { amount: string; currencyCode: string };
|
|
104
|
-
image?: { url: string; altText?: string | null } | null;
|
|
105
|
-
available?: boolean;
|
|
106
|
-
quantity?: number;
|
|
107
|
-
}, _options?: { _forceNewCart?: boolean }) => {
|
|
108
|
-
const forceNewCart = _options?._forceNewCart ?? false;
|
|
109
|
-
|
|
110
|
-
try {
|
|
111
|
-
const cartId = await getOrCreateCartId(forceNewCart);
|
|
112
|
-
|
|
113
|
-
const result = await addLinesMutation.mutateAsync({
|
|
114
|
-
cartId,
|
|
115
|
-
lines: [{
|
|
116
|
-
merchandiseId: item.variantId,
|
|
117
|
-
quantity: item.quantity ?? 1,
|
|
118
|
-
}],
|
|
119
|
-
});
|
|
120
|
-
|
|
121
|
-
if (result.cartLinesAdd.userErrors?.length > 0) {
|
|
122
|
-
const errorMessage = result.cartLinesAdd.userErrors[0].message;
|
|
123
|
-
|
|
124
|
-
if (isCartNotFoundError({ message: errorMessage }) && !forceNewCart) {
|
|
125
|
-
console.warn('Cart expired, creating new cart and retrying...');
|
|
126
|
-
setCartId(null);
|
|
127
|
-
return addToCart(item, { _forceNewCart: true });
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
throw new Error(errorMessage);
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
// Open cart drawer to show the added item
|
|
134
|
-
openCart();
|
|
135
|
-
toast.success('Added to cart');
|
|
136
|
-
} catch (error: any) {
|
|
137
|
-
if (isCartNotFoundError(error) && !forceNewCart) {
|
|
138
|
-
console.warn('Cart expired (caught), creating new cart and retrying...');
|
|
139
|
-
setCartId(null);
|
|
140
|
-
return addToCart(item, { _forceNewCart: true });
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
console.error('Add to cart failed:', error);
|
|
144
|
-
toast.error(error.message || 'Failed to add to cart');
|
|
145
|
-
throw error;
|
|
146
|
-
}
|
|
147
|
-
}, [setCartId, openCart, getOrCreateCartId, addLinesMutation]);
|
|
31
|
+
const addToCart = useCallback(async (variantId: string, quantity = 1) => {
|
|
32
|
+
await api.getState().addToCart([{ merchandiseId: variantId, quantity }]);
|
|
33
|
+
api.getState().openCart();
|
|
34
|
+
}, [api]);
|
|
148
35
|
|
|
149
36
|
/**
|
|
150
|
-
* Execute the actual
|
|
37
|
+
* Execute the actual quantity update via SDK store.
|
|
151
38
|
*/
|
|
152
39
|
const executeQuantityUpdate = useCallback(async (lineId: string, quantity: number) => {
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
if (!currentCartId) {
|
|
156
|
-
throw new Error('No cart found');
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
const result = await updateLinesMutation.mutateAsync({
|
|
160
|
-
cartId: currentCartId,
|
|
161
|
-
lines: [{
|
|
162
|
-
id: lineId,
|
|
163
|
-
quantity,
|
|
164
|
-
}],
|
|
165
|
-
});
|
|
166
|
-
|
|
167
|
-
if (result.cartLinesUpdate.userErrors?.length > 0) {
|
|
168
|
-
const errorMessage = result.cartLinesUpdate.userErrors[0].message;
|
|
169
|
-
|
|
170
|
-
if (isCartNotFoundError({ message: errorMessage })) {
|
|
171
|
-
console.warn('Cart expired during update, clearing cart');
|
|
172
|
-
clearCart();
|
|
173
|
-
toast.error('Your cart has expired. Please add items again.');
|
|
174
|
-
return;
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
throw new Error(errorMessage);
|
|
178
|
-
}
|
|
179
|
-
} catch (error: any) {
|
|
180
|
-
if (isCartNotFoundError(error)) {
|
|
181
|
-
console.warn('Cart expired during update (caught), clearing cart');
|
|
182
|
-
clearCart();
|
|
183
|
-
toast.error('Your cart has expired. Please add items again.');
|
|
184
|
-
return;
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
console.error('Update quantity failed:', error);
|
|
188
|
-
toast.error(error.message || 'Failed to update quantity');
|
|
189
|
-
}
|
|
190
|
-
}, [updateLinesMutation, clearCart]);
|
|
40
|
+
await api.getState().updateQuantity([{ id: lineId, quantity }]);
|
|
41
|
+
}, [api]);
|
|
191
42
|
|
|
192
43
|
/**
|
|
193
44
|
* Remove item from cart by line ID.
|
|
194
|
-
*
|
|
195
|
-
* Silently handles expired cart (just clears stale cartId).
|
|
196
45
|
*/
|
|
197
46
|
const removeFromCart = useCallback(async (lineId: string) => {
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
if (!currentCartId) {
|
|
201
|
-
return;
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
const result = await removeLinesMutation.mutateAsync({
|
|
205
|
-
cartId: currentCartId,
|
|
206
|
-
lineIds: [lineId],
|
|
207
|
-
});
|
|
208
|
-
|
|
209
|
-
if (result.cartLinesRemove.userErrors?.length > 0) {
|
|
210
|
-
const errorMessage = result.cartLinesRemove.userErrors[0].message;
|
|
211
|
-
|
|
212
|
-
if (isCartNotFoundError({ message: errorMessage })) {
|
|
213
|
-
console.warn('Cart expired during remove, clearing stale cartId');
|
|
214
|
-
setCartId(null);
|
|
215
|
-
return;
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
throw new Error(errorMessage);
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
toast.success('Removed from cart');
|
|
222
|
-
} catch (error: any) {
|
|
223
|
-
if (isCartNotFoundError(error)) {
|
|
224
|
-
console.warn('Cart expired during remove (caught), clearing stale cartId');
|
|
225
|
-
setCartId(null);
|
|
226
|
-
return;
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
console.error('Remove from cart failed:', error);
|
|
230
|
-
toast.error(error.message || 'Failed to remove from cart');
|
|
231
|
-
throw error;
|
|
232
|
-
}
|
|
233
|
-
}, [setCartId, removeLinesMutation]);
|
|
47
|
+
await api.getState().removeFromCart([lineId]);
|
|
48
|
+
}, [api]);
|
|
234
49
|
|
|
235
50
|
/**
|
|
236
|
-
* Update item quantity (debounced
|
|
237
|
-
*
|
|
238
|
-
* Debounces GraphQL API calls to prevent ThrottlerException on rapid clicks.
|
|
51
|
+
* Update item quantity (debounced).
|
|
239
52
|
* If quantity <= 0, removes the item instead.
|
|
240
53
|
*/
|
|
241
54
|
const updateQuantity = useCallback((lineId: string, quantity: number) => {
|
|
@@ -244,43 +57,35 @@ export function useCartActions() {
|
|
|
244
57
|
return;
|
|
245
58
|
}
|
|
246
59
|
|
|
247
|
-
// Cancel any pending update for this line
|
|
248
60
|
const existingTimeout = updateTimeoutRef.current.get(lineId);
|
|
249
61
|
if (existingTimeout) {
|
|
250
62
|
clearTimeout(existingTimeout);
|
|
251
63
|
}
|
|
252
64
|
|
|
253
|
-
// Store the pending update
|
|
254
|
-
pendingUpdatesRef.current.set(lineId, { lineId, quantity });
|
|
255
|
-
|
|
256
|
-
// Schedule debounced API call
|
|
257
65
|
const timeout = setTimeout(() => {
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
pendingUpdatesRef.current.delete(lineId);
|
|
261
|
-
updateTimeoutRef.current.delete(lineId);
|
|
262
|
-
executeQuantityUpdate(pending.lineId, pending.quantity);
|
|
263
|
-
}
|
|
66
|
+
updateTimeoutRef.current.delete(lineId);
|
|
67
|
+
executeQuantityUpdate(lineId, quantity);
|
|
264
68
|
}, QUANTITY_UPDATE_DEBOUNCE_MS);
|
|
265
69
|
|
|
266
70
|
updateTimeoutRef.current.set(lineId, timeout);
|
|
267
71
|
}, [removeFromCart, executeQuantityUpdate]);
|
|
268
72
|
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
73
|
+
// Cleanup pending debounce timeouts on unmount
|
|
74
|
+
useEffect(() => {
|
|
75
|
+
const timeouts = updateTimeoutRef.current;
|
|
76
|
+
return () => {
|
|
77
|
+
for (const timeout of timeouts.values()) {
|
|
78
|
+
clearTimeout(timeout);
|
|
79
|
+
}
|
|
80
|
+
timeouts.clear();
|
|
81
|
+
};
|
|
82
|
+
}, []);
|
|
277
83
|
|
|
278
84
|
return {
|
|
279
85
|
addToCart,
|
|
280
86
|
updateQuantity,
|
|
281
87
|
removeFromCart,
|
|
282
|
-
clearCart:
|
|
283
|
-
isLoading
|
|
284
|
-
updateLinesMutation.isPending || removeLinesMutation.isPending,
|
|
88
|
+
clearCart: useCallback(() => api.getState().clearCart(), [api]),
|
|
89
|
+
isLoading,
|
|
285
90
|
};
|
|
286
91
|
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { useMemo } from 'react';
|
|
4
|
+
import type { CartActions, CartData } from '@doswiftly/storefront-sdk/react';
|
|
5
|
+
import { assertNoUserErrors } from '@doswiftly/storefront-sdk';
|
|
6
|
+
import { useExecute } from '@/lib/graphql/client';
|
|
7
|
+
import type { CartQuery, CartCreateMutation, CartLinesAddMutation, CartLinesUpdateMutation, CartLinesRemoveMutation } from '@/generated/graphql';
|
|
8
|
+
import {
|
|
9
|
+
CartDocument,
|
|
10
|
+
CartCreateDocument,
|
|
11
|
+
CartLinesAddDocument,
|
|
12
|
+
CartLinesUpdateDocument,
|
|
13
|
+
CartLinesRemoveDocument,
|
|
14
|
+
} from '@/generated/graphql';
|
|
15
|
+
|
|
16
|
+
interface CartMutationResult {
|
|
17
|
+
cart: { id: string; totalQuantity: number } | null;
|
|
18
|
+
userErrors: Array<{ message: string; field?: string[]; code?: string }>;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function extractCartData(result: CartMutationResult): CartData {
|
|
22
|
+
assertNoUserErrors(result);
|
|
23
|
+
return { id: result.cart!.id, totalQuantity: result.cart!.totalQuantity };
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* CartActions DI implementation using template's GraphQL operations.
|
|
28
|
+
*
|
|
29
|
+
* Maps generated GraphQL documents to the SDK CartActions interface.
|
|
30
|
+
* Used by StoresProvider to wire createCartStore with template transport.
|
|
31
|
+
*/
|
|
32
|
+
export function useCartDI(): CartActions {
|
|
33
|
+
const execute = useExecute();
|
|
34
|
+
|
|
35
|
+
return useMemo(
|
|
36
|
+
(): CartActions => ({
|
|
37
|
+
fetchCart: async (cartId) => {
|
|
38
|
+
const data = await execute<CartQuery>(CartDocument.toString(), { id: cartId });
|
|
39
|
+
if (!data.cart) return null;
|
|
40
|
+
return { id: data.cart.id, totalQuantity: data.cart.totalQuantity };
|
|
41
|
+
},
|
|
42
|
+
|
|
43
|
+
createCart: async () => {
|
|
44
|
+
const data = await execute<CartCreateMutation>(CartCreateDocument.toString(), { input: {} });
|
|
45
|
+
assertNoUserErrors(data.cartCreate);
|
|
46
|
+
if (!data.cartCreate.cart) throw new Error('Failed to create cart');
|
|
47
|
+
return data.cartCreate.cart.id;
|
|
48
|
+
},
|
|
49
|
+
|
|
50
|
+
addLines: async (cartId, lines) => {
|
|
51
|
+
const data = await execute<CartLinesAddMutation>(CartLinesAddDocument.toString(), { cartId, lines });
|
|
52
|
+
return extractCartData(data.cartLinesAdd);
|
|
53
|
+
},
|
|
54
|
+
|
|
55
|
+
updateLines: async (cartId, lines) => {
|
|
56
|
+
const data = await execute<CartLinesUpdateMutation>(CartLinesUpdateDocument.toString(), { cartId, lines });
|
|
57
|
+
return extractCartData(data.cartLinesUpdate);
|
|
58
|
+
},
|
|
59
|
+
|
|
60
|
+
removeLines: async (cartId, lineIds) => {
|
|
61
|
+
const data = await execute<CartLinesRemoveMutation>(CartLinesRemoveDocument.toString(), { cartId, lineIds });
|
|
62
|
+
return extractCartData(data.cartLinesRemove);
|
|
63
|
+
},
|
|
64
|
+
}),
|
|
65
|
+
[execute],
|
|
66
|
+
);
|
|
67
|
+
}
|
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
import { useEffect } from "react";
|
|
4
4
|
import { useCart } from "@/lib/graphql/hooks";
|
|
5
5
|
import { useCartStore } from "@/stores/cart-store";
|
|
6
|
+
import { useHydrated } from "@doswiftly/storefront-sdk/react";
|
|
7
|
+
import type { CartLineFields } from "@/lib/graphql/fragments";
|
|
6
8
|
|
|
7
9
|
/**
|
|
8
10
|
* Mapped cart item for display components.
|
|
@@ -31,28 +33,30 @@ export interface CartItemData {
|
|
|
31
33
|
*/
|
|
32
34
|
export function useCartSync() {
|
|
33
35
|
const cartId = useCartStore((state) => state.cartId);
|
|
34
|
-
const
|
|
35
|
-
const
|
|
36
|
+
const clearCart = useCartStore((state) => state.clearCart);
|
|
37
|
+
const isHydrated = useHydrated();
|
|
36
38
|
|
|
37
|
-
const { data, isLoading, error, refetch } = useCart(cartId, {
|
|
39
|
+
const { data, isLoading, isSuccess, error, refetch } = useCart(cartId, {
|
|
38
40
|
enabled: isHydrated && Boolean(cartId),
|
|
39
41
|
retry: false,
|
|
40
42
|
});
|
|
41
43
|
|
|
42
44
|
const cart = data?.cart;
|
|
43
45
|
|
|
44
|
-
// Detect stale cart: cartId exists but server
|
|
45
|
-
|
|
46
|
+
// Detect stale cart: cartId exists but server confirmed no cart (isSuccess + !cart).
|
|
47
|
+
// Using isSuccess instead of !isLoading prevents false positives when queries are
|
|
48
|
+
// cancelled by mutation optimistic updates (cancelled query → status='pending', not 'success').
|
|
49
|
+
const isStaleCart = isHydrated && Boolean(cartId) && isSuccess && !cart;
|
|
46
50
|
|
|
47
51
|
// Auto-clear stale cartId
|
|
48
52
|
useEffect(() => {
|
|
49
53
|
if (isStaleCart) {
|
|
50
|
-
|
|
54
|
+
clearCart();
|
|
51
55
|
}
|
|
52
|
-
}, [isStaleCart,
|
|
56
|
+
}, [isStaleCart, clearCart]);
|
|
53
57
|
|
|
54
58
|
// Map GraphQL lines to display-friendly items
|
|
55
|
-
const items: CartItemData[] = (cart?.lines ?? []).map((line:
|
|
59
|
+
const items: CartItemData[] = (cart?.lines ?? []).map((line: CartLineFields) => {
|
|
56
60
|
const merchandiseTitle = line.merchandise.title ?? "";
|
|
57
61
|
// Hide generic variant names like "Default" or "Default Title"
|
|
58
62
|
const isDefaultVariant = /^default(\s+title)?$/i.test(merchandiseTitle);
|
|
@@ -63,10 +67,10 @@ export function useCartSync() {
|
|
|
63
67
|
lineId: line.id,
|
|
64
68
|
variantId: line.merchandise.id,
|
|
65
69
|
productId: line.productId || line.merchandise.id,
|
|
66
|
-
productHandle: line.productHandle,
|
|
70
|
+
productHandle: line.productHandle ?? undefined,
|
|
67
71
|
productTitle,
|
|
68
72
|
variantTitle,
|
|
69
|
-
productType: line.productType,
|
|
73
|
+
productType: line.productType ?? undefined,
|
|
70
74
|
quantity: line.quantity,
|
|
71
75
|
price: {
|
|
72
76
|
amount: line.merchandise.price.amount,
|
|
@@ -88,8 +92,8 @@ export function useCartSync() {
|
|
|
88
92
|
|
|
89
93
|
// Discount data from server
|
|
90
94
|
const discountCodes: string[] = (cart?.discountCodes ?? [])
|
|
91
|
-
.filter((dc
|
|
92
|
-
.map((dc
|
|
95
|
+
.filter((dc) => dc.applicable)
|
|
96
|
+
.map((dc) => dc.code);
|
|
93
97
|
const totalDiscount = subtotal - total;
|
|
94
98
|
|
|
95
99
|
return {
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { createNavigation } from 'next-intl/navigation';
|
|
2
|
+
import { defaultLocale, localePrefix } from './routing';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Navigation APIs for dynamic locales.
|
|
6
|
+
*
|
|
7
|
+
* No `locales` argument — any locale string accepted at runtime.
|
|
8
|
+
* Backend is SSOT for supportedLanguages.
|
|
9
|
+
* `defaultLocale` required for `as-needed` prefix mode (hides default in URL).
|
|
10
|
+
*/
|
|
11
|
+
export const { Link, redirect, usePathname, useRouter, getPathname } =
|
|
12
|
+
createNavigation({ defaultLocale, localePrefix });
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { getRequestConfig } from 'next-intl/server';
|
|
2
|
+
import { defaultLocale } from './routing';
|
|
3
|
+
|
|
4
|
+
export default getRequestConfig(async ({ requestLocale }) => {
|
|
5
|
+
// requestLocale is set by next-intl middleware (proxy.ts) which validates
|
|
6
|
+
// against dynamic locales from backend. If somehow invalid, fall back.
|
|
7
|
+
const locale = (await requestLocale) || defaultLocale;
|
|
8
|
+
|
|
9
|
+
let messages;
|
|
10
|
+
try {
|
|
11
|
+
messages = (await import(`../messages/${locale}.json`)).default;
|
|
12
|
+
} catch {
|
|
13
|
+
messages = (await import(`../messages/${defaultLocale}.json`)).default;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
return { locale, messages };
|
|
17
|
+
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* next-intl routing configuration (dynamic locales).
|
|
3
|
+
*
|
|
4
|
+
* - defaultLocale: from NEXT_PUBLIC_DEFAULT_LOCALE env var (set by CLI `doswiftly init`), fallback 'pl'.
|
|
5
|
+
* - localePrefix: 'as-needed' — default locale hidden in URL, others prefixed.
|
|
6
|
+
* - locales: NOT defined here — backend is SSOT for supportedLanguages.
|
|
7
|
+
* - Middleware (proxy.ts) fetches supportedLanguages dynamically per-request.
|
|
8
|
+
* - Navigation API (navigation.ts) accepts any locale string at runtime.
|
|
9
|
+
* - Layout validates against backend's shop.supportedLanguages.
|
|
10
|
+
*
|
|
11
|
+
* No `defineRouting` — we export primitives consumed by createNavigation and createMiddleware.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
export const defaultLocale =
|
|
15
|
+
(process.env.NEXT_PUBLIC_DEFAULT_LOCALE as string) || 'pl';
|
|
16
|
+
|
|
17
|
+
export const localePrefix = 'as-needed' as const;
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Auth Routes Configuration (SSOT)
|
|
3
3
|
*
|
|
4
4
|
* This file is the single source of truth for authentication routes.
|
|
5
|
-
* Used by
|
|
5
|
+
* Used by proxy.ts and can be imported by components if needed.
|
|
6
6
|
*
|
|
7
7
|
* IMPORTANT: Checkout is NOT protected to allow guest checkout (e-commerce best practice).
|
|
8
8
|
* Users can optionally log in during checkout to use saved addresses.
|
|
@@ -16,6 +16,9 @@
|
|
|
16
16
|
* export const guestOnlyRoutes = ['/auth/login', '/auth/register', '/auth/forgot-password'];
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
|
+
// Re-export platform constants and matching utility from SDK
|
|
20
|
+
export { AUTH_COOKIE_NAME, matchesRoute } from '@doswiftly/storefront-sdk';
|
|
21
|
+
|
|
19
22
|
/**
|
|
20
23
|
* Routes that require authentication.
|
|
21
24
|
* Unauthenticated users will be redirected to login.
|
|
@@ -30,12 +33,6 @@ export const protectedRoutes = ["/account"];
|
|
|
30
33
|
*/
|
|
31
34
|
export const guestOnlyRoutes = ["/auth/login", "/auth/register"];
|
|
32
35
|
|
|
33
|
-
/**
|
|
34
|
-
* Cookie name for customer access token.
|
|
35
|
-
* Must match the cookie name used by commerce-sdk.
|
|
36
|
-
*/
|
|
37
|
-
export const AUTH_COOKIE_NAME = "customerAccessToken";
|
|
38
|
-
|
|
39
36
|
/**
|
|
40
37
|
* Default redirect paths
|
|
41
38
|
*/
|
|
@@ -45,13 +42,3 @@ export const redirects = {
|
|
|
45
42
|
/** Where to redirect authenticated users trying to access guest-only routes */
|
|
46
43
|
authenticated: "/account",
|
|
47
44
|
} as const;
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Check if a pathname matches any route in the list.
|
|
51
|
-
* Supports both exact matches and prefix matches (e.g., /account matches /account/orders).
|
|
52
|
-
*/
|
|
53
|
-
export function matchesRoute(pathname: string, routes: string[]): boolean {
|
|
54
|
-
return routes.some(
|
|
55
|
-
(route) => pathname === route || pathname.startsWith(`${route}/`)
|
|
56
|
-
);
|
|
57
|
-
}
|