@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.
Files changed (277) hide show
  1. package/README.md +23 -323
  2. package/dist/commands/check.js +1 -1
  3. package/dist/commands/check.js.map +1 -1
  4. package/dist/commands/deploy.d.ts +20 -0
  5. package/dist/commands/deploy.d.ts.map +1 -1
  6. package/dist/commands/deploy.js +249 -17
  7. package/dist/commands/deploy.js.map +1 -1
  8. package/dist/commands/doctor.js +3 -3
  9. package/dist/commands/doctor.js.map +1 -1
  10. package/dist/commands/init.js +4 -4
  11. package/dist/commands/sdk.js +5 -5
  12. package/dist/commands/sdk.js.map +1 -1
  13. package/dist/commands/template.js +4 -4
  14. package/dist/commands/template.js.map +1 -1
  15. package/dist/commands/types.js +5 -5
  16. package/dist/commands/types.js.map +1 -1
  17. package/dist/commands/verify.js +2 -2
  18. package/dist/commands/verify.js.map +1 -1
  19. package/dist/lib/package-manager.d.ts +1 -1
  20. package/dist/lib/package-manager.js +1 -1
  21. package/package.json +4 -4
  22. package/templates/storefront-minimal/.github/workflows/build-template.yml +10 -0
  23. package/templates/storefront-minimal/wrangler.toml +11 -0
  24. package/templates/storefront-nextjs/.github/workflows/build-template.yml +10 -0
  25. package/templates/storefront-nextjs/README.md +16 -12
  26. package/templates/storefront-nextjs/app/account/orders/page.tsx +2 -2
  27. package/templates/storefront-nextjs/app/account/page.tsx +2 -2
  28. package/templates/storefront-nextjs/app/auth/login/page.tsx +1 -1
  29. package/templates/storefront-nextjs/app/auth/register/page.tsx +1 -1
  30. package/templates/storefront-nextjs/app/cart/page.tsx +1 -1
  31. package/templates/storefront-nextjs/app/categories/[slug]/page.tsx +2 -2
  32. package/templates/storefront-nextjs/app/categories/page.tsx +1 -1
  33. package/templates/storefront-nextjs/app/collections/[slug]/page.tsx +1 -1
  34. package/templates/storefront-nextjs/app/collections/page.tsx +1 -1
  35. package/templates/storefront-nextjs/app/page.tsx +1 -1
  36. package/templates/storefront-nextjs/app/products/[slug]/page.tsx +1 -1
  37. package/templates/storefront-nextjs/app/products/page.tsx +2 -2
  38. package/templates/storefront-nextjs/app/search/page.tsx +1 -1
  39. package/templates/storefront-nextjs/components/auth/auth-guard.tsx +1 -1
  40. package/templates/storefront-nextjs/components/commerce/add-to-cart-button.tsx +1 -1
  41. package/templates/storefront-nextjs/components/commerce/cart-icon.tsx +1 -1
  42. package/templates/storefront-nextjs/components/commerce/currency-selector.tsx +2 -2
  43. package/templates/storefront-nextjs/components/commerce/product-filters.tsx +1 -1
  44. package/templates/storefront-nextjs/components/commerce/product-price.tsx +1 -1
  45. package/templates/storefront-nextjs/components/commerce/search-input.tsx +1 -1
  46. package/templates/storefront-nextjs/components/commerce/sort-select.tsx +1 -1
  47. package/templates/storefront-nextjs/components/providers.tsx +1 -1
  48. package/templates/storefront-nextjs/lib/currency.tsx +3 -3
  49. package/templates/storefront-nextjs/lib/format.ts +1 -1
  50. package/templates/storefront-nextjs/lib/graphql-queries.ts +3 -3
  51. package/templates/storefront-nextjs/package.dev.json +1 -1
  52. package/templates/storefront-nextjs/package.json +1 -1
  53. package/templates/storefront-nextjs/package.json.template +1 -1
  54. package/templates/storefront-nextjs/wrangler.toml +11 -0
  55. package/templates/storefront-nextjs-shadcn/.github/workflows/build-template.yml +10 -0
  56. package/templates/storefront-nextjs-shadcn/.github/workflows/deploy.yml +47 -0
  57. package/templates/storefront-nextjs-shadcn/.github/workflows/preview.yml +47 -0
  58. package/templates/storefront-nextjs-shadcn/CLAUDE.md +172 -35
  59. package/templates/storefront-nextjs-shadcn/README.md +29 -162
  60. package/templates/storefront-nextjs-shadcn/app/{about → [locale]/about}/page.tsx +17 -14
  61. package/templates/storefront-nextjs-shadcn/app/[locale]/account/addresses/page.tsx +226 -0
  62. package/templates/storefront-nextjs-shadcn/app/[locale]/account/error.tsx +46 -0
  63. package/templates/storefront-nextjs-shadcn/app/[locale]/account/loading.tsx +19 -0
  64. package/templates/storefront-nextjs-shadcn/app/{account → [locale]/account}/loyalty/page.tsx +89 -193
  65. package/templates/storefront-nextjs-shadcn/app/[locale]/account/orders/[id]/loading.tsx +60 -0
  66. package/templates/storefront-nextjs-shadcn/app/[locale]/account/orders/[id]/page.tsx +119 -0
  67. package/templates/storefront-nextjs-shadcn/app/{account → [locale]/account}/orders/[id]/tracking/page.tsx +27 -25
  68. package/templates/storefront-nextjs-shadcn/app/[locale]/account/orders/page.tsx +101 -0
  69. package/templates/storefront-nextjs-shadcn/app/{account → [locale]/account}/page.tsx +9 -7
  70. package/templates/storefront-nextjs-shadcn/app/[locale]/account/settings/page.tsx +208 -0
  71. package/templates/storefront-nextjs-shadcn/app/{auth → [locale]/auth}/forgot-password/page.tsx +24 -17
  72. package/templates/storefront-nextjs-shadcn/app/{auth → [locale]/auth}/login/page.tsx +5 -2
  73. package/templates/storefront-nextjs-shadcn/app/{auth → [locale]/auth}/register/page.tsx +5 -2
  74. package/templates/storefront-nextjs-shadcn/app/[locale]/blog/[slug]/loading.tsx +17 -0
  75. package/templates/storefront-nextjs-shadcn/app/{blog → [locale]/blog}/[slug]/page.tsx +44 -3
  76. package/templates/storefront-nextjs-shadcn/app/[locale]/blog/loading.tsx +19 -0
  77. package/templates/storefront-nextjs-shadcn/app/{brands → [locale]/brands}/page.tsx +2 -1
  78. package/templates/storefront-nextjs-shadcn/app/[locale]/cart/loading.tsx +26 -0
  79. package/templates/storefront-nextjs-shadcn/app/{cart → [locale]/cart}/page.tsx +20 -13
  80. package/templates/storefront-nextjs-shadcn/app/[locale]/categories/[slug]/category-products-client.tsx +58 -0
  81. package/templates/storefront-nextjs-shadcn/app/[locale]/categories/[slug]/loading.tsx +32 -0
  82. package/templates/storefront-nextjs-shadcn/app/[locale]/categories/[slug]/page.tsx +95 -0
  83. package/templates/storefront-nextjs-shadcn/app/{categories → [locale]/categories}/page.tsx +21 -12
  84. package/templates/storefront-nextjs-shadcn/app/[locale]/checkout/error.tsx +43 -0
  85. package/templates/storefront-nextjs-shadcn/app/[locale]/checkout/loading.tsx +31 -0
  86. package/templates/storefront-nextjs-shadcn/app/{checkout → [locale]/checkout}/page.tsx +334 -253
  87. package/templates/storefront-nextjs-shadcn/app/{checkout → [locale]/checkout}/success/[orderId]/page.tsx +36 -34
  88. package/templates/storefront-nextjs-shadcn/app/[locale]/collections/[handle]/loading.tsx +19 -0
  89. package/templates/storefront-nextjs-shadcn/app/{collections → [locale]/collections}/[handle]/page.tsx +6 -4
  90. package/templates/storefront-nextjs-shadcn/app/[locale]/collections/loading.tsx +18 -0
  91. package/templates/storefront-nextjs-shadcn/app/{collections → [locale]/collections}/page.tsx +20 -12
  92. package/templates/storefront-nextjs-shadcn/app/{contact → [locale]/contact}/page.tsx +24 -21
  93. package/templates/storefront-nextjs-shadcn/app/{error.tsx → [locale]/error.tsx} +13 -8
  94. package/templates/storefront-nextjs-shadcn/app/[locale]/layout.tsx +92 -0
  95. package/templates/storefront-nextjs-shadcn/app/{not-found.tsx → [locale]/not-found.tsx} +13 -18
  96. package/templates/storefront-nextjs-shadcn/app/{page.tsx → [locale]/page.tsx} +8 -4
  97. package/templates/storefront-nextjs-shadcn/app/[locale]/products/[slug]/error.tsx +43 -0
  98. package/templates/storefront-nextjs-shadcn/app/[locale]/products/[slug]/loading.tsx +29 -0
  99. package/templates/storefront-nextjs-shadcn/app/{products → [locale]/products}/[slug]/page.tsx +17 -14
  100. package/templates/storefront-nextjs-shadcn/app/{products → [locale]/products}/[slug]/product-client.tsx +18 -62
  101. package/templates/storefront-nextjs-shadcn/app/[locale]/products/loading.tsx +32 -0
  102. package/templates/storefront-nextjs-shadcn/app/{products → [locale]/products}/page.tsx +6 -3
  103. package/templates/storefront-nextjs-shadcn/app/[locale]/products/products-client.tsx +450 -0
  104. package/templates/storefront-nextjs-shadcn/app/[locale]/search/loading.tsx +18 -0
  105. package/templates/storefront-nextjs-shadcn/app/{wishlist → [locale]/wishlist}/page.tsx +27 -28
  106. package/templates/storefront-nextjs-shadcn/app/api/auth/clear-token/route.ts +2 -86
  107. package/templates/storefront-nextjs-shadcn/app/api/auth/set-token/route.ts +2 -124
  108. package/templates/storefront-nextjs-shadcn/app/global-error.tsx +117 -0
  109. package/templates/storefront-nextjs-shadcn/app/globals.css +8 -0
  110. package/templates/storefront-nextjs-shadcn/app/layout.tsx +8 -35
  111. package/templates/storefront-nextjs-shadcn/codegen.ts +48 -31
  112. package/templates/storefront-nextjs-shadcn/components/account/address-form.tsx +25 -20
  113. package/templates/storefront-nextjs-shadcn/components/account/address-list.tsx +11 -10
  114. package/templates/storefront-nextjs-shadcn/components/account/customer-info.fragment.graphql +36 -0
  115. package/templates/storefront-nextjs-shadcn/components/account/order-details.tsx +17 -13
  116. package/templates/storefront-nextjs-shadcn/components/account/order-history.tsx +42 -30
  117. package/templates/storefront-nextjs-shadcn/components/account/order-summary.fragment.graphql +36 -0
  118. package/templates/storefront-nextjs-shadcn/components/auth/account-menu.tsx +18 -16
  119. package/templates/storefront-nextjs-shadcn/components/auth/login-form.tsx +37 -58
  120. package/templates/storefront-nextjs-shadcn/components/auth/register-form.tsx +85 -66
  121. package/templates/storefront-nextjs-shadcn/components/blog/blog-card.tsx +1 -1
  122. package/templates/storefront-nextjs-shadcn/components/blog/blog-sidebar.tsx +1 -1
  123. package/templates/storefront-nextjs-shadcn/components/brand/brand-card.tsx +1 -1
  124. package/templates/storefront-nextjs-shadcn/components/cart/cart-drawer.tsx +10 -6
  125. package/templates/storefront-nextjs-shadcn/components/cart/cart-icon.tsx +9 -6
  126. package/templates/storefront-nextjs-shadcn/components/cart/cart-item.tsx +8 -6
  127. package/templates/storefront-nextjs-shadcn/components/cart/cart-line.fragment.graphql +53 -0
  128. package/templates/storefront-nextjs-shadcn/components/cart/cart-summary.tsx +10 -8
  129. package/templates/storefront-nextjs-shadcn/components/cart/promo-code-input.tsx +8 -5
  130. package/templates/storefront-nextjs-shadcn/components/cart/shipping-estimator.tsx +38 -20
  131. package/templates/storefront-nextjs-shadcn/components/checkout/payment-method-card.tsx +15 -25
  132. package/templates/storefront-nextjs-shadcn/components/checkout/payment-step.tsx +10 -8
  133. package/templates/storefront-nextjs-shadcn/components/checkout/tax-breakdown.tsx +9 -6
  134. package/templates/storefront-nextjs-shadcn/components/commerce/currency-selector.tsx +7 -5
  135. package/templates/storefront-nextjs-shadcn/components/commerce/pagination.tsx +8 -5
  136. package/templates/storefront-nextjs-shadcn/components/commerce/product-actions.tsx +6 -4
  137. package/templates/storefront-nextjs-shadcn/components/commerce/search-input.tsx +10 -9
  138. package/templates/storefront-nextjs-shadcn/components/common/category-card.tsx +1 -1
  139. package/templates/storefront-nextjs-shadcn/components/common/collection-card.tsx +1 -1
  140. package/templates/storefront-nextjs-shadcn/components/common/price-display.tsx +35 -11
  141. package/templates/storefront-nextjs-shadcn/components/common/social-share.tsx +9 -6
  142. package/templates/storefront-nextjs-shadcn/components/discount/discount-breakdown.tsx +22 -12
  143. package/templates/storefront-nextjs-shadcn/components/discount/discount-code-input.tsx +18 -15
  144. package/templates/storefront-nextjs-shadcn/components/error/error-boundary.tsx +53 -28
  145. package/templates/storefront-nextjs-shadcn/components/filters/dynamic-attribute-filters.tsx +7 -5
  146. package/templates/storefront-nextjs-shadcn/components/filters/range-slider-filter.tsx +5 -5
  147. package/templates/storefront-nextjs-shadcn/components/gift-card/gift-card-balance.tsx +19 -15
  148. package/templates/storefront-nextjs-shadcn/components/gift-card/gift-card-input.tsx +13 -10
  149. package/templates/storefront-nextjs-shadcn/components/home/category-grid.tsx +10 -6
  150. package/templates/storefront-nextjs-shadcn/components/home/collection-card.fragment.graphql +21 -0
  151. package/templates/storefront-nextjs-shadcn/components/home/featured-collections.tsx +3 -13
  152. package/templates/storefront-nextjs-shadcn/components/home/featured-products.tsx +12 -8
  153. package/templates/storefront-nextjs-shadcn/components/home/hero-section.tsx +13 -8
  154. package/templates/storefront-nextjs-shadcn/components/home/index.ts +0 -1
  155. package/templates/storefront-nextjs-shadcn/components/home/newsletter-signup.tsx +10 -8
  156. package/templates/storefront-nextjs-shadcn/components/hydrated.tsx +24 -0
  157. package/templates/storefront-nextjs-shadcn/components/layout/breadcrumbs.tsx +41 -16
  158. package/templates/storefront-nextjs-shadcn/components/layout/category-node.fragment.graphql +22 -0
  159. package/templates/storefront-nextjs-shadcn/components/layout/currency-selector.tsx +7 -4
  160. package/templates/storefront-nextjs-shadcn/components/layout/footer.tsx +24 -23
  161. package/templates/storefront-nextjs-shadcn/components/layout/header.tsx +52 -34
  162. package/templates/storefront-nextjs-shadcn/components/layout/language-switcher.tsx +54 -0
  163. package/templates/storefront-nextjs-shadcn/components/layout/mobile-menu.tsx +33 -30
  164. package/templates/storefront-nextjs-shadcn/components/layout/navigation.tsx +27 -24
  165. package/templates/storefront-nextjs-shadcn/components/loyalty/points-balance.tsx +2 -11
  166. package/templates/storefront-nextjs-shadcn/components/loyalty/points-history.tsx +8 -25
  167. package/templates/storefront-nextjs-shadcn/components/loyalty/referral-section.tsx +32 -42
  168. package/templates/storefront-nextjs-shadcn/components/loyalty/rewards-catalog.tsx +17 -41
  169. package/templates/storefront-nextjs-shadcn/components/loyalty/tier-progress.tsx +2 -29
  170. package/templates/storefront-nextjs-shadcn/components/order/index.ts +6 -1
  171. package/templates/storefront-nextjs-shadcn/components/product/add-to-cart-button.tsx +6 -14
  172. package/templates/storefront-nextjs-shadcn/components/product/b2b-price-display.tsx +4 -2
  173. package/templates/storefront-nextjs-shadcn/components/product/filter-active-pills.tsx +72 -0
  174. package/templates/storefront-nextjs-shadcn/components/product/filter-mobile-sheet.tsx +87 -0
  175. package/templates/storefront-nextjs-shadcn/components/product/filter-price-range.tsx +140 -0
  176. package/templates/storefront-nextjs-shadcn/components/product/index.ts +9 -2
  177. package/templates/storefront-nextjs-shadcn/components/product/product-card.fragment.graphql +49 -0
  178. package/templates/storefront-nextjs-shadcn/components/product/product-card.tsx +11 -37
  179. package/templates/storefront-nextjs-shadcn/components/product/product-detail.fragment.graphql +52 -0
  180. package/templates/storefront-nextjs-shadcn/components/product/product-filters.tsx +179 -124
  181. package/templates/storefront-nextjs-shadcn/components/product/product-grid.tsx +3 -5
  182. package/templates/storefront-nextjs-shadcn/components/product/product-image.tsx +3 -7
  183. package/templates/storefront-nextjs-shadcn/components/product/product-price.tsx +2 -2
  184. package/templates/storefront-nextjs-shadcn/components/product/product-reviews.tsx +5 -4
  185. package/templates/storefront-nextjs-shadcn/components/product/product-sort.tsx +44 -19
  186. package/templates/storefront-nextjs-shadcn/components/product/product-variant-selector.tsx +8 -23
  187. package/templates/storefront-nextjs-shadcn/components/product/product-variant.fragment.graphql +51 -0
  188. package/templates/storefront-nextjs-shadcn/components/product/review-card.tsx +1 -1
  189. package/templates/storefront-nextjs-shadcn/components/product/review-form.tsx +26 -34
  190. package/templates/storefront-nextjs-shadcn/components/product/savings-display.tsx +17 -2
  191. package/templates/storefront-nextjs-shadcn/components/product/similar-products.tsx +3 -2
  192. package/templates/storefront-nextjs-shadcn/components/providers/index.ts +1 -1
  193. package/templates/storefront-nextjs-shadcn/components/providers/language-sync-provider.tsx +27 -0
  194. package/templates/storefront-nextjs-shadcn/components/providers/stores-provider.tsx +63 -0
  195. package/templates/storefront-nextjs-shadcn/components/providers/theme-provider.tsx +1 -1
  196. package/templates/storefront-nextjs-shadcn/components/returns/index.ts +2 -2
  197. package/templates/storefront-nextjs-shadcn/components/returns/return-request-form.tsx +59 -72
  198. package/templates/storefront-nextjs-shadcn/components/search/search-bar.tsx +7 -4
  199. package/templates/storefront-nextjs-shadcn/components/search/search-results.tsx +3 -2
  200. package/templates/storefront-nextjs-shadcn/components/shipping/shipping-method-selector.tsx +12 -9
  201. package/templates/storefront-nextjs-shadcn/components/ui/empty-state.tsx +23 -12
  202. package/templates/storefront-nextjs-shadcn/components/ui/form.tsx +174 -0
  203. package/templates/storefront-nextjs-shadcn/components/ui/index.ts +30 -2
  204. package/templates/storefront-nextjs-shadcn/components/ui/progress.tsx +40 -0
  205. package/templates/storefront-nextjs-shadcn/components/ui/sheet.tsx +107 -0
  206. package/templates/storefront-nextjs-shadcn/components/ui/slider.tsx +33 -0
  207. package/templates/storefront-nextjs-shadcn/components/ui/textarea.tsx +24 -0
  208. package/templates/storefront-nextjs-shadcn/components/wishlist/wishlist-button.tsx +7 -4
  209. package/templates/storefront-nextjs-shadcn/components/wishlist/wishlist-icon.tsx +4 -2
  210. package/templates/storefront-nextjs-shadcn/components/wishlist/wishlist-item.tsx +2 -10
  211. package/templates/storefront-nextjs-shadcn/generated/graphql.ts +13387 -0
  212. package/templates/storefront-nextjs-shadcn/graphql/custom.example.graphql +159 -0
  213. package/templates/storefront-nextjs-shadcn/hooks/index.ts +3 -0
  214. package/templates/storefront-nextjs-shadcn/hooks/use-auth-sync.ts +42 -0
  215. package/templates/storefront-nextjs-shadcn/hooks/use-auth.ts +17 -295
  216. package/templates/storefront-nextjs-shadcn/hooks/use-cart-actions.ts +34 -229
  217. package/templates/storefront-nextjs-shadcn/hooks/use-cart-di.ts +67 -0
  218. package/templates/storefront-nextjs-shadcn/hooks/use-cart-sync.ts +16 -12
  219. package/templates/storefront-nextjs-shadcn/i18n/navigation.ts +12 -0
  220. package/templates/storefront-nextjs-shadcn/i18n/request.ts +17 -0
  221. package/templates/storefront-nextjs-shadcn/i18n/routing.ts +17 -0
  222. package/templates/storefront-nextjs-shadcn/lib/auth/routes.ts +4 -17
  223. package/templates/storefront-nextjs-shadcn/lib/graphql/client.ts +22 -99
  224. package/templates/storefront-nextjs-shadcn/lib/graphql/config.ts +33 -0
  225. package/templates/storefront-nextjs-shadcn/lib/graphql/fragments.ts +34 -0
  226. package/templates/storefront-nextjs-shadcn/lib/graphql/hooks.ts +720 -632
  227. package/templates/storefront-nextjs-shadcn/lib/graphql/query-keys.ts +88 -0
  228. package/templates/storefront-nextjs-shadcn/lib/graphql/server.ts +132 -182
  229. package/templates/storefront-nextjs-shadcn/lib/graphql/types.ts +62 -0
  230. package/templates/storefront-nextjs-shadcn/lib/theme/theme-config.ts +0 -17
  231. package/templates/storefront-nextjs-shadcn/messages/en.json +869 -0
  232. package/templates/storefront-nextjs-shadcn/messages/pl.json +869 -0
  233. package/templates/storefront-nextjs-shadcn/next-env.d.ts +6 -0
  234. package/templates/storefront-nextjs-shadcn/next.config.ts +6 -5
  235. package/templates/storefront-nextjs-shadcn/package.dev.json +1 -3
  236. package/templates/storefront-nextjs-shadcn/package.json +14 -14
  237. package/templates/storefront-nextjs-shadcn/package.json.template +6 -7
  238. package/templates/storefront-nextjs-shadcn/proxy.ts +115 -47
  239. package/templates/storefront-nextjs-shadcn/stores/cart-store.ts +24 -56
  240. package/templates/storefront-nextjs-shadcn/stores/checkout-store.ts +64 -75
  241. package/templates/storefront-nextjs-shadcn/stores/wishlist-store.ts +178 -177
  242. package/templates/storefront-nextjs-shadcn/tsconfig.json +23 -5
  243. package/templates/storefront-nextjs-shadcn/wrangler.toml +11 -0
  244. package/templates/storefront-nextjs-shadcn/CART_INTEGRATION.md +0 -282
  245. package/templates/storefront-nextjs-shadcn/GRAPHQL_DOCUMENT_NAMES.md +0 -190
  246. package/templates/storefront-nextjs-shadcn/GRAPHQL_ERROR_HANDLING.md +0 -263
  247. package/templates/storefront-nextjs-shadcn/GRAPHQL_FIXES_SUMMARY.md +0 -135
  248. package/templates/storefront-nextjs-shadcn/GRAPHQL_INTEGRATION_COMPLETE.md +0 -142
  249. package/templates/storefront-nextjs-shadcn/INTEGRATION_CHECKLIST.md +0 -448
  250. package/templates/storefront-nextjs-shadcn/PRODUCT_DETAIL_PAGE_IMPLEMENTATION.md +0 -307
  251. package/templates/storefront-nextjs-shadcn/THEME_CUSTOMIZATION.md +0 -245
  252. package/templates/storefront-nextjs-shadcn/app/account/addresses/page.tsx +0 -215
  253. package/templates/storefront-nextjs-shadcn/app/account/orders/[id]/page.tsx +0 -128
  254. package/templates/storefront-nextjs-shadcn/app/account/orders/page.tsx +0 -80
  255. package/templates/storefront-nextjs-shadcn/app/account/settings/page.tsx +0 -171
  256. package/templates/storefront-nextjs-shadcn/app/categories/[slug]/page.tsx +0 -78
  257. package/templates/storefront-nextjs-shadcn/app/products/products-client.tsx +0 -192
  258. package/templates/storefront-nextjs-shadcn/components/providers/currency-provider.tsx +0 -103
  259. package/templates/storefront-nextjs-shadcn/graphql/collections.example.ts +0 -168
  260. package/templates/storefront-nextjs-shadcn/graphql/products.example.ts +0 -160
  261. package/templates/storefront-nextjs-shadcn/lib/auth/cookies.ts +0 -220
  262. package/templates/storefront-nextjs-shadcn/lib/config.ts +0 -46
  263. package/templates/storefront-nextjs-shadcn/lib/currency/IMPLEMENTATION_SUMMARY.md +0 -254
  264. package/templates/storefront-nextjs-shadcn/lib/currency/README.md +0 -464
  265. package/templates/storefront-nextjs-shadcn/lib/currency/cookie-manager.test.ts +0 -328
  266. package/templates/storefront-nextjs-shadcn/lib/currency/cookie-manager.ts +0 -295
  267. package/templates/storefront-nextjs-shadcn/lib/currency/index.ts +0 -27
  268. package/templates/storefront-nextjs-shadcn/lib/format.ts +0 -226
  269. package/templates/storefront-nextjs-shadcn/lib/hooks.ts +0 -30
  270. package/templates/storefront-nextjs-shadcn/stores/auth-store.ts +0 -66
  271. package/templates/storefront-nextjs-shadcn/stores/currency-store.ts +0 -103
  272. /package/templates/storefront-nextjs-shadcn/app/{blog → [locale]/blog}/page.tsx +0 -0
  273. /package/templates/storefront-nextjs-shadcn/app/{brands → [locale]/brands}/[slug]/page.tsx +0 -0
  274. /package/templates/storefront-nextjs-shadcn/app/{returns → [locale]/returns}/page.tsx +0 -0
  275. /package/templates/storefront-nextjs-shadcn/app/{search → [locale]/search}/page.tsx +0 -0
  276. /package/templates/storefront-nextjs-shadcn/app/{search → [locale]/search}/search-client.tsx +0 -0
  277. /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 "@/stores/currency-store";
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
- Share:
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="Share on Facebook"
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="Share on Twitter"
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="Share on LinkedIn"
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="Copy link"
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
- Share
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 "@/lib/format";
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 label for discount type
67
+ * Get translation key for discount type
67
68
  */
