@doswiftly/cli 0.1.1

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 (453) hide show
  1. package/README.md +357 -0
  2. package/bin/doswiftly.js +2 -0
  3. package/dist/commands/auth-github.d.ts +6 -0
  4. package/dist/commands/auth-github.d.ts.map +1 -0
  5. package/dist/commands/auth-github.js +89 -0
  6. package/dist/commands/auth-github.js.map +1 -0
  7. package/dist/commands/auth-token.d.ts +12 -0
  8. package/dist/commands/auth-token.d.ts.map +1 -0
  9. package/dist/commands/auth-token.js +43 -0
  10. package/dist/commands/auth-token.js.map +1 -0
  11. package/dist/commands/auth.d.ts +22 -0
  12. package/dist/commands/auth.d.ts.map +1 -0
  13. package/dist/commands/auth.js +348 -0
  14. package/dist/commands/auth.js.map +1 -0
  15. package/dist/commands/check.d.ts +5 -0
  16. package/dist/commands/check.d.ts.map +1 -0
  17. package/dist/commands/check.js +234 -0
  18. package/dist/commands/check.js.map +1 -0
  19. package/dist/commands/config.d.ts +3 -0
  20. package/dist/commands/config.d.ts.map +1 -0
  21. package/dist/commands/config.js +104 -0
  22. package/dist/commands/config.js.map +1 -0
  23. package/dist/commands/deploy.d.ts +37 -0
  24. package/dist/commands/deploy.d.ts.map +1 -0
  25. package/dist/commands/deploy.js +580 -0
  26. package/dist/commands/deploy.js.map +1 -0
  27. package/dist/commands/dev.d.ts +8 -0
  28. package/dist/commands/dev.d.ts.map +1 -0
  29. package/dist/commands/dev.js +83 -0
  30. package/dist/commands/dev.js.map +1 -0
  31. package/dist/commands/doctor.d.ts +5 -0
  32. package/dist/commands/doctor.d.ts.map +1 -0
  33. package/dist/commands/doctor.js +363 -0
  34. package/dist/commands/doctor.js.map +1 -0
  35. package/dist/commands/domain.d.ts +13 -0
  36. package/dist/commands/domain.d.ts.map +1 -0
  37. package/dist/commands/domain.js +128 -0
  38. package/dist/commands/domain.js.map +1 -0
  39. package/dist/commands/env.d.ts +25 -0
  40. package/dist/commands/env.d.ts.map +1 -0
  41. package/dist/commands/env.js +228 -0
  42. package/dist/commands/env.js.map +1 -0
  43. package/dist/commands/init.d.ts +11 -0
  44. package/dist/commands/init.d.ts.map +1 -0
  45. package/dist/commands/init.js +1028 -0
  46. package/dist/commands/init.js.map +1 -0
  47. package/dist/commands/inspect.d.ts +12 -0
  48. package/dist/commands/inspect.d.ts.map +1 -0
  49. package/dist/commands/inspect.js +162 -0
  50. package/dist/commands/inspect.js.map +1 -0
  51. package/dist/commands/migrate.d.ts +18 -0
  52. package/dist/commands/migrate.d.ts.map +1 -0
  53. package/dist/commands/migrate.js +355 -0
  54. package/dist/commands/migrate.js.map +1 -0
  55. package/dist/commands/preview.d.ts +29 -0
  56. package/dist/commands/preview.d.ts.map +1 -0
  57. package/dist/commands/preview.js +199 -0
  58. package/dist/commands/preview.js.map +1 -0
  59. package/dist/commands/proxy.d.ts +9 -0
  60. package/dist/commands/proxy.d.ts.map +1 -0
  61. package/dist/commands/proxy.js +37 -0
  62. package/dist/commands/proxy.js.map +1 -0
  63. package/dist/commands/sdk.d.ts +5 -0
  64. package/dist/commands/sdk.d.ts.map +1 -0
  65. package/dist/commands/sdk.js +82 -0
  66. package/dist/commands/sdk.js.map +1 -0
  67. package/dist/commands/template.d.ts +107 -0
  68. package/dist/commands/template.d.ts.map +1 -0
  69. package/dist/commands/template.js +1309 -0
  70. package/dist/commands/template.js.map +1 -0
  71. package/dist/commands/types.d.ts +5 -0
  72. package/dist/commands/types.d.ts.map +1 -0
  73. package/dist/commands/types.js +82 -0
  74. package/dist/commands/types.js.map +1 -0
  75. package/dist/commands/update.d.ts +2 -0
  76. package/dist/commands/update.d.ts.map +1 -0
  77. package/dist/commands/update.js +103 -0
  78. package/dist/commands/update.js.map +1 -0
  79. package/dist/commands/upgrade.d.ts +18 -0
  80. package/dist/commands/upgrade.d.ts.map +1 -0
  81. package/dist/commands/upgrade.js +55 -0
  82. package/dist/commands/upgrade.js.map +1 -0
  83. package/dist/commands/verify.d.ts +5 -0
  84. package/dist/commands/verify.d.ts.map +1 -0
  85. package/dist/commands/verify.js +232 -0
  86. package/dist/commands/verify.js.map +1 -0
  87. package/dist/commands/whoami.d.ts +5 -0
  88. package/dist/commands/whoami.d.ts.map +1 -0
  89. package/dist/commands/whoami.js +60 -0
  90. package/dist/commands/whoami.js.map +1 -0
  91. package/dist/config/types.d.ts +173 -0
  92. package/dist/config/types.d.ts.map +1 -0
  93. package/dist/config/types.js +48 -0
  94. package/dist/config/types.js.map +1 -0
  95. package/dist/index.d.ts +3 -0
  96. package/dist/index.d.ts.map +1 -0
  97. package/dist/index.js +416 -0
  98. package/dist/index.js.map +1 -0
  99. package/dist/lib/api-url.d.ts +14 -0
  100. package/dist/lib/api-url.d.ts.map +1 -0
  101. package/dist/lib/api-url.js +24 -0
  102. package/dist/lib/api-url.js.map +1 -0
  103. package/dist/lib/api.d.ts +67 -0
  104. package/dist/lib/api.d.ts.map +1 -0
  105. package/dist/lib/api.js +36 -0
  106. package/dist/lib/api.js.map +1 -0
  107. package/dist/lib/config.d.ts +39 -0
  108. package/dist/lib/config.d.ts.map +1 -0
  109. package/dist/lib/config.js +195 -0
  110. package/dist/lib/config.js.map +1 -0
  111. package/dist/lib/env-storage.d.ts +140 -0
  112. package/dist/lib/env-storage.d.ts.map +1 -0
  113. package/dist/lib/env-storage.js +464 -0
  114. package/dist/lib/env-storage.js.map +1 -0
  115. package/dist/lib/errors.d.ts +61 -0
  116. package/dist/lib/errors.d.ts.map +1 -0
  117. package/dist/lib/errors.js +204 -0
  118. package/dist/lib/errors.js.map +1 -0
  119. package/dist/lib/i18n.d.ts +99 -0
  120. package/dist/lib/i18n.d.ts.map +1 -0
  121. package/dist/lib/i18n.js +184 -0
  122. package/dist/lib/i18n.js.map +1 -0
  123. package/dist/lib/logger.d.ts +95 -0
  124. package/dist/lib/logger.d.ts.map +1 -0
  125. package/dist/lib/logger.js +168 -0
  126. package/dist/lib/logger.js.map +1 -0
  127. package/dist/lib/package-manager.d.ts +91 -0
  128. package/dist/lib/package-manager.d.ts.map +1 -0
  129. package/dist/lib/package-manager.js +205 -0
  130. package/dist/lib/package-manager.js.map +1 -0
  131. package/dist/lib/proxy-server.d.ts +24 -0
  132. package/dist/lib/proxy-server.d.ts.map +1 -0
  133. package/dist/lib/proxy-server.js +173 -0
  134. package/dist/lib/proxy-server.js.map +1 -0
  135. package/dist/lib/select-with-back.d.ts +34 -0
  136. package/dist/lib/select-with-back.d.ts.map +1 -0
  137. package/dist/lib/select-with-back.js +94 -0
  138. package/dist/lib/select-with-back.js.map +1 -0
  139. package/dist/lib/shared-api-client.d.ts +40 -0
  140. package/dist/lib/shared-api-client.d.ts.map +1 -0
  141. package/dist/lib/shared-api-client.js +92 -0
  142. package/dist/lib/shared-api-client.js.map +1 -0
  143. package/dist/lib/wizard-engine.d.ts +128 -0
  144. package/dist/lib/wizard-engine.d.ts.map +1 -0
  145. package/dist/lib/wizard-engine.js +168 -0
  146. package/dist/lib/wizard-engine.js.map +1 -0
  147. package/package.json +85 -0
  148. package/templates/storefront-minimal/.env.example +10 -0
  149. package/templates/storefront-minimal/.github/workflows/build-template.yml +109 -0
  150. package/templates/storefront-minimal/app/globals.css +18 -0
  151. package/templates/storefront-minimal/app/layout.tsx +26 -0
  152. package/templates/storefront-minimal/app/page.tsx +93 -0
  153. package/templates/storefront-minimal/lib/graphql-client.ts +23 -0
  154. package/templates/storefront-minimal/next.config.ts +15 -0
  155. package/templates/storefront-minimal/open-next.config.ts +3 -0
  156. package/templates/storefront-minimal/package.json +30 -0
  157. package/templates/storefront-minimal/postcss.config.mjs +5 -0
  158. package/templates/storefront-minimal/tailwind.config.ts +14 -0
  159. package/templates/storefront-minimal/tsconfig.json +27 -0
  160. package/templates/storefront-minimal/wrangler.toml +9 -0
  161. package/templates/storefront-nextjs/.env.example +68 -0
  162. package/templates/storefront-nextjs/.github/workflows/build-template.yml +109 -0
  163. package/templates/storefront-nextjs/.github/workflows/deploy.yml +25 -0
  164. package/templates/storefront-nextjs/.github/workflows/preview.yml +22 -0
  165. package/templates/storefront-nextjs/README.md +520 -0
  166. package/templates/storefront-nextjs/app/account/orders/page.tsx +216 -0
  167. package/templates/storefront-nextjs/app/account/page.tsx +167 -0
  168. package/templates/storefront-nextjs/app/auth/login/page.tsx +135 -0
  169. package/templates/storefront-nextjs/app/auth/register/page.tsx +228 -0
  170. package/templates/storefront-nextjs/app/cart/page.tsx +263 -0
  171. package/templates/storefront-nextjs/app/categories/[slug]/page.tsx +200 -0
  172. package/templates/storefront-nextjs/app/categories/page.tsx +58 -0
  173. package/templates/storefront-nextjs/app/checkout/page.tsx +351 -0
  174. package/templates/storefront-nextjs/app/collections/[slug]/page.tsx +158 -0
  175. package/templates/storefront-nextjs/app/collections/page.tsx +61 -0
  176. package/templates/storefront-nextjs/app/globals.css +98 -0
  177. package/templates/storefront-nextjs/app/layout.tsx +39 -0
  178. package/templates/storefront-nextjs/app/page.tsx +136 -0
  179. package/templates/storefront-nextjs/app/products/[slug]/page.tsx +119 -0
  180. package/templates/storefront-nextjs/app/products/page.tsx +107 -0
  181. package/templates/storefront-nextjs/app/search/page.tsx +127 -0
  182. package/templates/storefront-nextjs/components/auth/auth-guard.tsx +94 -0
  183. package/templates/storefront-nextjs/components/commerce/add-to-cart-button.tsx +77 -0
  184. package/templates/storefront-nextjs/components/commerce/cart-icon.tsx +29 -0
  185. package/templates/storefront-nextjs/components/commerce/currency-selector.tsx +217 -0
  186. package/templates/storefront-nextjs/components/commerce/pagination.tsx +62 -0
  187. package/templates/storefront-nextjs/components/commerce/product-actions.tsx +135 -0
  188. package/templates/storefront-nextjs/components/commerce/product-filters.tsx +109 -0
  189. package/templates/storefront-nextjs/components/commerce/product-price.tsx +375 -0
  190. package/templates/storefront-nextjs/components/commerce/search-input.tsx +178 -0
  191. package/templates/storefront-nextjs/components/commerce/sort-select.tsx +64 -0
  192. package/templates/storefront-nextjs/components/commerce/variant-selector.tsx +210 -0
  193. package/templates/storefront-nextjs/components/layout/footer.tsx +107 -0
  194. package/templates/storefront-nextjs/components/layout/header.tsx +104 -0
  195. package/templates/storefront-nextjs/components/providers.tsx +62 -0
  196. package/templates/storefront-nextjs/lib/auth/routes.ts +52 -0
  197. package/templates/storefront-nextjs/lib/currency.tsx +140 -0
  198. package/templates/storefront-nextjs/lib/format.ts +159 -0
  199. package/templates/storefront-nextjs/lib/graphql-queries.ts +629 -0
  200. package/templates/storefront-nextjs/lib/hooks.ts +30 -0
  201. package/templates/storefront-nextjs/middleware.ts +80 -0
  202. package/templates/storefront-nextjs/next.config.ts +37 -0
  203. package/templates/storefront-nextjs/open-next.config.ts +3 -0
  204. package/templates/storefront-nextjs/package.dev.json +30 -0
  205. package/templates/storefront-nextjs/package.json +32 -0
  206. package/templates/storefront-nextjs/package.json.template +32 -0
  207. package/templates/storefront-nextjs/postcss.config.mjs +8 -0
  208. package/templates/storefront-nextjs/tailwind.config.ts +111 -0
  209. package/templates/storefront-nextjs/tsconfig.json +27 -0
  210. package/templates/storefront-nextjs/wrangler.toml +9 -0
  211. package/templates/storefront-nextjs-shadcn/.env.example +68 -0
  212. package/templates/storefront-nextjs-shadcn/.github/workflows/build-template.yml +109 -0
  213. package/templates/storefront-nextjs-shadcn/.github/workflows/deploy.yml +25 -0
  214. package/templates/storefront-nextjs-shadcn/.github/workflows/preview.yml +22 -0
  215. package/templates/storefront-nextjs-shadcn/CART_INTEGRATION.md +282 -0
  216. package/templates/storefront-nextjs-shadcn/CLAUDE.md +96 -0
  217. package/templates/storefront-nextjs-shadcn/GRAPHQL_DOCUMENT_NAMES.md +190 -0
  218. package/templates/storefront-nextjs-shadcn/GRAPHQL_ERROR_HANDLING.md +263 -0
  219. package/templates/storefront-nextjs-shadcn/GRAPHQL_FIXES_SUMMARY.md +135 -0
  220. package/templates/storefront-nextjs-shadcn/GRAPHQL_INTEGRATION_COMPLETE.md +142 -0
  221. package/templates/storefront-nextjs-shadcn/INTEGRATION_CHECKLIST.md +448 -0
  222. package/templates/storefront-nextjs-shadcn/PRODUCT_DETAIL_PAGE_IMPLEMENTATION.md +307 -0
  223. package/templates/storefront-nextjs-shadcn/README.md +195 -0
  224. package/templates/storefront-nextjs-shadcn/THEME_CUSTOMIZATION.md +245 -0
  225. package/templates/storefront-nextjs-shadcn/app/about/page.tsx +34 -0
  226. package/templates/storefront-nextjs-shadcn/app/account/addresses/page.tsx +215 -0
  227. package/templates/storefront-nextjs-shadcn/app/account/loyalty/page.tsx +484 -0
  228. package/templates/storefront-nextjs-shadcn/app/account/orders/[id]/page.tsx +128 -0
  229. package/templates/storefront-nextjs-shadcn/app/account/orders/[id]/tracking/page.tsx +206 -0
  230. package/templates/storefront-nextjs-shadcn/app/account/orders/page.tsx +80 -0
  231. package/templates/storefront-nextjs-shadcn/app/account/page.tsx +107 -0
  232. package/templates/storefront-nextjs-shadcn/app/account/settings/page.tsx +195 -0
  233. package/templates/storefront-nextjs-shadcn/app/api/auth/clear-token/route.ts +87 -0
  234. package/templates/storefront-nextjs-shadcn/app/api/auth/set-token/route.ts +125 -0
  235. package/templates/storefront-nextjs-shadcn/app/auth/forgot-password/page.tsx +131 -0
  236. package/templates/storefront-nextjs-shadcn/app/auth/login/page.tsx +24 -0
  237. package/templates/storefront-nextjs-shadcn/app/auth/register/page.tsx +20 -0
  238. package/templates/storefront-nextjs-shadcn/app/blog/[slug]/page.tsx +323 -0
  239. package/templates/storefront-nextjs-shadcn/app/blog/page.tsx +159 -0
  240. package/templates/storefront-nextjs-shadcn/app/brands/[slug]/page.tsx +170 -0
  241. package/templates/storefront-nextjs-shadcn/app/brands/page.tsx +73 -0
  242. package/templates/storefront-nextjs-shadcn/app/cart/page.tsx +165 -0
  243. package/templates/storefront-nextjs-shadcn/app/categories/[slug]/page.tsx +78 -0
  244. package/templates/storefront-nextjs-shadcn/app/categories/page.tsx +75 -0
  245. package/templates/storefront-nextjs-shadcn/app/checkout/page.tsx +1752 -0
  246. package/templates/storefront-nextjs-shadcn/app/checkout/success/[orderId]/page.tsx +256 -0
  247. package/templates/storefront-nextjs-shadcn/app/collections/[handle]/page.tsx +74 -0
  248. package/templates/storefront-nextjs-shadcn/app/collections/page.tsx +75 -0
  249. package/templates/storefront-nextjs-shadcn/app/contact/page.tsx +114 -0
  250. package/templates/storefront-nextjs-shadcn/app/error.tsx +90 -0
  251. package/templates/storefront-nextjs-shadcn/app/globals.css +125 -0
  252. package/templates/storefront-nextjs-shadcn/app/layout.tsx +57 -0
  253. package/templates/storefront-nextjs-shadcn/app/not-found.tsx +68 -0
  254. package/templates/storefront-nextjs-shadcn/app/page.tsx +21 -0
  255. package/templates/storefront-nextjs-shadcn/app/products/[slug]/page.tsx +246 -0
  256. package/templates/storefront-nextjs-shadcn/app/products/[slug]/product-client.tsx +343 -0
  257. package/templates/storefront-nextjs-shadcn/app/products/page.tsx +25 -0
  258. package/templates/storefront-nextjs-shadcn/app/products/products-client.tsx +192 -0
  259. package/templates/storefront-nextjs-shadcn/app/returns/page.tsx +77 -0
  260. package/templates/storefront-nextjs-shadcn/app/robots.ts +53 -0
  261. package/templates/storefront-nextjs-shadcn/app/search/page.tsx +16 -0
  262. package/templates/storefront-nextjs-shadcn/app/search/search-client.tsx +47 -0
  263. package/templates/storefront-nextjs-shadcn/app/shipping/page.tsx +62 -0
  264. package/templates/storefront-nextjs-shadcn/app/sitemap.ts +144 -0
  265. package/templates/storefront-nextjs-shadcn/app/wishlist/page.tsx +179 -0
  266. package/templates/storefront-nextjs-shadcn/codegen.ts +51 -0
  267. package/templates/storefront-nextjs-shadcn/components/account/address-form.tsx +348 -0
  268. package/templates/storefront-nextjs-shadcn/components/account/address-list.tsx +144 -0
  269. package/templates/storefront-nextjs-shadcn/components/account/order-details.tsx +258 -0
  270. package/templates/storefront-nextjs-shadcn/components/account/order-history.tsx +107 -0
  271. package/templates/storefront-nextjs-shadcn/components/auth/account-menu.tsx +132 -0
  272. package/templates/storefront-nextjs-shadcn/components/auth/login-form.tsx +188 -0
  273. package/templates/storefront-nextjs-shadcn/components/auth/register-form.tsx +305 -0
  274. package/templates/storefront-nextjs-shadcn/components/blog/blog-card.tsx +240 -0
  275. package/templates/storefront-nextjs-shadcn/components/blog/blog-sidebar.tsx +177 -0
  276. package/templates/storefront-nextjs-shadcn/components/blog/index.ts +8 -0
  277. package/templates/storefront-nextjs-shadcn/components/brand/brand-card.tsx +119 -0
  278. package/templates/storefront-nextjs-shadcn/components/brand/brand-grid.tsx +64 -0
  279. package/templates/storefront-nextjs-shadcn/components/cart/cart-drawer.tsx +140 -0
  280. package/templates/storefront-nextjs-shadcn/components/cart/cart-icon.tsx +48 -0
  281. package/templates/storefront-nextjs-shadcn/components/cart/cart-item.tsx +112 -0
  282. package/templates/storefront-nextjs-shadcn/components/cart/cart-summary.tsx +84 -0
  283. package/templates/storefront-nextjs-shadcn/components/cart/index.ts +17 -0
  284. package/templates/storefront-nextjs-shadcn/components/cart/promo-code-input.tsx +121 -0
  285. package/templates/storefront-nextjs-shadcn/components/cart/shipping-estimator.tsx +162 -0
  286. package/templates/storefront-nextjs-shadcn/components/checkout/index.ts +25 -0
  287. package/templates/storefront-nextjs-shadcn/components/checkout/payment-method-card.tsx +187 -0
  288. package/templates/storefront-nextjs-shadcn/components/checkout/payment-step.tsx +160 -0
  289. package/templates/storefront-nextjs-shadcn/components/checkout/tax-breakdown.tsx +154 -0
  290. package/templates/storefront-nextjs-shadcn/components/commerce/currency-selector.tsx +225 -0
  291. package/templates/storefront-nextjs-shadcn/components/commerce/pagination.tsx +62 -0
  292. package/templates/storefront-nextjs-shadcn/components/commerce/product-actions.tsx +158 -0
  293. package/templates/storefront-nextjs-shadcn/components/commerce/search-input.tsx +174 -0
  294. package/templates/storefront-nextjs-shadcn/components/commerce/variant-selector.tsx +210 -0
  295. package/templates/storefront-nextjs-shadcn/components/common/category-card.tsx +97 -0
  296. package/templates/storefront-nextjs-shadcn/components/common/collection-card.tsx +187 -0
  297. package/templates/storefront-nextjs-shadcn/components/common/price-display.tsx +151 -0
  298. package/templates/storefront-nextjs-shadcn/components/common/social-share.tsx +166 -0
  299. package/templates/storefront-nextjs-shadcn/components/discount/discount-breakdown.tsx +245 -0
  300. package/templates/storefront-nextjs-shadcn/components/discount/discount-code-input.tsx +246 -0
  301. package/templates/storefront-nextjs-shadcn/components/discount/index.ts +19 -0
  302. package/templates/storefront-nextjs-shadcn/components/error/error-boundary.tsx +113 -0
  303. package/templates/storefront-nextjs-shadcn/components/error/index.ts +7 -0
  304. package/templates/storefront-nextjs-shadcn/components/filters/attribute-filter.tsx +153 -0
  305. package/templates/storefront-nextjs-shadcn/components/filters/checkbox-group-filter.tsx +167 -0
  306. package/templates/storefront-nextjs-shadcn/components/filters/color-swatch-filter.tsx +176 -0
  307. package/templates/storefront-nextjs-shadcn/components/filters/dynamic-attribute-filters.tsx +220 -0
  308. package/templates/storefront-nextjs-shadcn/components/filters/index.ts +36 -0
  309. package/templates/storefront-nextjs-shadcn/components/filters/range-slider-filter.tsx +193 -0
  310. package/templates/storefront-nextjs-shadcn/components/filters/toggle-filter.tsx +132 -0
  311. package/templates/storefront-nextjs-shadcn/components/gift-card/gift-card-balance.tsx +321 -0
  312. package/templates/storefront-nextjs-shadcn/components/gift-card/gift-card-input.tsx +309 -0
  313. package/templates/storefront-nextjs-shadcn/components/gift-card/index.ts +24 -0
  314. package/templates/storefront-nextjs-shadcn/components/home/category-grid.tsx +72 -0
  315. package/templates/storefront-nextjs-shadcn/components/home/featured-collections.tsx +107 -0
  316. package/templates/storefront-nextjs-shadcn/components/home/featured-products.tsx +85 -0
  317. package/templates/storefront-nextjs-shadcn/components/home/hero-section.tsx +34 -0
  318. package/templates/storefront-nextjs-shadcn/components/home/index.ts +8 -0
  319. package/templates/storefront-nextjs-shadcn/components/home/newsletter-signup.tsx +108 -0
  320. package/templates/storefront-nextjs-shadcn/components/layout/breadcrumbs.tsx +133 -0
  321. package/templates/storefront-nextjs-shadcn/components/layout/currency-selector.tsx +341 -0
  322. package/templates/storefront-nextjs-shadcn/components/layout/footer.tsx +128 -0
  323. package/templates/storefront-nextjs-shadcn/components/layout/header.tsx +147 -0
  324. package/templates/storefront-nextjs-shadcn/components/layout/index.ts +9 -0
  325. package/templates/storefront-nextjs-shadcn/components/layout/mobile-menu.tsx +211 -0
  326. package/templates/storefront-nextjs-shadcn/components/layout/navigation.tsx +95 -0
  327. package/templates/storefront-nextjs-shadcn/components/layout/theme-switcher.tsx +192 -0
  328. package/templates/storefront-nextjs-shadcn/components/loyalty/index.ts +11 -0
  329. package/templates/storefront-nextjs-shadcn/components/loyalty/points-balance.tsx +93 -0
  330. package/templates/storefront-nextjs-shadcn/components/loyalty/points-history.tsx +177 -0
  331. package/templates/storefront-nextjs-shadcn/components/loyalty/referral-section.tsx +250 -0
  332. package/templates/storefront-nextjs-shadcn/components/loyalty/rewards-catalog.tsx +217 -0
  333. package/templates/storefront-nextjs-shadcn/components/loyalty/tier-badge.tsx +106 -0
  334. package/templates/storefront-nextjs-shadcn/components/loyalty/tier-progress.tsx +131 -0
  335. package/templates/storefront-nextjs-shadcn/components/order/delivery-estimate.tsx +196 -0
  336. package/templates/storefront-nextjs-shadcn/components/order/index.ts +11 -0
  337. package/templates/storefront-nextjs-shadcn/components/order/order-tracking.tsx +200 -0
  338. package/templates/storefront-nextjs-shadcn/components/order/shipment-card.tsx +407 -0
  339. package/templates/storefront-nextjs-shadcn/components/order/tracking-status.tsx +222 -0
  340. package/templates/storefront-nextjs-shadcn/components/order/tracking-timeline.tsx +205 -0
  341. package/templates/storefront-nextjs-shadcn/components/product/add-to-cart-button.tsx +161 -0
  342. package/templates/storefront-nextjs-shadcn/components/product/b2b-price-display.tsx +250 -0
  343. package/templates/storefront-nextjs-shadcn/components/product/discount-badge.tsx +196 -0
  344. package/templates/storefront-nextjs-shadcn/components/product/index.ts +41 -0
  345. package/templates/storefront-nextjs-shadcn/components/product/product-card.tsx +147 -0
  346. package/templates/storefront-nextjs-shadcn/components/product/product-filters.tsx +217 -0
  347. package/templates/storefront-nextjs-shadcn/components/product/product-gallery.tsx +143 -0
  348. package/templates/storefront-nextjs-shadcn/components/product/product-grid.tsx +83 -0
  349. package/templates/storefront-nextjs-shadcn/components/product/product-image.tsx +155 -0
  350. package/templates/storefront-nextjs-shadcn/components/product/product-price.tsx +158 -0
  351. package/templates/storefront-nextjs-shadcn/components/product/product-quantity-selector.tsx +111 -0
  352. package/templates/storefront-nextjs-shadcn/components/product/product-reviews.tsx +238 -0
  353. package/templates/storefront-nextjs-shadcn/components/product/product-sort.tsx +58 -0
  354. package/templates/storefront-nextjs-shadcn/components/product/product-variant-selector.tsx +169 -0
  355. package/templates/storefront-nextjs-shadcn/components/product/review-card.tsx +220 -0
  356. package/templates/storefront-nextjs-shadcn/components/product/review-form.tsx +338 -0
  357. package/templates/storefront-nextjs-shadcn/components/product/review-summary.tsx +143 -0
  358. package/templates/storefront-nextjs-shadcn/components/product/sale-countdown.tsx +166 -0
  359. package/templates/storefront-nextjs-shadcn/components/product/savings-display.tsx +213 -0
  360. package/templates/storefront-nextjs-shadcn/components/product/similar-products.tsx +57 -0
  361. package/templates/storefront-nextjs-shadcn/components/product/stock-indicator.tsx +91 -0
  362. package/templates/storefront-nextjs-shadcn/components/providers/currency-provider.tsx +103 -0
  363. package/templates/storefront-nextjs-shadcn/components/providers/index.ts +8 -0
  364. package/templates/storefront-nextjs-shadcn/components/providers/query-provider.tsx +260 -0
  365. package/templates/storefront-nextjs-shadcn/components/providers/theme-provider.tsx +13 -0
  366. package/templates/storefront-nextjs-shadcn/components/returns/index.ts +26 -0
  367. package/templates/storefront-nextjs-shadcn/components/returns/return-request-form.tsx +608 -0
  368. package/templates/storefront-nextjs-shadcn/components/returns/return-status-card.tsx +554 -0
  369. package/templates/storefront-nextjs-shadcn/components/search/index.ts +8 -0
  370. package/templates/storefront-nextjs-shadcn/components/search/search-bar.tsx +140 -0
  371. package/templates/storefront-nextjs-shadcn/components/search/search-results.tsx +58 -0
  372. package/templates/storefront-nextjs-shadcn/components/search/search-suggestions.tsx +43 -0
  373. package/templates/storefront-nextjs-shadcn/components/seo/index.ts +12 -0
  374. package/templates/storefront-nextjs-shadcn/components/seo/json-ld.tsx +56 -0
  375. package/templates/storefront-nextjs-shadcn/components/seo/product-json-ld.ts +167 -0
  376. package/templates/storefront-nextjs-shadcn/components/shipping/index.ts +16 -0
  377. package/templates/storefront-nextjs-shadcn/components/shipping/shipping-method-selector.tsx +337 -0
  378. package/templates/storefront-nextjs-shadcn/components/ui/accordion.tsx +153 -0
  379. package/templates/storefront-nextjs-shadcn/components/ui/alert.tsx +59 -0
  380. package/templates/storefront-nextjs-shadcn/components/ui/badge.tsx +34 -0
  381. package/templates/storefront-nextjs-shadcn/components/ui/button.tsx +51 -0
  382. package/templates/storefront-nextjs-shadcn/components/ui/card.tsx +77 -0
  383. package/templates/storefront-nextjs-shadcn/components/ui/checkbox.tsx +30 -0
  384. package/templates/storefront-nextjs-shadcn/components/ui/dialog.tsx +137 -0
  385. package/templates/storefront-nextjs-shadcn/components/ui/empty-state.tsx +207 -0
  386. package/templates/storefront-nextjs-shadcn/components/ui/index.ts +67 -0
  387. package/templates/storefront-nextjs-shadcn/components/ui/input.tsx +65 -0
  388. package/templates/storefront-nextjs-shadcn/components/ui/label.tsx +26 -0
  389. package/templates/storefront-nextjs-shadcn/components/ui/pagination.tsx +205 -0
  390. package/templates/storefront-nextjs-shadcn/components/ui/radio-group.tsx +44 -0
  391. package/templates/storefront-nextjs-shadcn/components/ui/select.tsx +160 -0
  392. package/templates/storefront-nextjs-shadcn/components/ui/separator.tsx +28 -0
  393. package/templates/storefront-nextjs-shadcn/components/ui/skeleton.tsx +20 -0
  394. package/templates/storefront-nextjs-shadcn/components/ui/spinner.tsx +82 -0
  395. package/templates/storefront-nextjs-shadcn/components/ui/tabs.tsx +119 -0
  396. package/templates/storefront-nextjs-shadcn/components/ui/toast.tsx +96 -0
  397. package/templates/storefront-nextjs-shadcn/components/wishlist/index.ts +9 -0
  398. package/templates/storefront-nextjs-shadcn/components/wishlist/wishlist-button.tsx +148 -0
  399. package/templates/storefront-nextjs-shadcn/components/wishlist/wishlist-icon.tsx +47 -0
  400. package/templates/storefront-nextjs-shadcn/components/wishlist/wishlist-item.tsx +165 -0
  401. package/templates/storefront-nextjs-shadcn/components.json +19 -0
  402. package/templates/storefront-nextjs-shadcn/generated/.gitkeep +2 -0
  403. package/templates/storefront-nextjs-shadcn/graphql/.gitkeep +31 -0
  404. package/templates/storefront-nextjs-shadcn/graphql/collections.example.ts +168 -0
  405. package/templates/storefront-nextjs-shadcn/graphql/products.example.ts +160 -0
  406. package/templates/storefront-nextjs-shadcn/hooks/index.ts +9 -0
  407. package/templates/storefront-nextjs-shadcn/hooks/use-auth.ts +310 -0
  408. package/templates/storefront-nextjs-shadcn/hooks/use-cart-actions.ts +286 -0
  409. package/templates/storefront-nextjs-shadcn/hooks/use-cart-sync.ts +110 -0
  410. package/templates/storefront-nextjs-shadcn/hooks/use-filter-params.test.ts +173 -0
  411. package/templates/storefront-nextjs-shadcn/hooks/use-filter-params.ts +298 -0
  412. package/templates/storefront-nextjs-shadcn/lib/auth/cookies.ts +220 -0
  413. package/templates/storefront-nextjs-shadcn/lib/auth/routes.ts +57 -0
  414. package/templates/storefront-nextjs-shadcn/lib/config.ts +46 -0
  415. package/templates/storefront-nextjs-shadcn/lib/currency/IMPLEMENTATION_SUMMARY.md +254 -0
  416. package/templates/storefront-nextjs-shadcn/lib/currency/README.md +464 -0
  417. package/templates/storefront-nextjs-shadcn/lib/currency/cookie-manager.test.ts +328 -0
  418. package/templates/storefront-nextjs-shadcn/lib/currency/cookie-manager.ts +295 -0
  419. package/templates/storefront-nextjs-shadcn/lib/currency/index.ts +27 -0
  420. package/templates/storefront-nextjs-shadcn/lib/format.test.ts +397 -0
  421. package/templates/storefront-nextjs-shadcn/lib/format.ts +226 -0
  422. package/templates/storefront-nextjs-shadcn/lib/graphql/client.ts +109 -0
  423. package/templates/storefront-nextjs-shadcn/lib/graphql/hooks.ts +1183 -0
  424. package/templates/storefront-nextjs-shadcn/lib/graphql/server.ts +267 -0
  425. package/templates/storefront-nextjs-shadcn/lib/hooks.ts +30 -0
  426. package/templates/storefront-nextjs-shadcn/lib/theme/theme-config.ts +89 -0
  427. package/templates/storefront-nextjs-shadcn/lib/utils.ts +6 -0
  428. package/templates/storefront-nextjs-shadcn/next.config.ts +47 -0
  429. package/templates/storefront-nextjs-shadcn/open-next.config.ts +3 -0
  430. package/templates/storefront-nextjs-shadcn/package.dev.json +30 -0
  431. package/templates/storefront-nextjs-shadcn/package.json +60 -0
  432. package/templates/storefront-nextjs-shadcn/package.json.template +46 -0
  433. package/templates/storefront-nextjs-shadcn/postcss.config.mjs +8 -0
  434. package/templates/storefront-nextjs-shadcn/proxy.ts +80 -0
  435. package/templates/storefront-nextjs-shadcn/public/icons/payment/apple-pay.svg +8 -0
  436. package/templates/storefront-nextjs-shadcn/public/icons/payment/bank-transfer.svg +10 -0
  437. package/templates/storefront-nextjs-shadcn/public/icons/payment/blik.svg +6 -0
  438. package/templates/storefront-nextjs-shadcn/public/icons/payment/cash-on-delivery.svg +11 -0
  439. package/templates/storefront-nextjs-shadcn/public/icons/payment/google-pay.svg +11 -0
  440. package/templates/storefront-nextjs-shadcn/public/icons/payment/mastercard.svg +7 -0
  441. package/templates/storefront-nextjs-shadcn/public/icons/payment/paypal.svg +7 -0
  442. package/templates/storefront-nextjs-shadcn/public/icons/payment/payu.svg +7 -0
  443. package/templates/storefront-nextjs-shadcn/public/icons/payment/przelewy24.svg +7 -0
  444. package/templates/storefront-nextjs-shadcn/public/icons/payment/stripe.svg +4 -0
  445. package/templates/storefront-nextjs-shadcn/public/icons/payment/visa.svg +5 -0
  446. package/templates/storefront-nextjs-shadcn/stores/auth-store.ts +66 -0
  447. package/templates/storefront-nextjs-shadcn/stores/cart-store.ts +56 -0
  448. package/templates/storefront-nextjs-shadcn/stores/checkout-store.ts +184 -0
  449. package/templates/storefront-nextjs-shadcn/stores/currency-store.ts +103 -0
  450. package/templates/storefront-nextjs-shadcn/stores/wishlist-store.ts +291 -0
  451. package/templates/storefront-nextjs-shadcn/tailwind.config.ts +111 -0
  452. package/templates/storefront-nextjs-shadcn/tsconfig.json +27 -0
  453. package/templates/storefront-nextjs-shadcn/wrangler.toml +9 -0
