@classytic/commerce-sdk 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 (133) hide show
  1. package/LICENSE +14 -0
  2. package/README.md +164 -0
  3. package/dist/adjustment-MNH3AT6S.js +5 -0
  4. package/dist/adjustment-MNH3AT6S.js.map +1 -0
  5. package/dist/analytics/index.d.ts +27 -0
  6. package/dist/analytics/index.js +6 -0
  7. package/dist/analytics/index.js.map +1 -0
  8. package/dist/analytics-DMcD-o8w.d.ts +76 -0
  9. package/dist/api-factory-B_h4RKBm.d.ts +280 -0
  10. package/dist/auth/index.d.ts +39 -0
  11. package/dist/auth/index.js +5 -0
  12. package/dist/auth/index.js.map +1 -0
  13. package/dist/catalog/index.d.ts +571 -0
  14. package/dist/catalog/index.js +9 -0
  15. package/dist/catalog/index.js.map +1 -0
  16. package/dist/chunk-24FDD6UR.js +75 -0
  17. package/dist/chunk-24FDD6UR.js.map +1 -0
  18. package/dist/chunk-2TF7QNYV.js +159 -0
  19. package/dist/chunk-2TF7QNYV.js.map +1 -0
  20. package/dist/chunk-2YAZ5WG6.js +479 -0
  21. package/dist/chunk-2YAZ5WG6.js.map +1 -0
  22. package/dist/chunk-36NLLAVH.js +177 -0
  23. package/dist/chunk-36NLLAVH.js.map +1 -0
  24. package/dist/chunk-3OYSJB3P.js +126 -0
  25. package/dist/chunk-3OYSJB3P.js.map +1 -0
  26. package/dist/chunk-5E57JODA.js +135 -0
  27. package/dist/chunk-5E57JODA.js.map +1 -0
  28. package/dist/chunk-7LZCW4VF.js +13 -0
  29. package/dist/chunk-7LZCW4VF.js.map +1 -0
  30. package/dist/chunk-ANYGZ6O5.js +830 -0
  31. package/dist/chunk-ANYGZ6O5.js.map +1 -0
  32. package/dist/chunk-AQAISI4F.js +183 -0
  33. package/dist/chunk-AQAISI4F.js.map +1 -0
  34. package/dist/chunk-B6MPVOV7.js +328 -0
  35. package/dist/chunk-B6MPVOV7.js.map +1 -0
  36. package/dist/chunk-CILP56G2.js +94 -0
  37. package/dist/chunk-CILP56G2.js.map +1 -0
  38. package/dist/chunk-ERQ52WHY.js +534 -0
  39. package/dist/chunk-ERQ52WHY.js.map +1 -0
  40. package/dist/chunk-FOTUJPM4.js +640 -0
  41. package/dist/chunk-FOTUJPM4.js.map +1 -0
  42. package/dist/chunk-IHCBBLLW.js +198 -0
  43. package/dist/chunk-IHCBBLLW.js.map +1 -0
  44. package/dist/chunk-J4JBQET2.js +76 -0
  45. package/dist/chunk-J4JBQET2.js.map +1 -0
  46. package/dist/chunk-L4OEI4VZ.js +123 -0
  47. package/dist/chunk-L4OEI4VZ.js.map +1 -0
  48. package/dist/chunk-LRV7MWWX.js +616 -0
  49. package/dist/chunk-LRV7MWWX.js.map +1 -0
  50. package/dist/chunk-N43VE355.js +126 -0
  51. package/dist/chunk-N43VE355.js.map +1 -0
  52. package/dist/chunk-PYYLHUV6.js +3 -0
  53. package/dist/chunk-PYYLHUV6.js.map +1 -0
  54. package/dist/chunk-QCTXAMLA.js +261 -0
  55. package/dist/chunk-QCTXAMLA.js.map +1 -0
  56. package/dist/chunk-RIKAPJNG.js +40 -0
  57. package/dist/chunk-RIKAPJNG.js.map +1 -0
  58. package/dist/chunk-U3XT35GZ.js +202 -0
  59. package/dist/chunk-U3XT35GZ.js.map +1 -0
  60. package/dist/chunk-W22WB3WZ.js +148 -0
  61. package/dist/chunk-W22WB3WZ.js.map +1 -0
  62. package/dist/chunk-WTIJMKML.js +27 -0
  63. package/dist/chunk-WTIJMKML.js.map +1 -0
  64. package/dist/chunk-X2CQFJPR.js +75 -0
  65. package/dist/chunk-X2CQFJPR.js.map +1 -0
  66. package/dist/chunk-YYFKLOKO.js +769 -0
  67. package/dist/chunk-YYFKLOKO.js.map +1 -0
  68. package/dist/client-Cs7E_usr.d.ts +113 -0
  69. package/dist/content/index.d.ts +309 -0
  70. package/dist/content/index.js +6 -0
  71. package/dist/content/index.js.map +1 -0
  72. package/dist/core/index.d.ts +166 -0
  73. package/dist/core/index.js +5 -0
  74. package/dist/core/index.js.map +1 -0
  75. package/dist/core/react.d.ts +107 -0
  76. package/dist/core/react.js +5 -0
  77. package/dist/core/react.js.map +1 -0
  78. package/dist/coupon-BZSZ0y3n.d.ts +129 -0
  79. package/dist/coupon-CDzL4bJG.d.ts +655 -0
  80. package/dist/crud.factory-DyKaPHcU.d.ts +181 -0
  81. package/dist/finance/index.d.ts +81 -0
  82. package/dist/finance/index.js +5 -0
  83. package/dist/finance/index.js.map +1 -0
  84. package/dist/finance-BJdfKRw0.d.ts +135 -0
  85. package/dist/index.d.ts +32 -0
  86. package/dist/index.js +29 -0
  87. package/dist/index.js.map +1 -0
  88. package/dist/inventory/index.d.ts +512 -0
  89. package/dist/inventory/index.js +16 -0
  90. package/dist/inventory/index.js.map +1 -0
  91. package/dist/inventory-B5pssqRx.d.ts +748 -0
  92. package/dist/logistics/index.d.ts +248 -0
  93. package/dist/logistics/index.js +7 -0
  94. package/dist/logistics/index.js.map +1 -0
  95. package/dist/logistics-CrpKadKE.d.ts +410 -0
  96. package/dist/media-CNLJK93J.d.ts +721 -0
  97. package/dist/movement-R3CERFAM.js +5 -0
  98. package/dist/movement-R3CERFAM.js.map +1 -0
  99. package/dist/order-B3dCvHgK.d.ts +360 -0
  100. package/dist/payment-BRboLqvU.d.ts +127 -0
  101. package/dist/payments/index.d.ts +55 -0
  102. package/dist/payments/index.js +6 -0
  103. package/dist/payments/index.js.map +1 -0
  104. package/dist/platform/index.d.ts +645 -0
  105. package/dist/platform/index.js +8 -0
  106. package/dist/platform/index.js.map +1 -0
  107. package/dist/pos-BCqkx2-K.d.ts +527 -0
  108. package/dist/product-p09zXkXB.d.ts +260 -0
  109. package/dist/purchase-54PER2PY.js +5 -0
  110. package/dist/purchase-54PER2PY.js.map +1 -0
  111. package/dist/request-MP6NV5ZE.js +5 -0
  112. package/dist/request-MP6NV5ZE.js.map +1 -0
  113. package/dist/sales/index.d.ts +587 -0
  114. package/dist/sales/index.js +9 -0
  115. package/dist/sales/index.js.map +1 -0
  116. package/dist/server.d.ts +23 -0
  117. package/dist/server.js +37 -0
  118. package/dist/server.js.map +1 -0
  119. package/dist/size-guide-DgjzjM5P.d.ts +554 -0
  120. package/dist/stock-2LP4HJSB.js +5 -0
  121. package/dist/stock-2LP4HJSB.js.map +1 -0
  122. package/dist/stock-CfrU5_Wr.d.ts +632 -0
  123. package/dist/supplier-BWJTRZ5Z.js +5 -0
  124. package/dist/supplier-BWJTRZ5Z.js.map +1 -0
  125. package/dist/transaction/index.d.ts +104 -0
  126. package/dist/transaction/index.js +8 -0
  127. package/dist/transaction/index.js.map +1 -0
  128. package/dist/transaction-Bf6WjYCh.d.ts +84 -0
  129. package/dist/transaction-dL3WW-er.d.ts +442 -0
  130. package/dist/transfer-4XSS6HWT.js +5 -0
  131. package/dist/transfer-4XSS6HWT.js.map +1 -0
  132. package/dist/user-data-DdLjAGwO.d.ts +132 -0
  133. package/package.json +147 -0
