@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,34 +1,45 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
import { useCurrencyStore } from "
|
|
3
|
+
import { useCurrencyStore } from "@doswiftly/storefront-sdk/react";
|
|
4
|
+
import { CURRENCY_LOCALES } from "@doswiftly/storefront-sdk";
|
|
5
|
+
|
|
6
|
+
/** Resolve locale from currency code using the centralized CURRENCY_LOCALES map */
|
|
7
|
+
function getLocaleForCurrency(currencyCode: string): string {
|
|
8
|
+
return CURRENCY_LOCALES[currencyCode] || "en-US";
|
|
9
|
+
}
|
|
4
10
|
|
|
5
11
|
export interface PriceDisplayProps {
|
|
6
12
|
amount: string | number;
|
|
7
13
|
currency?: string;
|
|
8
14
|
className?: string;
|
|
9
15
|
showCurrency?: boolean;
|
|
10
|
-
locale?: string;
|
|
11
16
|
}
|
|
12
17
|
|
|
13
18
|
/**
|
|
14
19
|
* PriceDisplay - Formatted price with currency
|
|
15
|
-
* Automatically uses the user's preferred currency from the currency store
|
|
20
|
+
* Automatically uses the user's preferred currency from the currency store.
|
|
21
|
+
* Locale is derived from currency code — no hardcoded locale.
|
|
16
22
|
*/
|
|
17
23
|
export function PriceDisplay({
|
|
18
24
|
amount,
|
|
19
25
|
currency,
|
|
20
26
|
className = "",
|
|
21
27
|
showCurrency = true,
|
|
22
|
-
locale = "pl-PL",
|
|
23
28
|
}: PriceDisplayProps) {
|
|
24
29
|
const preferredCurrency = useCurrencyStore((state) => state.currency);
|
|
30
|
+
const isLoaded = useCurrencyStore((state) => state.isLoaded);
|
|
25
31
|
const finalCurrency = currency || preferredCurrency || "PLN";
|
|
32
|
+
const locale = getLocaleForCurrency(finalCurrency);
|
|
33
|
+
|
|
34
|
+
if (!isLoaded && !currency) {
|
|
35
|
+
return <span className={`inline-block h-4 w-16 animate-pulse rounded bg-muted ${className}`} />;
|
|
36
|
+
}
|
|
26
37
|
|
|
27
38
|
const formatPrice = (value: string | number, curr: string) => {
|
|
28
39
|
const numericValue = typeof value === "string" ? parseFloat(value) : value;
|
|
29
40
|
|
|
30
41
|
if (isNaN(numericValue)) {
|
|
31
|
-
return "
|
|
42
|
+
return "\u2014";
|
|
32
43
|
}
|
|
33
44
|
|
|
34
45
|
if (showCurrency) {
|
|
@@ -56,7 +67,6 @@ export interface PriceRangeDisplayProps {
|
|
|
56
67
|
maxAmount: string | number;
|
|
57
68
|
currency?: string;
|
|
58
69
|
className?: string;
|
|
59
|
-
locale?: string;
|
|
60
70
|
}
|
|
61
71
|
|
|
62
72
|
/**
|
|
@@ -67,16 +77,21 @@ export function PriceRangeDisplay({
|
|
|
67
77
|
maxAmount,
|
|
68
78
|
currency,
|
|
69
79
|
className = "",
|
|
70
|
-
locale = "pl-PL",
|
|
71
80
|
}: PriceRangeDisplayProps) {
|
|
72
81
|
const preferredCurrency = useCurrencyStore((state) => state.currency);
|
|
82
|
+
const isLoaded = useCurrencyStore((state) => state.isLoaded);
|
|
73
83
|
const finalCurrency = currency || preferredCurrency || "PLN";
|
|
84
|
+
const locale = getLocaleForCurrency(finalCurrency);
|
|
85
|
+
|
|
86
|
+
if (!isLoaded && !currency) {
|
|
87
|
+
return <span className={`inline-block h-4 w-24 animate-pulse rounded bg-muted ${className}`} />;
|
|
88
|
+
}
|
|
74
89
|
|
|
75
90
|
const formatPrice = (value: string | number) => {
|
|
76
91
|
const numericValue = typeof value === "string" ? parseFloat(value) : value;
|
|
77
92
|
|
|
78
93
|
if (isNaN(numericValue)) {
|
|
79
|
-
return "
|
|
94
|
+
return "\u2014";
|
|
80
95
|
}
|
|
81
96
|
|
|
82
97
|
return new Intl.NumberFormat(locale, {
|
|
@@ -109,7 +124,6 @@ export interface ComparePriceDisplayProps {
|
|
|
109
124
|
salePrice: string | number;
|
|
110
125
|
currency?: string;
|
|
111
126
|
className?: string;
|
|
112
|
-
locale?: string;
|
|
113
127
|
}
|
|
114
128
|
|
|
115
129
|
/**
|
|
@@ -120,16 +134,26 @@ export function ComparePriceDisplay({
|
|
|
120
134
|
salePrice,
|
|
121
135
|
currency,
|
|
122
136
|
className = "",
|
|
123
|
-
locale = "pl-PL",
|
|
124
137
|
}: ComparePriceDisplayProps) {
|
|
125
138
|
const preferredCurrency = useCurrencyStore((state) => state.currency);
|
|
139
|
+
const isLoaded = useCurrencyStore((state) => state.isLoaded);
|
|
126
140
|
const finalCurrency = currency || preferredCurrency || "PLN";
|
|
141
|
+
const locale = getLocaleForCurrency(finalCurrency);
|
|
142
|
+
|
|
143
|
+
if (!isLoaded && !currency) {
|
|
144
|
+
return (
|
|
145
|
+
<div className={`flex items-center gap-2 ${className}`}>
|
|
146
|
+
<span className="inline-block h-5 w-16 animate-pulse rounded bg-muted" />
|
|
147
|
+
<span className="inline-block h-4 w-12 animate-pulse rounded bg-muted" />
|
|
148
|
+
</div>
|
|
149
|
+
);
|
|
150
|
+
}
|
|
127
151
|
|
|
128
152
|
const formatPrice = (value: string | number) => {
|
|
129
153
|
const numericValue = typeof value === "string" ? parseFloat(value) : value;
|
|
130
154
|
|
|
131
155
|
if (isNaN(numericValue)) {
|
|
132
|
-
return "
|
|
156
|
+
return "\u2014";
|
|
133
157
|
}
|
|
134
158
|
|
|
135
159
|
return new Intl.NumberFormat(locale, {
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import { useState } from "react";
|
|
4
4
|
import { Facebook, Twitter, Linkedin, Link2, Check } from "lucide-react";
|
|
5
5
|
import { Button } from "@/components/ui/button";
|
|
6
|
+
import { useTranslations } from "next-intl";
|
|
6
7
|
|
|
7
8
|
export interface SocialShareProps {
|
|
8
9
|
url: string;
|
|
@@ -20,6 +21,7 @@ export function SocialShare({
|
|
|
20
21
|
description = "",
|
|
21
22
|
className = "",
|
|
22
23
|
}: SocialShareProps) {
|
|
24
|
+
const t = useTranslations("socialShare");
|
|
23
25
|
const [copied, setCopied] = useState(false);
|
|
24
26
|
|
|
25
27
|
const encodedUrl = encodeURIComponent(url);
|
|
@@ -58,14 +60,14 @@ export function SocialShare({
|
|
|
58
60
|
return (
|
|
59
61
|
<div className={`flex items-center gap-2 ${className}`}>
|
|
60
62
|
<span className="text-sm font-medium text-muted-foreground mr-2">
|
|
61
|
-
|
|
63
|
+
{t("share")}
|
|
62
64
|
</span>
|
|
63
65
|
|
|
64
66
|
<Button
|
|
65
67
|
variant="outline"
|
|
66
68
|
size="sm"
|
|
67
69
|
onClick={() => handleShare("facebook")}
|
|
68
|
-
aria-label="
|
|
70
|
+
aria-label={t("shareOnFacebook")}
|
|
69
71
|
className="h-9 w-9 p-0"
|
|
70
72
|
>
|
|
71
73
|
<Facebook className="h-4 w-4" />
|
|
@@ -75,7 +77,7 @@ export function SocialShare({
|
|
|
75
77
|
variant="outline"
|
|
76
78
|
size="sm"
|
|
77
79
|
onClick={() => handleShare("twitter")}
|
|
78
|
-
aria-label="
|
|
80
|
+
aria-label={t("shareOnTwitter")}
|
|
79
81
|
className="h-9 w-9 p-0"
|
|
80
82
|
>
|
|
81
83
|
<Twitter className="h-4 w-4" />
|
|
@@ -85,7 +87,7 @@ export function SocialShare({
|
|
|
85
87
|
variant="outline"
|
|
86
88
|
size="sm"
|
|
87
89
|
onClick={() => handleShare("linkedin")}
|
|
88
|
-
aria-label="
|
|
90
|
+
aria-label={t("shareOnLinkedIn")}
|
|
89
91
|
className="h-9 w-9 p-0"
|
|
90
92
|
>
|
|
91
93
|
<Linkedin className="h-4 w-4" />
|
|
@@ -95,7 +97,7 @@ export function SocialShare({
|
|
|
95
97
|
variant="outline"
|
|
96
98
|
size="sm"
|
|
97
99
|
onClick={handleCopyLink}
|
|
98
|
-
aria-label="
|
|
100
|
+
aria-label={t("copyLink")}
|
|
99
101
|
className="h-9 w-9 p-0"
|
|
100
102
|
>
|
|
101
103
|
{copied ? (
|
|
@@ -124,6 +126,7 @@ export function SocialShareButton({
|
|
|
124
126
|
description = "",
|
|
125
127
|
className = "",
|
|
126
128
|
}: SocialShareButtonProps) {
|
|
129
|
+
const t = useTranslations("socialShare");
|
|
127
130
|
const [isOpen, setIsOpen] = useState(false);
|
|
128
131
|
|
|
129
132
|
const handleNativeShare = async () => {
|
|
@@ -148,7 +151,7 @@ export function SocialShareButton({
|
|
|
148
151
|
<div className={`relative ${className}`}>
|
|
149
152
|
<Button variant="outline" size="sm" onClick={handleNativeShare}>
|
|
150
153
|
<Link2 className="mr-2 h-4 w-4" />
|
|
151
|
-
|
|
154
|
+
{t("shareButton")}
|
|
152
155
|
</Button>
|
|
153
156
|
|
|
154
157
|
{isOpen && !navigator.share && (
|
|
@@ -15,7 +15,8 @@
|
|
|
15
15
|
import { cn } from "@/lib/utils";
|
|
16
16
|
import { Tag, X, Percent, Truck, Gift } from "lucide-react";
|
|
17
17
|
import { Button } from "@/components/ui/button";
|
|
18
|
-
import { formatPrice } from "
|
|
18
|
+
import { formatPrice } from "@doswiftly/storefront-sdk";
|
|
19
|
+
import { useTranslations } from "next-intl";
|
|
19
20
|
|
|
20
21
|
export interface AppliedDiscount {
|
|
21
22
|
id: string;
|
|
@@ -63,20 +64,25 @@ function getDiscountIcon(type: AppliedDiscount["type"]) {
|
|
|
63
64
|
}
|
|
64
65
|
|
|
65
66
|
/**
|
|
66
|
-
* Get
|
|
67
|
+
* Get translation key for discount type
|
|
67
68
|
*/
|
|
68
|
-
function getDiscountTypeLabel(
|
|
69
|
+
function getDiscountTypeLabel(
|
|
70
|
+
discount: AppliedDiscount,
|
|
71
|
+
t: ReturnType<typeof useTranslations<"discountBreakdown">>
|
|
72
|
+
): string {
|
|
69
73
|
switch (discount.type) {
|
|
70
74
|
case "PERCENTAGE":
|
|
71
|
-
return discount.value
|
|
75
|
+
return discount.value
|
|
76
|
+
? t("percentage", { value: discount.value })
|
|
77
|
+
: t("percentageDefault");
|
|
72
78
|
case "FIXED_AMOUNT":
|
|
73
|
-
return "
|
|
79
|
+
return t("fixedAmount");
|
|
74
80
|
case "FREE_SHIPPING":
|
|
75
|
-
return "
|
|
81
|
+
return t("freeShipping");
|
|
76
82
|
case "BUY_X_GET_Y":
|
|
77
|
-
return "
|
|
83
|
+
return t("buyXGetY");
|
|
78
84
|
default:
|
|
79
|
-
return "
|
|
85
|
+
return t("default");
|
|
80
86
|
}
|
|
81
87
|
}
|
|
82
88
|
|
|
@@ -95,6 +101,8 @@ export function DiscountBreakdown({
|
|
|
95
101
|
compact = false,
|
|
96
102
|
className,
|
|
97
103
|
}: DiscountBreakdownProps) {
|
|
104
|
+
const t = useTranslations("discountBreakdown");
|
|
105
|
+
|
|
98
106
|
if (discounts.length === 0) {
|
|
99
107
|
return null;
|
|
100
108
|
}
|
|
@@ -133,7 +141,7 @@ export function DiscountBreakdown({
|
|
|
133
141
|
</span>
|
|
134
142
|
{!compact && (
|
|
135
143
|
<span className="text-xs text-muted-foreground">
|
|
136
|
-
{getDiscountTypeLabel(discount)}
|
|
144
|
+
{getDiscountTypeLabel(discount, t)}
|
|
137
145
|
</span>
|
|
138
146
|
)}
|
|
139
147
|
</div>
|
|
@@ -180,7 +188,7 @@ export function DiscountBreakdown({
|
|
|
180
188
|
)}
|
|
181
189
|
>
|
|
182
190
|
<span className={cn("font-medium", compact && "text-sm")}>
|
|
183
|
-
|
|
191
|
+
{t("totalSavings")}
|
|
184
192
|
</span>
|
|
185
193
|
<span
|
|
186
194
|
className={cn(
|
|
@@ -211,18 +219,20 @@ export interface DiscountSummaryLineProps {
|
|
|
211
219
|
}
|
|
212
220
|
|
|
213
221
|
export function DiscountSummaryLine({
|
|
214
|
-
label
|
|
222
|
+
label,
|
|
215
223
|
amount,
|
|
216
224
|
code,
|
|
217
225
|
onRemove,
|
|
218
226
|
className,
|
|
219
227
|
}: DiscountSummaryLineProps) {
|
|
228
|
+
const t = useTranslations("discountBreakdown");
|
|
229
|
+
const displayLabel = label ?? t("default");
|
|
220
230
|
return (
|
|
221
231
|
<div className={cn("flex items-center justify-between text-sm", className)}>
|
|
222
232
|
<div className="flex items-center gap-1.5">
|
|
223
233
|
<Tag className="h-3.5 w-3.5 text-green-600" />
|
|
224
234
|
<span className="text-muted-foreground">
|
|
225
|
-
{
|
|
235
|
+
{displayLabel}
|
|
226
236
|
{code && <span className="ml-1 font-medium text-foreground">({code})</span>}
|
|
227
237
|
</span>
|
|
228
238
|
</div>
|
|
@@ -13,12 +13,13 @@
|
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
15
|
import { useState, useCallback } from "react";
|
|
16
|
+
import { useTranslations } from "next-intl";
|
|
16
17
|
import { cn } from "@/lib/utils";
|
|
17
18
|
import { Tag, Loader2, Check, X, AlertCircle } from "lucide-react";
|
|
18
19
|
import { Input } from "@/components/ui/input";
|
|
19
20
|
import { Button } from "@/components/ui/button";
|
|
20
21
|
import { Alert, AlertDescription } from "@/components/ui/alert";
|
|
21
|
-
import { formatPrice } from "
|
|
22
|
+
import { formatPrice } from "@doswiftly/storefront-sdk";
|
|
22
23
|
|
|
23
24
|
export interface DiscountValidationResult {
|
|
24
25
|
valid: boolean;
|
|
@@ -64,10 +65,12 @@ export function DiscountCodeInput({
|
|
|
64
65
|
onValidate,
|
|
65
66
|
appliedCodes = [],
|
|
66
67
|
isApplying = false,
|
|
67
|
-
placeholder
|
|
68
|
+
placeholder,
|
|
68
69
|
disabled = false,
|
|
69
70
|
className,
|
|
70
71
|
}: DiscountCodeInputProps) {
|
|
72
|
+
const t = useTranslations("checkout.discount");
|
|
73
|
+
const tc = useTranslations("common");
|
|
71
74
|
const [code, setCode] = useState("");
|
|
72
75
|
const [isValidating, setIsValidating] = useState(false);
|
|
73
76
|
const [validationResult, setValidationResult] = useState<DiscountValidationResult | null>(null);
|
|
@@ -79,13 +82,13 @@ export function DiscountCodeInput({
|
|
|
79
82
|
const trimmedCode = code.trim().toUpperCase();
|
|
80
83
|
|
|
81
84
|
if (!trimmedCode) {
|
|
82
|
-
setError("
|
|
85
|
+
setError(t("enterCode"));
|
|
83
86
|
return;
|
|
84
87
|
}
|
|
85
88
|
|
|
86
89
|
// Check if already applied
|
|
87
90
|
if (appliedCodes.includes(trimmedCode)) {
|
|
88
|
-
setError("
|
|
91
|
+
setError(t("alreadyApplied"));
|
|
89
92
|
return;
|
|
90
93
|
}
|
|
91
94
|
|
|
@@ -99,10 +102,10 @@ export function DiscountCodeInput({
|
|
|
99
102
|
setValidationResult(result);
|
|
100
103
|
|
|
101
104
|
if (!result.valid) {
|
|
102
|
-
setError(result.errorMessage || "
|
|
105
|
+
setError(result.errorMessage || t("invalidCode"));
|
|
103
106
|
}
|
|
104
|
-
} catch (e:
|
|
105
|
-
setError(e
|
|
107
|
+
} catch (e: unknown) {
|
|
108
|
+
setError(e instanceof Error ? e.message : t("validationFailed"));
|
|
106
109
|
} finally {
|
|
107
110
|
setIsValidating(false);
|
|
108
111
|
}
|
|
@@ -148,18 +151,18 @@ export function DiscountCodeInput({
|
|
|
148
151
|
if (!validationResult?.valid) return null;
|
|
149
152
|
|
|
150
153
|
if (validationResult.estimatedSavings) {
|
|
151
|
-
return
|
|
154
|
+
return t("savings", { savings: formatPrice(validationResult.estimatedSavings) });
|
|
152
155
|
}
|
|
153
156
|
|
|
154
157
|
if (validationResult.discountType === "PERCENTAGE" && validationResult.discountValue) {
|
|
155
|
-
return
|
|
158
|
+
return t("percentOff", { value: validationResult.discountValue });
|
|
156
159
|
}
|
|
157
160
|
|
|
158
161
|
if (validationResult.discountType === "FREE_SHIPPING") {
|
|
159
|
-
return "
|
|
162
|
+
return t("freeShippingDiscount");
|
|
160
163
|
}
|
|
161
164
|
|
|
162
|
-
return "
|
|
165
|
+
return t("codeValid");
|
|
163
166
|
};
|
|
164
167
|
|
|
165
168
|
return (
|
|
@@ -178,7 +181,7 @@ export function DiscountCodeInput({
|
|
|
178
181
|
}}
|
|
179
182
|
onBlur={handleValidate}
|
|
180
183
|
onKeyDown={handleKeyDown}
|
|
181
|
-
placeholder={placeholder}
|
|
184
|
+
placeholder={placeholder ?? t("enterCode")}
|
|
182
185
|
disabled={disabled || isLoading}
|
|
183
186
|
className={cn(
|
|
184
187
|
"pl-9 pr-8 uppercase",
|
|
@@ -207,10 +210,10 @@ export function DiscountCodeInput({
|
|
|
207
210
|
) : validationResult?.valid ? (
|
|
208
211
|
<>
|
|
209
212
|
<Check className="mr-2 h-4 w-4" />
|
|
210
|
-
|
|
213
|
+
{tc("apply")}
|
|
211
214
|
</>
|
|
212
215
|
) : (
|
|
213
|
-
"
|
|
216
|
+
tc("apply")
|
|
214
217
|
)}
|
|
215
218
|
</Button>
|
|
216
219
|
</div>
|
|
@@ -236,7 +239,7 @@ export function DiscountCodeInput({
|
|
|
236
239
|
{/* Minimum order info */}
|
|
237
240
|
{validationResult?.minimumOrderAmount && (
|
|
238
241
|
<p className="text-xs text-muted-foreground">
|
|
239
|
-
|
|
242
|
+
{t("minOrderAmount")} {formatPrice(validationResult.minimumOrderAmount)}
|
|
240
243
|
</p>
|
|
241
244
|
)}
|
|
242
245
|
</div>
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
import { Component, type ReactNode } from 'react';
|
|
13
|
+
import { useTranslations } from 'next-intl';
|
|
13
14
|
import { AlertTriangle, RefreshCcw } from 'lucide-react';
|
|
14
15
|
import { Button } from '@/components/ui/button';
|
|
15
16
|
import { Card, CardContent, CardHeader, CardTitle, CardDescription } from '@/components/ui/card';
|
|
@@ -32,6 +33,51 @@ interface ErrorBoundaryState {
|
|
|
32
33
|
error: Error | null;
|
|
33
34
|
}
|
|
34
35
|
|
|
36
|
+
/** Default fallback UI — functional component so it can use useTranslations */
|
|
37
|
+
function DefaultErrorFallback({
|
|
38
|
+
title,
|
|
39
|
+
description,
|
|
40
|
+
error,
|
|
41
|
+
onReset,
|
|
42
|
+
}: {
|
|
43
|
+
title?: string;
|
|
44
|
+
description?: string;
|
|
45
|
+
error: Error | null;
|
|
46
|
+
onReset: () => void;
|
|
47
|
+
}) {
|
|
48
|
+
const t = useTranslations('errors');
|
|
49
|
+
|
|
50
|
+
return (
|
|
51
|
+
<div className="flex min-h-[400px] items-center justify-center p-4">
|
|
52
|
+
<Card className="w-full max-w-md">
|
|
53
|
+
<CardHeader className="text-center">
|
|
54
|
+
<div className="mx-auto mb-4 flex h-12 w-12 items-center justify-center rounded-full bg-destructive/10">
|
|
55
|
+
<AlertTriangle className="h-6 w-6 text-destructive" />
|
|
56
|
+
</div>
|
|
57
|
+
<CardTitle className="text-xl">
|
|
58
|
+
{title || t('somethingWentWrong')}
|
|
59
|
+
</CardTitle>
|
|
60
|
+
<CardDescription>
|
|
61
|
+
{description || t('unexpectedError')}
|
|
62
|
+
</CardDescription>
|
|
63
|
+
</CardHeader>
|
|
64
|
+
<CardContent className="flex flex-col gap-3">
|
|
65
|
+
{/* Show error message in development */}
|
|
66
|
+
{process.env.NODE_ENV === 'development' && error && (
|
|
67
|
+
<div className="rounded-md bg-muted p-3 text-xs">
|
|
68
|
+
<p className="font-medium text-destructive">{error.message}</p>
|
|
69
|
+
</div>
|
|
70
|
+
)}
|
|
71
|
+
<Button onClick={onReset} className="w-full">
|
|
72
|
+
<RefreshCcw className="mr-2 h-4 w-4" />
|
|
73
|
+
{t('tryAgain')}
|
|
74
|
+
</Button>
|
|
75
|
+
</CardContent>
|
|
76
|
+
</Card>
|
|
77
|
+
</div>
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
|
|
35
81
|
/**
|
|
36
82
|
* ErrorBoundary - Catches and displays errors gracefully
|
|
37
83
|
*
|
|
@@ -74,35 +120,14 @@ export class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundarySt
|
|
|
74
120
|
return this.props.fallback;
|
|
75
121
|
}
|
|
76
122
|
|
|
77
|
-
// Default fallback UI
|
|
123
|
+
// Default fallback UI (functional component for useTranslations)
|
|
78
124
|
return (
|
|
79
|
-
<
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
<CardTitle className="text-xl">
|
|
86
|
-
{this.props.title || 'Coś poszło nie tak'}
|
|
87
|
-
</CardTitle>
|
|
88
|
-
<CardDescription>
|
|
89
|
-
{this.props.description || 'Wystąpił nieoczekiwany błąd. Spróbuj odświeżyć stronę.'}
|
|
90
|
-
</CardDescription>
|
|
91
|
-
</CardHeader>
|
|
92
|
-
<CardContent className="flex flex-col gap-3">
|
|
93
|
-
{/* Show error message in development */}
|
|
94
|
-
{process.env.NODE_ENV === 'development' && this.state.error && (
|
|
95
|
-
<div className="rounded-md bg-muted p-3 text-xs">
|
|
96
|
-
<p className="font-medium text-destructive">{this.state.error.message}</p>
|
|
97
|
-
</div>
|
|
98
|
-
)}
|
|
99
|
-
<Button onClick={this.handleReset} className="w-full">
|
|
100
|
-
<RefreshCcw className="mr-2 h-4 w-4" />
|
|
101
|
-
Spróbuj ponownie
|
|
102
|
-
</Button>
|
|
103
|
-
</CardContent>
|
|
104
|
-
</Card>
|
|
105
|
-
</div>
|
|
125
|
+
<DefaultErrorFallback
|
|
126
|
+
title={this.props.title}
|
|
127
|
+
description={this.props.description}
|
|
128
|
+
error={this.state.error}
|
|
129
|
+
onReset={this.handleReset}
|
|
130
|
+
/>
|
|
106
131
|
);
|
|
107
132
|
}
|
|
108
133
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
3
|
import { useState, useCallback } from "react";
|
|
4
|
+
import { useTranslations } from "next-intl";
|
|
4
5
|
import { Filter, X, ChevronDown, ChevronUp } from "lucide-react";
|
|
5
6
|
import { cn } from "@/lib/utils";
|
|
6
7
|
import { Button } from "@/components/ui/button";
|
|
@@ -85,6 +86,7 @@ export function DynamicAttributeFilters({
|
|
|
85
86
|
className,
|
|
86
87
|
collapsible = false,
|
|
87
88
|
}: DynamicAttributeFiltersProps) {
|
|
89
|
+
const t = useTranslations("filters");
|
|
88
90
|
const [isExpanded, setIsExpanded] = useState(!collapsible);
|
|
89
91
|
|
|
90
92
|
// Calculate active filter count
|
|
@@ -100,7 +102,7 @@ export function DynamicAttributeFilters({
|
|
|
100
102
|
<div className={cn("p-4", className)}>
|
|
101
103
|
<div className="flex items-center gap-2">
|
|
102
104
|
<Spinner className="h-4 w-4" />
|
|
103
|
-
<span className="text-sm text-muted-foreground">
|
|
105
|
+
<span className="text-sm text-muted-foreground">{t("loading")}</span>
|
|
104
106
|
</div>
|
|
105
107
|
</div>
|
|
106
108
|
);
|
|
@@ -115,7 +117,7 @@ export function DynamicAttributeFilters({
|
|
|
115
117
|
<div className="flex items-center justify-between">
|
|
116
118
|
<div className="flex items-center gap-2">
|
|
117
119
|
<Filter className="h-4 w-4 text-muted-foreground" />
|
|
118
|
-
<h3 className="text-sm font-medium text-foreground">
|
|
120
|
+
<h3 className="text-sm font-medium text-foreground">{t("title")}</h3>
|
|
119
121
|
{activeCount > 0 && (
|
|
120
122
|
<span className="flex items-center justify-center h-5 w-5 rounded-full bg-primary text-primary-foreground text-xs">
|
|
121
123
|
{activeCount}
|
|
@@ -132,7 +134,7 @@ export function DynamicAttributeFilters({
|
|
|
132
134
|
className="h-7 text-xs text-muted-foreground hover:text-foreground"
|
|
133
135
|
>
|
|
134
136
|
<X className="h-3 w-3 mr-1" />
|
|
135
|
-
|
|
137
|
+
{t("clearAll")}
|
|
136
138
|
</Button>
|
|
137
139
|
)}
|
|
138
140
|
|
|
@@ -159,7 +161,7 @@ export function DynamicAttributeFilters({
|
|
|
159
161
|
{/* Price filter */}
|
|
160
162
|
{filters.priceRange && onPriceChange && (
|
|
161
163
|
<div className="space-y-3">
|
|
162
|
-
<h4 className="text-sm font-medium text-foreground">
|
|
164
|
+
<h4 className="text-sm font-medium text-foreground">{t("price")}</h4>
|
|
163
165
|
<div className="flex items-center gap-2">
|
|
164
166
|
<input
|
|
165
167
|
type="number"
|
|
@@ -204,7 +206,7 @@ export function DynamicAttributeFilters({
|
|
|
204
206
|
|
|
205
207
|
{/* Product count */}
|
|
206
208
|
<p className="text-xs text-muted-foreground pt-2 border-t">
|
|
207
|
-
{filters.totalProducts}
|
|
209
|
+
{t("productCount", { count: filters.totalProducts })}
|
|
208
210
|
</p>
|
|
209
211
|
</div>
|
|
210
212
|
);
|
|
@@ -179,15 +179,15 @@ function formatValue(
|
|
|
179
179
|
/**
|
|
180
180
|
* Simple debounce function
|
|
181
181
|
*/
|
|
182
|
-
function debounce<
|
|
183
|
-
fn:
|
|
182
|
+
function debounce<TArgs extends unknown[]>(
|
|
183
|
+
fn: (...args: TArgs) => void,
|
|
184
184
|
delay: number
|
|
185
|
-
):
|
|
185
|
+
): (...args: TArgs) => void {
|
|
186
186
|
let timeoutId: NodeJS.Timeout;
|
|
187
|
-
return (
|
|
187
|
+
return (...args: TArgs) => {
|
|
188
188
|
clearTimeout(timeoutId);
|
|
189
189
|
timeoutId = setTimeout(() => fn(...args), delay);
|
|
190
|
-
}
|
|
190
|
+
};
|
|
191
191
|
}
|
|
192
192
|
|
|
193
193
|
export default RangeSliderFilter;
|