@@ -0,0 +1,1183 @@
1
+ 'use client';
2
+
3
+ import { useQuery, useMutation, useQueryClient, type UseQueryOptions, type UseMutationOptions } from '@tanstack/react-query';
4
+ import { getGraphQLClient } from './client';
5
+ import { useCurrencyStore } from '@/stores/currency-store';
6
+ import type { TypedDocumentNode } from '@graphql-typed-document-node/core';
7
+
8
+ // ============================================================================
9
+ // TYPES
10
+ // ============================================================================
11
+
12
+ /**
13
+ * Normalized response for paginated queries
14
+ * Converts GraphQL edges/nodes structure to flat arrays
15
+ */
16
+ export interface NormalizedConnection<T> {
17
+ items: T[];
18
+ pageInfo: {
19
+ hasNextPage: boolean;
20
+ hasPreviousPage: boolean;
21
+ startCursor?: string | null;
22
+ endCursor?: string | null;
23
+ };
24
+ totalCount?: number;
25
+ }
26
+
27
+ /**
28
+ * GraphQL connection edge structure
29
+ */
30
+ interface Edge<T> {
31
+ node: T;
32
+ cursor: string;
33
+ }
34
+
35
+ /**
36
+ * GraphQL connection structure
37
+ */
38
+ interface Connection<T> {
39
+ edges: Edge<T>[];
40
+ pageInfo: {
41
+ hasNextPage: boolean;
42
+ hasPreviousPage: boolean;
43
+ startCursor?: string | null;
44
+ endCursor?: string | null;
45
+ };
46
+ totalCount?: number;
47
+ }
48
+
49
+ // ============================================================================
50
+ // UTILITY FUNCTIONS
51
+ // ============================================================================
52
+
53
+ /**
54
+ * Normalize GraphQL connection to flat array
55
+ *
56
+ * Converts edges/nodes structure to a simple array of items
57
+ * for easier consumption in components.
58
+ *
59
+ * @param connection - GraphQL connection object
60
+ * @returns Normalized response with flat items array
61
+ *
62
+ * @example
63
+ * ```typescript
64
+ * const data = { products: { edges: [...], pageInfo: {...} } };
65
+ * const normalized = normalizeConnection(data.products);
66
+ * // normalized.items is now a flat array
67
+ * ```
68
+ */
69
+ export function normalizeConnection<T>(
70
+ connection: Connection<T>
71
+ ): NormalizedConnection<T> {
72
+ return {
73
+ items: connection.edges.map((edge) => edge.node),
74
+ pageInfo: connection.pageInfo,
75
+ totalCount: connection.totalCount,
76
+ };
77
+ }
78
+
79
+ // ============================================================================
80
+ // GENERIC QUERY HOOK
81
+ // ============================================================================
82
+
83
+ /**
84
+ * Generic query hook with currency-aware caching
85
+ *
86
+ * Wraps React Query's useQuery with automatic currency injection
87
+ * into query keys for proper cache invalidation when currency changes.
88
+ *
89
+ * @param document - TypedDocumentNode from codegen
90
+ * @param variables - Query variables
91
+ * @param options - React Query options
92
+ * @returns React Query result
93
+ *
94
+ * @example
95
+ * ```typescript
96
+ * const { data } = useGraphQLQuery(ProductDocument, { handle: 'my-product' });
97
+ * ```
98
+ */
99
+ export function useGraphQLQuery<TResult, TVariables>(
100
+ document: TypedDocumentNode<TResult, TVariables>,
101
+ variables?: TVariables,
102
+ options?: Omit<UseQueryOptions<TResult>, 'queryKey' | 'queryFn'>
103
+ ) {
104
+ const client = getGraphQLClient();
105
+ const currency = useCurrencyStore((s: any) => s.currency);
106
+
107
+ // Generate query key from document name and variables
108
+ // Include currency to invalidate cache when currency changes
109
+ const queryKey = [
110
+ // Extract operation name from document
111
+ (document as any).definitions?.[0]?.name?.value || 'GraphQLQuery',
112
+ variables,
113
+ currency,
114
+ ];
115
+
116
+ return useQuery({
117
+ queryKey,
118
+ queryFn: () => client.request(document, variables as any),
119
+ ...options,
120
+ });
121
+ }
122
+
123
+ /**
124
+ * Generic mutation hook
125
+ *
126
+ * Wraps React Query's useMutation for GraphQL mutations.
127
+ *
128
+ * @param document - TypedDocumentNode from codegen
129
+ * @param options - React Query mutation options
130
+ * @returns React Query mutation result
131
+ *
132
+ * @example
133
+ * ```typescript
134
+ * const mutation = useGraphQLMutation(CartCreateDocument);
135
+ * await mutation.mutateAsync({ input: {...} });
136
+ * ```
137
+ */
138
+ export function useGraphQLMutation<TResult, TVariables>(
139
+ document: TypedDocumentNode<TResult, TVariables>,
140
+ options?: UseMutationOptions<TResult, Error, TVariables>
141
+ ) {
142
+ const client = getGraphQLClient();
143
+
144
+ return useMutation({
145
+ mutationFn: (variables: TVariables) => client.request(document, variables as any),
146
+ ...options,
147
+ });
148
+ }
149
+
150
+ // ============================================================================
151
+ // PRODUCT HOOKS
152
+ // ============================================================================
153
+
154
+ /**
155
+ * Fetch single product by handle or ID
156
+ *
157
+ * Automatically includes current currency in request headers
158
+ * and query key for proper cache invalidation.
159
+ *
160
+ * @param handleOrId - Product handle (string) or ID (gid://)
161
+ * @param options - React Query options
162
+ * @returns Product query result
163
+ *
164
+ * @example
165
+ * ```typescript
166
+ * // In a Client Component
167
+ * 'use client';
168
+ *
169
+ * export function ProductPrice({ handle }) {
170
+ * const { data, isLoading } = useProduct(handle);
171
+ *
172
+ * if (isLoading) return <div>Loading...</div>;
173
+ *
174
+ * return (
175
+ * <div suppressHydrationWarning>
176
+ * {data.product.priceRange.minVariantPrice.amount}{' '}
177
+ * {data.product.priceRange.minVariantPrice.currencyCode}
178
+ * </div>
179
+ * );
180
+ * }
181
+ * ```
182
+ */
183
+ export function useProduct(
184
+ handleOrId: string,
185
+ options?: Omit<UseQueryOptions<any>, 'queryKey' | 'queryFn'>
186
+ ) {
187
+ const client = getGraphQLClient();
188
+ const currency = useCurrencyStore((s: any) => s.currency);
189
+
190
+ // Determine if it's an ID or handle
191
+ const isId = handleOrId.startsWith('gid://');
192
+
193
+ return useQuery({
194
+ queryKey: ['Product', handleOrId, currency],
195
+ queryFn: async () => {
196
+ // Dynamic import to avoid circular dependencies
197
+ const { ProductDocument } = await import('@/generated/graphql');
198
+
199
+ const variables = isId ? { id: handleOrId } : { handle: handleOrId };
200
+ return client.request(ProductDocument, variables as any);
201
+ },
202
+ ...options,
203
+ });
204
+ }
205
+
206
+ /**
207
+ * Fetch products with pagination and normalization
208
+ *
209
+ * Automatically normalizes GraphQL edges/nodes structure to flat arrays.
210
+ * Includes currency in query key for cache invalidation.
211
+ *
212
+ * @param variables - Query variables (first, after, query, sortKey, reverse)
213
+ * @param options - React Query options
214
+ * @returns Normalized products response
215
+ *
216
+ * @example
217
+ * ```typescript
218
+ * // In a Client Component
219
+ * 'use client';
220
+ *
221
+ * export function ProductList() {
222
+ * const { data, isLoading } = useProducts({ first: 20 });
223
+ *
224
+ * if (isLoading) return <div>Loading...</div>;
225
+ *
226
+ * return (
227
+ * <div>
228
+ * {data.products.map(product => (
229
+ * <ProductCard key={product.id} product={product} />
230
+ * ))}
231
+ * </div>
232
+ * );
233
+ * }
234
+ * ```
235
+ */
236
+ /**
237
+ * Map frontend sort values to GraphQL enum values
238
+ */
239
+ function normalizeSortKey(sortKey?: string): { sortKey?: string; reverse?: boolean } {
240
+ if (!sortKey) return { sortKey: 'BEST_SELLING', reverse: false };
241
+
242
+ const sortMap: Record<string, { sortKey: string; reverse: boolean }> = {
243
+ 'relevance': { sortKey: 'RELEVANCE', reverse: false },
244
+ 'best-selling': { sortKey: 'BEST_SELLING', reverse: false },
245
+ 'price-low-to-high': { sortKey: 'PRICE', reverse: false },
246
+ 'price-high-to-low': { sortKey: 'PRICE', reverse: true },
247
+ 'title-asc': { sortKey: 'TITLE', reverse: false },
248
+ 'title-desc': { sortKey: 'TITLE', reverse: true },
249
+ 'created-desc': { sortKey: 'CREATED', reverse: true },
250
+ 'created-asc': { sortKey: 'CREATED', reverse: false },
251
+ };
252
+
253
+ return sortMap[sortKey] || { sortKey: 'BEST_SELLING', reverse: false };
254
+ }
255
+
256
+ export function useProducts(
257
+ variables?: {
258
+ first?: number;
259
+ after?: string;
260
+ query?: string;
261
+ sortKey?: string;
262
+ reverse?: boolean;
263
+ },
264
+ options?: Omit<UseQueryOptions<any>, 'queryKey' | 'queryFn'>
265
+ ) {
266
+ const client = getGraphQLClient();
267
+ const currency = useCurrencyStore((s: any) => s.currency);
268
+
269
+ return useQuery({
270
+ queryKey: ['Products', variables, currency],
271
+ queryFn: async () => {
272
+ // Dynamic import to avoid circular dependencies
273
+ const { ProductsDocument } = await import('@/generated/graphql');
274
+
275
+ // Normalize sort key to GraphQL enum format
276
+ const { sortKey: normalizedSortKey, reverse: normalizedReverse } = normalizeSortKey(variables?.sortKey);
277
+
278
+ const data = await client.request(ProductsDocument, {
279
+ first: variables?.first ?? 20,
280
+ after: variables?.after,
281
+ query: variables?.query,
282
+ sortKey: normalizedSortKey as any,
283
+ reverse: variables?.reverse !== undefined ? variables.reverse : normalizedReverse,
284
+ });
285
+
286
+ // Normalize: edges/nodes → flat array
287
+ return {
288
+ products: data.products.edges.map((edge: any) => edge.node),
289
+ pageInfo: data.products.pageInfo,
290
+ totalCount: data.products.totalCount,
291
+ };
292
+ },
293
+ ...options,
294
+ });
295
+ }
296
+
297
+ // ============================================================================
298
+ // COLLECTION HOOKS
299
+ // ============================================================================
300
+
301
+ /**
302
+ * Fetch single collection by handle or ID
303
+ *
304
+ * @param handleOrId - Collection handle or ID
305
+ * @param options - React Query options
306
+ * @returns Collection query result
307
+ *
308
+ * @example
309
+ * ```typescript
310
+ * const { data } = useCollection('featured-products');
311
+ * ```
312
+ */
313
+ export function useCollection(
314
+ handleOrId: string,
315
+ options?: Omit<UseQueryOptions<any>, 'queryKey' | 'queryFn'>
316
+ ) {
317
+ const client = getGraphQLClient();
318
+ const currency = useCurrencyStore((s: any) => s.currency);
319
+
320
+ const isId = handleOrId.startsWith('gid://');
321
+
322
+ return useQuery({
323
+ queryKey: ['Collection', handleOrId, currency],
324
+ queryFn: async () => {
325
+ const { CollectionDocument } = await import('@/generated/graphql');
326
+
327
+ // Type-safe conditional variables
328
+ const variables = isId
329
+ ? { id: handleOrId } as { id: string }
330
+ : { handle: handleOrId } as { handle: string };
331
+
332
+ return client.request(CollectionDocument, variables as any);
333
+ },
334
+ ...options,
335
+ });
336
+ }
337
+
338
+ /**
339
+ * Fetch collections with pagination and normalization
340
+ *
341
+ * @param variables - Query variables
342
+ * @param options - React Query options
343
+ * @returns Normalized collections response
344
+ *
345
+ * @example
346
+ * ```typescript
347
+ * const { data } = useCollections({ first: 10 });
348
+ * ```
349
+ */
350
+ export function useCollections(
351
+ variables?: {
352
+ first?: number;
353
+ after?: string;
354
+ query?: string;
355
+ sortKey?: string;
356
+ reverse?: boolean;
357
+ },
358
+ options?: Omit<UseQueryOptions<any>, 'queryKey' | 'queryFn'>
359
+ ) {
360
+ const client = getGraphQLClient();
361
+ const currency = useCurrencyStore((s: any) => s.currency);
362
+
363
+ return useQuery({
364
+ queryKey: ['Collections', variables, currency],
365
+ queryFn: async () => {
366
+ const { CollectionsDocument } = await import('@/generated/graphql');
367
+
368
+ const data = await client.request(CollectionsDocument, {
369
+ first: variables?.first ?? 20,
370
+ after: variables?.after,
371
+ query: variables?.query,
372
+ sortKey: variables?.sortKey as any,
373
+ reverse: variables?.reverse,
374
+ });
375
+
376
+ // Normalize: edges/nodes → flat array
377
+ return {
378
+ collections: data.collections.edges.map((edge: any) => edge.node),
379
+ pageInfo: data.collections.pageInfo,
380
+ totalCount: data.collections.totalCount,
381
+ };
382
+ },
383
+ ...options,
384
+ });
385
+ }
386
+
387
+ // ============================================================================
388
+ // CATEGORY HOOKS
389
+ // ============================================================================
390
+
391
+ /**
392
+ * Fetch categories with hierarchical structure
393
+ *
394
+ * Categories are hierarchical (tree structure) and used for catalog organization.
395
+ * Use for filters, navigation, and SEO.
396
+ *
397
+ * Returns flat array of all categories (roots + children) for easy filtering.
398
+ *
399
+ * @param options - React Query options
400
+ * @returns Categories response with flat array
401
+ *
402
+ * @example
403
+ * ```typescript
404
+ * const { data } = useCategories();
405
+ * const categories = data?.categories ?? [];
406
+ * ```
407
+ */
408
+ export function useCategories(
409
+ options?: Omit<UseQueryOptions<any>, 'queryKey' | 'queryFn'>
410
+ ) {
411
+ const client = getGraphQLClient();
412
+ const currency = useCurrencyStore((s: any) => s.currency);
413
+
414
+ return useQuery({
415
+ queryKey: ['Categories', currency],
416
+ queryFn: async () => {
417
+ const { CategoriesDocument } = await import('@/generated/graphql');
418
+
419
+ const data = await client.request(CategoriesDocument);
420
+
421
+ // Flatten hierarchical structure to array for filters
422
+ const flattenCategories = (cats: any[]): any[] => {
423
+ return cats.flatMap((cat: any) => [
424
+ cat,
425
+ ...(cat.children ? flattenCategories(cat.children) : [])
426
+ ]);
427
+ };
428
+
429
+ const allCategories = flattenCategories(data.categories.roots || []);
430
+
431
+ return {
432
+ categories: allCategories,
433
+ roots: data.categories.roots,
434
+ totalCount: data.categories.totalCount,
435
+ };
436
+ },
437
+ ...options,
438
+ });
439
+ }
440
+
441
+ // ============================================================================
442
+ // CART HOOKS
443
+ // ============================================================================
444
+
445
+ /**
446
+ * Fetch cart by ID
447
+ *
448
+ * Includes currency in query key to refetch when currency changes.
449
+ * Cart prices are locked for 24 hours, but currency header is still
450
+ * included for consistency.
451
+ *
452
+ * @param cartId - Cart ID
453
+ * @param options - React Query options
454
+ * @returns Cart query result
455
+ *
456
+ * @example
457
+ * ```typescript
458
+ * const { data } = useCart(cartId);
459
+ * ```
460
+ */
461
+ export function useCart(
462
+ cartId: string | null,
463
+ options?: Omit<UseQueryOptions<any>, 'queryKey' | 'queryFn'>
464
+ ) {
465
+ const client = getGraphQLClient();
466
+ const currency = useCurrencyStore((s: any) => s.currency);
467
+
468
+ return useQuery({
469
+ queryKey: ['Cart', cartId, currency],
470
+ queryFn: async () => {
471
+ if (!cartId) return null;
472
+
473
+ const { CartDocument } = await import('@/generated/graphql');
474
+
475
+ return client.request(CartDocument, { id: cartId });
476
+ },
477
+ enabled: Boolean(cartId),
478
+ ...options,
479
+ });
480
+ }
481
+
482
+ /**
483
+ * Create a new cart
484
+ *
485
+ * @param options - React Query mutation options
486
+ * @returns Cart create mutation
487
+ *
488
+ * @example
489
+ * ```typescript
490
+ * const createCart = useCartCreate();
491
+ *
492
+ * const handleCreate = async () => {
493
+ * const { cartCreate } = await createCart.mutateAsync({
494
+ * input: { lines: [...] }
495
+ * });
496
+ *
497
+ * if (cartCreate.cart) {
498
+ * // Store cart ID
499
+ * localStorage.setItem('cartId', cartCreate.cart.id);
500
+ * }
501
+ * };
502
+ * ```
503
+ */
504
+ export function useCartCreate(
505
+ options?: UseMutationOptions<any, Error, any>
506
+ ) {
507
+ const client = getGraphQLClient();
508
+ const queryClient = useQueryClient();
509
+
510
+ return useMutation({
511
+ mutationFn: async (variables: any) => {
512
+ const { CartCreateDocument } = await import('@/generated/graphql');
513
+ return client.request(CartCreateDocument, variables);
514
+ },
515
+ onSuccess: () => {
516
+ // Invalidate cart queries
517
+ queryClient.invalidateQueries({ queryKey: ['Cart'] });
518
+ },
519
+ ...options,
520
+ });
521
+ }
522
+
523
+ /**
524
+ * Add lines to cart
525
+ *
526
+ * @param options - React Query mutation options
527
+ * @returns Cart lines add mutation
528
+ *
529
+ * @example
530
+ * ```typescript
531
+ * const addLines = useCartLinesAdd();
532
+ *
533
+ * const handleAddToCart = async () => {
534
+ * await addLines.mutateAsync({
535
+ * cartId: 'cart-123',
536
+ * lines: [{ merchandiseId: 'variant-456', quantity: 1 }]
537
+ * });
538
+ * };
539
+ * ```
540
+ */
541
+ export function useCartLinesAdd(
542
+ options?: UseMutationOptions<any, Error, any>
543
+ ) {
544
+ const client = getGraphQLClient();
545
+ const queryClient = useQueryClient();
546
+
547
+ return useMutation({
548
+ mutationFn: async (variables: any) => {
549
+ const { CartLinesAddDocument } = await import('@/generated/graphql');
550
+ return client.request(CartLinesAddDocument, variables);
551
+ },
552
+ onSuccess: () => {
553
+ // Invalidate cart queries
554
+ queryClient.invalidateQueries({ queryKey: ['Cart'] });
555
+ },
556
+ ...options,
557
+ });
558
+ }
559
+
560
+ /**
561
+ * Update cart lines
562
+ *
563
+ * @param options - React Query mutation options
564
+ * @returns Cart lines update mutation
565
+ *
566
+ * @example
567
+ * ```typescript
568
+ * const updateLines = useCartLinesUpdate();
569
+ *
570
+ * const handleUpdateQuantity = async (lineId: string, quantity: number) => {
571
+ * await updateLines.mutateAsync({
572
+ * cartId: 'cart-123',
573
+ * lines: [{ id: lineId, quantity }]
574
+ * });
575
+ * };
576
+ * ```
577
+ */
578
+ export function useCartLinesUpdate(
579
+ options?: UseMutationOptions<any, Error, any>
580
+ ) {
581
+ const client = getGraphQLClient();
582
+ const queryClient = useQueryClient();
583
+
584
+ return useMutation({
585
+ mutationFn: async (variables: any) => {
586
+ const { CartLinesUpdateDocument } = await import('@/generated/graphql');
587
+ return client.request(CartLinesUpdateDocument, variables);
588
+ },
589
+ onSuccess: () => {
590
+ // Invalidate cart queries
591
+ queryClient.invalidateQueries({ queryKey: ['Cart'] });
592
+ },
593
+ ...options,
594
+ });
595
+ }
596
+
597
+ /**
598
+ * Remove lines from cart
599
+ *
600
+ * @param options - React Query mutation options
601
+ * @returns Cart lines remove mutation
602
+ *
603
+ * @example
604
+ * ```typescript
605
+ * const removeLines = useCartLinesRemove();
606
+ *
607
+ * const handleRemove = async (lineId: string) => {
608
+ * await removeLines.mutateAsync({
609
+ * cartId: 'cart-123',
610
+ * lineIds: [lineId]
611
+ * });
612
+ * };
613
+ * ```
614
+ */
615
+ export function useCartLinesRemove(
616
+ options?: UseMutationOptions<any, Error, any>
617
+ ) {
618
+ const client = getGraphQLClient();
619
+ const queryClient = useQueryClient();
620
+
621
+ return useMutation({
622
+ mutationFn: async (variables: any) => {
623
+ const { CartLinesRemoveDocument } = await import('@/generated/graphql');
624
+ return client.request(CartLinesRemoveDocument, variables);
625
+ },
626
+ onSuccess: () => {
627
+ // Invalidate cart queries
628
+ queryClient.invalidateQueries({ queryKey: ['Cart'] });
629
+ },
630
+ ...options,
631
+ });
632
+ }
633
+
634
+ /**
635
+ * Update discount codes on cart
636
+ *
637
+ * Invalidates cart query on success so all consumers (useCartSync)
638
+ * automatically receive updated discount data.
639
+ *
640
+ * @param options - React Query mutation options
641
+ * @returns Cart discount codes update mutation
642
+ */
643
+ export function useCartDiscountCodesUpdate(
644
+ options?: UseMutationOptions<any, Error, any>
645
+ ) {
646
+ const client = getGraphQLClient();
647
+ const queryClient = useQueryClient();
648
+
649
+ return useMutation({
650
+ mutationFn: async (variables: any) => {
651
+ const { CartDiscountCodesUpdateDocument } = await import('@/generated/graphql');
652
+ return client.request(CartDiscountCodesUpdateDocument, variables);
653
+ },
654
+ onSuccess: () => {
655
+ queryClient.invalidateQueries({ queryKey: ['Cart'] });
656
+ },
657
+ ...options,
658
+ });
659
+ }
660
+
661
+ // ============================================================================
662
+ // CHECKOUT HOOKS
663
+ // ============================================================================
664
+
665
+ /**
666
+ * Fetch checkout by ID
667
+ *
668
+ * @param checkoutId - Checkout ID
669
+ * @param options - React Query options
670
+ * @returns Checkout query result
671
+ */
672
+ export function useCheckout(
673
+ checkoutId: string | null,
674
+ options?: Omit<UseQueryOptions<any>, 'queryKey' | 'queryFn'>
675
+ ) {
676
+ const client = getGraphQLClient();
677
+ const currency = useCurrencyStore((s: any) => s.currency);
678
+
679
+ return useQuery({
680
+ queryKey: ['Checkout', checkoutId, currency],
681
+ queryFn: async () => {
682
+ if (!checkoutId) return null;
683
+
684
+ const { CheckoutDocument } = await import('@/generated/graphql');
685
+ return client.request(CheckoutDocument, { id: checkoutId });
686
+ },
687
+ enabled: Boolean(checkoutId),
688
+ ...options,
689
+ });
690
+ }
691
+
692
+ /**
693
+ * Create checkout from cart
694
+ *
695
+ * @param options - React Query mutation options
696
+ * @returns Checkout create mutation
697
+ */
698
+ export function useCheckoutCreate(
699
+ options?: UseMutationOptions<any, Error, any>
700
+ ) {
701
+ const client = getGraphQLClient();
702
+ const queryClient = useQueryClient();
703
+
704
+ return useMutation({
705
+ mutationFn: async (variables: any) => {
706
+ const { CheckoutCreateDocument } = await import('@/generated/graphql');
707
+ return client.request(CheckoutCreateDocument, variables);
708
+ },
709
+ onSuccess: () => {
710
+ queryClient.invalidateQueries({ queryKey: ['Checkout'] });
711
+ },
712
+ ...options,
713
+ });
714
+ }
715
+
716
+ /**
717
+ * Update checkout shipping address
718
+ *
719
+ * @param options - React Query mutation options
720
+ * @returns Checkout shipping address update mutation
721
+ */
722
+ export function useCheckoutShippingAddressUpdate(
723
+ options?: UseMutationOptions<any, Error, any>
724
+ ) {
725
+ const client = getGraphQLClient();
726
+ const queryClient = useQueryClient();
727
+
728
+ return useMutation({
729
+ mutationFn: async (variables: any) => {
730
+ const { CheckoutShippingAddressUpdateDocument } = await import('@/generated/graphql');
731
+ return client.request(CheckoutShippingAddressUpdateDocument, variables);
732
+ },
733
+ onSuccess: () => {
734
+ queryClient.invalidateQueries({ queryKey: ['Checkout'] });
735
+ },
736
+ ...options,
737
+ });
738
+ }
739
+
740
+ /**
741
+ * Update checkout billing address
742
+ *
743
+ * @param options - React Query mutation options
744
+ * @returns Checkout billing address update mutation
745
+ */
746
+ export function useCheckoutBillingAddressUpdate(
747
+ options?: UseMutationOptions<any, Error, any>
748
+ ) {
749
+ const client = getGraphQLClient();
750
+ const queryClient = useQueryClient();
751
+
752
+ return useMutation({
753
+ mutationFn: async (variables: any) => {
754
+ const { CheckoutBillingAddressUpdateDocument } = await import('@/generated/graphql');
755
+ return client.request(CheckoutBillingAddressUpdateDocument, variables);
756
+ },
757
+ onSuccess: () => {
758
+ queryClient.invalidateQueries({ queryKey: ['Checkout'] });
759
+ },
760
+ ...options,
761
+ });
762
+ }
763
+
764
+ /**
765
+ * Update checkout email
766
+ *
767
+ * @param options - React Query mutation options
768
+ * @returns Checkout email update mutation
769
+ */
770
+ export function useCheckoutEmailUpdate(
771
+ options?: UseMutationOptions<any, Error, any>
772
+ ) {
773
+ const client = getGraphQLClient();
774
+ const queryClient = useQueryClient();
775
+
776
+ return useMutation({
777
+ mutationFn: async (variables: any) => {
778
+ const { CheckoutEmailUpdateDocument } = await import('@/generated/graphql');
779
+ return client.request(CheckoutEmailUpdateDocument, variables);
780
+ },
781
+ onSuccess: () => {
782
+ queryClient.invalidateQueries({ queryKey: ['Checkout'] });
783
+ },
784
+ ...options,
785
+ });
786
+ }
787
+
788
+ /**
789
+ * Update checkout shipping line (select shipping method)
790
+ *
791
+ * @param options - React Query mutation options
792
+ * @returns Checkout shipping line update mutation
793
+ */
794
+ export function useCheckoutShippingLineUpdate(
795
+ options?: UseMutationOptions<any, Error, any>
796
+ ) {
797
+ const client = getGraphQLClient();
798
+ const queryClient = useQueryClient();
799
+
800
+ return useMutation({
801
+ mutationFn: async (variables: any) => {
802
+ const { CheckoutShippingLineUpdateDocument } = await import('@/generated/graphql');
803
+ return client.request(CheckoutShippingLineUpdateDocument, variables);
804
+ },
805
+ onSuccess: () => {
806
+ queryClient.invalidateQueries({ queryKey: ['Checkout'] });
807
+ },
808
+ ...options,
809
+ });
810
+ }
811
+
812
+ /**
813
+ * Apply discount code to checkout
814
+ *
815
+ * @param options - React Query mutation options
816
+ * @returns Checkout discount code apply mutation
817
+ */
818
+ export function useCheckoutDiscountCodeApply(
819
+ options?: UseMutationOptions<any, Error, any>
820
+ ) {
821
+ const client = getGraphQLClient();
822
+ const queryClient = useQueryClient();
823
+
824
+ return useMutation({
825
+ mutationFn: async (variables: any) => {
826
+ const { CheckoutDiscountCodeApplyDocument } = await import('@/generated/graphql');
827
+ return client.request(CheckoutDiscountCodeApplyDocument, variables);
828
+ },
829
+ onSuccess: () => {
830
+ queryClient.invalidateQueries({ queryKey: ['Checkout'] });
831
+ },
832
+ ...options,
833
+ });
834
+ }
835
+
836
+ /**
837
+ * Remove discount code from checkout
838
+ *
839
+ * @param options - React Query mutation options
840
+ * @returns Checkout discount code remove mutation
841
+ */
842
+ export function useCheckoutDiscountCodeRemove(
843
+ options?: UseMutationOptions<any, Error, any>
844
+ ) {
845
+ const client = getGraphQLClient();
846
+ const queryClient = useQueryClient();
847
+
848
+ return useMutation({
849
+ mutationFn: async (variables: any) => {
850
+ const { CheckoutDiscountCodeRemoveDocument } = await import('@/generated/graphql');
851
+ return client.request(CheckoutDiscountCodeRemoveDocument, variables);
852
+ },
853
+ onSuccess: () => {
854
+ queryClient.invalidateQueries({ queryKey: ['Checkout'] });
855
+ },
856
+ ...options,
857
+ });
858
+ }
859
+
860
+ /**
861
+ * Complete checkout (finalize order)
862
+ *
863
+ * @param options - React Query mutation options
864
+ * @returns Checkout complete mutation
865
+ */
866
+ export function useCheckoutComplete(
867
+ options?: UseMutationOptions<any, Error, any>
868
+ ) {
869
+ const client = getGraphQLClient();
870
+ const queryClient = useQueryClient();
871
+
872
+ return useMutation({
873
+ mutationFn: async (variables: any) => {
874
+ const { CheckoutCompleteDocument } = await import('@/generated/graphql');
875
+ return client.request(CheckoutCompleteDocument, variables);
876
+ },
877
+ onSuccess: () => {
878
+ queryClient.invalidateQueries({ queryKey: ['Checkout'] });
879
+ queryClient.invalidateQueries({ queryKey: ['Cart'] });
880
+ },
881
+ ...options,
882
+ });
883
+ }
884
+
885
+ /**
886
+ * Apply gift card code to checkout
887
+ *
888
+ * @param options - React Query mutation options
889
+ * @returns Checkout gift card apply mutation
890
+ */
891
+ export function useCheckoutGiftCardApply(
892
+ options?: UseMutationOptions<any, Error, any>
893
+ ) {
894
+ const client = getGraphQLClient();
895
+ const queryClient = useQueryClient();
896
+
897
+ return useMutation({
898
+ mutationFn: async (variables: any) => {
899
+ const { CheckoutGiftCardApplyDocument } = await import('@/generated/graphql');
900
+ return client.request(CheckoutGiftCardApplyDocument, variables);
901
+ },
902
+ onSuccess: () => {
903
+ queryClient.invalidateQueries({ queryKey: ['Checkout'] });
904
+ },
905
+ ...options,
906
+ });
907
+ }
908
+
909
+ /**
910
+ * Remove gift card from checkout
911
+ *
912
+ * @param options - React Query mutation options
913
+ * @returns Checkout gift card remove mutation
914
+ */
915
+ export function useCheckoutGiftCardRemove(
916
+ options?: UseMutationOptions<any, Error, any>
917
+ ) {
918
+ const client = getGraphQLClient();
919
+ const queryClient = useQueryClient();
920
+
921
+ return useMutation({
922
+ mutationFn: async (variables: any) => {
923
+ const { CheckoutGiftCardRemoveDocument } = await import('@/generated/graphql');
924
+ return client.request(CheckoutGiftCardRemoveDocument, variables);
925
+ },
926
+ onSuccess: () => {
927
+ queryClient.invalidateQueries({ queryKey: ['Checkout'] });
928
+ },
929
+ ...options,
930
+ });
931
+ }
932
+
933
+ // ============================================================================
934
+ // CUSTOMER HOOKS
935
+ // ============================================================================
936
+
937
+ /**
938
+ * Customer login mutation
939
+ *
940
+ * @param options - React Query mutation options
941
+ * @returns Customer login mutation
942
+ *
943
+ * @example
944
+ * ```typescript
945
+ * const login = useCustomerLogin();
946
+ *
947
+ * const handleLogin = async (email: string, password: string) => {
948
+ * const { customerAccessTokenCreate } = await login.mutateAsync({
949
+ * input: { email, password }
950
+ * });
951
+ *
952
+ * if (customerAccessTokenCreate.customerAccessToken) {
953
+ * // Store token in httpOnly cookie via API route
954
+ * await fetch('/api/auth/set-token', {
955
+ * method: 'POST',
956
+ * body: JSON.stringify({
957
+ * token: customerAccessTokenCreate.customerAccessToken.accessToken
958
+ * })
959
+ * });
960
+ * }
961
+ * };
962
+ * ```
963
+ */
964
+ export function useCustomerLogin(
965
+ options?: UseMutationOptions<any, Error, any>
966
+ ) {
967
+ const client = getGraphQLClient();
968
+
969
+ return useMutation({
970
+ mutationFn: async (variables: any) => {
971
+ const { CustomerLoginDocument } = await import('@/generated/graphql');
972
+ return client.request(CustomerLoginDocument, variables);
973
+ },
974
+ ...options,
975
+ });
976
+ }
977
+
978
+ /**
979
+ * Customer logout mutation
980
+ *
981
+ * @param options - React Query mutation options
982
+ * @returns Customer logout mutation
983
+ *
984
+ * @example
985
+ * ```typescript
986
+ * const logout = useCustomerLogout();
987
+ *
988
+ * const handleLogout = async () => {
989
+ * await logout.mutateAsync({ customerAccessToken: token });
990
+ *
991
+ * // Clear cookie via API route
992
+ * await fetch('/api/auth/clear-token', { method: 'POST' });
993
+ * };
994
+ * ```
995
+ */
996
+ export function useCustomerLogout(
997
+ options?: UseMutationOptions<any, Error, any>
998
+ ) {
999
+ const client = getGraphQLClient();
1000
+ const queryClient = useQueryClient();
1001
+
1002
+ return useMutation({
1003
+ mutationFn: async (variables: any) => {
1004
+ const { CustomerLogoutDocument } = await import('@/generated/graphql');
1005
+ return client.request(CustomerLogoutDocument, variables);
1006
+ },
1007
+ onSuccess: () => {
1008
+ // Clear all queries on logout
1009
+ queryClient.clear();
1010
+ },
1011
+ ...options,
1012
+ });
1013
+ }
1014
+
1015
+ // ============================================================================
1016
+ // LOYALTY HOOKS
1017
+ // ============================================================================
1018
+
1019
+ /**
1020
+ * Fetch loyalty member data
1021
+ *
1022
+ * @param options - React Query options
1023
+ * @returns Loyalty member query result
1024
+ */
1025
+ export function useLoyaltyMember(
1026
+ options?: Omit<UseQueryOptions<any>, 'queryKey' | 'queryFn'>
1027
+ ) {
1028
+ const client = getGraphQLClient();
1029
+ const currency = useCurrencyStore((s: any) => s.currency);
1030
+
1031
+ return useQuery({
1032
+ queryKey: ['LoyaltyMember', currency],
1033
+ queryFn: async () => {
1034
+ const { LoyaltyMemberDocument } = await import('@/generated/graphql');
1035
+ return client.request(LoyaltyMemberDocument);
1036
+ },
1037
+ ...options,
1038
+ });
1039
+ }
1040
+
1041
+ /**
1042
+ * Fetch loyalty rewards
1043
+ *
1044
+ * @param options - React Query options
1045
+ * @returns Loyalty rewards query result
1046
+ */
1047
+ export function useLoyaltyRewards(
1048
+ options?: Omit<UseQueryOptions<any>, 'queryKey' | 'queryFn'>
1049
+ ) {
1050
+ const client = getGraphQLClient();
1051
+ const currency = useCurrencyStore((s: any) => s.currency);
1052
+
1053
+ return useQuery({
1054
+ queryKey: ['LoyaltyRewards', currency],
1055
+ queryFn: async () => {
1056
+ const { LoyaltyRewardsDocument } = await import('@/generated/graphql');
1057
+ return client.request(LoyaltyRewardsDocument);
1058
+ },
1059
+ ...options,
1060
+ });
1061
+ }
1062
+
1063
+ /**
1064
+ * Fetch loyalty transactions with pagination
1065
+ *
1066
+ * @param variables - Query variables (first, after)
1067
+ * @param options - React Query options
1068
+ * @returns Loyalty transactions query result
1069
+ */
1070
+ export function useLoyaltyTransactions(
1071
+ variables?: { first?: number; after?: string },
1072
+ options?: Omit<UseQueryOptions<any>, 'queryKey' | 'queryFn'>
1073
+ ) {
1074
+ const client = getGraphQLClient();
1075
+ const currency = useCurrencyStore((s: any) => s.currency);
1076
+
1077
+ return useQuery({
1078
+ queryKey: ['LoyaltyTransactions', variables, currency],
1079
+ queryFn: async () => {
1080
+ const { LoyaltyTransactionsDocument } = await import('@/generated/graphql');
1081
+ return client.request(LoyaltyTransactionsDocument, {
1082
+ first: variables?.first ?? 20,
1083
+ after: variables?.after,
1084
+ });
1085
+ },
1086
+ ...options,
1087
+ });
1088
+ }
1089
+
1090
+ /**
1091
+ * Fetch loyalty settings
1092
+ *
1093
+ * @param options - React Query options
1094
+ * @returns Loyalty settings query result
1095
+ */
1096
+ export function useLoyaltySettings(
1097
+ options?: Omit<UseQueryOptions<any>, 'queryKey' | 'queryFn'>
1098
+ ) {
1099
+ const client = getGraphQLClient();
1100
+
1101
+ return useQuery({
1102
+ queryKey: ['LoyaltySettings'],
1103
+ queryFn: async () => {
1104
+ const { LoyaltySettingsDocument } = await import('@/generated/graphql');
1105
+ return client.request(LoyaltySettingsDocument);
1106
+ },
1107
+ ...options,
1108
+ });
1109
+ }
1110
+
1111
+ /**
1112
+ * Fetch referral stats
1113
+ *
1114
+ * @param options - React Query options
1115
+ * @returns Referral stats query result
1116
+ */
1117
+ export function useReferralStats(
1118
+ options?: Omit<UseQueryOptions<any>, 'queryKey' | 'queryFn'>
1119
+ ) {
1120
+ const client = getGraphQLClient();
1121
+
1122
+ return useQuery({
1123
+ queryKey: ['ReferralStats'],
1124
+ queryFn: async () => {
1125
+ const { ReferralStatsDocument } = await import('@/generated/graphql');
1126
+ return client.request(ReferralStatsDocument);
1127
+ },
1128
+ ...options,
1129
+ });
1130
+ }
1131
+
1132
+ /**
1133
+ * Redeem loyalty reward mutation
1134
+ *
1135
+ * @param options - React Query mutation options
1136
+ * @returns Redeem reward mutation
1137
+ */
1138
+ export function useRedeemLoyaltyReward(
1139
+ options?: UseMutationOptions<any, Error, any>
1140
+ ) {
1141
+ const client = getGraphQLClient();
1142
+ const queryClient = useQueryClient();
1143
+
1144
+ return useMutation({
1145
+ mutationFn: async (variables: any) => {
1146
+ const { RedeemLoyaltyRewardDocument } = await import('@/generated/graphql');
1147
+ return client.request(RedeemLoyaltyRewardDocument, variables);
1148
+ },
1149
+ onSuccess: () => {
1150
+ // Invalidate loyalty queries to refresh points and rewards
1151
+ queryClient.invalidateQueries({ queryKey: ['LoyaltyMember'] });
1152
+ queryClient.invalidateQueries({ queryKey: ['LoyaltyRewards'] });
1153
+ queryClient.invalidateQueries({ queryKey: ['LoyaltyTransactions'] });
1154
+ },
1155
+ ...options,
1156
+ });
1157
+ }
1158
+
1159
+ // ============================================================================
1160
+ // CACHE UTILITIES
1161
+ // ============================================================================
1162
+
1163
+ /**
1164
+ * Hook to invalidate all queries when currency changes
1165
+ *
1166
+ * This is automatically handled by including currency in query keys,
1167
+ * but this utility can be used for manual invalidation if needed.
1168
+ *
1169
+ * @example
1170
+ * ```typescript
1171
+ * const invalidateOnCurrencyChange = useInvalidateOnCurrencyChange();
1172
+ *
1173
+ * // Manually trigger invalidation
1174
+ * invalidateOnCurrencyChange();
1175
+ * ```
1176
+ */
1177
+ export function useInvalidateOnCurrencyChange() {
1178
+ const queryClient = useQueryClient();
1179
+
1180
+ return () => {
1181
+ queryClient.invalidateQueries();
1182
+ };
1183
+ }