@@ -0,0 +1,640 @@
1
+ import { BaseApi } from './chunk-QCTXAMLA.js';
2
+ import { createCrudHooks } from './chunk-B6MPVOV7.js';
3
+ import { getToastHandler } from './chunk-U3XT35GZ.js';
4
+ import { useQuery, useQueryClient, useMutation } from '@tanstack/react-query';
5
+
6
+ // src/catalog/api/product.ts
7
+ var ProductApi = class extends BaseApi {
8
+ constructor(config = {}) {
9
+ super("products", config);
10
+ }
11
+ /**
12
+ * Get product by slug
13
+ * GET /products/slug/:slug
14
+ * (Public endpoint)
15
+ *
16
+ * @param token - Auth token (optional, public endpoint)
17
+ * @param slug - Product slug
18
+ * @param options - Additional fetch options
19
+ * @returns Product object
20
+ */
21
+ async getBySlug({
22
+ token = null,
23
+ slug,
24
+ options = {}
25
+ }) {
26
+ if (!slug) {
27
+ throw new Error("Product slug is required");
28
+ }
29
+ return this.request("GET", `${this.baseUrl}/slug/${slug}`, {
30
+ token: token || void 0,
31
+ options: {
32
+ cache: this.config.cache,
33
+ ...options
34
+ }
35
+ });
36
+ }
37
+ /**
38
+ * Get product recommendations
39
+ * GET /products/:id/recommendations
40
+ * (Public endpoint)
41
+ *
42
+ * @param token - Auth token (optional)
43
+ * @param productId - Product ID to get recommendations for
44
+ * @param options - Additional fetch options
45
+ * @returns List of recommended products
46
+ */
47
+ async getRecommendations({
48
+ token = null,
49
+ productId,
50
+ options = {}
51
+ }) {
52
+ if (!productId) {
53
+ throw new Error("Product ID is required");
54
+ }
55
+ return this.request("GET", `${this.baseUrl}/${productId}/recommendations`, {
56
+ token: token || void 0,
57
+ options: {
58
+ cache: this.config.cache,
59
+ ...options
60
+ }
61
+ });
62
+ }
63
+ /**
64
+ * Get soft-deleted products (Recycle Bin)
65
+ * GET /products/deleted
66
+ * (Admin only)
67
+ *
68
+ * @param token - Auth token (required)
69
+ * @param params - Query parameters for pagination/filtering
70
+ * @param options - Additional fetch options
71
+ * @returns Paginated list of deleted products
72
+ */
73
+ async getDeleted({
74
+ token,
75
+ params = {},
76
+ options = {}
77
+ }) {
78
+ return this.request("GET", `${this.baseUrl}/deleted`, {
79
+ token,
80
+ params,
81
+ options: {
82
+ cache: this.config.cache,
83
+ ...options
84
+ }
85
+ });
86
+ }
87
+ /**
88
+ * Restore a soft-deleted product
89
+ * POST /products/:id/restore
90
+ * (Admin only)
91
+ *
92
+ * @param token - Auth token (required)
93
+ * @param id - Product ID to restore
94
+ * @param options - Additional fetch options
95
+ * @returns Restored product
96
+ */
97
+ async restore({
98
+ token,
99
+ id,
100
+ options = {}
101
+ }) {
102
+ if (!id) {
103
+ throw new Error("Product ID is required");
104
+ }
105
+ return this.request("POST", `${this.baseUrl}/${id}/restore`, {
106
+ token,
107
+ options
108
+ });
109
+ }
110
+ /**
111
+ * Permanently delete a product (Hard delete)
112
+ * DELETE /products/:id?hard=true
113
+ * (Admin only - use with caution)
114
+ *
115
+ * @param token - Auth token (required)
116
+ * @param id - Product ID to permanently delete
117
+ * @param options - Additional fetch options
118
+ * @returns Delete confirmation
119
+ */
120
+ async hardDelete({
121
+ token,
122
+ id,
123
+ options = {}
124
+ }) {
125
+ if (!id) {
126
+ throw new Error("Product ID is required");
127
+ }
128
+ return this.delete({
129
+ token,
130
+ id,
131
+ options: {
132
+ ...options,
133
+ // @ts-ignore - params is handled internally
134
+ params: { hard: "true" }
135
+ }
136
+ });
137
+ }
138
+ /**
139
+ * Sync product stock quantity
140
+ * POST /products/:id/sync-stock
141
+ *
142
+ * Recomputes product.quantity by summing all StockEntry quantities across branches.
143
+ * (Requires: admin, warehouse-admin, warehouse-staff, or store-manager role)
144
+ *
145
+ * @param token - Auth token (required)
146
+ * @param id - Product ID to sync stock for
147
+ * @param options - Additional fetch options
148
+ * @returns Sync result with new quantity
149
+ */
150
+ async syncStock({
151
+ token,
152
+ id,
153
+ options = {}
154
+ }) {
155
+ if (!id) {
156
+ throw new Error("Product ID is required");
157
+ }
158
+ return this.request("POST", `${this.baseUrl}/${id}/sync-stock`, {
159
+ token,
160
+ options
161
+ });
162
+ }
163
+ };
164
+ var productApi = new ProductApi();
165
+
166
+ // src/catalog/api/category.ts
167
+ var CategoryApi = class extends BaseApi {
168
+ constructor(config = {}) {
169
+ super("categories", config);
170
+ }
171
+ /**
172
+ * Get category tree (nested structure)
173
+ * GET /categories/tree
174
+ *
175
+ * **This is the main endpoint - FE should cache this and derive everything else from it.**
176
+ *
177
+ * Returns nested tree structure with children. Use helper functions to flatten, search, or extract children.
178
+ *
179
+ * @param token - Auth token (optional, public endpoint)
180
+ * @param options - Additional fetch options
181
+ * @returns Nested category tree
182
+ *
183
+ * @example
184
+ * ```typescript
185
+ * const { data } = await categoryApi.getTree({ token: null });
186
+ * // data = [{ slug: "clothing", name: "Clothing", children: [...] }]
187
+ * ```
188
+ */
189
+ async getTree({
190
+ token = null,
191
+ options = {}
192
+ } = {}) {
193
+ return this.request("GET", `${this.baseUrl}/tree`, {
194
+ token: token || void 0,
195
+ options: {
196
+ cache: this.config.cache,
197
+ ...options
198
+ }
199
+ });
200
+ }
201
+ /**
202
+ * Get category by slug
203
+ * GET /categories/slug/:slug
204
+ *
205
+ * For URL resolution when you need full category details.
206
+ *
207
+ * @param token - Auth token (optional, public endpoint)
208
+ * @param slug - Category slug (e.g., "electronics", "t-shirts")
209
+ * @param options - Additional fetch options
210
+ * @returns Category object
211
+ *
212
+ * @example
213
+ * ```typescript
214
+ * const { data } = await categoryApi.getBySlug({
215
+ * token: null,
216
+ * slug: 'electronics'
217
+ * });
218
+ * ```
219
+ */
220
+ async getBySlug({
221
+ token = null,
222
+ slug,
223
+ options = {}
224
+ }) {
225
+ if (!slug) {
226
+ throw new Error("Category slug is required");
227
+ }
228
+ return this.request("GET", `${this.baseUrl}/slug/${slug}`, {
229
+ token: token || void 0,
230
+ options: {
231
+ cache: this.config.cache,
232
+ ...options
233
+ }
234
+ });
235
+ }
236
+ /**
237
+ * Sync product counts for all categories
238
+ * POST /categories/sync-product-count
239
+ *
240
+ * Recalculates `productCount` for all categories based on current products.
241
+ * Use when manual data fixes or migrations may have desynced counts.
242
+ *
243
+ * @param token - Auth token (admin or inventory staff required)
244
+ * @param options - Additional fetch options
245
+ * @returns Number of categories updated
246
+ *
247
+ * @example
248
+ * ```typescript
249
+ * const { data } = await categoryApi.syncProductCount({ token });
250
+ * // data = { updated: 42 }
251
+ * ```
252
+ */
253
+ async syncProductCount({
254
+ token,
255
+ options = {}
256
+ }) {
257
+ return this.request("POST", `${this.baseUrl}/sync-product-count`, {
258
+ token,
259
+ options
260
+ });
261
+ }
262
+ };
263
+ var categoryApi = new CategoryApi();
264
+
265
+ // src/catalog/api/size-guide.ts
266
+ var SizeGuideApi = class extends BaseApi {
267
+ constructor(config = {}) {
268
+ super("size-guides", config);
269
+ }
270
+ /**
271
+ * Get size guide by slug
272
+ * GET /size-guides/slug/:slug
273
+ *
274
+ * For product detail pages to fetch the appropriate size guide.
275
+ *
276
+ * @param token - Auth token (optional, public endpoint)
277
+ * @param slug - Size guide slug (e.g., "t-shirts-tops")
278
+ * @param options - Additional fetch options
279
+ * @returns Size guide object
280
+ *
281
+ * @example
282
+ * ```typescript
283
+ * const { data } = await sizeGuideApi.getBySlug({
284
+ * token: null,
285
+ * slug: 't-shirts-tops'
286
+ * });
287
+ * ```
288
+ */
289
+ async getBySlug({
290
+ token = null,
291
+ slug,
292
+ options = {}
293
+ }) {
294
+ if (!slug) {
295
+ throw new Error("Size guide slug is required");
296
+ }
297
+ return this.request("GET", `${this.baseUrl}/slug/${slug}`, {
298
+ token: token || void 0,
299
+ options: {
300
+ cache: this.config.cache,
301
+ ...options
302
+ }
303
+ });
304
+ }
305
+ };
306
+ var sizeGuideApi = new SizeGuideApi();
307
+
308
+ // src/catalog/api/review.ts
309
+ var ReviewApi = class extends BaseApi {
310
+ constructor(config = {}) {
311
+ super("reviews", config);
312
+ }
313
+ /**
314
+ * Get current user's review for a product
315
+ * GET /reviews/my/:productId
316
+ *
317
+ * @param token - Auth token (required)
318
+ * @param productId - Product ID
319
+ * @param options - Additional fetch options
320
+ * @returns Review or null
321
+ */
322
+ async getMyReview({
323
+ token,
324
+ productId,
325
+ options = {}
326
+ }) {
327
+ if (!productId) {
328
+ throw new Error("Product ID is required");
329
+ }
330
+ return this.request("GET", `${this.baseUrl}/my/${productId}`, {
331
+ token,
332
+ options: {
333
+ cache: this.config.cache,
334
+ ...options
335
+ }
336
+ });
337
+ }
338
+ };
339
+ var reviewApi = new ReviewApi();
340
+ var productHooks = createCrudHooks({
341
+ api: productApi,
342
+ entityKey: "products",
343
+ singular: "Product",
344
+ plural: "Products",
345
+ defaults: {
346
+ staleTime: 5 * 60 * 1e3
347
+ // 5 minutes
348
+ }
349
+ });
350
+ var {
351
+ KEYS: PRODUCT_KEYS,
352
+ useList: useProducts,
353
+ useDetail: useProductDetail,
354
+ useActions: useProductActions,
355
+ useNavigation: useProductNavigation
356
+ } = productHooks;
357
+ function useProductBySlug(token, slug, options = {}) {
358
+ return useQuery({
359
+ queryKey: [...PRODUCT_KEYS.all, "slug", slug],
360
+ queryFn: () => productApi.getBySlug({ token, slug }),
361
+ enabled: !!slug,
362
+ staleTime: 5 * 60 * 1e3,
363
+ // 5 minutes
364
+ ...options
365
+ });
366
+ }
367
+ function useProductRecommendations(productId, options = {}) {
368
+ const { data, isLoading, error } = useQuery({
369
+ queryKey: [...PRODUCT_KEYS.all, "recommendations", productId],
370
+ queryFn: () => productApi.getRecommendations({ token: null, productId }),
371
+ enabled: !!productId,
372
+ staleTime: 10 * 60 * 1e3,
373
+ // 10 minutes
374
+ ...options
375
+ });
376
+ return {
377
+ recommendations: data?.data ?? [],
378
+ isLoading,
379
+ error
380
+ };
381
+ }
382
+ function useDeletedProducts(token, params = {}, options = {}) {
383
+ return useQuery({
384
+ queryKey: [...PRODUCT_KEYS.all, "deleted", params],
385
+ queryFn: () => productApi.getDeleted({ token, params }),
386
+ enabled: !!token,
387
+ staleTime: 2 * 60 * 1e3,
388
+ // 2 minutes
389
+ ...options
390
+ });
391
+ }
392
+ function useRestoreProduct(token) {
393
+ const queryClient = useQueryClient();
394
+ const toast = getToastHandler();
395
+ return useMutation({
396
+ mutationFn: (id) => productApi.restore({ token, id }),
397
+ onSuccess: () => {
398
+ toast.success("Product restored successfully");
399
+ queryClient.invalidateQueries({ queryKey: [...PRODUCT_KEYS.all, "deleted"] });
400
+ queryClient.invalidateQueries({ queryKey: PRODUCT_KEYS.lists() });
401
+ },
402
+ onError: (error) => {
403
+ toast.error(error.message || "Failed to restore product");
404
+ }
405
+ });
406
+ }
407
+ function useHardDeleteProduct(token) {
408
+ const queryClient = useQueryClient();
409
+ const toast = getToastHandler();
410
+ return useMutation({
411
+ mutationFn: (id) => productApi.hardDelete({ token, id }),
412
+ onSuccess: () => {
413
+ toast.success("Product permanently deleted");
414
+ queryClient.invalidateQueries({ queryKey: [...PRODUCT_KEYS.all, "deleted"] });
415
+ },
416
+ onError: (error) => {
417
+ toast.error(error.message || "Failed to permanently delete product");
418
+ }
419
+ });
420
+ }
421
+ function useSyncProductStock(token) {
422
+ const queryClient = useQueryClient();
423
+ const toast = getToastHandler();
424
+ return useMutation({
425
+ mutationFn: (id) => productApi.syncStock({ token, id }),
426
+ onSuccess: (result, id) => {
427
+ toast.success(`Stock synced: ${result.totalQuantity} units`);
428
+ queryClient.invalidateQueries({ queryKey: PRODUCT_KEYS.detail(id) });
429
+ queryClient.invalidateQueries({ queryKey: PRODUCT_KEYS.lists() });
430
+ },
431
+ onError: (error) => {
432
+ toast.error(error.message || "Failed to sync stock");
433
+ }
434
+ });
435
+ }
436
+ var categoryHooks = createCrudHooks({
437
+ api: categoryApi,
438
+ entityKey: "categories",
439
+ singular: "Category",
440
+ plural: "Categories",
441
+ defaults: {
442
+ staleTime: 10 * 60 * 1e3
443
+ // 10 minutes
444
+ }
445
+ });
446
+ var {
447
+ KEYS: CATEGORY_KEYS,
448
+ useList: useCategories,
449
+ useDetail: useCategoryDetail,
450
+ useActions: useCategoryActions,
451
+ useNavigation: useCategoryNavigation
452
+ } = categoryHooks;
453
+ function useCategoryTree(token, options = {}) {
454
+ return useQuery({
455
+ queryKey: [...CATEGORY_KEYS.all, "tree"],
456
+ queryFn: () => categoryApi.getTree({ token }),
457
+ staleTime: 30 * 60 * 1e3,
458
+ // 30 minutes (categories rarely change)
459
+ gcTime: 60 * 60 * 1e3,
460
+ // 60 minutes
461
+ ...options
462
+ });
463
+ }
464
+ function useCategoryBySlug(token, slug, options = {}) {
465
+ return useQuery({
466
+ queryKey: [...CATEGORY_KEYS.all, "slug", slug],
467
+ queryFn: () => categoryApi.getBySlug({ token, slug }),
468
+ enabled: !!slug,
469
+ staleTime: 30 * 60 * 1e3,
470
+ // 30 minutes
471
+ ...options
472
+ });
473
+ }
474
+ function useCategorySyncProductCount(token) {
475
+ const queryClient = useQueryClient();
476
+ const toast = getToastHandler();
477
+ return useMutation({
478
+ mutationFn: () => categoryApi.syncProductCount({ token }),
479
+ onSuccess: (result) => {
480
+ const count = result?.data?.updated ?? 0;
481
+ toast.success(`Synced product counts for ${count} categories`);
482
+ queryClient.invalidateQueries({ queryKey: CATEGORY_KEYS.all });
483
+ },
484
+ onError: (error) => {
485
+ toast.error(error.message || "Failed to sync product counts");
486
+ }
487
+ });
488
+ }
489
+ function flattenCategoryTree(nodes, depth = 0, result = []) {
490
+ for (const node of nodes || []) {
491
+ result.push({
492
+ ...node,
493
+ depth,
494
+ displayName: "\xA0\xA0".repeat(depth) + node.name
495
+ });
496
+ if (node.children?.length) {
497
+ flattenCategoryTree(node.children, depth + 1, result);
498
+ }
499
+ }
500
+ return result;
501
+ }
502
+ function getParentCategoryOptions(tree) {
503
+ return (tree || []).map((node) => ({
504
+ value: node.slug,
505
+ label: node.name
506
+ }));
507
+ }
508
+ function getAllCategoryOptions(tree) {
509
+ return flattenCategoryTree(tree).map((node) => ({
510
+ value: node.slug,
511
+ label: node.displayName
512
+ }));
513
+ }
514
+ function findCategoryBySlug(tree, slug) {
515
+ if (!tree || !slug) return void 0;
516
+ for (const node of tree) {
517
+ if (node.slug === slug) return node;
518
+ if (node.children?.length) {
519
+ const found = findCategoryBySlug(node.children, slug);
520
+ if (found) return found;
521
+ }
522
+ }
523
+ return void 0;
524
+ }
525
+ function getCategoryBreadcrumb(tree, slug) {
526
+ if (!tree || !slug) return [];
527
+ function findPath(nodes, target, path = []) {
528
+ for (const node of nodes) {
529
+ const currentPath = [...path, node];
530
+ if (node.slug === target) return currentPath;
531
+ if (node.children?.length) {
532
+ const found = findPath(node.children, target, currentPath);
533
+ if (found) return found;
534
+ }
535
+ }
536
+ return null;
537
+ }
538
+ return findPath(tree, slug) || [];
539
+ }
540
+ function getChildCategorySlugs(tree, parentSlug) {
541
+ const parent = findCategoryBySlug(tree, parentSlug);
542
+ if (!parent?.children?.length) return [];
543
+ const slugs = [];
544
+ function collectSlugs(nodes) {
545
+ for (const node of nodes) {
546
+ slugs.push(node.slug);
547
+ if (node.children?.length) {
548
+ collectSlugs(node.children);
549
+ }
550
+ }
551
+ }
552
+ collectSlugs(parent.children);
553
+ return slugs;
554
+ }
555
+ function getRootCategories(tree) {
556
+ return tree || [];
557
+ }
558
+ var sizeGuideHooks = createCrudHooks({
559
+ api: sizeGuideApi,
560
+ entityKey: "size-guides",
561
+ singular: "Size Guide",
562
+ plural: "Size Guides",
563
+ defaults: {
564
+ staleTime: 30 * 60 * 1e3
565
+ // 30 minutes (size guides change rarely)
566
+ }
567
+ });
568
+ var {
569
+ KEYS: SIZE_GUIDE_KEYS,
570
+ useList: useSizeGuides,
571
+ useDetail: useSizeGuideDetail,
572
+ useActions: useSizeGuideActions,
573
+ useNavigation: useSizeGuideNavigation
574
+ } = sizeGuideHooks;
575
+ function useSizeGuideBySlug(token, slug, options = {}) {
576
+ return useQuery({
577
+ queryKey: [...SIZE_GUIDE_KEYS.all, "slug", slug],
578
+ queryFn: () => sizeGuideApi.getBySlug({ token, slug }),
579
+ enabled: !!slug,
580
+ staleTime: 30 * 60 * 1e3,
581
+ // 30 minutes
582
+ ...options
583
+ });
584
+ }
585
+ function getSizeGuideOptions(sizeGuides) {
586
+ return (sizeGuides || []).map((guide) => ({
587
+ value: guide._id,
588
+ label: guide.name
589
+ }));
590
+ }
591
+ function findSizeGuideById(sizeGuides, id) {
592
+ return sizeGuides?.find((guide) => guide._id === id);
593
+ }
594
+ function findSizeGuideBySlug(sizeGuides, slug) {
595
+ return sizeGuides?.find((guide) => guide.slug === slug);
596
+ }
597
+ function formatMeasurement(value, unit) {
598
+ const unitLabel = unit === "inches" ? "in" : "cm";
599
+ return `${value} ${unitLabel}`;
600
+ }
601
+ function getSizeTableHeaders(guide) {
602
+ if (!guide?.measurementLabels) return ["Size"];
603
+ return ["Size", ...guide.measurementLabels];
604
+ }
605
+ function getSizeTableRows(guide) {
606
+ if (!guide?.sizes) return [];
607
+ return guide.sizes.map((size) => ({
608
+ name: size.name,
609
+ measurements: size.measurements
610
+ }));
611
+ }
612
+ var reviewHooks = createCrudHooks({
613
+ api: reviewApi,
614
+ entityKey: "reviews",
615
+ singular: "Review",
616
+ plural: "Reviews",
617
+ defaults: {
618
+ staleTime: 5 * 60 * 1e3
619
+ // 5 minutes
620
+ }
621
+ });
622
+ var {
623
+ KEYS: REVIEW_KEYS,
624
+ useList: useReviews,
625
+ useDetail: useReviewDetail,
626
+ useActions: useReviewActions,
627
+ useNavigation: useReviewNavigation
628
+ } = reviewHooks;
629
+ function useMyReview(token, productId, options = {}) {
630
+ return useQuery({
631
+ queryKey: [...REVIEW_KEYS.all, "my", productId],
632
+ queryFn: () => reviewApi.getMyReview({ token, productId }),
633
+ enabled: Boolean(token && productId),
634
+ ...options
635
+ });
636
+ }
637
+
638
+ export { CATEGORY_KEYS, CategoryApi, PRODUCT_KEYS, ProductApi, REVIEW_KEYS, ReviewApi, SIZE_GUIDE_KEYS, SizeGuideApi, categoryApi, categoryHooks, findCategoryBySlug, findSizeGuideById, findSizeGuideBySlug, flattenCategoryTree, formatMeasurement, getAllCategoryOptions, getCategoryBreadcrumb, getChildCategorySlugs, getParentCategoryOptions, getRootCategories, getSizeGuideOptions, getSizeTableHeaders, getSizeTableRows, productApi, productHooks, reviewApi, reviewHooks, sizeGuideApi, sizeGuideHooks, useCategories, useCategoryActions, useCategoryBySlug, useCategoryDetail, useCategoryNavigation, useCategorySyncProductCount, useCategoryTree, useDeletedProducts, useHardDeleteProduct, useMyReview, useProductActions, useProductBySlug, useProductDetail, useProductNavigation, useProductRecommendations, useProducts, useRestoreProduct, useReviewActions, useReviewDetail, useReviewNavigation, useReviews, useSizeGuideActions, useSizeGuideBySlug, useSizeGuideDetail, useSizeGuideNavigation, useSizeGuides, useSyncProductStock };
639
+ //# sourceMappingURL=chunk-FOTUJPM4.js.map
640
+ //# sourceMappingURL=chunk-FOTUJPM4.js.map