68
- function getDiscountTypeLabel(discount: AppliedDiscount): string {
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 ? `${discount.value}% zniżki` : "Rabat procentowy";
75
+ return discount.value
76
+ ? t("percentage", { value: discount.value })
77
+ : t("percentageDefault");
72
78
  case "FIXED_AMOUNT":
73
- return "Rabat kwotowy";
79
+ return t("fixedAmount");
74
80
  case "FREE_SHIPPING":
75
- return "Darmowa dostawa";
81
+ return t("freeShipping");
76
82
  case "BUY_X_GET_Y":
77
- return "Kup X, dostań Y";
83
+ return t("buyXGetY");
78
84
  default:
79
- return "Rabat";
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
- Łączne oszczędności
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 = "Rabat",
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
- {label}
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 "@/lib/format";
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 = "Wpisz kod rabatowy",
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("Wpisz kod rabatowy");
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("Ten kod jest już zastosowany");
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 || "Kod jest nieprawidłowy");
105
+ setError(result.errorMessage || t("invalidCode"));
103
106
  }
104
- } catch (e: any) {
105
- setError(e.message || "Nie udało się zweryfikować kodu");
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 `Oszczędzisz ${formatPrice(validationResult.estimatedSavings)}`;
154
+ return t("savings", { savings: formatPrice(validationResult.estimatedSavings) });
152
155
  }
