@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,215 +0,0 @@
1
- "use client";
2
-
3
- import { useState } from "react";
4
- import { Plus } from "lucide-react";
5
- import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
6
- import { getGraphQLClient } from "@/lib/graphql/client";
7
- import { useAuthStore } from "@/stores/auth-store";
8
- import {
9
- CustomerDocument,
10
- CustomerAddressCreateDocument,
11
- CustomerAddressUpdateDocument,
12
- CustomerAddressDeleteDocument,
13
- CustomerDefaultAddressUpdateDocument,
14
- } from "@/generated/graphql";
15
- import { Button } from "@/components/ui/button";
16
- import { Breadcrumbs } from "@/components/layout/breadcrumbs";
17
- import {
18
- AddressList,
19
- type Address,
20
- } from "@/components/account/address-list";
21
- import {
22
- AddressForm,
23
- type AddressFormData,
24
- } from "@/components/account/address-form";
25
- import {
26
- Dialog,
27
- DialogContent,
28
- DialogHeader,
29
- DialogTitle,
30
- } from "@/components/ui/dialog";
31
-
32
- export default function AddressesPage() {
33
- const client = getGraphQLClient();
34
- const queryClient = useQueryClient();
35
- const { accessToken } = useAuthStore();
36
-
37
- // Fetch customer with addresses
38
- const { data: customerData, isLoading } = useQuery({
39
- queryKey: ["customer", "addresses", accessToken],
40
- queryFn: async () => {
41
- if (!accessToken) return null;
42
- const result = await client.request(CustomerDocument, {
43
- customerAccessToken: accessToken,
44
- });
45
- return result.customer;
46
- },
47
- enabled: !!accessToken,
48
- });
49
-
50
- const [isFormOpen, setIsFormOpen] = useState(false);
51
- const [editingAddress, setEditingAddress] = useState<Address | undefined>();
52
-
53
- // Delete address mutation
54
- const deleteMutation = useMutation({
55
- mutationFn: async (id: string) => {
56
- return client.request(CustomerAddressDeleteDocument, {
57
- id,
58
- customerAccessToken: accessToken!,
59
- });
60
- },
61
- onSuccess: () => {
62
- queryClient.invalidateQueries({ queryKey: ["customer", "addresses"] });
63
- },
64
- });
65
-
66
- // Set default address mutation
67
- const setDefaultMutation = useMutation({
68
- mutationFn: async (addressId: string) => {
69
- return client.request(CustomerDefaultAddressUpdateDocument, {
70
- addressId,
71
- customerAccessToken: accessToken!,
72
- });
73
- },
74
- onSuccess: () => {
75
- queryClient.invalidateQueries({ queryKey: ["customer", "addresses"] });
76
- },
77
- });
78
-
79
- // Create/Update address mutation
80
- const saveMutation = useMutation({
81
- mutationFn: async ({
82
- id,
83
- address,
84
- }: {
85
- id?: string;
86
- address: any;
87
- }) => {
88
- if (id) {
89
- return client.request(CustomerAddressUpdateDocument, {
90
- id,
91
- address,
92
- customerAccessToken: accessToken!,
93
- });
94
- } else {
95
- return client.request(CustomerAddressCreateDocument, {
96
- address,
97
- customerAccessToken: accessToken!,
98
- });
99
- }
100
- },
101
- onSuccess: () => {
102
- queryClient.invalidateQueries({ queryKey: ["customer", "addresses"] });
103
- setIsFormOpen(false);
104
- },
105
- });
106
-
107
- const addresses = customerData?.addresses?.edges?.map((edge) => ({
108
- id: edge.node.id,
109
- firstName: edge.node.firstName || "",
110
- lastName: edge.node.lastName || "",
111
- company: edge.node.company || "",
112
- address1: edge.node.address1 || "",
113
- address2: edge.node.address2 || "",
114
- city: edge.node.city || "",
115
- province: edge.node.province || "",
116
- zip: edge.node.zip || "",
117
- country: edge.node.country || "",
118
- phone: edge.node.phone || "",
119
- isDefault: edge.node.id === customerData?.defaultAddress?.id,
120
- })) || [];
121
-
122
- const handleAdd = () => {
123
- setEditingAddress(undefined);
124
- setIsFormOpen(true);
125
- };
126
-
127
- const handleEdit = (address: Address) => {
128
- setEditingAddress(address);
129
- setIsFormOpen(true);
130
- };
131
-
132
- const handleDelete = (id: string) => {
133
- if (confirm("Are you sure you want to delete this address?")) {
134
- deleteMutation.mutate(id);
135
- }
136
- };
137
-
138
- const handleSetDefault = (id: string) => {
139
- setDefaultMutation.mutate(id);
140
- };
141
-
142
- const handleSubmit = async (data: AddressFormData) => {
143
- const address = {
144
- firstName: data.firstName,
145
- lastName: data.lastName,
146
- company: data.company || null,
147
- address1: data.address1,
148
- address2: data.address2 || null,
149
- city: data.city,
150
- province: data.province,
151
- zip: data.zip,
152
- country: data.country,
153
- phone: data.phone || null,
154
- };
155
-
156
- await saveMutation.mutateAsync({
157
- id: editingAddress?.id,
158
- address,
159
- });
160
- };
161
-
162
- if (isLoading) {
163
- return (
164
- <div className="container mx-auto px-4 py-8">
165
- <div className="animate-pulse space-y-4">
166
- <div className="h-8 bg-muted rounded w-1/4"></div>
167
- <div className="h-64 bg-muted rounded"></div>
168
- </div>
169
- </div>
170
- );
171
- }
172
-
173
- return (
174
- <div className="container mx-auto px-4 py-8">
175
- <Breadcrumbs className="mb-6" />
176
-
177
- <div className="mb-8 flex items-center justify-between">
178
- <div>
179
- <h1 className="text-3xl font-bold text-foreground">Addresses</h1>
180
- <p className="mt-2 text-muted-foreground">
181
- Manage your shipping and billing addresses
182
- </p>
183
- </div>
184
- <Button onClick={handleAdd}>
185
- <Plus className="mr-2 h-4 w-4" />
186
- Add Address
187
- </Button>
188
- </div>
189
-
190
- <AddressList
191
- addresses={addresses}
192
- onEdit={handleEdit}
193
- onDelete={handleDelete}
194
- onSetDefault={handleSetDefault}
195
- onAdd={handleAdd}
196
- />
197
-
198
- {/* Address Form Dialog */}
199
- <Dialog open={isFormOpen} onOpenChange={setIsFormOpen}>
200
- <DialogContent className="max-w-2xl max-h-[90vh] overflow-y-auto">
201
- <DialogHeader>
202
- <DialogTitle>
203
- {editingAddress ? "Edit Address" : "Add New Address"}
204
- </DialogTitle>
205
- </DialogHeader>
206
- <AddressForm
207
- address={editingAddress}
208
- onSubmit={handleSubmit}
209
- onCancel={() => setIsFormOpen(false)}
210
- />
211
- </DialogContent>
212
- </Dialog>
213
- </div>
214
- );
215
- }
@@ -1,128 +0,0 @@
1
- "use client";
2
-
3
- import { useParams } from "next/navigation";
4
- import Link from "next/link";
5
- import { ChevronLeft } from "lucide-react";
6
- import { useQuery } from "@tanstack/react-query";
7
- import { getGraphQLClient } from "@/lib/graphql/client";
8
- import { useAuthStore } from "@/stores/auth-store";
9
- import { CustomerDocument } from "@/generated/graphql";
10
- import { Button } from "@/components/ui/button";
11
- import { Breadcrumbs } from "@/components/layout/breadcrumbs";
12
- import {
13
- OrderDetails,
14
- type OrderDetailsData,
15
- } from "@/components/account/order-details";
16
-
17
- export default function OrderDetailPage() {
18
- const params = useParams();
19
- const orderId = params.id as string;
20
- const { accessToken } = useAuthStore();
21
- const client = getGraphQLClient();
22
-
23
- // Fetch customer orders
24
- const { data: customerData, isLoading } = useQuery({
25
- queryKey: ["customer", "orders", accessToken],
26
- queryFn: async () => {
27
- if (!accessToken) return null;
28
- return client.request(CustomerDocument, { customerAccessToken: accessToken });
29
- },
30
- enabled: !!accessToken,
31
- });
32
-
33
- // Find specific order
34
- const order = customerData?.customer?.orders?.edges?.find(
35
- (edge) => edge.node.id === orderId
36
- )?.node;
37
-
38
- if (isLoading) {
39
- return (
40
- <div className="container mx-auto px-4 py-8">
41
- <div className="animate-pulse space-y-4">
42
- <div className="h-8 bg-muted rounded w-1/4"></div>
43
- <div className="h-64 bg-muted rounded"></div>
44
- </div>
45
- </div>
46
- );
47
- }
48
-
49
- if (!order) {
50
- return (
51
- <div className="container mx-auto px-4 py-8">
52
- <div className="text-center">
53
- <h1 className="text-2xl font-bold">Order not found</h1>
54
- <Link href="/account/orders">
55
- <Button className="mt-4">Back to Orders</Button>
56
- </Link>
57
- </div>
58
- </div>
59
- );
60
- }
61
-
62
- // Transform order data to match OrderDetailsData interface
63
- const orderDetails: OrderDetailsData = {
64
- id: order.id,
65
- orderNumber: order.orderNumber?.toString() || order.id,
66
- date: new Date(order.processedAt).toLocaleDateString(),
67
- status: order.fulfillmentStatus?.toLowerCase() || "pending",
68
- items: order.lineItems.edges.map((edge) => ({
69
- id: edge.node.variant?.id || edge.node.title,
70
- title: edge.node.title,
71
- variantTitle: edge.node.variant?.title || "",
72
- quantity: edge.node.quantity,
73
- price: edge.node.originalTotalPrice.amount,
74
- currency: edge.node.originalTotalPrice.currencyCode,
75
- imageUrl: edge.node.variant?.image?.url || "",
76
- })),
77
- subtotal: order.subtotalPrice?.amount || "0",
78
- shipping: order.totalShippingPrice?.amount || "0",
79
- tax: order.totalTax?.amount || "0",
80
- total: order.totalPrice.amount,
81
- currency: order.totalPrice.currencyCode,
82
- shippingAddress: order.shippingAddress
83
- ? {
84
- firstName: order.shippingAddress.firstName || "",
85
- lastName: order.shippingAddress.lastName || "",
86
- address1: order.shippingAddress.address1 || "",
87
- address2: order.shippingAddress.address2 || "",
88
- city: order.shippingAddress.city || "",
89
- province: order.shippingAddress.province || "",
90
- zip: order.shippingAddress.zip || "",
91
- country: order.shippingAddress.country || "",
92
- phone: order.shippingAddress.phone || "",
93
- }
94
- : undefined,
95
- billingAddress: order.billingAddress
96
- ? {
97
- firstName: order.billingAddress.firstName || "",
98
- lastName: order.billingAddress.lastName || "",
99
- address1: order.billingAddress.address1 || "",
100
- address2: order.billingAddress.address2 || "",
101
- city: order.billingAddress.city || "",
102
- province: order.billingAddress.province || "",
103
- zip: order.billingAddress.zip || "",
104
- country: order.billingAddress.country || "",
105
- phone: order.billingAddress.phone || "",
106
- }
107
- : undefined,
108
- trackingNumber: order.successfulFulfillments?.[0]?.trackingInfo?.[0]?.number,
109
- estimatedDelivery: order.successfulFulfillments?.[0]?.estimatedDeliveryAt,
110
- };
111
-
112
- return (
113
- <div className="container mx-auto px-4 py-8">
114
- <Breadcrumbs className="mb-6" />
115
-
116
- <div className="mb-6">
117
- <Button variant="ghost" asChild>
118
- <Link href="/account/orders">
119
- <ChevronLeft className="mr-2 h-4 w-4" />
120
- Back to Orders
121
- </Link>
122
- </Button>
123
- </div>
124
-
125
- <OrderDetails order={orderDetails} />
126
- </div>
127
- );
128
- }
@@ -1,80 +0,0 @@
1
- "use client";
2
-
3
- import { useQuery } from "@tanstack/react-query";
4
- import { getGraphQLClient } from "@/lib/graphql/client";
5
- import { useAuthStore } from "@/stores/auth-store";
6
- import { CustomerDocument } from "@/generated/graphql";
7
- import { Breadcrumbs } from "@/components/layout/breadcrumbs";
8
- import { OrderHistory, type Order } from "@/components/account/order-history";
9
- import { Skeleton } from "@/components/ui/skeleton";
10
-
11
- export default function OrdersPage() {
12
- const client = getGraphQLClient();
13
- const { accessToken, isAuthenticated } = useAuthStore();
14
-
15
- const { data, isLoading, error } = useQuery({
16
- queryKey: ["customer", "orders", accessToken],
17
- queryFn: async () => {
18
- if (!accessToken) return null;
19
- const result = await client.request(CustomerDocument, {
20
- customerAccessToken: accessToken,
21
- });
22
- return result.customer;
23
- },
24
- enabled: isAuthenticated && !!accessToken,
25
- });
26
-
27
- if (isLoading) {
28
- return (
29
- <div className="container mx-auto px-4 py-8">
30
- <Breadcrumbs className="mb-6" />
31
- <div className="mb-8">
32
- <Skeleton className="h-10 w-64 mb-2" />
33
- <Skeleton className="h-6 w-96" />
34
- </div>
35
- <div className="space-y-4">
36
- {[...Array(3)].map((_, i) => (
37
- <Skeleton key={i} className="h-32 w-full" />
38
- ))}
39
- </div>
40
- </div>
41
- );
42
- }
43
-
44
- if (error) {
45
- return (
46
- <div className="container mx-auto px-4 py-8">
47
- <Breadcrumbs className="mb-6" />
48
- <div className="rounded-lg border border-red-200 bg-red-50 p-8 text-center">
49
- <p className="text-red-800">Failed to load orders</p>
50
- </div>
51
- </div>
52
- );
53
- }
54
-
55
- const orders: Order[] =
56
- data?.orders?.edges.map((edge) => ({
57
- id: edge.node.id,
58
- orderNumber: edge.node.orderNumber,
59
- date: edge.node.createdAt,
60
- status: (edge.node.fulfillmentStatus || "processing") as Order["status"],
61
- total: edge.node.totalPrice.amount,
62
- currency: edge.node.totalPrice.currencyCode,
63
- itemCount: edge.node.lineItems?.edges.length || 0,
64
- })) || [];
65
-
66
- return (
67
- <div className="container mx-auto px-4 py-8">
68
- <Breadcrumbs className="mb-6" />
69
-
70
- <div className="mb-8">
71
- <h1 className="text-3xl font-bold text-foreground">Order History</h1>
72
- <p className="mt-2 text-muted-foreground">
73
- View and track your orders
74
- </p>
75
- </div>
76
-
77
- <OrderHistory orders={orders} />
78
- </div>
79
- );
80
- }
@@ -1,171 +0,0 @@
1
- "use client";
2
-
3
- import { useState } from "react";
4
- import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
5
- import { getGraphQLClient } from "@/lib/graphql/client";
6
- import { useAuthStore } from "@/stores/auth-store";
7
- import { CustomerDocument, CustomerUpdateDocument } from "@/generated/graphql";
8
- import { Breadcrumbs } from "@/components/layout/breadcrumbs";
9
- import { Button } from "@/components/ui/button";
10
- import { Input } from "@/components/ui/input";
11
- import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
12
-
13
- export default function SettingsPage() {
14
- const { accessToken } = useAuthStore();
15
- const client = getGraphQLClient();
16
- const queryClient = useQueryClient();
17
-
18
- const [email, setEmail] = useState("");
19
- const [firstName, setFirstName] = useState("");
20
- const [lastName, setLastName] = useState("");
21
- const [phone, setPhone] = useState("");
22
-
23
- // Fetch customer data
24
- const { data: customerData } = useQuery({
25
- queryKey: ["customer", accessToken],
26
- queryFn: async () => {
27
- if (!accessToken) return null;
28
- return client.request(CustomerDocument, { customerAccessToken: accessToken });
29
- },
30
- enabled: !!accessToken,
31
- });
32
-
33
- // Initialize form with customer data
34
- useState(() => {
35
- if (customerData?.customer) {
36
- setEmail(customerData.customer.email || "");
37
- setFirstName(customerData.customer.firstName || "");
38
- setLastName(customerData.customer.lastName || "");
39
- setPhone(customerData.customer.phone || "");
40
- }
41
- });
42
-
43
- // Update customer mutation
44
- const updateMutation = useMutation({
45
- mutationFn: async (customer: any) => {
46
- return client.request(CustomerUpdateDocument, {
47
- customer,
48
- customerAccessToken: accessToken!,
49
- });
50
- },
51
- onSuccess: () => {
52
- queryClient.invalidateQueries({ queryKey: ["customer"] });
53
- alert("Settings saved successfully!");
54
- },
55
- onError: () => {
56
- alert("Failed to save settings");
57
- },
58
- });
59
-
60
- const handleSave = (e: React.FormEvent) => {
61
- e.preventDefault();
62
- updateMutation.mutate({
63
- firstName,
64
- lastName,
65
- email,
66
- phone,
67
- });
68
- };
69
-
70
- return (
71
- <div className="container mx-auto px-4 py-8">
72
- <Breadcrumbs className="mb-6" />
73
-
74
- <div className="mx-auto max-w-2xl">
75
- <h1 className="mb-8 text-3xl font-bold text-foreground">Account Settings</h1>
76
-
77
- <div className="space-y-6">
78
- {/* Personal Information */}
79
- <Card>
80
- <CardHeader>
81
- <CardTitle>Personal Information</CardTitle>
82
- </CardHeader>
83
- <CardContent>
84
- <form onSubmit={handleSave} className="space-y-4">
85
- <div className="grid gap-4 sm:grid-cols-2">
86
- <div className="space-y-2">
87
- <label htmlFor="firstName" className="text-sm font-medium">
88
- First Name
89
- </label>
90
- <Input
91
- id="firstName"
92
- value={firstName}
93
- onChange={(e) => setFirstName(e.target.value)}
94
- />
95
- </div>
96
- <div className="space-y-2">
97
- <label htmlFor="lastName" className="text-sm font-medium">
98
- Last Name
99
- </label>
100
- <Input
101
- id="lastName"
102
- value={lastName}
103
- onChange={(e) => setLastName(e.target.value)}
104
- />
105
- </div>
106
- </div>
107
- <div className="space-y-2">
108
- <label htmlFor="email" className="text-sm font-medium">
109
- Email
110
- </label>
111
- <Input
112
- id="email"
113
- type="email"
114
- value={email}
115
- onChange={(e) => setEmail(e.target.value)}
116
- />
117
- </div>
118
- <div className="space-y-2">
119
- <label htmlFor="phone" className="text-sm font-medium">
120
- Phone
121
- </label>
122
- <Input
123
- id="phone"
124
- type="tel"
125
- value={phone}
126
- onChange={(e) => setPhone(e.target.value)}
127
- />
128
- </div>
129
- <Button type="submit" disabled={updateMutation.isPending}>
130
- {updateMutation.isPending ? "Saving..." : "Save Changes"}
131
- </Button>
132
- </form>
133
- </CardContent>
134
- </Card>
135
-
136
- {/* Change Password */}
137
- <Card>
138
- <CardHeader>
139
- <CardTitle>Change Password</CardTitle>
140
- </CardHeader>
141
- <CardContent>
142
- <form className="space-y-4">
143
- <div className="space-y-2">
144
- <label htmlFor="currentPassword" className="text-sm font-medium">
145
- Current Password
146
- </label>
147
- <Input id="currentPassword" type="password" />
148
- </div>
149
- <div className="space-y-2">
150
- <label htmlFor="newPassword" className="text-sm font-medium">
151
- New Password
152
- </label>
153
- <Input id="newPassword" type="password" />
154
- </div>
155
- <div className="space-y-2">
156
- <label htmlFor="confirmPassword" className="text-sm font-medium">
157
- Confirm New Password
158
- </label>
159
- <Input id="confirmPassword" type="password" />
160
- </div>
161
- <Button type="submit">Update Password</Button>
162
- </form>
163
- </CardContent>
164
- </Card>
165
-
166
- {/* Email preferences are managed via the self-service preferences portal */}
167
- </div>
168
- </div>
169
- </div>
170
- );
171
- }
@@ -1,78 +0,0 @@
1
- "use client";
2
-
3
- import { useParams } from "next/navigation";
4
- import { ProductGrid } from "@/components/product/product-grid";
5
- import { Breadcrumbs } from "@/components/layout/breadcrumbs";
6
- import { Skeleton } from "@/components/ui/skeleton";
7
- import { useProducts } from "@/lib/graphql/hooks";
8
-
9
- export default function CategoryPage() {
10
- const params = useParams();
11
- const slug = params.slug as string;
12
-
13
- // Fetch products for this category using GraphQL query
14
- const { data, isLoading, error } = useProducts({
15
- first: 20,
16
- query: `category:${slug}`,
17
- });
18
-
19
- const products = data?.products ?? [];
20
-
21
- if (isLoading) {
22
- return (
23
- <div className="container mx-auto px-4 py-8">
24
- <Breadcrumbs className="mb-6" />
25
- <div className="mb-8">
26
- <Skeleton className="h-10 w-64 mb-4" />
27
- <Skeleton className="h-6 w-96" />
28
- </div>
29
- <div className="grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-4">
30
- {Array.from({ length: 8 }).map((_, i) => (
31
- <Skeleton key={i} className="aspect-square w-full" />
32
- ))}
33
- </div>
34
- </div>
35
- );
36
- }
37
-
38
- if (error) {
39
- return (
40
- <div className="container mx-auto px-4 py-8">
41
- <Breadcrumbs className="mb-6" />
42
- <div className="rounded-lg border border-border bg-muted/50 p-12 text-center">
43
- <h1 className="text-2xl font-bold text-foreground mb-2">
44
- Category Not Found
45
- </h1>
46
- <p className="text-muted-foreground">
47
- The category you're looking for doesn't exist.
48
- </p>
49
- </div>
50
- </div>
51
- );
52
- }
53
-
54
- return (
55
- <div className="container mx-auto px-4 py-8">
56
- <Breadcrumbs className="mb-6" />
57
-
58
- {/* Category Header */}
59
- <div className="mb-8">
60
- <h1 className="text-3xl font-bold text-foreground capitalize">
61
- {slug.replace(/-/g, " ")}
62
- </h1>
63
- <p className="mt-2 text-muted-foreground">
64
- Browse products in this category
65
- </p>
66
- </div>
67
-
68
- {/* Products Grid */}
69
- <ProductGrid
70
- products={products}
71
- columns={4}
72
- priorityCount={8}
73
- showBadges
74
- emptyMessage="No products in this category"
75
- />
76
- </div>
77
- );
78
- }