@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.
- package/LICENSE +14 -0
- package/README.md +104 -0
- package/dist/adjustment-DTSLM7AN.js +5 -0
- package/dist/adjustment-DTSLM7AN.js.map +1 -0
- package/dist/analytics/index.d.ts +27 -0
- package/dist/analytics/index.js +6 -0
- package/dist/analytics/index.js.map +1 -0
- package/dist/analytics-DMcD-o8w.d.ts +76 -0
- package/dist/api-factory-B_h4RKBm.d.ts +280 -0
- package/dist/auth/index.d.ts +39 -0
- package/dist/auth/index.js +5 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/catalog/index.d.ts +479 -0
- package/dist/catalog/index.js +9 -0
- package/dist/catalog/index.js.map +1 -0
- package/dist/chunk-4ZQK3FFN.js +40 -0
- package/dist/chunk-4ZQK3FFN.js.map +1 -0
- package/dist/chunk-5L6EXDGH.js +465 -0
- package/dist/chunk-5L6EXDGH.js.map +1 -0
- package/dist/chunk-5ZFW3FEI.js +183 -0
- package/dist/chunk-5ZFW3FEI.js.map +1 -0
- package/dist/chunk-66OQAZSL.js +94 -0
- package/dist/chunk-66OQAZSL.js.map +1 -0
- package/dist/chunk-6RYGA6MF.js +123 -0
- package/dist/chunk-6RYGA6MF.js.map +1 -0
- package/dist/chunk-B6MPVOV7.js +328 -0
- package/dist/chunk-B6MPVOV7.js.map +1 -0
- package/dist/chunk-BDA2WSJA.js +148 -0
- package/dist/chunk-BDA2WSJA.js.map +1 -0
- package/dist/chunk-EIVYT3HM.js +126 -0
- package/dist/chunk-EIVYT3HM.js.map +1 -0
- package/dist/chunk-EPQN7ZKZ.js +27 -0
- package/dist/chunk-EPQN7ZKZ.js.map +1 -0
- package/dist/chunk-FA7QFJ2G.js +177 -0
- package/dist/chunk-FA7QFJ2G.js.map +1 -0
- package/dist/chunk-I5TIKUIQ.js +261 -0
- package/dist/chunk-I5TIKUIQ.js.map +1 -0
- package/dist/chunk-ILQUH444.js +135 -0
- package/dist/chunk-ILQUH444.js.map +1 -0
- package/dist/chunk-IXMWZJLV.js +616 -0
- package/dist/chunk-IXMWZJLV.js.map +1 -0
- package/dist/chunk-KZIGRIQG.js +75 -0
- package/dist/chunk-KZIGRIQG.js.map +1 -0
- package/dist/chunk-OF5M6R2S.js +769 -0
- package/dist/chunk-OF5M6R2S.js.map +1 -0
- package/dist/chunk-PYYLHUV6.js +3 -0
- package/dist/chunk-PYYLHUV6.js.map +1 -0
- package/dist/chunk-QO5AGZFP.js +159 -0
- package/dist/chunk-QO5AGZFP.js.map +1 -0
- package/dist/chunk-QUMTBLNE.js +76 -0
- package/dist/chunk-QUMTBLNE.js.map +1 -0
- package/dist/chunk-R5Z7NYLH.js +126 -0
- package/dist/chunk-R5Z7NYLH.js.map +1 -0
- package/dist/chunk-SZYWG5IB.js +75 -0
- package/dist/chunk-SZYWG5IB.js.map +1 -0
- package/dist/chunk-U3XT35GZ.js +202 -0
- package/dist/chunk-U3XT35GZ.js.map +1 -0
- package/dist/chunk-UGELTUIZ.js +830 -0
- package/dist/chunk-UGELTUIZ.js.map +1 -0
- package/dist/chunk-VR36QVX2.js +122 -0
- package/dist/chunk-VR36QVX2.js.map +1 -0
- package/dist/chunk-WUOQK7BO.js +13 -0
- package/dist/chunk-WUOQK7BO.js.map +1 -0
- package/dist/chunk-X6PV5MHG.js +582 -0
- package/dist/chunk-X6PV5MHG.js.map +1 -0
- package/dist/chunk-ZWLMFLLH.js +534 -0
- package/dist/chunk-ZWLMFLLH.js.map +1 -0
- package/dist/content/index.d.ts +309 -0
- package/dist/content/index.js +6 -0
- package/dist/content/index.js.map +1 -0
- package/dist/core/index.d.ts +107 -0
- package/dist/core/index.js +5 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/react.d.ts +107 -0
- package/dist/core/react.js +5 -0
- package/dist/core/react.js.map +1 -0
- package/dist/coupon-CHFcw7cd.d.ts +632 -0
- package/dist/coupon-zGkvO-Xx.d.ts +129 -0
- package/dist/crud.factory-DyKaPHcU.d.ts +181 -0
- package/dist/finance/index.d.ts +81 -0
- package/dist/finance/index.js +5 -0
- package/dist/finance/index.js.map +1 -0
- package/dist/finance-BJdfKRw0.d.ts +135 -0
- package/dist/index.d.ts +31 -0
- package/dist/index.js +29 -0
- package/dist/index.js.map +1 -0
- package/dist/inventory/index.d.ts +512 -0
- package/dist/inventory/index.js +16 -0
- package/dist/inventory/index.js.map +1 -0
- package/dist/inventory-DCiIZh8P.d.ts +742 -0
- package/dist/logistics/index.d.ts +226 -0
- package/dist/logistics/index.js +7 -0
- package/dist/logistics/index.js.map +1 -0
- package/dist/logistics-V8a9lUN3.d.ts +428 -0
- package/dist/media-CNLJK93J.d.ts +721 -0
- package/dist/movement-7MV3ADY5.js +5 -0
- package/dist/movement-7MV3ADY5.js.map +1 -0
- package/dist/payment-BRboLqvU.d.ts +127 -0
- package/dist/payments/index.d.ts +55 -0
- package/dist/payments/index.js +6 -0
- package/dist/payments/index.js.map +1 -0
- package/dist/platform/index.d.ts +645 -0
- package/dist/platform/index.js +8 -0
- package/dist/platform/index.js.map +1 -0
- package/dist/pos-D1jkkFl0.d.ts +885 -0
- package/dist/product-p09zXkXB.d.ts +260 -0
- package/dist/purchase-24BGT2HA.js +5 -0
- package/dist/purchase-24BGT2HA.js.map +1 -0
- package/dist/request-652PS6VR.js +5 -0
- package/dist/request-652PS6VR.js.map +1 -0
- package/dist/sales/index.d.ts +585 -0
- package/dist/sales/index.js +9 -0
- package/dist/sales/index.js.map +1 -0
- package/dist/server.d.ts +120 -0
- package/dist/server.js +27 -0
- package/dist/server.js.map +1 -0
- package/dist/size-guide-DgjzjM5P.d.ts +554 -0
- package/dist/stock-DEApGC-w.d.ts +632 -0
- package/dist/stock-OOUW57VQ.js +5 -0
- package/dist/stock-OOUW57VQ.js.map +1 -0
- package/dist/supplier-OC6JAWV6.js +5 -0
- package/dist/supplier-OC6JAWV6.js.map +1 -0
- package/dist/transaction/index.d.ts +104 -0
- package/dist/transaction/index.js +8 -0
- package/dist/transaction/index.js.map +1 -0
- package/dist/transaction-BTmoHpWh.d.ts +428 -0
- package/dist/transaction-u5oaNuav.d.ts +84 -0
- package/dist/transfer-7SYSH3RG.js +5 -0
- package/dist/transfer-7SYSH3RG.js.map +1 -0
- package/dist/user-data-DdLjAGwO.d.ts +132 -0
- package/package.json +146 -0
|
@@ -0,0 +1,830 @@
|
|
|
1
|
+
import { posApi } from './chunk-66OQAZSL.js';
|
|
2
|
+
import { BaseApi } from './chunk-I5TIKUIQ.js';
|
|
3
|
+
import { createQueryKeys, createCrudHooks } from './chunk-B6MPVOV7.js';
|
|
4
|
+
import { getToastHandler } from './chunk-U3XT35GZ.js';
|
|
5
|
+
import { handleApiRequest } from './chunk-VR36QVX2.js';
|
|
6
|
+
import { useQueryClient, useQuery, useMutation } from '@tanstack/react-query';
|
|
7
|
+
|
|
8
|
+
// src/sales/types/order.ts
|
|
9
|
+
var OrderStatus = /* @__PURE__ */ ((OrderStatus2) => {
|
|
10
|
+
OrderStatus2["PENDING"] = "pending";
|
|
11
|
+
OrderStatus2["PROCESSING"] = "processing";
|
|
12
|
+
OrderStatus2["CONFIRMED"] = "confirmed";
|
|
13
|
+
OrderStatus2["SHIPPED"] = "shipped";
|
|
14
|
+
OrderStatus2["DELIVERED"] = "delivered";
|
|
15
|
+
OrderStatus2["CANCELLED"] = "cancelled";
|
|
16
|
+
return OrderStatus2;
|
|
17
|
+
})(OrderStatus || {});
|
|
18
|
+
var PaymentStatus = /* @__PURE__ */ ((PaymentStatus2) => {
|
|
19
|
+
PaymentStatus2["PENDING"] = "pending";
|
|
20
|
+
PaymentStatus2["VERIFIED"] = "verified";
|
|
21
|
+
PaymentStatus2["FAILED"] = "failed";
|
|
22
|
+
PaymentStatus2["REFUNDED"] = "refunded";
|
|
23
|
+
PaymentStatus2["PARTIALLY_REFUNDED"] = "partially_refunded";
|
|
24
|
+
PaymentStatus2["CANCELLED"] = "cancelled";
|
|
25
|
+
return PaymentStatus2;
|
|
26
|
+
})(PaymentStatus || {});
|
|
27
|
+
|
|
28
|
+
// src/sales/api/cart.ts
|
|
29
|
+
var ENDPOINT = "/api/v1/cart";
|
|
30
|
+
var cartApi = {
|
|
31
|
+
/**
|
|
32
|
+
* Get current user's cart
|
|
33
|
+
* GET /api/v1/cart
|
|
34
|
+
*
|
|
35
|
+
* Auto-creates cart if it doesn't exist for the user.
|
|
36
|
+
* Returns cart with fully populated product details.
|
|
37
|
+
*
|
|
38
|
+
* @param token - User authentication token
|
|
39
|
+
* @returns Cart with items array
|
|
40
|
+
*/
|
|
41
|
+
getCart: async (token) => {
|
|
42
|
+
const response = await handleApiRequest("GET", ENDPOINT, { token });
|
|
43
|
+
return response.data;
|
|
44
|
+
},
|
|
45
|
+
/**
|
|
46
|
+
* Add item to cart
|
|
47
|
+
* POST /api/v1/cart/items
|
|
48
|
+
*
|
|
49
|
+
* @param token - User authentication token
|
|
50
|
+
* @param data - Product ID, quantity, and optional variant SKU
|
|
51
|
+
* @returns Updated cart
|
|
52
|
+
*/
|
|
53
|
+
addToCart: async (token, data) => {
|
|
54
|
+
const response = await handleApiRequest("POST", `${ENDPOINT}/items`, {
|
|
55
|
+
token,
|
|
56
|
+
body: data
|
|
57
|
+
});
|
|
58
|
+
return response.data;
|
|
59
|
+
},
|
|
60
|
+
/**
|
|
61
|
+
* Update cart item quantity
|
|
62
|
+
* PATCH /api/v1/cart/items/:itemId
|
|
63
|
+
*
|
|
64
|
+
* @param token - User authentication token
|
|
65
|
+
* @param itemId - Cart item ID (from cart.items[]._id)
|
|
66
|
+
* @param quantity - New quantity (minimum: 1)
|
|
67
|
+
* @returns Updated cart
|
|
68
|
+
*/
|
|
69
|
+
updateCartItem: async (token, itemId, quantity) => {
|
|
70
|
+
const response = await handleApiRequest("PATCH", `${ENDPOINT}/items/${itemId}`, {
|
|
71
|
+
token,
|
|
72
|
+
body: { quantity }
|
|
73
|
+
});
|
|
74
|
+
return response.data;
|
|
75
|
+
},
|
|
76
|
+
/**
|
|
77
|
+
* Remove item from cart
|
|
78
|
+
* DELETE /api/v1/cart/items/:itemId
|
|
79
|
+
*
|
|
80
|
+
* @param token - User authentication token
|
|
81
|
+
* @param itemId - Cart item ID (from cart.items[]._id)
|
|
82
|
+
* @returns Updated cart
|
|
83
|
+
*/
|
|
84
|
+
removeCartItem: async (token, itemId) => {
|
|
85
|
+
const response = await handleApiRequest("DELETE", `${ENDPOINT}/items/${itemId}`, {
|
|
86
|
+
token
|
|
87
|
+
});
|
|
88
|
+
return response.data;
|
|
89
|
+
},
|
|
90
|
+
/**
|
|
91
|
+
* Clear all items from cart
|
|
92
|
+
* DELETE /api/v1/cart
|
|
93
|
+
*
|
|
94
|
+
* @param token - User authentication token
|
|
95
|
+
* @returns Empty cart
|
|
96
|
+
*/
|
|
97
|
+
clearCart: async (token) => {
|
|
98
|
+
const response = await handleApiRequest("DELETE", ENDPOINT, { token });
|
|
99
|
+
return response.data;
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
// src/sales/api/order.ts
|
|
104
|
+
var OrderApi = class extends BaseApi {
|
|
105
|
+
constructor() {
|
|
106
|
+
super(...arguments);
|
|
107
|
+
// ============ Customer ============
|
|
108
|
+
/**
|
|
109
|
+
* Checkout - create order from cart
|
|
110
|
+
* POST /api/v1/orders
|
|
111
|
+
*/
|
|
112
|
+
this.checkout = ({ token, organizationId, data }) => this.create({ token, organizationId, data });
|
|
113
|
+
/** Get my orders */
|
|
114
|
+
this.getMyOrders = ({ token, params = {} }) => this.request("GET", `${this.baseUrl}/my`, { token, params });
|
|
115
|
+
/** Get my order detail */
|
|
116
|
+
this.getMyOrder = ({ token, id }) => this.request("GET", `${this.baseUrl}/my/${id}`, { token });
|
|
117
|
+
/** Cancel order */
|
|
118
|
+
this.cancel = ({ token, id, reason, refund = false }) => this.request("POST", `${this.baseUrl}/${id}/cancel`, {
|
|
119
|
+
token,
|
|
120
|
+
data: { reason, refund }
|
|
121
|
+
});
|
|
122
|
+
/** Request cancellation (awaits admin review) */
|
|
123
|
+
this.requestCancellation = ({ token, id, reason }) => this.request("POST", `${this.baseUrl}/${id}/cancel-request`, {
|
|
124
|
+
token,
|
|
125
|
+
data: { reason }
|
|
126
|
+
});
|
|
127
|
+
// ============ Admin ============
|
|
128
|
+
/** Update order status */
|
|
129
|
+
this.updateStatus = ({ token, organizationId, id, data }) => this.request("PATCH", `${this.baseUrl}/${id}/status`, {
|
|
130
|
+
token,
|
|
131
|
+
organizationId,
|
|
132
|
+
data
|
|
133
|
+
});
|
|
134
|
+
/**
|
|
135
|
+
* Fulfill order (ship)
|
|
136
|
+
* - Decrements inventory from branch
|
|
137
|
+
* - recordCogs: true -> also creates COGS expense transaction
|
|
138
|
+
*/
|
|
139
|
+
this.fulfill = ({ token, organizationId, id, data = {} }) => this.request("POST", `${this.baseUrl}/${id}/fulfill`, {
|
|
140
|
+
token,
|
|
141
|
+
organizationId,
|
|
142
|
+
data
|
|
143
|
+
});
|
|
144
|
+
/** Refund order */
|
|
145
|
+
this.refund = ({ token, organizationId, id, data = {} }) => this.request("POST", `${this.baseUrl}/${id}/refund`, {
|
|
146
|
+
token,
|
|
147
|
+
organizationId,
|
|
148
|
+
data
|
|
149
|
+
});
|
|
150
|
+
// ============ Shipping ============
|
|
151
|
+
/** Get shipping info */
|
|
152
|
+
this.getShipping = ({ token, id }) => this.request("GET", `${this.baseUrl}/${id}/shipping`, { token });
|
|
153
|
+
/** Request shipping pickup */
|
|
154
|
+
this.requestShipping = ({ token, organizationId, id, data }) => this.request("POST", `${this.baseUrl}/${id}/shipping`, {
|
|
155
|
+
token,
|
|
156
|
+
organizationId,
|
|
157
|
+
data
|
|
158
|
+
});
|
|
159
|
+
/** Update shipping status */
|
|
160
|
+
this.updateShipping = ({ token, organizationId, id, data }) => this.request("PATCH", `${this.baseUrl}/${id}/shipping`, {
|
|
161
|
+
token,
|
|
162
|
+
organizationId,
|
|
163
|
+
data
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
var orderApi = new OrderApi("orders");
|
|
168
|
+
var order_default = orderApi;
|
|
169
|
+
|
|
170
|
+
// src/sales/api/customer.ts
|
|
171
|
+
var CustomerApi = class extends BaseApi {
|
|
172
|
+
constructor(config = {}) {
|
|
173
|
+
super("customers", config);
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Get current user's customer profile
|
|
177
|
+
* GET /customers/me
|
|
178
|
+
*/
|
|
179
|
+
async getMe({
|
|
180
|
+
token,
|
|
181
|
+
options = {}
|
|
182
|
+
}) {
|
|
183
|
+
if (!token) {
|
|
184
|
+
throw new Error("Authentication required");
|
|
185
|
+
}
|
|
186
|
+
return handleApiRequest("GET", `${this.baseUrl}/me`, {
|
|
187
|
+
token,
|
|
188
|
+
cache: this.config.cache,
|
|
189
|
+
...options
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Membership actions
|
|
194
|
+
* POST /customers/:id/membership
|
|
195
|
+
*/
|
|
196
|
+
async membershipAction({
|
|
197
|
+
token,
|
|
198
|
+
id,
|
|
199
|
+
data
|
|
200
|
+
}) {
|
|
201
|
+
if (!token) {
|
|
202
|
+
throw new Error("Authentication required");
|
|
203
|
+
}
|
|
204
|
+
return handleApiRequest("POST", `${this.baseUrl}/${id}/membership`, {
|
|
205
|
+
token,
|
|
206
|
+
body: data,
|
|
207
|
+
cache: this.config.cache
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
var customerApi = new CustomerApi();
|
|
212
|
+
var CART_KEYS = createQueryKeys("cart");
|
|
213
|
+
function calculateItemPrice(item) {
|
|
214
|
+
if (!item?.product) return 0;
|
|
215
|
+
const product = item.product;
|
|
216
|
+
const basePrice = product.currentPrice ?? product.basePrice ?? 0;
|
|
217
|
+
if (item.variantSku && product.variants && product.variants.length > 0) {
|
|
218
|
+
const variant = product.variants.find((v) => v.sku === item.variantSku);
|
|
219
|
+
if (variant) {
|
|
220
|
+
return basePrice + (variant.priceModifier || 0);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
return basePrice;
|
|
224
|
+
}
|
|
225
|
+
function calculateItemTotal(item) {
|
|
226
|
+
return calculateItemPrice(item) * (item.quantity || 1);
|
|
227
|
+
}
|
|
228
|
+
function calculateCartSubtotal(items) {
|
|
229
|
+
return items?.reduce((total, item) => total + calculateItemTotal(item), 0) || 0;
|
|
230
|
+
}
|
|
231
|
+
function getCartItemCount(items) {
|
|
232
|
+
return items?.reduce((count, item) => count + (item.quantity || 0), 0) || 0;
|
|
233
|
+
}
|
|
234
|
+
function getCartItemVariant(item) {
|
|
235
|
+
if (!item?.variantSku || !item?.product?.variants) return null;
|
|
236
|
+
return item.product.variants.find((v) => v.sku === item.variantSku) || null;
|
|
237
|
+
}
|
|
238
|
+
function formatVariantAttributes(attributes) {
|
|
239
|
+
if (!attributes || Object.keys(attributes).length === 0) return "";
|
|
240
|
+
return Object.entries(attributes).map(([key, value]) => `${key.charAt(0).toUpperCase() + key.slice(1)}: ${value}`).join(", ");
|
|
241
|
+
}
|
|
242
|
+
var CART_QUERY_KEY = ["cart"];
|
|
243
|
+
function useCart(token, options = {}) {
|
|
244
|
+
const queryClient = useQueryClient();
|
|
245
|
+
const toast = getToastHandler();
|
|
246
|
+
const { enabled = true, staleTime = 2 * 60 * 1e3, gcTime = 10 * 60 * 1e3 } = options;
|
|
247
|
+
const {
|
|
248
|
+
data: cart,
|
|
249
|
+
isLoading,
|
|
250
|
+
error,
|
|
251
|
+
isFetching,
|
|
252
|
+
refetch
|
|
253
|
+
} = useQuery({
|
|
254
|
+
queryKey: CART_QUERY_KEY,
|
|
255
|
+
queryFn: () => cartApi.getCart(token),
|
|
256
|
+
enabled: enabled && !!token,
|
|
257
|
+
staleTime,
|
|
258
|
+
gcTime
|
|
259
|
+
});
|
|
260
|
+
const addMutation = useMutation({
|
|
261
|
+
mutationFn: (data) => cartApi.addToCart(token, data),
|
|
262
|
+
onMutate: async () => {
|
|
263
|
+
await queryClient.cancelQueries({ queryKey: CART_QUERY_KEY });
|
|
264
|
+
return { previousCart: queryClient.getQueryData(CART_QUERY_KEY) };
|
|
265
|
+
},
|
|
266
|
+
onError: (err, _, context) => {
|
|
267
|
+
if (context?.previousCart) {
|
|
268
|
+
queryClient.setQueryData(CART_QUERY_KEY, context.previousCart);
|
|
269
|
+
}
|
|
270
|
+
toast.error?.(err.message || "Failed to add item to cart");
|
|
271
|
+
},
|
|
272
|
+
onSuccess: (data) => {
|
|
273
|
+
queryClient.setQueryData(CART_QUERY_KEY, data);
|
|
274
|
+
toast.success?.("Added to cart!");
|
|
275
|
+
}
|
|
276
|
+
});
|
|
277
|
+
const updateMutation = useMutation({
|
|
278
|
+
mutationFn: ({ itemId, quantity }) => cartApi.updateCartItem(token, itemId, quantity),
|
|
279
|
+
onMutate: async ({ itemId, quantity }) => {
|
|
280
|
+
await queryClient.cancelQueries({ queryKey: CART_QUERY_KEY });
|
|
281
|
+
const previousCart = queryClient.getQueryData(CART_QUERY_KEY);
|
|
282
|
+
queryClient.setQueryData(
|
|
283
|
+
CART_QUERY_KEY,
|
|
284
|
+
(old) => old ? {
|
|
285
|
+
...old,
|
|
286
|
+
items: old.items.map(
|
|
287
|
+
(i) => i._id === itemId ? { ...i, quantity } : i
|
|
288
|
+
)
|
|
289
|
+
} : old
|
|
290
|
+
);
|
|
291
|
+
return { previousCart };
|
|
292
|
+
},
|
|
293
|
+
onError: (err, _, context) => {
|
|
294
|
+
if (context?.previousCart) {
|
|
295
|
+
queryClient.setQueryData(CART_QUERY_KEY, context.previousCart);
|
|
296
|
+
}
|
|
297
|
+
toast.error?.(err.message || "Failed to update cart");
|
|
298
|
+
},
|
|
299
|
+
onSuccess: (data) => {
|
|
300
|
+
queryClient.setQueryData(CART_QUERY_KEY, data);
|
|
301
|
+
}
|
|
302
|
+
});
|
|
303
|
+
const removeMutation = useMutation({
|
|
304
|
+
mutationFn: (itemId) => cartApi.removeCartItem(token, itemId),
|
|
305
|
+
onMutate: async (itemId) => {
|
|
306
|
+
await queryClient.cancelQueries({ queryKey: CART_QUERY_KEY });
|
|
307
|
+
const previousCart = queryClient.getQueryData(CART_QUERY_KEY);
|
|
308
|
+
queryClient.setQueryData(
|
|
309
|
+
CART_QUERY_KEY,
|
|
310
|
+
(old) => old ? { ...old, items: old.items.filter((i) => i._id !== itemId) } : old
|
|
311
|
+
);
|
|
312
|
+
return { previousCart };
|
|
313
|
+
},
|
|
314
|
+
onError: (err, _, context) => {
|
|
315
|
+
if (context?.previousCart) {
|
|
316
|
+
queryClient.setQueryData(CART_QUERY_KEY, context.previousCart);
|
|
317
|
+
}
|
|
318
|
+
toast.error?.(err.message || "Failed to remove item");
|
|
319
|
+
},
|
|
320
|
+
onSuccess: (data) => {
|
|
321
|
+
queryClient.setQueryData(CART_QUERY_KEY, data);
|
|
322
|
+
toast.success?.("Item removed");
|
|
323
|
+
}
|
|
324
|
+
});
|
|
325
|
+
const clearMutation = useMutation({
|
|
326
|
+
mutationFn: () => cartApi.clearCart(token),
|
|
327
|
+
onMutate: async () => {
|
|
328
|
+
await queryClient.cancelQueries({ queryKey: CART_QUERY_KEY });
|
|
329
|
+
const previousCart = queryClient.getQueryData(CART_QUERY_KEY);
|
|
330
|
+
queryClient.setQueryData(
|
|
331
|
+
CART_QUERY_KEY,
|
|
332
|
+
(old) => old ? { ...old, items: [] } : old
|
|
333
|
+
);
|
|
334
|
+
return { previousCart };
|
|
335
|
+
},
|
|
336
|
+
onError: (err, _, context) => {
|
|
337
|
+
if (context?.previousCart) {
|
|
338
|
+
queryClient.setQueryData(CART_QUERY_KEY, context.previousCart);
|
|
339
|
+
}
|
|
340
|
+
toast.error?.(err.message || "Failed to clear cart");
|
|
341
|
+
},
|
|
342
|
+
onSuccess: (data) => {
|
|
343
|
+
queryClient.setQueryData(CART_QUERY_KEY, data);
|
|
344
|
+
toast.success?.("Cart cleared");
|
|
345
|
+
}
|
|
346
|
+
});
|
|
347
|
+
const items = cart?.items || [];
|
|
348
|
+
const isUpdating = addMutation.isPending || updateMutation.isPending || removeMutation.isPending || clearMutation.isPending;
|
|
349
|
+
return {
|
|
350
|
+
cart,
|
|
351
|
+
items,
|
|
352
|
+
itemCount: getCartItemCount(items),
|
|
353
|
+
subtotal: calculateCartSubtotal(items),
|
|
354
|
+
isLoading,
|
|
355
|
+
isFetching,
|
|
356
|
+
isUpdating,
|
|
357
|
+
error,
|
|
358
|
+
addToCart: (data) => addMutation.mutate(data),
|
|
359
|
+
addToCartAsync: (data) => addMutation.mutateAsync(data),
|
|
360
|
+
updateCartItem: (data) => updateMutation.mutate(data),
|
|
361
|
+
updateCartItemAsync: (data) => updateMutation.mutateAsync(data),
|
|
362
|
+
removeCartItem: (itemId) => removeMutation.mutate(itemId),
|
|
363
|
+
removeCartItemAsync: (itemId) => removeMutation.mutateAsync(itemId),
|
|
364
|
+
clearCart: () => clearMutation.mutate(),
|
|
365
|
+
clearCartAsync: () => clearMutation.mutateAsync(),
|
|
366
|
+
refetch: () => refetch(),
|
|
367
|
+
getItemPrice: calculateItemPrice
|
|
368
|
+
};
|
|
369
|
+
}
|
|
370
|
+
function useCartCount(token, options = {}) {
|
|
371
|
+
const { enabled = true, staleTime = 2 * 60 * 1e3, gcTime = 10 * 60 * 1e3 } = options;
|
|
372
|
+
const { data: cart, isLoading } = useQuery({
|
|
373
|
+
queryKey: CART_QUERY_KEY,
|
|
374
|
+
queryFn: () => cartApi.getCart(token),
|
|
375
|
+
enabled: enabled && !!token,
|
|
376
|
+
staleTime,
|
|
377
|
+
gcTime
|
|
378
|
+
});
|
|
379
|
+
return {
|
|
380
|
+
count: getCartItemCount(cart?.items || []),
|
|
381
|
+
isLoading
|
|
382
|
+
};
|
|
383
|
+
}
|
|
384
|
+
var createOrderKeys = () => ({
|
|
385
|
+
all: ["orders"],
|
|
386
|
+
lists: () => [...createOrderKeys().all, "list"],
|
|
387
|
+
list: (params) => [...createOrderKeys().lists(), params],
|
|
388
|
+
details: () => [...createOrderKeys().all, "detail"],
|
|
389
|
+
detail: (id) => [...createOrderKeys().details(), id],
|
|
390
|
+
// Customer-specific keys
|
|
391
|
+
myOrders: (params) => [...createOrderKeys().all, "my", params],
|
|
392
|
+
myDetail: (id) => [...createOrderKeys().all, "my", "detail", id]
|
|
393
|
+
});
|
|
394
|
+
var orderHooks = createCrudHooks({
|
|
395
|
+
api: orderApi,
|
|
396
|
+
entityKey: "orders",
|
|
397
|
+
singular: "Order",
|
|
398
|
+
plural: "Orders",
|
|
399
|
+
defaults: {
|
|
400
|
+
staleTime: 1 * 60 * 1e3
|
|
401
|
+
// 1 minute (orders change frequently)
|
|
402
|
+
}
|
|
403
|
+
});
|
|
404
|
+
var ORDER_KEYS = createOrderKeys();
|
|
405
|
+
var {
|
|
406
|
+
useList: useOrders,
|
|
407
|
+
useDetail: useOrderDetail,
|
|
408
|
+
useActions: useOrderActions,
|
|
409
|
+
useNavigation: useOrderNavigation
|
|
410
|
+
} = orderHooks;
|
|
411
|
+
function useMyOrders(token, params = {}, options = {}) {
|
|
412
|
+
const { data, isLoading, isFetching, error, refetch } = useQuery({
|
|
413
|
+
queryKey: ORDER_KEYS.myOrders(params),
|
|
414
|
+
queryFn: async () => {
|
|
415
|
+
const response = await orderApi.getMyOrders({ token, params });
|
|
416
|
+
return response;
|
|
417
|
+
},
|
|
418
|
+
enabled: !!token && options.enabled !== false,
|
|
419
|
+
staleTime: options.staleTime ?? 30 * 1e3
|
|
420
|
+
});
|
|
421
|
+
const orders = data?.data || data?.docs || [];
|
|
422
|
+
const pagination = data?.pagination;
|
|
423
|
+
return {
|
|
424
|
+
orders,
|
|
425
|
+
total: pagination?.total || orders.length,
|
|
426
|
+
page: pagination?.page || 1,
|
|
427
|
+
limit: pagination?.limit || 10,
|
|
428
|
+
hasMore: pagination?.hasMore ?? false,
|
|
429
|
+
isLoading,
|
|
430
|
+
isFetching,
|
|
431
|
+
error,
|
|
432
|
+
refetch
|
|
433
|
+
};
|
|
434
|
+
}
|
|
435
|
+
function useMyOrderDetail(token, orderId, options = {}) {
|
|
436
|
+
return useQuery({
|
|
437
|
+
queryKey: ORDER_KEYS.myDetail(orderId),
|
|
438
|
+
queryFn: async () => {
|
|
439
|
+
const response = await orderApi.getMyOrder({ token, id: orderId });
|
|
440
|
+
return response.data;
|
|
441
|
+
},
|
|
442
|
+
enabled: !!token && !!orderId && options.enabled !== false,
|
|
443
|
+
staleTime: options.staleTime ?? 30 * 1e3
|
|
444
|
+
});
|
|
445
|
+
}
|
|
446
|
+
function useCustomerOrderActions(token) {
|
|
447
|
+
const queryClient = useQueryClient();
|
|
448
|
+
const toast = getToastHandler();
|
|
449
|
+
const checkoutMutation = useMutation({
|
|
450
|
+
mutationFn: async (data) => {
|
|
451
|
+
const response = await orderApi.checkout({ token, data });
|
|
452
|
+
return response.data;
|
|
453
|
+
},
|
|
454
|
+
onSuccess: () => {
|
|
455
|
+
queryClient.setQueryData(["cart"], null);
|
|
456
|
+
queryClient.invalidateQueries({ queryKey: ["cart"] });
|
|
457
|
+
queryClient.invalidateQueries({ queryKey: ORDER_KEYS.all });
|
|
458
|
+
toast.success("Order placed successfully!");
|
|
459
|
+
},
|
|
460
|
+
onError: (error) => {
|
|
461
|
+
toast.error(error.message || "Failed to place order");
|
|
462
|
+
}
|
|
463
|
+
});
|
|
464
|
+
const requestCancelMutation = useMutation({
|
|
465
|
+
mutationFn: async ({ orderId, reason }) => {
|
|
466
|
+
const response = await orderApi.requestCancellation({ token, id: orderId, reason });
|
|
467
|
+
return response.data;
|
|
468
|
+
},
|
|
469
|
+
onSuccess: () => {
|
|
470
|
+
queryClient.invalidateQueries({ queryKey: ORDER_KEYS.all });
|
|
471
|
+
toast.success("Cancellation request submitted");
|
|
472
|
+
},
|
|
473
|
+
onError: (error) => {
|
|
474
|
+
toast.error(error.message || "Failed to request cancellation");
|
|
475
|
+
}
|
|
476
|
+
});
|
|
477
|
+
return {
|
|
478
|
+
checkout: checkoutMutation.mutateAsync,
|
|
479
|
+
isCheckingOut: checkoutMutation.isPending,
|
|
480
|
+
requestCancel: requestCancelMutation.mutateAsync,
|
|
481
|
+
isRequestingCancel: requestCancelMutation.isPending,
|
|
482
|
+
isLoading: checkoutMutation.isPending || requestCancelMutation.isPending
|
|
483
|
+
};
|
|
484
|
+
}
|
|
485
|
+
function useAdminOrderActions(token) {
|
|
486
|
+
const queryClient = useQueryClient();
|
|
487
|
+
const toast = getToastHandler();
|
|
488
|
+
const updateStatusMutation = useMutation({
|
|
489
|
+
mutationFn: async ({ orderId, status, note }) => {
|
|
490
|
+
const response = await orderApi.updateStatus({
|
|
491
|
+
token,
|
|
492
|
+
id: orderId,
|
|
493
|
+
data: { status, note }
|
|
494
|
+
});
|
|
495
|
+
return response.data;
|
|
496
|
+
},
|
|
497
|
+
onSuccess: () => {
|
|
498
|
+
queryClient.invalidateQueries({ queryKey: ORDER_KEYS.all });
|
|
499
|
+
toast.success("Order status updated");
|
|
500
|
+
},
|
|
501
|
+
onError: (error) => {
|
|
502
|
+
toast.error(error.message || "Failed to update status");
|
|
503
|
+
}
|
|
504
|
+
});
|
|
505
|
+
const fulfillMutation = useMutation({
|
|
506
|
+
mutationFn: async ({ orderId, ...data }) => {
|
|
507
|
+
const response = await orderApi.fulfill({ token, id: orderId, data });
|
|
508
|
+
return response.data;
|
|
509
|
+
},
|
|
510
|
+
onSuccess: () => {
|
|
511
|
+
queryClient.invalidateQueries({ queryKey: ORDER_KEYS.all });
|
|
512
|
+
queryClient.invalidateQueries({ queryKey: ["branches"] });
|
|
513
|
+
queryClient.invalidateQueries({ queryKey: ["stock"] });
|
|
514
|
+
toast.success("Order fulfilled successfully");
|
|
515
|
+
},
|
|
516
|
+
onError: (error) => {
|
|
517
|
+
toast.error(error.message || "Failed to fulfill order");
|
|
518
|
+
}
|
|
519
|
+
});
|
|
520
|
+
const refundMutation = useMutation({
|
|
521
|
+
mutationFn: async ({ orderId, amount, reason }) => {
|
|
522
|
+
const response = await orderApi.refund({ token, id: orderId, data: { amount, reason } });
|
|
523
|
+
return response.data;
|
|
524
|
+
},
|
|
525
|
+
onSuccess: () => {
|
|
526
|
+
queryClient.invalidateQueries({ queryKey: ORDER_KEYS.all });
|
|
527
|
+
toast.success("Refund processed successfully");
|
|
528
|
+
},
|
|
529
|
+
onError: (error) => {
|
|
530
|
+
toast.error(error.message || "Failed to process refund");
|
|
531
|
+
}
|
|
532
|
+
});
|
|
533
|
+
const cancelMutation = useMutation({
|
|
534
|
+
mutationFn: async ({ orderId, reason, refund }) => {
|
|
535
|
+
const response = await orderApi.cancel({ token, id: orderId, reason, refund });
|
|
536
|
+
return response.data;
|
|
537
|
+
},
|
|
538
|
+
onSuccess: () => {
|
|
539
|
+
queryClient.invalidateQueries({ queryKey: ORDER_KEYS.all });
|
|
540
|
+
toast.success("Order cancelled");
|
|
541
|
+
},
|
|
542
|
+
onError: (error) => {
|
|
543
|
+
toast.error(error.message || "Failed to cancel order");
|
|
544
|
+
}
|
|
545
|
+
});
|
|
546
|
+
const requestShippingMutation = useMutation({
|
|
547
|
+
mutationFn: async ({ orderId, ...data }) => {
|
|
548
|
+
const response = await orderApi.requestShipping({ token, id: orderId, data });
|
|
549
|
+
return response.data;
|
|
550
|
+
},
|
|
551
|
+
onSuccess: () => {
|
|
552
|
+
queryClient.invalidateQueries({ queryKey: ORDER_KEYS.all });
|
|
553
|
+
toast.success("Shipping pickup requested");
|
|
554
|
+
},
|
|
555
|
+
onError: (error) => {
|
|
556
|
+
toast.error(error.message || "Failed to request shipping");
|
|
557
|
+
}
|
|
558
|
+
});
|
|
559
|
+
const updateShippingMutation = useMutation({
|
|
560
|
+
mutationFn: async ({ orderId, ...data }) => {
|
|
561
|
+
const response = await orderApi.updateShipping({ token, id: orderId, data });
|
|
562
|
+
return response.data;
|
|
563
|
+
},
|
|
564
|
+
onSuccess: () => {
|
|
565
|
+
queryClient.invalidateQueries({ queryKey: ORDER_KEYS.all });
|
|
566
|
+
toast.success("Shipping status updated");
|
|
567
|
+
},
|
|
568
|
+
onError: (error) => {
|
|
569
|
+
toast.error(error.message || "Failed to update shipping");
|
|
570
|
+
}
|
|
571
|
+
});
|
|
572
|
+
return {
|
|
573
|
+
updateStatus: updateStatusMutation.mutateAsync,
|
|
574
|
+
isUpdatingStatus: updateStatusMutation.isPending,
|
|
575
|
+
fulfillOrder: fulfillMutation.mutateAsync,
|
|
576
|
+
isFulfilling: fulfillMutation.isPending,
|
|
577
|
+
refundOrder: refundMutation.mutateAsync,
|
|
578
|
+
isRefunding: refundMutation.isPending,
|
|
579
|
+
cancelOrder: cancelMutation.mutateAsync,
|
|
580
|
+
isCancelling: cancelMutation.isPending,
|
|
581
|
+
requestShipping: requestShippingMutation.mutateAsync,
|
|
582
|
+
isRequestingShipping: requestShippingMutation.isPending,
|
|
583
|
+
updateShipping: updateShippingMutation.mutateAsync,
|
|
584
|
+
isUpdatingShipping: updateShippingMutation.isPending,
|
|
585
|
+
isLoading: updateStatusMutation.isPending || fulfillMutation.isPending || refundMutation.isPending || cancelMutation.isPending || requestShippingMutation.isPending || updateShippingMutation.isPending
|
|
586
|
+
};
|
|
587
|
+
}
|
|
588
|
+
var customerHooks = createCrudHooks({
|
|
589
|
+
api: customerApi,
|
|
590
|
+
entityKey: "customers",
|
|
591
|
+
singular: "Customer",
|
|
592
|
+
plural: "Customers",
|
|
593
|
+
defaults: {
|
|
594
|
+
staleTime: 5 * 60 * 1e3
|
|
595
|
+
// 5 minutes
|
|
596
|
+
}
|
|
597
|
+
});
|
|
598
|
+
var {
|
|
599
|
+
KEYS: CUSTOMER_KEYS,
|
|
600
|
+
useList: useCustomers,
|
|
601
|
+
useDetail: useCustomerDetail,
|
|
602
|
+
useActions: useCustomerActions,
|
|
603
|
+
useNavigation: useCustomerNavigation
|
|
604
|
+
} = customerHooks;
|
|
605
|
+
function useCurrentCustomer(token, options = {}) {
|
|
606
|
+
return useQuery({
|
|
607
|
+
queryKey: [...CUSTOMER_KEYS.all, "me"],
|
|
608
|
+
queryFn: async () => {
|
|
609
|
+
const response = await customerApi.getMe({ token });
|
|
610
|
+
return response.data;
|
|
611
|
+
},
|
|
612
|
+
enabled: !!token && options.enabled !== false,
|
|
613
|
+
staleTime: options.staleTime ?? 5 * 60 * 1e3
|
|
614
|
+
});
|
|
615
|
+
}
|
|
616
|
+
function useCustomerMembership(token) {
|
|
617
|
+
const queryClient = useQueryClient();
|
|
618
|
+
const toast = getToastHandler();
|
|
619
|
+
const mutation = useMutation({
|
|
620
|
+
mutationFn: async ({ id, action, points, reason, type }) => {
|
|
621
|
+
const response = await customerApi.membershipAction({
|
|
622
|
+
token,
|
|
623
|
+
id,
|
|
624
|
+
data: { action, points, reason, type }
|
|
625
|
+
});
|
|
626
|
+
return response.data;
|
|
627
|
+
},
|
|
628
|
+
onSuccess: () => {
|
|
629
|
+
queryClient.invalidateQueries({ queryKey: CUSTOMER_KEYS.lists() });
|
|
630
|
+
queryClient.invalidateQueries({ queryKey: CUSTOMER_KEYS.details() });
|
|
631
|
+
toast.success("Membership updated successfully");
|
|
632
|
+
},
|
|
633
|
+
onError: (error) => {
|
|
634
|
+
toast.error(error.message || "Failed to update membership");
|
|
635
|
+
}
|
|
636
|
+
});
|
|
637
|
+
return {
|
|
638
|
+
membershipAction: mutation.mutateAsync,
|
|
639
|
+
isPending: mutation.isPending
|
|
640
|
+
};
|
|
641
|
+
}
|
|
642
|
+
var POS_KEYS = {
|
|
643
|
+
all: ["pos"],
|
|
644
|
+
products: (branchId) => [...POS_KEYS.all, "products", branchId],
|
|
645
|
+
productsList: (branchId, params) => [...POS_KEYS.products(branchId), params],
|
|
646
|
+
lookup: (code, branchId) => [...POS_KEYS.all, "lookup", code, branchId],
|
|
647
|
+
orders: () => [...POS_KEYS.all, "orders"],
|
|
648
|
+
receipt: (orderId) => [...POS_KEYS.orders(), orderId, "receipt"]
|
|
649
|
+
};
|
|
650
|
+
function usePosProducts(token, branchId, filters = {}, options = {}) {
|
|
651
|
+
const queryKey = POS_KEYS.productsList(branchId, filters);
|
|
652
|
+
const { data, isLoading, isFetching, error, refetch } = useQuery({
|
|
653
|
+
queryKey,
|
|
654
|
+
queryFn: () => posApi.getProducts({
|
|
655
|
+
token,
|
|
656
|
+
branchId,
|
|
657
|
+
category: filters.category,
|
|
658
|
+
search: filters.search,
|
|
659
|
+
inStockOnly: filters.inStockOnly,
|
|
660
|
+
lowStockOnly: filters.lowStockOnly,
|
|
661
|
+
after: filters.after,
|
|
662
|
+
limit: filters.limit || 50,
|
|
663
|
+
sort: filters.sort || "name"
|
|
664
|
+
}),
|
|
665
|
+
enabled: !!token && options.enabled !== false,
|
|
666
|
+
staleTime: 30 * 1e3,
|
|
667
|
+
// 30 seconds
|
|
668
|
+
refetchOnWindowFocus: true
|
|
669
|
+
});
|
|
670
|
+
return {
|
|
671
|
+
products: data?.docs || [],
|
|
672
|
+
summary: data?.summary || { totalItems: 0, totalQuantity: 0, lowStockCount: 0, outOfStockCount: 0 },
|
|
673
|
+
branch: data?.branch || { _id: "", code: "", name: "" },
|
|
674
|
+
hasMore: data?.hasMore || false,
|
|
675
|
+
nextCursor: data?.next || null,
|
|
676
|
+
isLoading,
|
|
677
|
+
isFetching,
|
|
678
|
+
error,
|
|
679
|
+
refetch
|
|
680
|
+
};
|
|
681
|
+
}
|
|
682
|
+
function usePosLookup(token, code, branchId, options = {}) {
|
|
683
|
+
return useQuery({
|
|
684
|
+
queryKey: POS_KEYS.lookup(code, branchId),
|
|
685
|
+
queryFn: () => posApi.lookup({ token, code, branchId }),
|
|
686
|
+
enabled: !!token && !!code && code.length >= 2 && options.enabled !== false,
|
|
687
|
+
staleTime: 10 * 1e3,
|
|
688
|
+
// 10 seconds
|
|
689
|
+
retry: false
|
|
690
|
+
// Don't retry failed lookups
|
|
691
|
+
});
|
|
692
|
+
}
|
|
693
|
+
function usePosLookupMutation(token) {
|
|
694
|
+
const toast = getToastHandler();
|
|
695
|
+
const mutation = useMutation({
|
|
696
|
+
mutationFn: ({ code, branchId }) => posApi.lookup({ token, code, branchId }),
|
|
697
|
+
onError: (error) => {
|
|
698
|
+
toast.error(error.message || "Lookup failed");
|
|
699
|
+
}
|
|
700
|
+
});
|
|
701
|
+
return {
|
|
702
|
+
lookup: mutation.mutateAsync,
|
|
703
|
+
isLooking: mutation.isPending,
|
|
704
|
+
error: mutation.error
|
|
705
|
+
};
|
|
706
|
+
}
|
|
707
|
+
function usePosReceipt(token, orderId, options = {}) {
|
|
708
|
+
return useQuery({
|
|
709
|
+
queryKey: POS_KEYS.receipt(orderId),
|
|
710
|
+
queryFn: async () => {
|
|
711
|
+
const result = await posApi.getReceipt({ token, orderId });
|
|
712
|
+
return result;
|
|
713
|
+
},
|
|
714
|
+
enabled: !!token && !!orderId && options.enabled !== false,
|
|
715
|
+
staleTime: Infinity
|
|
716
|
+
// Receipts don't change
|
|
717
|
+
});
|
|
718
|
+
}
|
|
719
|
+
function usePosOrders(token) {
|
|
720
|
+
const queryClient = useQueryClient();
|
|
721
|
+
const createOrderMutation = useMutation({
|
|
722
|
+
mutationFn: (data) => posApi.createOrder({ token, data }),
|
|
723
|
+
onSuccess: (_result, variables) => {
|
|
724
|
+
queryClient.invalidateQueries({
|
|
725
|
+
queryKey: POS_KEYS.products(variables.branchId)
|
|
726
|
+
});
|
|
727
|
+
}
|
|
728
|
+
});
|
|
729
|
+
return {
|
|
730
|
+
createOrder: createOrderMutation.mutateAsync,
|
|
731
|
+
isCreatingOrder: createOrderMutation.isPending
|
|
732
|
+
};
|
|
733
|
+
}
|
|
734
|
+
function usePosStockActions(token, branchId) {
|
|
735
|
+
const queryClient = useQueryClient();
|
|
736
|
+
const toast = getToastHandler();
|
|
737
|
+
const adjustMutation = useMutation({
|
|
738
|
+
mutationFn: (data) => posApi.adjustStock({ token, data }),
|
|
739
|
+
onSuccess: () => {
|
|
740
|
+
toast.success("Stock adjusted");
|
|
741
|
+
queryClient.invalidateQueries({ queryKey: POS_KEYS.products(branchId) });
|
|
742
|
+
},
|
|
743
|
+
onError: (error) => {
|
|
744
|
+
toast.error(error.message || "Failed to adjust stock");
|
|
745
|
+
}
|
|
746
|
+
});
|
|
747
|
+
const setMutation = useMutation({
|
|
748
|
+
mutationFn: (params) => posApi.setStock({
|
|
749
|
+
token,
|
|
750
|
+
productId: params.productId,
|
|
751
|
+
data: {
|
|
752
|
+
quantity: params.quantity,
|
|
753
|
+
branchId: params.branchId || branchId,
|
|
754
|
+
variantSku: params.variantSku,
|
|
755
|
+
reason: params.reason
|
|
756
|
+
}
|
|
757
|
+
}),
|
|
758
|
+
onSuccess: () => {
|
|
759
|
+
toast.success("Stock updated");
|
|
760
|
+
queryClient.invalidateQueries({ queryKey: POS_KEYS.products(branchId) });
|
|
761
|
+
},
|
|
762
|
+
onError: (error) => {
|
|
763
|
+
toast.error(error.message || "Failed to set stock");
|
|
764
|
+
}
|
|
765
|
+
});
|
|
766
|
+
const bulkMutation = useMutation({
|
|
767
|
+
mutationFn: (data) => posApi.bulkAdjust({ token, data }),
|
|
768
|
+
onSuccess: () => {
|
|
769
|
+
toast.success("Bulk adjustment complete");
|
|
770
|
+
queryClient.invalidateQueries({ queryKey: POS_KEYS.products(branchId) });
|
|
771
|
+
},
|
|
772
|
+
onError: (error) => {
|
|
773
|
+
toast.error(error.message || "Failed to bulk adjust");
|
|
774
|
+
}
|
|
775
|
+
});
|
|
776
|
+
return {
|
|
777
|
+
adjustStock: adjustMutation.mutateAsync,
|
|
778
|
+
isAdjusting: adjustMutation.isPending,
|
|
779
|
+
setStock: setMutation.mutateAsync,
|
|
780
|
+
isSetting: setMutation.isPending,
|
|
781
|
+
bulkAdjust: bulkMutation.mutateAsync,
|
|
782
|
+
isBulkAdjusting: bulkMutation.isPending,
|
|
783
|
+
isLoading: adjustMutation.isPending || setMutation.isPending || bulkMutation.isPending
|
|
784
|
+
};
|
|
785
|
+
}
|
|
786
|
+
function generateIdempotencyKey(terminalId) {
|
|
787
|
+
const terminal = terminalId || "default";
|
|
788
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
789
|
+
const counter = Math.floor(Math.random() * 1e4).toString().padStart(4, "0");
|
|
790
|
+
return `pos_${terminal}_${timestamp}_${counter}`;
|
|
791
|
+
}
|
|
792
|
+
function calculateVariantPrice(basePrice, priceModifier = 0) {
|
|
793
|
+
return basePrice + priceModifier;
|
|
794
|
+
}
|
|
795
|
+
function formatVariantLabel(attributes) {
|
|
796
|
+
if (!attributes || Object.keys(attributes).length === 0) return "";
|
|
797
|
+
return Object.entries(attributes).map(([key, value]) => `${key.charAt(0).toUpperCase() + key.slice(1)}: ${value}`).join(", ");
|
|
798
|
+
}
|
|
799
|
+
function isVariantProduct(product) {
|
|
800
|
+
return product.productType === "variant" || !!product.variants && product.variants.length > 0;
|
|
801
|
+
}
|
|
802
|
+
function getAvailableVariants(product) {
|
|
803
|
+
if (!product.variants) return [];
|
|
804
|
+
return product.variants.filter((v) => v.isActive);
|
|
805
|
+
}
|
|
806
|
+
function findVariantBySku(product, sku) {
|
|
807
|
+
if (!product.variants) return null;
|
|
808
|
+
return product.variants.find((v) => v.sku === sku) || null;
|
|
809
|
+
}
|
|
810
|
+
function getVariantStock(product, variantSku) {
|
|
811
|
+
if (!product.branchStock?.variants) return 0;
|
|
812
|
+
const variantStock = product.branchStock.variants.find((v) => v.sku === variantSku);
|
|
813
|
+
return variantStock?.quantity || 0;
|
|
814
|
+
}
|
|
815
|
+
function isInStock(product, variantSku) {
|
|
816
|
+
if (variantSku) {
|
|
817
|
+
const stock = getVariantStock(product, variantSku);
|
|
818
|
+
return stock > 0;
|
|
819
|
+
}
|
|
820
|
+
return product.branchStock?.inStock ?? false;
|
|
821
|
+
}
|
|
822
|
+
function getPosProductImage(product) {
|
|
823
|
+
const firstImage = product.images?.[0];
|
|
824
|
+
if (!firstImage) return "/placeholder.png";
|
|
825
|
+
return firstImage.variants?.thumbnail || firstImage.url;
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
export { CART_KEYS, CUSTOMER_KEYS, CustomerApi, ORDER_KEYS, OrderStatus, POS_KEYS, PaymentStatus, calculateCartSubtotal, calculateItemPrice, calculateItemTotal, calculateVariantPrice, cartApi, customerApi, customerHooks, findVariantBySku, formatVariantAttributes, formatVariantLabel, generateIdempotencyKey, getAvailableVariants, getCartItemCount, getCartItemVariant, getPosProductImage, getVariantStock, isInStock, isVariantProduct, orderApi, orderHooks, order_default, useAdminOrderActions, useCart, useCartCount, useCurrentCustomer, useCustomerActions, useCustomerDetail, useCustomerMembership, useCustomerNavigation, useCustomerOrderActions, useCustomers, useMyOrderDetail, useMyOrders, useOrderActions, useOrderDetail, useOrderNavigation, useOrders, usePosLookup, usePosLookupMutation, usePosOrders, usePosProducts, usePosReceipt, usePosStockActions };
|
|
829
|
+
//# sourceMappingURL=chunk-UGELTUIZ.js.map
|
|
830
|
+
//# sourceMappingURL=chunk-UGELTUIZ.js.map
|