153
156
 
154
157
  if (validationResult.discountType === "PERCENTAGE" && validationResult.discountValue) {
155
- return `${validationResult.discountValue}% zniżki`;
158
+ return t("percentOff", { value: validationResult.discountValue });
156
159
  }
157
160
 
158
161
  if (validationResult.discountType === "FREE_SHIPPING") {
159
- return "Darmowa dostawa";
162
+ return t("freeShippingDiscount");
160
163
  }
161
164
 
162
- return "Kod jest prawidłowy";
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
- Zastosuj
213
+ {tc("apply")}
211
214
  </>
212
215
  ) : (
213
- "Zastosuj"
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
- Minimalna kwota zamówienia: {formatPrice(validationResult.minimumOrderAmount)}
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
- <div className="flex min-h-[400px] items-center justify-center p-4">
80
- <Card className="w-full max-w-md">
81
- <CardHeader className="text-center">
82
- <div className="mx-auto mb-4 flex h-12 w-12 items-center justify-center rounded-full bg-destructive/10">
83
- <AlertTriangle className="h-6 w-6 text-destructive" />
84
- </div>
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">Loading filters...</span>
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">Filters</h3>
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
- Clear all
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">Price</h4>
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} products
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<T extends (...args: any[]) => void>(
183
- fn: T,
182
+ function debounce<TArgs extends unknown[]>(
183
+ fn: (...args: TArgs) => void,
184
184
  delay: number
185
- ): T {
185
+ ): (...args: TArgs) => void {
186
186
  let timeoutId: NodeJS.Timeout;
187
- return ((...args: Parameters<T>) => {
187
+ return (...args: TArgs) => {
188
188
  clearTimeout(timeoutId);
189
189
  timeoutId = setTimeout(() => fn(...args), delay);
190
- }) as T;
190
+ };
191
191
  }
192
192
 
193
193
  export default RangeSliderFilter;