@classytic/commerce-sdk 0.1.0

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.

Potentially problematic release.


This version of @classytic/commerce-sdk might be problematic. Click here for more details.

Files changed (131) hide show
  1. package/LICENSE +14 -0
  2. package/README.md +104 -0
  3. package/dist/adjustment-DTSLM7AN.js +5 -0
  4. package/dist/adjustment-DTSLM7AN.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 +479 -0
  14. package/dist/catalog/index.js +9 -0
  15. package/dist/catalog/index.js.map +1 -0
  16. package/dist/chunk-4ZQK3FFN.js +40 -0
  17. package/dist/chunk-4ZQK3FFN.js.map +1 -0
  18. package/dist/chunk-5L6EXDGH.js +465 -0
  19. package/dist/chunk-5L6EXDGH.js.map +1 -0
  20. package/dist/chunk-5ZFW3FEI.js +183 -0
  21. package/dist/chunk-5ZFW3FEI.js.map +1 -0
  22. package/dist/chunk-66OQAZSL.js +94 -0
  23. package/dist/chunk-66OQAZSL.js.map +1 -0
  24. package/dist/chunk-6RYGA6MF.js +123 -0
  25. package/dist/chunk-6RYGA6MF.js.map +1 -0
  26. package/dist/chunk-B6MPVOV7.js +328 -0
  27. package/dist/chunk-B6MPVOV7.js.map +1 -0
  28. package/dist/chunk-BDA2WSJA.js +148 -0
  29. package/dist/chunk-BDA2WSJA.js.map +1 -0
  30. package/dist/chunk-EIVYT3HM.js +126 -0
  31. package/dist/chunk-EIVYT3HM.js.map +1 -0
  32. package/dist/chunk-EPQN7ZKZ.js +27 -0
  33. package/dist/chunk-EPQN7ZKZ.js.map +1 -0
  34. package/dist/chunk-FA7QFJ2G.js +177 -0
  35. package/dist/chunk-FA7QFJ2G.js.map +1 -0
  36. package/dist/chunk-I5TIKUIQ.js +261 -0
  37. package/dist/chunk-I5TIKUIQ.js.map +1 -0
  38. package/dist/chunk-ILQUH444.js +135 -0
  39. package/dist/chunk-ILQUH444.js.map +1 -0
  40. package/dist/chunk-IXMWZJLV.js +616 -0
  41. package/dist/chunk-IXMWZJLV.js.map +1 -0
  42. package/dist/chunk-KZIGRIQG.js +75 -0
  43. package/dist/chunk-KZIGRIQG.js.map +1 -0
  44. package/dist/chunk-OF5M6R2S.js +769 -0
  45. package/dist/chunk-OF5M6R2S.js.map +1 -0
  46. package/dist/chunk-PYYLHUV6.js +3 -0
  47. package/dist/chunk-PYYLHUV6.js.map +1 -0
  48. package/dist/chunk-QO5AGZFP.js +159 -0
  49. package/dist/chunk-QO5AGZFP.js.map +1 -0
  50. package/dist/chunk-QUMTBLNE.js +76 -0
  51. package/dist/chunk-QUMTBLNE.js.map +1 -0
  52. package/dist/chunk-R5Z7NYLH.js +126 -0
  53. package/dist/chunk-R5Z7NYLH.js.map +1 -0
  54. package/dist/chunk-SZYWG5IB.js +75 -0
  55. package/dist/chunk-SZYWG5IB.js.map +1 -0
  56. package/dist/chunk-U3XT35GZ.js +202 -0
  57. package/dist/chunk-U3XT35GZ.js.map +1 -0
  58. package/dist/chunk-UGELTUIZ.js +830 -0
  59. package/dist/chunk-UGELTUIZ.js.map +1 -0
  60. package/dist/chunk-VR36QVX2.js +122 -0
  61. package/dist/chunk-VR36QVX2.js.map +1 -0
  62. package/dist/chunk-WUOQK7BO.js +13 -0
  63. package/dist/chunk-WUOQK7BO.js.map +1 -0
  64. package/dist/chunk-X6PV5MHG.js +582 -0
  65. package/dist/chunk-X6PV5MHG.js.map +1 -0
  66. package/dist/chunk-ZWLMFLLH.js +534 -0
  67. package/dist/chunk-ZWLMFLLH.js.map +1 -0
  68. package/dist/content/index.d.ts +309 -0
  69. package/dist/content/index.js +6 -0
  70. package/dist/content/index.js.map +1 -0
  71. package/dist/core/index.d.ts +107 -0
  72. package/dist/core/index.js +5 -0
  73. package/dist/core/index.js.map +1 -0
  74. package/dist/core/react.d.ts +107 -0
  75. package/dist/core/react.js +5 -0
  76. package/dist/core/react.js.map +1 -0
  77. package/dist/coupon-CHFcw7cd.d.ts +632 -0
  78. package/dist/coupon-zGkvO-Xx.d.ts +129 -0
  79. package/dist/crud.factory-DyKaPHcU.d.ts +181 -0
  80. package/dist/finance/index.d.ts +81 -0
  81. package/dist/finance/index.js +5 -0
  82. package/dist/finance/index.js.map +1 -0
  83. package/dist/finance-BJdfKRw0.d.ts +135 -0
  84. package/dist/index.d.ts +31 -0
  85. package/dist/index.js +29 -0
  86. package/dist/index.js.map +1 -0
  87. package/dist/inventory/index.d.ts +512 -0
  88. package/dist/inventory/index.js +16 -0
  89. package/dist/inventory/index.js.map +1 -0
  90. package/dist/inventory-DCiIZh8P.d.ts +742 -0
  91. package/dist/logistics/index.d.ts +226 -0
  92. package/dist/logistics/index.js +7 -0
  93. package/dist/logistics/index.js.map +1 -0
  94. package/dist/logistics-V8a9lUN3.d.ts +428 -0
  95. package/dist/media-CNLJK93J.d.ts +721 -0
  96. package/dist/movement-7MV3ADY5.js +5 -0
  97. package/dist/movement-7MV3ADY5.js.map +1 -0
  98. package/dist/payment-BRboLqvU.d.ts +127 -0
  99. package/dist/payments/index.d.ts +55 -0
  100. package/dist/payments/index.js +6 -0
  101. package/dist/payments/index.js.map +1 -0
  102. package/dist/platform/index.d.ts +645 -0
  103. package/dist/platform/index.js +8 -0
  104. package/dist/platform/index.js.map +1 -0
  105. package/dist/pos-D1jkkFl0.d.ts +885 -0
  106. package/dist/product-p09zXkXB.d.ts +260 -0
  107. package/dist/purchase-24BGT2HA.js +5 -0
  108. package/dist/purchase-24BGT2HA.js.map +1 -0
  109. package/dist/request-652PS6VR.js +5 -0
  110. package/dist/request-652PS6VR.js.map +1 -0
  111. package/dist/sales/index.d.ts +585 -0
  112. package/dist/sales/index.js +9 -0
  113. package/dist/sales/index.js.map +1 -0
  114. package/dist/server.d.ts +120 -0
  115. package/dist/server.js +27 -0
  116. package/dist/server.js.map +1 -0
  117. package/dist/size-guide-DgjzjM5P.d.ts +554 -0
  118. package/dist/stock-DEApGC-w.d.ts +632 -0
  119. package/dist/stock-OOUW57VQ.js +5 -0
  120. package/dist/stock-OOUW57VQ.js.map +1 -0
  121. package/dist/supplier-OC6JAWV6.js +5 -0
  122. package/dist/supplier-OC6JAWV6.js.map +1 -0
  123. package/dist/transaction/index.d.ts +104 -0
  124. package/dist/transaction/index.js +8 -0
  125. package/dist/transaction/index.js.map +1 -0
  126. package/dist/transaction-BTmoHpWh.d.ts +428 -0
  127. package/dist/transaction-u5oaNuav.d.ts +84 -0
  128. package/dist/transfer-7SYSH3RG.js +5 -0
  129. package/dist/transfer-7SYSH3RG.js.map +1 -0
  130. package/dist/user-data-DdLjAGwO.d.ts +132 -0
  131. package/package.json +146 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/catalog/api/product.ts","../src/catalog/api/category.ts","../src/catalog/api/size-guide.ts","../src/catalog/hooks/product.ts","../src/catalog/hooks/category.ts","../src/catalog/hooks/size-guide.ts"],"names":["useQuery","useQueryClient","useMutation"],"mappings":"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","file":"chunk-X6PV5MHG.js","sourcesContent":["/**\r\n * Product API Client\r\n *\r\n * **Authentication:**\r\n * - Public: List, Get, GetBySlug, GetRecommendations\r\n * - Admin: Create, Update, Delete, GetDeleted, Restore, HardDelete, SyncStock\r\n *\r\n * **Base URL:** `/api/v1/products`\r\n */\r\n\r\nimport { BaseApi, type ApiResponse, type PaginatedResponse } from '../../core';\r\nimport type {\r\n Product,\r\n CreateProductPayload,\r\n UpdateProductPayload,\r\n ProductSyncStockResponse,\r\n} from '../types';\r\n\r\ntype FetchOptions = {\r\n cache?: RequestCache;\r\n revalidate?: number;\r\n tags?: string[];\r\n};\r\n\r\n/**\r\n * Product API Client\r\n * Extends BaseApi with product-specific endpoints\r\n */\r\nclass ProductApi extends BaseApi<Product, CreateProductPayload, UpdateProductPayload> {\r\n constructor(config = {}) {\r\n super('products', config);\r\n }\r\n\r\n /**\r\n * Get product by slug\r\n * GET /products/slug/:slug\r\n * (Public endpoint)\r\n *\r\n * @param token - Auth token (optional, public endpoint)\r\n * @param slug - Product slug\r\n * @param options - Additional fetch options\r\n * @returns Product object\r\n */\r\n async getBySlug({\r\n token = null,\r\n slug,\r\n options = {},\r\n }: {\r\n token?: string | null;\r\n slug: string;\r\n options?: FetchOptions;\r\n }): Promise<ApiResponse<Product>> {\r\n if (!slug) {\r\n throw new Error('Product slug is required');\r\n }\r\n\r\n return this.request<ApiResponse<Product>>('GET', `${this.baseUrl}/slug/${slug}`, {\r\n token: token || undefined,\r\n options: {\r\n cache: this.config.cache,\r\n ...options,\r\n },\r\n });\r\n }\r\n\r\n /**\r\n * Get product recommendations\r\n * GET /products/:id/recommendations\r\n * (Public endpoint)\r\n *\r\n * @param token - Auth token (optional)\r\n * @param productId - Product ID to get recommendations for\r\n * @param options - Additional fetch options\r\n * @returns List of recommended products\r\n */\r\n async getRecommendations({\r\n token = null,\r\n productId,\r\n options = {},\r\n }: {\r\n token?: string | null;\r\n productId: string;\r\n options?: FetchOptions;\r\n }): Promise<ApiResponse<Product[]>> {\r\n if (!productId) {\r\n throw new Error('Product ID is required');\r\n }\r\n\r\n return this.request<ApiResponse<Product[]>>('GET', `${this.baseUrl}/${productId}/recommendations`, {\r\n token: token || undefined,\r\n options: {\r\n cache: this.config.cache,\r\n ...options,\r\n },\r\n });\r\n }\r\n\r\n /**\r\n * Get soft-deleted products (Recycle Bin)\r\n * GET /products/deleted\r\n * (Admin only)\r\n *\r\n * @param token - Auth token (required)\r\n * @param params - Query parameters for pagination/filtering\r\n * @param options - Additional fetch options\r\n * @returns Paginated list of deleted products\r\n */\r\n async getDeleted({\r\n token,\r\n params = {},\r\n options = {},\r\n }: {\r\n token: string;\r\n params?: Record<string, unknown>;\r\n options?: FetchOptions;\r\n }): Promise<PaginatedResponse<Product>> {\r\n return this.request<PaginatedResponse<Product>>('GET', `${this.baseUrl}/deleted`, {\r\n token,\r\n params,\r\n options: {\r\n cache: this.config.cache,\r\n ...options,\r\n },\r\n });\r\n }\r\n\r\n /**\r\n * Restore a soft-deleted product\r\n * POST /products/:id/restore\r\n * (Admin only)\r\n *\r\n * @param token - Auth token (required)\r\n * @param id - Product ID to restore\r\n * @param options - Additional fetch options\r\n * @returns Restored product\r\n */\r\n async restore({\r\n token,\r\n id,\r\n options = {},\r\n }: {\r\n token: string;\r\n id: string;\r\n options?: FetchOptions;\r\n }): Promise<ApiResponse<Product>> {\r\n if (!id) {\r\n throw new Error('Product ID is required');\r\n }\r\n\r\n return this.request<ApiResponse<Product>>('POST', `${this.baseUrl}/${id}/restore`, {\r\n token,\r\n options,\r\n });\r\n }\r\n\r\n /**\r\n * Permanently delete a product (Hard delete)\r\n * DELETE /products/:id?hard=true\r\n * (Admin only - use with caution)\r\n *\r\n * @param token - Auth token (required)\r\n * @param id - Product ID to permanently delete\r\n * @param options - Additional fetch options\r\n * @returns Delete confirmation\r\n */\r\n async hardDelete({\r\n token,\r\n id,\r\n options = {},\r\n }: {\r\n token: string;\r\n id: string;\r\n options?: FetchOptions;\r\n }): Promise<ApiResponse<{ deleted: boolean }>> {\r\n if (!id) {\r\n throw new Error('Product ID is required');\r\n }\r\n\r\n return this.delete({\r\n token,\r\n id,\r\n options: {\r\n ...options,\r\n // @ts-ignore - params is handled internally\r\n params: { hard: 'true' },\r\n },\r\n });\r\n }\r\n\r\n /**\r\n * Sync product stock quantity\r\n * POST /products/:id/sync-stock\r\n *\r\n * Recomputes product.quantity by summing all StockEntry quantities across branches.\r\n * (Requires: admin, warehouse-admin, warehouse-staff, or store-manager role)\r\n *\r\n * @param token - Auth token (required)\r\n * @param id - Product ID to sync stock for\r\n * @param options - Additional fetch options\r\n * @returns Sync result with new quantity\r\n */\r\n async syncStock({\r\n token,\r\n id,\r\n options = {},\r\n }: {\r\n token: string;\r\n id: string;\r\n options?: FetchOptions;\r\n }): Promise<ProductSyncStockResponse> {\r\n if (!id) {\r\n throw new Error('Product ID is required');\r\n }\r\n\r\n return this.request<ProductSyncStockResponse>('POST', `${this.baseUrl}/${id}/sync-stock`, {\r\n token,\r\n options,\r\n });\r\n }\r\n}\r\n\r\n// Create and export a singleton instance\r\nexport const productApi = new ProductApi();\r\nexport { ProductApi };\r\n","/**\r\n * Category API Client\r\n *\r\n * **Authentication:**\r\n * - Public: List, Get, Tree, GetBySlug\r\n * - Admin: Create, Update, Delete\r\n *\r\n * **Base URL:** `/api/v1/categories`\r\n *\r\n * **Slug-Based Design:**\r\n * - Categories use slugs as identifiers (not ObjectIds)\r\n * - Products store category as slug string for fast queries\r\n * - Example: `db.products.find({ category: \"electronics\" })`\r\n */\r\n\r\nimport { BaseApi, type ApiResponse } from '../../core';\r\nimport type {\r\n Category,\r\n CategoryTreeNode,\r\n CreateCategoryPayload,\r\n UpdateCategoryPayload,\r\n CategoryTreeResponse,\r\n} from '../types';\r\n\r\ntype FetchOptions = {\r\n cache?: RequestCache;\r\n revalidate?: number;\r\n tags?: string[];\r\n};\r\n\r\n/**\r\n * Category API Client\r\n * Extends BaseApi with category-specific endpoints\r\n */\r\nclass CategoryApi extends BaseApi<Category, CreateCategoryPayload, UpdateCategoryPayload> {\r\n constructor(config = {}) {\r\n super('categories', config);\r\n }\r\n\r\n /**\r\n * Get category tree (nested structure)\r\n * GET /categories/tree\r\n *\r\n * **This is the main endpoint - FE should cache this and derive everything else from it.**\r\n *\r\n * Returns nested tree structure with children. Use helper functions to flatten, search, or extract children.\r\n *\r\n * @param token - Auth token (optional, public endpoint)\r\n * @param options - Additional fetch options\r\n * @returns Nested category tree\r\n *\r\n * @example\r\n * ```typescript\r\n * const { data } = await categoryApi.getTree({ token: null });\r\n * // data = [{ slug: \"clothing\", name: \"Clothing\", children: [...] }]\r\n * ```\r\n */\r\n async getTree({\r\n token = null,\r\n options = {},\r\n }: {\r\n token?: string | null;\r\n options?: FetchOptions;\r\n } = {}): Promise<CategoryTreeResponse> {\r\n return this.request<CategoryTreeResponse>('GET', `${this.baseUrl}/tree`, {\r\n token: token || undefined,\r\n options: {\r\n cache: this.config.cache,\r\n ...options,\r\n },\r\n });\r\n }\r\n\r\n /**\r\n * Get category by slug\r\n * GET /categories/slug/:slug\r\n *\r\n * For URL resolution when you need full category details.\r\n *\r\n * @param token - Auth token (optional, public endpoint)\r\n * @param slug - Category slug (e.g., \"electronics\", \"t-shirts\")\r\n * @param options - Additional fetch options\r\n * @returns Category object\r\n *\r\n * @example\r\n * ```typescript\r\n * const { data } = await categoryApi.getBySlug({\r\n * token: null,\r\n * slug: 'electronics'\r\n * });\r\n * ```\r\n */\r\n async getBySlug({\r\n token = null,\r\n slug,\r\n options = {},\r\n }: {\r\n token?: string | null;\r\n slug: string;\r\n options?: FetchOptions;\r\n }): Promise<ApiResponse<Category>> {\r\n if (!slug) {\r\n throw new Error('Category slug is required');\r\n }\r\n\r\n return this.request<ApiResponse<Category>>('GET', `${this.baseUrl}/slug/${slug}`, {\r\n token: token || undefined,\r\n options: {\r\n cache: this.config.cache,\r\n ...options,\r\n },\r\n });\r\n }\r\n\r\n /**\r\n * Sync product counts for all categories\r\n * POST /categories/sync-product-count\r\n *\r\n * Recalculates `productCount` for all categories based on current products.\r\n * Use when manual data fixes or migrations may have desynced counts.\r\n *\r\n * @param token - Auth token (admin or inventory staff required)\r\n * @param options - Additional fetch options\r\n * @returns Number of categories updated\r\n *\r\n * @example\r\n * ```typescript\r\n * const { data } = await categoryApi.syncProductCount({ token });\r\n * // data = { updated: 42 }\r\n * ```\r\n */\r\n async syncProductCount({\r\n token,\r\n options = {},\r\n }: {\r\n token: string;\r\n options?: FetchOptions;\r\n }): Promise<ApiResponse<{ updated: number }>> {\r\n return this.request<ApiResponse<{ updated: number }>>('POST', `${this.baseUrl}/sync-product-count`, {\r\n token,\r\n options,\r\n });\r\n }\r\n}\r\n\r\n// Create and export a singleton instance\r\nexport const categoryApi = new CategoryApi();\r\nexport { CategoryApi };\r\n","/**\r\n * Size Guide API Client\r\n *\r\n * **Authentication:**\r\n * - Public: List, Get, GetBySlug\r\n * - Admin: Create, Update, Delete\r\n *\r\n * **Base URL:** `/api/v1/size-guides`\r\n *\r\n * **Slug-Based Design:**\r\n * - Size guides use slugs as identifiers\r\n * - Products store `sizeGuideSlug` to reference a size guide\r\n */\r\n\r\nimport { BaseApi, type ApiResponse } from '../../core';\r\nimport type {\r\n SizeGuide,\r\n CreateSizeGuidePayload,\r\n UpdateSizeGuidePayload,\r\n} from '../types';\r\n\r\ntype FetchOptions = {\r\n cache?: RequestCache;\r\n revalidate?: number;\r\n tags?: string[];\r\n};\r\n\r\n/**\r\n * Size Guide API Client\r\n * Extends BaseApi with size-guide-specific endpoints\r\n */\r\nclass SizeGuideApi extends BaseApi<SizeGuide, CreateSizeGuidePayload, UpdateSizeGuidePayload> {\r\n constructor(config = {}) {\r\n super('size-guides', config);\r\n }\r\n\r\n /**\r\n * Get size guide by slug\r\n * GET /size-guides/slug/:slug\r\n *\r\n * For product detail pages to fetch the appropriate size guide.\r\n *\r\n * @param token - Auth token (optional, public endpoint)\r\n * @param slug - Size guide slug (e.g., \"t-shirts-tops\")\r\n * @param options - Additional fetch options\r\n * @returns Size guide object\r\n *\r\n * @example\r\n * ```typescript\r\n * const { data } = await sizeGuideApi.getBySlug({\r\n * token: null,\r\n * slug: 't-shirts-tops'\r\n * });\r\n * ```\r\n */\r\n async getBySlug({\r\n token = null,\r\n slug,\r\n options = {},\r\n }: {\r\n token?: string | null;\r\n slug: string;\r\n options?: FetchOptions;\r\n }): Promise<ApiResponse<SizeGuide>> {\r\n if (!slug) {\r\n throw new Error('Size guide slug is required');\r\n }\r\n\r\n return this.request<ApiResponse<SizeGuide>>('GET', `${this.baseUrl}/slug/${slug}`, {\r\n token: token || undefined,\r\n options: {\r\n cache: this.config.cache,\r\n ...options,\r\n },\r\n });\r\n }\r\n}\r\n\r\n// Create and export a singleton instance\r\nexport const sizeGuideApi = new SizeGuideApi();\r\nexport { SizeGuideApi };\r\n","\"use client\";\n\n/**\n * Product Hooks\n *\n * Pre-built hooks for product CRUD operations with:\n * - Optimistic updates\n * - Smart caching\n * - Type safety\n */\n\nimport { useQuery, useMutation, useQueryClient, type UseQueryOptions } from \"@tanstack/react-query\";\nimport { createCrudHooks, type CrudApi, getToastHandler } from \"../../core/react\";\nimport { productApi } from \"../api\";\nimport type {\n Product,\n CreateProductPayload,\n UpdateProductPayload,\n ProductSyncStockResponse,\n} from \"../types\";\nimport type { ApiResponse, PaginatedResponse } from \"../../core\";\n\n// Type helper for API compatibility\ntype AnyApi = CrudApi<any, any, any>;\n\n// ============================================\n// CRUD Hooks (Factory-generated)\n// ============================================\n\n/**\n * Product CRUD hooks with optimistic updates\n */\nexport const productHooks = createCrudHooks<Product, CreateProductPayload, UpdateProductPayload>({\n api: productApi as AnyApi,\n entityKey: \"products\",\n singular: \"Product\",\n plural: \"Products\",\n defaults: {\n staleTime: 5 * 60 * 1000, // 5 minutes\n },\n});\n\nexport const {\n KEYS: PRODUCT_KEYS,\n useList: useProducts,\n useDetail: useProductDetail,\n useActions: useProductActions,\n useNavigation: useProductNavigation,\n} = productHooks;\n\n// ============================================\n// Custom Product Hooks\n// ============================================\n\n/**\n * Hook to get product by slug\n *\n * @param token - Auth token (optional for public access)\n * @param slug - Product slug\n * @param options - React Query options\n * @returns Query result with product data\n *\n * @example\n * ```tsx\n * function ProductPage({ slug }) {\n * const { data, isLoading } = useProductBySlug(null, slug);\n *\n * if (isLoading) return <Spinner />;\n *\n * return <h1>{data?.data?.name}</h1>;\n * }\n * ```\n */\nexport function useProductBySlug(\n token: string | null | undefined,\n slug: string,\n options: Omit<UseQueryOptions<ApiResponse<Product>>, \"queryKey\" | \"queryFn\"> = {}\n) {\n return useQuery<ApiResponse<Product>>({\n queryKey: [...PRODUCT_KEYS.all, \"slug\", slug],\n queryFn: () => productApi.getBySlug({ token, slug }),\n enabled: !!slug,\n staleTime: 5 * 60 * 1000, // 5 minutes\n ...options,\n });\n}\n\nexport interface UseProductRecommendationsReturn {\n recommendations: Product[];\n isLoading: boolean;\n error: Error | null;\n}\n\n/**\n * Hook to get product recommendations\n *\n * @param productId - Product ID to get recommendations for\n * @param options - React Query options\n * @returns Object with recommendations array, isLoading, and error\n *\n * @example\n * ```tsx\n * function ProductRecommendations({ productId }) {\n * const { recommendations, isLoading } = useProductRecommendations(productId);\n *\n * if (isLoading) return <Spinner />;\n *\n * return (\n * <div>\n * {recommendations.map(product => (\n * <ProductCard key={product._id} product={product} />\n * ))}\n * </div>\n * );\n * }\n * ```\n */\nexport function useProductRecommendations(\n productId: string,\n options: Omit<UseQueryOptions<ApiResponse<Product[]>>, \"queryKey\" | \"queryFn\"> = {}\n): UseProductRecommendationsReturn {\n const { data, isLoading, error } = useQuery<ApiResponse<Product[]>>({\n queryKey: [...PRODUCT_KEYS.all, \"recommendations\", productId],\n queryFn: () => productApi.getRecommendations({ token: null, productId }),\n enabled: !!productId,\n staleTime: 10 * 60 * 1000, // 10 minutes\n ...options,\n });\n\n return {\n recommendations: data?.data ?? [],\n isLoading,\n error: error as Error | null,\n };\n}\n\n/**\n * Hook to get soft-deleted products (Recycle Bin)\n *\n * @param token - Auth token (required, admin only)\n * @param params - Query parameters for pagination/filtering\n * @param options - React Query options\n * @returns Query result with deleted products\n *\n * @example\n * ```tsx\n * function RecycleBin() {\n * const { data, isLoading } = useDeletedProducts(token, { page: 1, limit: 20 });\n *\n * if (isLoading) return <Spinner />;\n *\n * return (\n * <div>\n * {data?.docs?.map(product => (\n * <DeletedProductRow key={product._id} product={product} />\n * ))}\n * </div>\n * );\n * }\n * ```\n */\nexport function useDeletedProducts(\n token: string,\n params: Record<string, unknown> = {},\n options: Omit<UseQueryOptions<PaginatedResponse<Product>>, \"queryKey\" | \"queryFn\"> = {}\n) {\n return useQuery<PaginatedResponse<Product>>({\n queryKey: [...PRODUCT_KEYS.all, \"deleted\", params],\n queryFn: () => productApi.getDeleted({ token, params }),\n enabled: !!token,\n staleTime: 2 * 60 * 1000, // 2 minutes\n ...options,\n });\n}\n\n/**\n * Hook to restore a soft-deleted product\n *\n * @param token - Auth token (required, admin only)\n * @returns Mutation result with restore function\n *\n * @example\n * ```tsx\n * function RestoreButton({ productId }) {\n * const { mutate: restore, isPending } = useRestoreProduct(token);\n *\n * return (\n * <Button onClick={() => restore(productId)} disabled={isPending}>\n * Restore Product\n * </Button>\n * );\n * }\n * ```\n */\nexport function useRestoreProduct(token: string) {\n const queryClient = useQueryClient();\n const toast = getToastHandler();\n\n return useMutation({\n mutationFn: (id: string) => productApi.restore({ token, id }),\n onSuccess: () => {\n toast.success(\"Product restored successfully\");\n // Invalidate both deleted and main product lists\n queryClient.invalidateQueries({ queryKey: [...PRODUCT_KEYS.all, \"deleted\"] });\n queryClient.invalidateQueries({ queryKey: PRODUCT_KEYS.lists() });\n },\n onError: (error: Error) => {\n toast.error(error.message || \"Failed to restore product\");\n },\n });\n}\n\n/**\n * Hook to permanently delete a product (Hard delete)\n *\n * @param token - Auth token (required, admin only)\n * @returns Mutation result with hard delete function\n *\n * @example\n * ```tsx\n * function PermanentDeleteButton({ productId }) {\n * const { mutate: hardDelete, isPending } = useHardDeleteProduct(token);\n *\n * return (\n * <Button\n * variant=\"destructive\"\n * onClick={() => hardDelete(productId)}\n * disabled={isPending}\n * >\n * Permanently Delete\n * </Button>\n * );\n * }\n * ```\n */\nexport function useHardDeleteProduct(token: string) {\n const queryClient = useQueryClient();\n const toast = getToastHandler();\n\n return useMutation({\n mutationFn: (id: string) => productApi.hardDelete({ token, id }),\n onSuccess: () => {\n toast.success(\"Product permanently deleted\");\n // Invalidate deleted products list\n queryClient.invalidateQueries({ queryKey: [...PRODUCT_KEYS.all, \"deleted\"] });\n },\n onError: (error: Error) => {\n toast.error(error.message || \"Failed to permanently delete product\");\n },\n });\n}\n\n/**\n * Hook to sync product stock quantity\n *\n * Recomputes product.quantity by summing all StockEntry quantities across branches.\n *\n * @param token - Auth token (requires: admin, warehouse-admin, warehouse-staff, or store-manager role)\n * @returns Mutation result with sync function\n *\n * @example\n * ```tsx\n * function SyncStockButton({ productId }) {\n * const { mutate: syncStock, isPending } = useSyncProductStock(token);\n *\n * return (\n * <Button onClick={() => syncStock(productId)} disabled={isPending}>\n * Sync Stock\n * </Button>\n * );\n * }\n * ```\n */\nexport function useSyncProductStock(token: string) {\n const queryClient = useQueryClient();\n const toast = getToastHandler();\n\n return useMutation<ProductSyncStockResponse, Error, string>({\n mutationFn: (id: string) => productApi.syncStock({ token, id }),\n onSuccess: (result, id) => {\n toast.success(`Stock synced: ${result.totalQuantity} units`);\n // Invalidate product detail to refresh quantity\n queryClient.invalidateQueries({ queryKey: PRODUCT_KEYS.detail(id) });\n queryClient.invalidateQueries({ queryKey: PRODUCT_KEYS.lists() });\n },\n onError: (error: Error) => {\n toast.error(error.message || \"Failed to sync stock\");\n },\n });\n}\n","\"use client\";\n\n/**\n * Category Hooks\n *\n * Pre-built hooks for category CRUD operations with:\n * - Category tree support\n * - Optimistic updates\n * - Smart caching\n * - Type safety\n */\n\nimport { useQuery, useMutation, useQueryClient, type UseQueryOptions } from \"@tanstack/react-query\";\nimport { createCrudHooks, type CrudApi, getToastHandler } from \"../../core/react\";\nimport { categoryApi } from \"../api\";\nimport type {\n Category,\n CategoryTreeNode,\n CreateCategoryPayload,\n UpdateCategoryPayload,\n CategoryTreeResponse,\n} from \"../types\";\nimport type { ApiResponse } from \"../../core\";\n\n// Type helper for API compatibility\ntype AnyApi = CrudApi<any, any, any>;\n\n// ============================================\n// Types\n// ============================================\n\ninterface FlattenedNode extends CategoryTreeNode {\n depth: number;\n displayName: string;\n}\n\ninterface SelectOption {\n value: string;\n label: string;\n}\n\n// ============================================\n// CRUD Hooks (Factory-generated)\n// ============================================\n\n/**\n * Category CRUD hooks\n */\nexport const categoryHooks = createCrudHooks<Category, CreateCategoryPayload, UpdateCategoryPayload>({\n api: categoryApi as AnyApi,\n entityKey: \"categories\",\n singular: \"Category\",\n plural: \"Categories\",\n defaults: {\n staleTime: 10 * 60 * 1000, // 10 minutes\n },\n});\n\nexport const {\n KEYS: CATEGORY_KEYS,\n useList: useCategories,\n useDetail: useCategoryDetail,\n useActions: useCategoryActions,\n useNavigation: useCategoryNavigation,\n} = categoryHooks;\n\n// ============================================\n// Custom Category Hooks\n// ============================================\n\n/**\n * Hook to get category tree (nested structure)\n * FE should cache this and derive everything else from it\n *\n * @param token - Auth token (optional for public access)\n * @param options - React Query options\n * @returns Query result with tree data\n *\n * @example\n * ```tsx\n * function CategoryNav() {\n * const { data, isLoading } = useCategoryTree(token);\n *\n * if (isLoading) return <Spinner />;\n *\n * return (\n * <nav>\n * {data?.data?.map(category => (\n * <CategoryItem key={category.slug} category={category} />\n * ))}\n * </nav>\n * );\n * }\n * ```\n */\nexport function useCategoryTree(\n token?: string | null,\n options: Omit<UseQueryOptions<CategoryTreeResponse>, \"queryKey\" | \"queryFn\"> = {}\n) {\n return useQuery<CategoryTreeResponse>({\n queryKey: [...CATEGORY_KEYS.all, \"tree\"],\n queryFn: () => categoryApi.getTree({ token }),\n staleTime: 30 * 60 * 1000, // 30 minutes (categories rarely change)\n gcTime: 60 * 60 * 1000, // 60 minutes\n ...options,\n });\n}\n\n/**\n * Hook to get category by slug\n *\n * @param token - Auth token (optional for public access)\n * @param slug - Category slug\n * @param options - React Query options\n * @returns Query result with category data\n *\n * @example\n * ```tsx\n * function CategoryPage({ slug }) {\n * const { data, isLoading } = useCategoryBySlug(token, slug);\n *\n * if (isLoading) return <Spinner />;\n *\n * return <h1>{data?.data?.name}</h1>;\n * }\n * ```\n */\nexport function useCategoryBySlug(\n token: string | null | undefined,\n slug: string,\n options: Omit<UseQueryOptions<ApiResponse<Category>>, \"queryKey\" | \"queryFn\"> = {}\n) {\n return useQuery<ApiResponse<Category>>({\n queryKey: [...CATEGORY_KEYS.all, \"slug\", slug],\n queryFn: () => categoryApi.getBySlug({ token, slug }),\n enabled: !!slug,\n staleTime: 30 * 60 * 1000, // 30 minutes\n ...options,\n });\n}\n\n/**\n * Hook to sync product counts for all categories\n * POST /categories/sync-product-count\n *\n * Use when manual data fixes or migrations may have desynced counts.\n *\n * @param token - Auth token (admin or inventory staff required)\n * @returns Mutation result with sync function\n *\n * @example\n * ```tsx\n * function AdminPanel() {\n * const { mutate: sync, isPending } = useCategorySyncProductCount(token);\n *\n * return (\n * <Button onClick={() => sync()} disabled={isPending}>\n * Sync Product Counts\n * </Button>\n * );\n * }\n * ```\n */\nexport function useCategorySyncProductCount(token: string) {\n const queryClient = useQueryClient();\n const toast = getToastHandler();\n\n return useMutation({\n mutationFn: () => categoryApi.syncProductCount({ token }),\n onSuccess: (result) => {\n const count = result?.data?.updated ?? 0;\n toast.success(`Synced product counts for ${count} categories`);\n // Invalidate category queries to refresh counts\n queryClient.invalidateQueries({ queryKey: CATEGORY_KEYS.all });\n },\n onError: (error: Error) => {\n toast.error(error.message || \"Failed to sync product counts\");\n },\n });\n}\n\n// ============================================\n// Helper Functions\n// ============================================\n\n/**\n * Flatten category tree with depth indicator\n * Useful for building hierarchical selects\n *\n * @param nodes - Category tree nodes\n * @param depth - Current depth (used recursively)\n * @param result - Accumulator array (used recursively)\n * @returns Flattened array with depth and displayName\n *\n * @example\n * ```typescript\n * const { data } = useCategoryTree(token);\n * const flat = flattenCategoryTree(data?.data);\n * // flat = [\n * // { slug: 'clothing', displayName: 'Clothing', depth: 0, ... },\n * // { slug: 't-shirts', displayName: ' T-Shirts', depth: 1, ... },\n * // ]\n * ```\n */\nexport function flattenCategoryTree(\n nodes: CategoryTreeNode[] | undefined,\n depth = 0,\n result: FlattenedNode[] = []\n): FlattenedNode[] {\n for (const node of nodes || []) {\n result.push({\n ...node,\n depth,\n displayName: \"\\u00A0\\u00A0\".repeat(depth) + node.name,\n });\n if (node.children?.length) {\n flattenCategoryTree(node.children, depth + 1, result);\n }\n }\n return result;\n}\n\n/**\n * Build parent category options for select (root categories only)\n *\n * @param tree - Category tree from useCategoryTree\n * @returns Options array with value/label for select inputs\n *\n * @example\n * ```tsx\n * function ParentSelect() {\n * const { data } = useCategoryTree(token);\n * const options = getParentCategoryOptions(data?.data);\n *\n * return (\n * <Select>\n * {options.map(opt => (\n * <SelectItem key={opt.value} value={opt.value}>\n * {opt.label}\n * </SelectItem>\n * ))}\n * </Select>\n * );\n * }\n * ```\n */\nexport function getParentCategoryOptions(tree: CategoryTreeNode[] | undefined): SelectOption[] {\n return (tree || []).map((node) => ({\n value: node.slug,\n label: node.name,\n }));\n}\n\n/**\n * Build all category options for select (flattened with hierarchy)\n *\n * @param tree - Category tree from useCategoryTree\n * @returns Options array with value/label showing hierarchy\n *\n * @example\n * ```tsx\n * function CategorySelect() {\n * const { data } = useCategoryTree(token);\n * const options = getAllCategoryOptions(data?.data);\n *\n * return (\n * <Select>\n * {options.map(opt => (\n * <SelectItem key={opt.value} value={opt.value}>\n * {opt.label}\n * </SelectItem>\n * ))}\n * </Select>\n * );\n * }\n * ```\n */\nexport function getAllCategoryOptions(tree: CategoryTreeNode[] | undefined): SelectOption[] {\n return flattenCategoryTree(tree).map((node) => ({\n value: node.slug,\n label: node.displayName,\n }));\n}\n\n/**\n * Find a category in the tree by slug\n *\n * @param tree - Category tree nodes\n * @param slug - Category slug to find\n * @returns Category node or undefined\n */\nexport function findCategoryBySlug(\n tree: CategoryTreeNode[] | undefined,\n slug: string\n): CategoryTreeNode | undefined {\n if (!tree || !slug) return undefined;\n\n for (const node of tree) {\n if (node.slug === slug) return node;\n if (node.children?.length) {\n const found = findCategoryBySlug(node.children, slug);\n if (found) return found;\n }\n }\n return undefined;\n}\n\n/**\n * Get breadcrumb path for a category\n *\n * @param tree - Category tree nodes\n * @param slug - Category slug\n * @returns Array of categories from root to target\n */\nexport function getCategoryBreadcrumb(\n tree: CategoryTreeNode[] | undefined,\n slug: string\n): CategoryTreeNode[] {\n if (!tree || !slug) return [];\n\n function findPath(\n nodes: CategoryTreeNode[],\n target: string,\n path: CategoryTreeNode[] = []\n ): CategoryTreeNode[] | null {\n for (const node of nodes) {\n const currentPath = [...path, node];\n if (node.slug === target) return currentPath;\n if (node.children?.length) {\n const found = findPath(node.children, target, currentPath);\n if (found) return found;\n }\n }\n return null;\n }\n\n return findPath(tree, slug) || [];\n}\n\n/**\n * Get all children slugs for a category (recursive)\n *\n * @param tree - Category tree nodes\n * @param parentSlug - Parent category slug\n * @returns Array of child category slugs\n */\nexport function getChildCategorySlugs(\n tree: CategoryTreeNode[] | undefined,\n parentSlug: string\n): string[] {\n const parent = findCategoryBySlug(tree, parentSlug);\n if (!parent?.children?.length) return [];\n\n const slugs: string[] = [];\n\n function collectSlugs(nodes: CategoryTreeNode[]) {\n for (const node of nodes) {\n slugs.push(node.slug);\n if (node.children?.length) {\n collectSlugs(node.children);\n }\n }\n }\n\n collectSlugs(parent.children);\n return slugs;\n}\n\n/**\n * Get root categories only\n *\n * @param tree - Category tree nodes\n * @returns Array of root category nodes\n */\nexport function getRootCategories(tree: CategoryTreeNode[] | undefined): CategoryTreeNode[] {\n return tree || [];\n}\n","\"use client\";\n\n/**\n * Size Guide Hooks\n *\n * Pre-built hooks for size guide CRUD operations with:\n * - Optimistic updates\n * - Smart caching\n * - Type safety\n */\n\nimport { useQuery, type UseQueryOptions } from \"@tanstack/react-query\";\nimport { createCrudHooks, type CrudApi } from \"../../core/react\";\nimport { sizeGuideApi } from \"../api\";\nimport type {\n SizeGuide,\n CreateSizeGuidePayload,\n UpdateSizeGuidePayload,\n} from \"../types\";\nimport type { ApiResponse } from \"../../core\";\n\n// Type helper for API compatibility\ntype AnyApi = CrudApi<any, any, any>;\n\n// ============================================\n// CRUD Hooks (Factory-generated)\n// ============================================\n\n/**\n * Size Guide CRUD hooks\n */\nexport const sizeGuideHooks = createCrudHooks<SizeGuide, CreateSizeGuidePayload, UpdateSizeGuidePayload>({\n api: sizeGuideApi as AnyApi,\n entityKey: \"size-guides\",\n singular: \"Size Guide\",\n plural: \"Size Guides\",\n defaults: {\n staleTime: 30 * 60 * 1000, // 30 minutes (size guides change rarely)\n },\n});\n\nexport const {\n KEYS: SIZE_GUIDE_KEYS,\n useList: useSizeGuides,\n useDetail: useSizeGuideDetail,\n useActions: useSizeGuideActions,\n useNavigation: useSizeGuideNavigation,\n} = sizeGuideHooks;\n\n// ============================================\n// Custom Size Guide Hooks\n// ============================================\n\n/**\n * Hook to get size guide by slug\n *\n * @param token - Auth token (optional for public access)\n * @param slug - Size guide slug\n * @param options - React Query options\n * @returns Query result with size guide data\n *\n * @example\n * ```tsx\n * function SizeGuideDisplay({ slug }) {\n * const { data, isLoading } = useSizeGuideBySlug(null, slug);\n *\n * if (isLoading) return <Spinner />;\n *\n * return (\n * <div>\n * <h2>{data?.data?.name}</h2>\n * <SizeTable guide={data?.data} />\n * </div>\n * );\n * }\n * ```\n */\nexport function useSizeGuideBySlug(\n token: string | null | undefined,\n slug: string,\n options: Omit<UseQueryOptions<ApiResponse<SizeGuide>>, \"queryKey\" | \"queryFn\"> = {}\n) {\n return useQuery<ApiResponse<SizeGuide>>({\n queryKey: [...SIZE_GUIDE_KEYS.all, \"slug\", slug],\n queryFn: () => sizeGuideApi.getBySlug({ token, slug }),\n enabled: !!slug,\n staleTime: 30 * 60 * 1000, // 30 minutes\n ...options,\n });\n}\n\n// ============================================\n// Helper Functions\n// ============================================\n\n/**\n * Format size guide as select options\n *\n * @param sizeGuides - Array of size guides\n * @returns Options array with value/label for select inputs\n *\n * @example\n * ```tsx\n * function SizeGuideSelect() {\n * const { data } = useSizeGuides(token);\n * const options = getSizeGuideOptions(data?.docs);\n *\n * return (\n * <Select>\n * {options.map(opt => (\n * <SelectItem key={opt.value} value={opt.value}>\n * {opt.label}\n * </SelectItem>\n * ))}\n * </Select>\n * );\n * }\n * ```\n */\nexport function getSizeGuideOptions(sizeGuides: SizeGuide[] | undefined): { value: string; label: string }[] {\n return (sizeGuides || []).map((guide) => ({\n value: guide._id,\n label: guide.name,\n }));\n}\n\n/**\n * Get size guide by ID from a list\n *\n * @param sizeGuides - Array of size guides\n * @param id - Size guide ID\n * @returns Size guide or undefined\n */\nexport function findSizeGuideById(\n sizeGuides: SizeGuide[] | undefined,\n id: string\n): SizeGuide | undefined {\n return sizeGuides?.find((guide) => guide._id === id);\n}\n\n/**\n * Get size guide by slug from a list\n *\n * @param sizeGuides - Array of size guides\n * @param slug - Size guide slug\n * @returns Size guide or undefined\n */\nexport function findSizeGuideBySlug(\n sizeGuides: SizeGuide[] | undefined,\n slug: string\n): SizeGuide | undefined {\n return sizeGuides?.find((guide) => guide.slug === slug);\n}\n\n/**\n * Format measurement value with unit\n *\n * @param value - Measurement value\n * @param unit - Measurement unit ('inches' or 'cm')\n * @returns Formatted measurement string\n *\n * @example\n * ```typescript\n * formatMeasurement(\"34-36\", \"inches\") // \"34-36 in\"\n * formatMeasurement(\"88\", \"cm\") // \"88 cm\"\n * ```\n */\nexport function formatMeasurement(value: string, unit: 'inches' | 'cm'): string {\n const unitLabel = unit === 'inches' ? 'in' : 'cm';\n return `${value} ${unitLabel}`;\n}\n\n/**\n * Get measurement labels as table headers\n *\n * @param guide - Size guide object\n * @returns Array of header labels including \"Size\" as first column\n *\n * @example\n * ```typescript\n * const headers = getSizeTableHeaders(sizeGuide);\n * // [\"Size\", \"Chest\", \"Length\", \"Shoulder\"]\n * ```\n */\nexport function getSizeTableHeaders(guide: SizeGuide | undefined): string[] {\n if (!guide?.measurementLabels) return [\"Size\"];\n return [\"Size\", ...guide.measurementLabels];\n}\n\n/**\n * Get size table rows\n *\n * @param guide - Size guide object\n * @returns Array of row data with size name and measurements\n *\n * @example\n * ```typescript\n * const rows = getSizeTableRows(sizeGuide);\n * // [\n * // { name: \"S\", measurements: { chest: \"34-36\", length: \"28\" } },\n * // { name: \"M\", measurements: { chest: \"38-40\", length: \"29\" } },\n * // ]\n * ```\n */\nexport function getSizeTableRows(guide: SizeGuide | undefined): Array<{\n name: string;\n measurements: Record<string, string>;\n}> {\n if (!guide?.sizes) return [];\n return guide.sizes.map((size) => ({\n name: size.name,\n measurements: size.measurements,\n }));\n}\n"]}
@@ -0,0 +1,534 @@
1
+ import { getToastHandler } from './chunk-U3XT35GZ.js';
2
+ import { handleApiRequest } from './chunk-VR36QVX2.js';
3
+ import { useQuery, useQueryClient, useMutation } from '@tanstack/react-query';
4
+
5
+ // src/content/api/cms.ts
6
+ var CMS_BASE = "/api/v1/cms";
7
+ async function getCmsPage({
8
+ slug,
9
+ options = {}
10
+ }) {
11
+ if (!slug) throw new Error("Slug is required");
12
+ try {
13
+ return await handleApiRequest(
14
+ "GET",
15
+ `${CMS_BASE}/${slug}`,
16
+ options
17
+ );
18
+ } catch (error) {
19
+ if (error instanceof Error && error.message.includes("Document not found")) {
20
+ return {
21
+ success: false,
22
+ data: null,
23
+ message: "CMS page not found, using static fallback"
24
+ };
25
+ }
26
+ throw error;
27
+ }
28
+ }
29
+ async function updateCmsPage({
30
+ slug,
31
+ token,
32
+ data,
33
+ options = {}
34
+ }) {
35
+ if (!slug) throw new Error("Slug is required");
36
+ return handleApiRequest(
37
+ "PATCH",
38
+ `${CMS_BASE}/${slug}`,
39
+ { token, body: data, ...options }
40
+ );
41
+ }
42
+
43
+ // src/content/api/media.ts
44
+ var MediaApi = class {
45
+ constructor(config = {}) {
46
+ this.baseUrl = `${config.basePath || "/api/v1"}/media`;
47
+ this.defaultCache = config.cache || "no-store";
48
+ }
49
+ /**
50
+ * Upload single file
51
+ * POST /api/media/upload
52
+ *
53
+ * @example
54
+ * const file = event.target.files[0];
55
+ * const result = await mediaApi.upload({
56
+ * token: 'xxx',
57
+ * file,
58
+ * folder: 'products',
59
+ * alt: 'Product image'
60
+ * });
61
+ */
62
+ async upload({
63
+ token,
64
+ file,
65
+ folder,
66
+ alt,
67
+ title,
68
+ options = {}
69
+ }) {
70
+ const formData = new FormData();
71
+ if (folder) formData.append("folder", folder);
72
+ if (alt) formData.append("alt", alt);
73
+ if (title) formData.append("title", title);
74
+ formData.append("file", file);
75
+ return handleApiRequest("POST", `${this.baseUrl}/upload`, {
76
+ token,
77
+ body: formData,
78
+ cache: this.defaultCache,
79
+ ...options
80
+ });
81
+ }
82
+ /**
83
+ * Upload multiple files (max 20)
84
+ * POST /api/media/upload-multiple
85
+ *
86
+ * @example
87
+ * const files = Array.from(event.target.files);
88
+ * const result = await mediaApi.uploadMultiple({
89
+ * token: 'xxx',
90
+ * files,
91
+ * folder: 'products'
92
+ * });
93
+ */
94
+ async uploadMultiple({
95
+ token,
96
+ files,
97
+ folder,
98
+ options = {}
99
+ }) {
100
+ const formData = new FormData();
101
+ if (folder) formData.append("folder", folder);
102
+ files.forEach((file) => formData.append("files[]", file));
103
+ return handleApiRequest("POST", `${this.baseUrl}/upload-multiple`, {
104
+ token,
105
+ body: formData,
106
+ cache: this.defaultCache,
107
+ ...options
108
+ });
109
+ }
110
+ /**
111
+ * Get all media with filtering
112
+ * GET /api/media
113
+ *
114
+ * @example
115
+ * const result = await mediaApi.getAll({
116
+ * token: 'xxx',
117
+ * params: {
118
+ * folder: 'products',
119
+ * search: 'shirt',
120
+ * limit: 20,
121
+ * sort: '-createdAt'
122
+ * }
123
+ * });
124
+ */
125
+ async getAll({
126
+ token,
127
+ params = {},
128
+ options = {}
129
+ } = {}) {
130
+ const cleanParams = Object.fromEntries(
131
+ Object.entries(params).filter(([, v]) => v !== void 0 && v !== null)
132
+ );
133
+ const queryString = new URLSearchParams(
134
+ cleanParams
135
+ ).toString();
136
+ const url = queryString ? `${this.baseUrl}?${queryString}` : this.baseUrl;
137
+ return handleApiRequest("GET", url, {
138
+ token,
139
+ cache: this.defaultCache,
140
+ ...options
141
+ });
142
+ }
143
+ /**
144
+ * Get single media by ID
145
+ * GET /api/media/:id
146
+ *
147
+ * @example
148
+ * const result = await mediaApi.getById({ token: 'xxx', id: '123abc' });
149
+ */
150
+ async getById({
151
+ token,
152
+ id,
153
+ options = {}
154
+ }) {
155
+ if (!id) throw new Error("ID is required");
156
+ return handleApiRequest("GET", `${this.baseUrl}/${id}`, {
157
+ token,
158
+ cache: this.defaultCache,
159
+ ...options
160
+ });
161
+ }
162
+ /**
163
+ * Update media metadata (alt, title)
164
+ * PATCH /api/media/:id
165
+ *
166
+ * @example
167
+ * await mediaApi.update({
168
+ * token: 'xxx',
169
+ * id: '123',
170
+ * data: { alt: 'New alt text', title: 'New title' }
171
+ * });
172
+ */
173
+ async update({
174
+ token,
175
+ id,
176
+ data,
177
+ options = {}
178
+ }) {
179
+ if (!id) throw new Error("ID is required");
180
+ return handleApiRequest("PATCH", `${this.baseUrl}/${id}`, {
181
+ token,
182
+ body: data,
183
+ cache: this.defaultCache,
184
+ ...options
185
+ });
186
+ }
187
+ /**
188
+ * Delete single media
189
+ * DELETE /api/media/:id
190
+ *
191
+ * @example
192
+ * await mediaApi.delete({ token: 'xxx', id: '123' });
193
+ */
194
+ async delete({
195
+ token,
196
+ id,
197
+ options = {}
198
+ }) {
199
+ if (!id) throw new Error("ID is required");
200
+ return handleApiRequest("DELETE", `${this.baseUrl}/${id}`, {
201
+ token,
202
+ cache: this.defaultCache,
203
+ ...options
204
+ });
205
+ }
206
+ /**
207
+ * Bulk delete multiple files
208
+ * POST /api/media/bulk-delete
209
+ *
210
+ * @example
211
+ * await mediaApi.bulkDelete({
212
+ * token: 'xxx',
213
+ * ids: ['123', '456', '789']
214
+ * });
215
+ */
216
+ async bulkDelete({
217
+ token,
218
+ ids,
219
+ options = {}
220
+ }) {
221
+ if (!ids.length) throw new Error("IDs array is required");
222
+ return handleApiRequest("POST", `${this.baseUrl}/bulk-delete`, {
223
+ token,
224
+ body: { ids },
225
+ cache: this.defaultCache,
226
+ ...options
227
+ });
228
+ }
229
+ /**
230
+ * Move files to different folder
231
+ * POST /api/media/move
232
+ *
233
+ * @example
234
+ * await mediaApi.moveToFolder({
235
+ * token: 'xxx',
236
+ * ids: ['123', '456'],
237
+ * targetFolder: 'banners'
238
+ * });
239
+ */
240
+ async moveToFolder({
241
+ token,
242
+ data,
243
+ options = {}
244
+ }) {
245
+ if (!data.ids.length) throw new Error("IDs array is required");
246
+ if (!data.targetFolder) throw new Error("Target folder is required");
247
+ return handleApiRequest("POST", `${this.baseUrl}/move`, {
248
+ token,
249
+ body: data,
250
+ cache: this.defaultCache,
251
+ ...options
252
+ });
253
+ }
254
+ /**
255
+ * Get allowed folders
256
+ * GET /api/media/folders
257
+ *
258
+ * @example
259
+ * const result = await mediaApi.getFolders({ token: 'xxx' });
260
+ * // result.data = ['general', 'products', 'categories', ...]
261
+ */
262
+ async getFolders({
263
+ token,
264
+ options = {}
265
+ }) {
266
+ return handleApiRequest("GET", `${this.baseUrl}/folders`, {
267
+ token,
268
+ cache: this.defaultCache,
269
+ ...options
270
+ });
271
+ }
272
+ /**
273
+ * Helper: Get variant URL by name
274
+ * Falls back to original URL if variant not found
275
+ *
276
+ * @example
277
+ * const thumbnailUrl = mediaApi.getVariantUrl(media, 'thumbnail');
278
+ * <img src={thumbnailUrl} />
279
+ */
280
+ getVariantUrl(media, variantName) {
281
+ return media.variants?.find((v) => v.name === variantName)?.url || media.url;
282
+ }
283
+ /**
284
+ * Helper: Get thumbnail URL
285
+ */
286
+ getThumbnailUrl(media) {
287
+ return this.getVariantUrl(media, "thumbnail");
288
+ }
289
+ /**
290
+ * Helper: Get medium URL
291
+ */
292
+ getMediumUrl(media) {
293
+ return this.getVariantUrl(media, "medium");
294
+ }
295
+ };
296
+ var mediaApi = new MediaApi();
297
+ var MEDIA_KEYS = {
298
+ all: ["media"],
299
+ lists: () => [...MEDIA_KEYS.all, "list"],
300
+ list: (params) => [...MEDIA_KEYS.lists(), params],
301
+ details: () => [...MEDIA_KEYS.all, "detail"],
302
+ detail: (id) => [...MEDIA_KEYS.details(), id],
303
+ folders: () => [...MEDIA_KEYS.all, "folders"]
304
+ };
305
+ function useMediaList(token, params = {}, options = {}) {
306
+ const {
307
+ enabled = true,
308
+ staleTime = 2 * 60 * 1e3,
309
+ gcTime = 5 * 60 * 1e3,
310
+ refetchOnWindowFocus = false
311
+ } = options;
312
+ return useQuery({
313
+ queryKey: MEDIA_KEYS.list(params),
314
+ queryFn: () => mediaApi.getAll({ token, params }),
315
+ enabled: enabled && !!token,
316
+ staleTime,
317
+ gcTime,
318
+ refetchOnWindowFocus
319
+ });
320
+ }
321
+ function useMediaDetail(token, id, options = {}) {
322
+ const { enabled = true, staleTime = 2 * 60 * 1e3, gcTime = 5 * 60 * 1e3 } = options;
323
+ return useQuery({
324
+ queryKey: MEDIA_KEYS.detail(id),
325
+ queryFn: () => mediaApi.getById({ token, id }),
326
+ enabled: enabled && !!token && !!id,
327
+ staleTime,
328
+ gcTime
329
+ });
330
+ }
331
+ function useMediaFolders(token, options = {}) {
332
+ const { enabled = true, staleTime = 10 * 60 * 1e3, gcTime = 15 * 60 * 1e3 } = options;
333
+ return useQuery({
334
+ queryKey: MEDIA_KEYS.folders(),
335
+ queryFn: () => mediaApi.getFolders({ token }),
336
+ enabled: enabled && !!token,
337
+ staleTime,
338
+ gcTime
339
+ });
340
+ }
341
+ function useMediaUpload(token) {
342
+ const queryClient = useQueryClient();
343
+ const toast = getToastHandler();
344
+ const mutation = useMutation({
345
+ mutationFn: async ({ files, folder }) => {
346
+ const response = await mediaApi.uploadMultiple({ token, files, folder });
347
+ return response.data;
348
+ },
349
+ onSuccess: () => {
350
+ queryClient.invalidateQueries({ queryKey: MEDIA_KEYS.lists() });
351
+ toast.success("Media uploaded successfully");
352
+ },
353
+ onError: (error) => {
354
+ toast.error(error.message || "Failed to upload media");
355
+ }
356
+ });
357
+ return {
358
+ upload: (params) => mutation.mutate(params),
359
+ uploadAsync: (params) => mutation.mutateAsync(params),
360
+ isUploading: mutation.isPending,
361
+ error: mutation.error
362
+ };
363
+ }
364
+ function useMediaBulkDelete(token) {
365
+ const queryClient = useQueryClient();
366
+ const toast = getToastHandler();
367
+ const mutation = useMutation({
368
+ mutationFn: async (ids) => {
369
+ const response = await mediaApi.bulkDelete({ token, ids });
370
+ return response.data;
371
+ },
372
+ onMutate: async (ids) => {
373
+ await queryClient.cancelQueries({ queryKey: MEDIA_KEYS.lists() });
374
+ const previousLists = queryClient.getQueriesData({ queryKey: MEDIA_KEYS.lists() });
375
+ queryClient.setQueriesData({ queryKey: MEDIA_KEYS.lists() }, (old) => {
376
+ const data = old;
377
+ if (!data?.docs) return old;
378
+ return {
379
+ ...data,
380
+ docs: data.docs.filter((item) => !ids.includes(item._id)),
381
+ total: (data.total || 0) - ids.length
382
+ };
383
+ });
384
+ return { previousLists };
385
+ },
386
+ onError: (_error, _ids, context) => {
387
+ if (context?.previousLists) {
388
+ context.previousLists.forEach(([queryKey, data]) => {
389
+ queryClient.setQueryData(queryKey, data);
390
+ });
391
+ }
392
+ toast.error("Failed to delete media");
393
+ },
394
+ onSuccess: (data) => {
395
+ const deletedCount = data.success.length;
396
+ toast.success(`${deletedCount} item(s) deleted successfully`);
397
+ },
398
+ onSettled: () => {
399
+ queryClient.invalidateQueries({ queryKey: MEDIA_KEYS.lists() });
400
+ }
401
+ });
402
+ return {
403
+ bulkDelete: (ids) => mutation.mutate(ids),
404
+ bulkDeleteAsync: (ids) => mutation.mutateAsync(ids),
405
+ isDeleting: mutation.isPending,
406
+ error: mutation.error
407
+ };
408
+ }
409
+ function useMediaMove(token) {
410
+ const queryClient = useQueryClient();
411
+ const toast = getToastHandler();
412
+ const mutation = useMutation({
413
+ mutationFn: async (data) => {
414
+ const response = await mediaApi.moveToFolder({ token, data });
415
+ return response.data;
416
+ },
417
+ onSuccess: (data, variables) => {
418
+ queryClient.invalidateQueries({ queryKey: MEDIA_KEYS.lists() });
419
+ toast.success(`${data.modifiedCount} item(s) moved to ${variables.targetFolder}`);
420
+ },
421
+ onError: (error) => {
422
+ toast.error(error.message || "Failed to move media");
423
+ }
424
+ });
425
+ return {
426
+ move: (data) => mutation.mutate(data),
427
+ moveAsync: (data) => mutation.mutateAsync(data),
428
+ isMoving: mutation.isPending,
429
+ error: mutation.error
430
+ };
431
+ }
432
+ function useMediaUpdate(token) {
433
+ const queryClient = useQueryClient();
434
+ const toast = getToastHandler();
435
+ const mutation = useMutation({
436
+ mutationFn: async ({ id, data }) => {
437
+ const response = await mediaApi.update({ token, id, data });
438
+ return response.data;
439
+ },
440
+ onMutate: async ({ id, data }) => {
441
+ await queryClient.cancelQueries({ queryKey: MEDIA_KEYS.detail(id) });
442
+ const previous = queryClient.getQueryData(MEDIA_KEYS.detail(id));
443
+ queryClient.setQueryData(MEDIA_KEYS.detail(id), (old) => ({
444
+ ...old,
445
+ ...data
446
+ }));
447
+ return { previous, id };
448
+ },
449
+ onError: (_error, _variables, context) => {
450
+ if (context?.previous) {
451
+ queryClient.setQueryData(MEDIA_KEYS.detail(context.id), context.previous);
452
+ }
453
+ toast.error("Failed to update media");
454
+ },
455
+ onSuccess: () => {
456
+ toast.success("Media updated successfully");
457
+ },
458
+ onSettled: (_data, _error, variables) => {
459
+ queryClient.invalidateQueries({ queryKey: MEDIA_KEYS.detail(variables.id) });
460
+ queryClient.invalidateQueries({ queryKey: MEDIA_KEYS.lists() });
461
+ }
462
+ });
463
+ return {
464
+ update: (params) => mutation.mutate(params),
465
+ updateAsync: (params) => mutation.mutateAsync(params),
466
+ isUpdating: mutation.isPending,
467
+ error: mutation.error
468
+ };
469
+ }
470
+ function getMediaVariantUrl(media, variantName) {
471
+ return media.variants?.find((v) => v.name === variantName)?.url || media.url;
472
+ }
473
+ function getMediaThumbnailUrl(media) {
474
+ return getMediaVariantUrl(media, "thumbnail");
475
+ }
476
+ function getMediaMediumUrl(media) {
477
+ return getMediaVariantUrl(media, "medium");
478
+ }
479
+ var CMS_KEYS = {
480
+ all: ["cms"],
481
+ page: (slug) => [...CMS_KEYS.all, slug]
482
+ };
483
+ function useCMSPage(slug, options = {}) {
484
+ const { data, isLoading, isFetching, error, refetch } = useQuery({
485
+ queryKey: CMS_KEYS.page(slug),
486
+ queryFn: async () => {
487
+ const response = await getCmsPage({ slug });
488
+ return response.data;
489
+ },
490
+ enabled: !!slug && options.enabled !== false,
491
+ staleTime: options.staleTime ?? 5 * 60 * 1e3
492
+ // 5 minutes
493
+ });
494
+ return {
495
+ page: data || null,
496
+ isLoading,
497
+ isFetching,
498
+ error,
499
+ refetch
500
+ };
501
+ }
502
+ function useCMSUpdate(token) {
503
+ const queryClient = useQueryClient();
504
+ const toast = getToastHandler();
505
+ const mutation = useMutation({
506
+ mutationFn: async ({ slug, data }) => {
507
+ const response = await updateCmsPage({ slug, token, data });
508
+ return response.data;
509
+ },
510
+ onSuccess: (_, { slug }) => {
511
+ queryClient.invalidateQueries({ queryKey: CMS_KEYS.page(slug) });
512
+ toast.success("Page saved successfully");
513
+ if (typeof window !== "undefined") {
514
+ fetch("/revalidate", {
515
+ method: "POST",
516
+ headers: { "Content-Type": "application/json" },
517
+ body: JSON.stringify({ slug, type: "both" })
518
+ }).catch(() => {
519
+ });
520
+ }
521
+ },
522
+ onError: (error) => {
523
+ toast.error(error.message || "Failed to save page");
524
+ }
525
+ });
526
+ return {
527
+ updatePage: mutation.mutateAsync,
528
+ isUpdating: mutation.isPending
529
+ };
530
+ }
531
+
532
+ export { CMS_KEYS, MEDIA_KEYS, MediaApi, getCmsPage, getMediaMediumUrl, getMediaThumbnailUrl, getMediaVariantUrl, mediaApi, updateCmsPage, useCMSPage, useCMSUpdate, useMediaBulkDelete, useMediaDetail, useMediaFolders, useMediaList, useMediaMove, useMediaUpdate, useMediaUpload };
533
+ //# sourceMappingURL=chunk-ZWLMFLLH.js.map
534
+ //# sourceMappingURL=chunk-ZWLMFLLH.js.map