@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,465 @@
|
|
|
1
|
+
import { BaseApi } from './chunk-I5TIKUIQ.js';
|
|
2
|
+
import { getToastHandler } from './chunk-U3XT35GZ.js';
|
|
3
|
+
import { handleApiRequest } from './chunk-VR36QVX2.js';
|
|
4
|
+
import { useQuery, useQueryClient, useMutation } from '@tanstack/react-query';
|
|
5
|
+
|
|
6
|
+
// src/logistics/api/logistics.ts
|
|
7
|
+
var LogisticsApi = class extends BaseApi {
|
|
8
|
+
constructor(config = {}) {
|
|
9
|
+
super("logistics", config);
|
|
10
|
+
}
|
|
11
|
+
// ============================================
|
|
12
|
+
// CHARGE CALCULATION (Public)
|
|
13
|
+
// ============================================
|
|
14
|
+
/**
|
|
15
|
+
* Calculate delivery charge via provider API (e.g., RedX)
|
|
16
|
+
* GET /logistics/charge
|
|
17
|
+
*
|
|
18
|
+
* Use this to get real-time delivery charges from the logistics provider
|
|
19
|
+
* before creating an order.
|
|
20
|
+
*
|
|
21
|
+
* @param deliveryAreaId - Area internalId from @classytic/bd-areas
|
|
22
|
+
* @param amount - COD amount in BDT (use 0 for prepaid orders)
|
|
23
|
+
* @param weight - Parcel weight in grams (default: 500g)
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* import { searchAreas } from '@classytic/bd-areas';
|
|
27
|
+
*
|
|
28
|
+
* // 1. User selects area
|
|
29
|
+
* const areas = searchAreas('mohamm');
|
|
30
|
+
* const selectedArea = areas[0]; // { internalId: 1206, name: 'Mohammadpur', ... }
|
|
31
|
+
*
|
|
32
|
+
* // 2. Calculate delivery charge
|
|
33
|
+
* const { data } = await logisticsApi.calculateCharge({
|
|
34
|
+
* deliveryAreaId: selectedArea.internalId,
|
|
35
|
+
* amount: isCOD ? cartTotal : 0,
|
|
36
|
+
* });
|
|
37
|
+
* // { deliveryCharge: 60, codCharge: 15, totalCharge: 75 }
|
|
38
|
+
*/
|
|
39
|
+
async calculateCharge({
|
|
40
|
+
deliveryAreaId,
|
|
41
|
+
pickupAreaId,
|
|
42
|
+
amount,
|
|
43
|
+
weight,
|
|
44
|
+
provider,
|
|
45
|
+
options = {}
|
|
46
|
+
}) {
|
|
47
|
+
if (!deliveryAreaId || amount === void 0) {
|
|
48
|
+
throw new Error("deliveryAreaId and amount are required");
|
|
49
|
+
}
|
|
50
|
+
const queryString = this.createQueryString({
|
|
51
|
+
deliveryAreaId,
|
|
52
|
+
pickupAreaId,
|
|
53
|
+
amount,
|
|
54
|
+
weight,
|
|
55
|
+
provider
|
|
56
|
+
});
|
|
57
|
+
return handleApiRequest("GET", `${this.baseUrl}/charge?${queryString}`, {
|
|
58
|
+
cache: "no-store",
|
|
59
|
+
...options
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
// ============================================
|
|
63
|
+
// CONFIG ENDPOINTS (Admin - Read-only)
|
|
64
|
+
// ============================================
|
|
65
|
+
/**
|
|
66
|
+
* Get logistics configuration (read-only from .env)
|
|
67
|
+
* GET /logistics/config
|
|
68
|
+
*
|
|
69
|
+
* NOTE: Configuration is managed via environment variables.
|
|
70
|
+
* To change settings, update .env file and restart server.
|
|
71
|
+
*/
|
|
72
|
+
async getConfig({
|
|
73
|
+
token,
|
|
74
|
+
options = {}
|
|
75
|
+
}) {
|
|
76
|
+
return handleApiRequest("GET", `${this.baseUrl}/config`, {
|
|
77
|
+
token,
|
|
78
|
+
cache: "no-store",
|
|
79
|
+
...options
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
// ============================================
|
|
83
|
+
// PICKUP STORES (Admin)
|
|
84
|
+
// ============================================
|
|
85
|
+
/**
|
|
86
|
+
* Get pickup stores from RedX API
|
|
87
|
+
* GET /logistics/pickup-stores
|
|
88
|
+
*
|
|
89
|
+
* Pickup stores are created by admin in RedX dashboard.
|
|
90
|
+
* Use this to list available pickup locations when creating shipments.
|
|
91
|
+
*
|
|
92
|
+
* @example
|
|
93
|
+
* // Admin: List pickup stores for shipment creation
|
|
94
|
+
* const { data: stores } = await logisticsApi.getPickupStores({ token });
|
|
95
|
+
*
|
|
96
|
+
* // Display in dropdown for admin to select
|
|
97
|
+
* stores.forEach(store => {
|
|
98
|
+
* console.log(`${store.name} - ${store.areaName} (ID: ${store.id})`);
|
|
99
|
+
* });
|
|
100
|
+
*
|
|
101
|
+
* // Use selected store when creating shipment
|
|
102
|
+
* await logisticsApi.createShipment({
|
|
103
|
+
* token,
|
|
104
|
+
* data: {
|
|
105
|
+
* orderId: order._id,
|
|
106
|
+
* pickupStoreId: selectedStore.id, // From dropdown
|
|
107
|
+
* },
|
|
108
|
+
* });
|
|
109
|
+
*/
|
|
110
|
+
async getPickupStores({
|
|
111
|
+
token,
|
|
112
|
+
provider,
|
|
113
|
+
options = {}
|
|
114
|
+
}) {
|
|
115
|
+
const queryString = provider ? `?provider=${provider}` : "";
|
|
116
|
+
return handleApiRequest(
|
|
117
|
+
"GET",
|
|
118
|
+
`${this.baseUrl}/pickup-stores${queryString}`,
|
|
119
|
+
{
|
|
120
|
+
token,
|
|
121
|
+
cache: "no-store",
|
|
122
|
+
...options
|
|
123
|
+
}
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
// ============================================
|
|
127
|
+
// SHIPMENT ENDPOINTS (Admin/Store Manager)
|
|
128
|
+
// ============================================
|
|
129
|
+
/**
|
|
130
|
+
* Create shipment for an order via RedX API
|
|
131
|
+
* POST /logistics/shipments
|
|
132
|
+
*
|
|
133
|
+
* This creates a parcel in RedX and updates the order with tracking info.
|
|
134
|
+
*
|
|
135
|
+
* @example
|
|
136
|
+
* // Basic: Create shipment with default pickup store
|
|
137
|
+
* const shipment = await logisticsApi.createShipment({
|
|
138
|
+
* token,
|
|
139
|
+
* data: { orderId: order._id },
|
|
140
|
+
* });
|
|
141
|
+
*
|
|
142
|
+
* @example
|
|
143
|
+
* // With specific pickup store (from getPickupStores)
|
|
144
|
+
* const { data: stores } = await logisticsApi.getPickupStores({ token });
|
|
145
|
+
* const shipment = await logisticsApi.createShipment({
|
|
146
|
+
* token,
|
|
147
|
+
* data: {
|
|
148
|
+
* orderId: order._id,
|
|
149
|
+
* pickupStoreId: stores[0].id, // Select pickup location
|
|
150
|
+
* weight: 500, // Parcel weight in grams
|
|
151
|
+
* instructions: 'Handle with care',
|
|
152
|
+
* },
|
|
153
|
+
* });
|
|
154
|
+
*
|
|
155
|
+
* // Response includes tracking ID
|
|
156
|
+
* console.log(`Tracking: ${shipment.data.trackingId}`);
|
|
157
|
+
*/
|
|
158
|
+
async createShipment({
|
|
159
|
+
token,
|
|
160
|
+
data,
|
|
161
|
+
options = {}
|
|
162
|
+
}) {
|
|
163
|
+
if (!data?.orderId) throw new Error("Order ID is required");
|
|
164
|
+
return handleApiRequest("POST", `${this.baseUrl}/shipments`, {
|
|
165
|
+
token,
|
|
166
|
+
body: data,
|
|
167
|
+
...options
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Get shipment by ID
|
|
172
|
+
* GET /logistics/shipments/:id
|
|
173
|
+
*/
|
|
174
|
+
async getShipment({
|
|
175
|
+
token,
|
|
176
|
+
id,
|
|
177
|
+
options = {}
|
|
178
|
+
}) {
|
|
179
|
+
if (!id) throw new Error("Shipment ID is required");
|
|
180
|
+
return handleApiRequest("GET", `${this.baseUrl}/shipments/${id}`, {
|
|
181
|
+
token,
|
|
182
|
+
cache: "no-store",
|
|
183
|
+
...options
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Track shipment (fetch latest from provider)
|
|
188
|
+
* GET /logistics/shipments/:id/track
|
|
189
|
+
*/
|
|
190
|
+
async trackShipment({
|
|
191
|
+
token,
|
|
192
|
+
id,
|
|
193
|
+
options = {}
|
|
194
|
+
}) {
|
|
195
|
+
if (!id) throw new Error("Shipment ID is required");
|
|
196
|
+
return handleApiRequest("GET", `${this.baseUrl}/shipments/${id}/track`, {
|
|
197
|
+
token,
|
|
198
|
+
cache: "no-store",
|
|
199
|
+
...options
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Update shipment status manually
|
|
204
|
+
* PATCH /logistics/shipments/:id/status
|
|
205
|
+
*/
|
|
206
|
+
async updateShipmentStatus({
|
|
207
|
+
token,
|
|
208
|
+
id,
|
|
209
|
+
data,
|
|
210
|
+
options = {}
|
|
211
|
+
}) {
|
|
212
|
+
if (!id) throw new Error("Shipment ID is required");
|
|
213
|
+
if (!data?.status) throw new Error("Status is required");
|
|
214
|
+
return handleApiRequest("PATCH", `${this.baseUrl}/shipments/${id}/status`, {
|
|
215
|
+
token,
|
|
216
|
+
body: data,
|
|
217
|
+
...options
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Cancel shipment
|
|
222
|
+
* POST /logistics/shipments/:id/cancel
|
|
223
|
+
*/
|
|
224
|
+
async cancelShipment({
|
|
225
|
+
token,
|
|
226
|
+
id,
|
|
227
|
+
data,
|
|
228
|
+
options = {}
|
|
229
|
+
}) {
|
|
230
|
+
if (!id) throw new Error("Shipment ID is required");
|
|
231
|
+
return handleApiRequest("POST", `${this.baseUrl}/shipments/${id}/cancel`, {
|
|
232
|
+
token,
|
|
233
|
+
body: data || {},
|
|
234
|
+
...options
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
// ============================================
|
|
238
|
+
// HEALTH & MONITORING (Admin)
|
|
239
|
+
// ============================================
|
|
240
|
+
/**
|
|
241
|
+
* Get circuit breaker status for all providers
|
|
242
|
+
* GET /logistics/health/circuit-status
|
|
243
|
+
*/
|
|
244
|
+
async getCircuitStatus({
|
|
245
|
+
token,
|
|
246
|
+
options = {}
|
|
247
|
+
}) {
|
|
248
|
+
return handleApiRequest("GET", `${this.baseUrl}/health/circuit-status`, {
|
|
249
|
+
token,
|
|
250
|
+
cache: "no-store",
|
|
251
|
+
...options
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* Reset circuit breaker for a provider
|
|
256
|
+
* POST /logistics/health/circuit-reset/:provider
|
|
257
|
+
*/
|
|
258
|
+
async resetProviderCircuit({
|
|
259
|
+
token,
|
|
260
|
+
provider,
|
|
261
|
+
options = {}
|
|
262
|
+
}) {
|
|
263
|
+
if (!provider) throw new Error("Provider name is required");
|
|
264
|
+
return handleApiRequest(
|
|
265
|
+
"POST",
|
|
266
|
+
`${this.baseUrl}/health/circuit-reset/${provider}`,
|
|
267
|
+
{
|
|
268
|
+
token,
|
|
269
|
+
body: {},
|
|
270
|
+
...options
|
|
271
|
+
}
|
|
272
|
+
);
|
|
273
|
+
}
|
|
274
|
+
};
|
|
275
|
+
var logisticsApi = new LogisticsApi();
|
|
276
|
+
var LOGISTICS_KEYS = {
|
|
277
|
+
all: ["logistics"],
|
|
278
|
+
pickupStores: (provider) => [...LOGISTICS_KEYS.all, "pickup-stores", provider],
|
|
279
|
+
shipment: (id) => [...LOGISTICS_KEYS.all, "shipment", id],
|
|
280
|
+
tracking: (id) => [...LOGISTICS_KEYS.all, "tracking", id],
|
|
281
|
+
charge: (params) => [...LOGISTICS_KEYS.all, "charge", params],
|
|
282
|
+
config: () => [...LOGISTICS_KEYS.all, "config"]
|
|
283
|
+
};
|
|
284
|
+
function usePickupStores(token, provider, options = {}) {
|
|
285
|
+
return useQuery({
|
|
286
|
+
queryKey: LOGISTICS_KEYS.pickupStores(provider),
|
|
287
|
+
queryFn: async () => {
|
|
288
|
+
const response = await logisticsApi.getPickupStores({ token, provider });
|
|
289
|
+
return response.data || [];
|
|
290
|
+
},
|
|
291
|
+
enabled: options.enabled !== false && !!token,
|
|
292
|
+
staleTime: options.staleTime ?? 5 * 60 * 1e3
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
function useDeliveryChargeCalculation(token, params, options = {}) {
|
|
296
|
+
const hasValidParams = !!params?.deliveryAreaId && params?.amount !== void 0;
|
|
297
|
+
return useQuery({
|
|
298
|
+
queryKey: LOGISTICS_KEYS.charge(
|
|
299
|
+
params ? { deliveryAreaId: params.deliveryAreaId, amount: params.amount, weight: params.weight } : { deliveryAreaId: 0, amount: 0 }
|
|
300
|
+
),
|
|
301
|
+
queryFn: async () => {
|
|
302
|
+
if (!params) throw new Error("Params required");
|
|
303
|
+
const response = await logisticsApi.calculateCharge({
|
|
304
|
+
deliveryAreaId: params.deliveryAreaId,
|
|
305
|
+
pickupAreaId: params.pickupAreaId,
|
|
306
|
+
amount: params.amount,
|
|
307
|
+
weight: params.weight,
|
|
308
|
+
provider: params.provider
|
|
309
|
+
});
|
|
310
|
+
if (!response.data) throw new Error("No charge data returned");
|
|
311
|
+
return response.data;
|
|
312
|
+
},
|
|
313
|
+
enabled: options.enabled !== false && hasValidParams,
|
|
314
|
+
staleTime: options.staleTime ?? 60 * 1e3
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
function useDeliveryCharge({
|
|
318
|
+
deliveryAreaId,
|
|
319
|
+
amount,
|
|
320
|
+
weight = 500,
|
|
321
|
+
enabled = true
|
|
322
|
+
}) {
|
|
323
|
+
const { data, isLoading, isFetching, error, refetch } = useQuery({
|
|
324
|
+
queryKey: LOGISTICS_KEYS.charge({
|
|
325
|
+
deliveryAreaId: deliveryAreaId || 0,
|
|
326
|
+
amount,
|
|
327
|
+
weight
|
|
328
|
+
}),
|
|
329
|
+
queryFn: async () => {
|
|
330
|
+
if (!deliveryAreaId) return null;
|
|
331
|
+
const response = await logisticsApi.calculateCharge({
|
|
332
|
+
deliveryAreaId,
|
|
333
|
+
amount,
|
|
334
|
+
weight
|
|
335
|
+
});
|
|
336
|
+
return response.data || null;
|
|
337
|
+
},
|
|
338
|
+
enabled: enabled && !!deliveryAreaId,
|
|
339
|
+
staleTime: 5 * 60 * 1e3,
|
|
340
|
+
gcTime: 10 * 60 * 1e3,
|
|
341
|
+
retry: 1
|
|
342
|
+
});
|
|
343
|
+
return {
|
|
344
|
+
charges: data || null,
|
|
345
|
+
deliveryCharge: data?.deliveryCharge ?? 0,
|
|
346
|
+
codCharge: data?.codCharge ?? 0,
|
|
347
|
+
totalCharge: data?.totalCharge ?? 0,
|
|
348
|
+
isLoading,
|
|
349
|
+
isFetching,
|
|
350
|
+
error,
|
|
351
|
+
refetch
|
|
352
|
+
};
|
|
353
|
+
}
|
|
354
|
+
function useShipment(token, shipmentId, options = {}) {
|
|
355
|
+
return useQuery({
|
|
356
|
+
queryKey: LOGISTICS_KEYS.shipment(shipmentId || ""),
|
|
357
|
+
queryFn: async () => {
|
|
358
|
+
if (!shipmentId) throw new Error("Shipment ID required");
|
|
359
|
+
const response = await logisticsApi.getShipment({ token, id: shipmentId });
|
|
360
|
+
if (!response.data) throw new Error("Shipment not found");
|
|
361
|
+
return response.data;
|
|
362
|
+
},
|
|
363
|
+
enabled: options.enabled !== false && !!token && !!shipmentId,
|
|
364
|
+
staleTime: options.staleTime ?? 30 * 1e3
|
|
365
|
+
});
|
|
366
|
+
}
|
|
367
|
+
function useTrackShipment(token, shipmentId, options = {}) {
|
|
368
|
+
return useQuery({
|
|
369
|
+
queryKey: LOGISTICS_KEYS.tracking(shipmentId || ""),
|
|
370
|
+
queryFn: async () => {
|
|
371
|
+
if (!shipmentId) throw new Error("Shipment ID required");
|
|
372
|
+
const response = await logisticsApi.trackShipment({ token, id: shipmentId });
|
|
373
|
+
if (!response.data) throw new Error("Tracking data not found");
|
|
374
|
+
return response.data;
|
|
375
|
+
},
|
|
376
|
+
enabled: options.enabled !== false && !!token && !!shipmentId,
|
|
377
|
+
staleTime: options.staleTime ?? 60 * 1e3,
|
|
378
|
+
refetchInterval: options.refetchInterval ?? 5 * 60 * 1e3
|
|
379
|
+
});
|
|
380
|
+
}
|
|
381
|
+
function useCreateShipment(token) {
|
|
382
|
+
const queryClient = useQueryClient();
|
|
383
|
+
const toast = getToastHandler();
|
|
384
|
+
return useMutation({
|
|
385
|
+
mutationFn: async (data) => {
|
|
386
|
+
const response = await logisticsApi.createShipment({ token, data });
|
|
387
|
+
return response.data;
|
|
388
|
+
},
|
|
389
|
+
onSuccess: () => {
|
|
390
|
+
toast.success("Shipment created successfully");
|
|
391
|
+
queryClient.invalidateQueries({ queryKey: ["orders"] });
|
|
392
|
+
queryClient.invalidateQueries({ queryKey: LOGISTICS_KEYS.all });
|
|
393
|
+
},
|
|
394
|
+
onError: (error) => {
|
|
395
|
+
toast.error(error.message || "Failed to create shipment");
|
|
396
|
+
}
|
|
397
|
+
});
|
|
398
|
+
}
|
|
399
|
+
function useCancelShipment(token) {
|
|
400
|
+
const queryClient = useQueryClient();
|
|
401
|
+
const toast = getToastHandler();
|
|
402
|
+
return useMutation({
|
|
403
|
+
mutationFn: async ({ shipmentId, reason }) => {
|
|
404
|
+
const response = await logisticsApi.cancelShipment({
|
|
405
|
+
token,
|
|
406
|
+
id: shipmentId,
|
|
407
|
+
data: { reason }
|
|
408
|
+
});
|
|
409
|
+
return response.data;
|
|
410
|
+
},
|
|
411
|
+
onSuccess: () => {
|
|
412
|
+
toast.success("Shipment cancelled");
|
|
413
|
+
queryClient.invalidateQueries({ queryKey: ["orders"] });
|
|
414
|
+
queryClient.invalidateQueries({ queryKey: LOGISTICS_KEYS.all });
|
|
415
|
+
},
|
|
416
|
+
onError: (error) => {
|
|
417
|
+
toast.error(error.message || "Failed to cancel shipment");
|
|
418
|
+
}
|
|
419
|
+
});
|
|
420
|
+
}
|
|
421
|
+
function useUpdateShipmentStatus(token) {
|
|
422
|
+
const queryClient = useQueryClient();
|
|
423
|
+
const toast = getToastHandler();
|
|
424
|
+
return useMutation({
|
|
425
|
+
mutationFn: async ({
|
|
426
|
+
shipmentId,
|
|
427
|
+
status,
|
|
428
|
+
message
|
|
429
|
+
}) => {
|
|
430
|
+
const response = await logisticsApi.updateShipmentStatus({
|
|
431
|
+
token,
|
|
432
|
+
id: shipmentId,
|
|
433
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
434
|
+
data: { status, message }
|
|
435
|
+
});
|
|
436
|
+
return response.data;
|
|
437
|
+
},
|
|
438
|
+
onSuccess: () => {
|
|
439
|
+
toast.success("Shipment status updated");
|
|
440
|
+
queryClient.invalidateQueries({ queryKey: ["orders"] });
|
|
441
|
+
queryClient.invalidateQueries({ queryKey: LOGISTICS_KEYS.all });
|
|
442
|
+
},
|
|
443
|
+
onError: (error) => {
|
|
444
|
+
toast.error(error.message || "Failed to update status");
|
|
445
|
+
}
|
|
446
|
+
});
|
|
447
|
+
}
|
|
448
|
+
function useLogisticsActions(token) {
|
|
449
|
+
const createShipmentMutation = useCreateShipment(token);
|
|
450
|
+
const cancelShipmentMutation = useCancelShipment(token);
|
|
451
|
+
const updateStatusMutation = useUpdateShipmentStatus(token);
|
|
452
|
+
return {
|
|
453
|
+
createShipment: createShipmentMutation.mutateAsync,
|
|
454
|
+
isCreatingShipment: createShipmentMutation.isPending,
|
|
455
|
+
cancelShipment: cancelShipmentMutation.mutateAsync,
|
|
456
|
+
isCancellingShipment: cancelShipmentMutation.isPending,
|
|
457
|
+
updateShipmentStatus: updateStatusMutation.mutateAsync,
|
|
458
|
+
isUpdatingStatus: updateStatusMutation.isPending,
|
|
459
|
+
isLoading: createShipmentMutation.isPending || cancelShipmentMutation.isPending || updateStatusMutation.isPending
|
|
460
|
+
};
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
export { LOGISTICS_KEYS, LogisticsApi, logisticsApi, useCancelShipment, useCreateShipment, useDeliveryCharge, useDeliveryChargeCalculation, useLogisticsActions, usePickupStores, useShipment, useTrackShipment, useUpdateShipmentStatus };
|
|
464
|
+
//# sourceMappingURL=chunk-5L6EXDGH.js.map
|
|
465
|
+
//# sourceMappingURL=chunk-5L6EXDGH.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/logistics/api/logistics.ts","../src/logistics/hooks/logistics.ts"],"names":[],"mappings":"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","file":"chunk-5L6EXDGH.js","sourcesContent":["// @/logistics/api/logistics.ts\r\nimport { BaseApi, type RequestOptions, type ApiResponse } from \"../../core/api-factory\";\r\nimport { handleApiRequest } from \"../../core/api-handler\";\r\nimport type {\r\n Shipment,\r\n TrackingResult,\r\n PickupStore,\r\n LogisticsConfig,\r\n ProviderCharges,\r\n CreateShipmentPayload,\r\n UpdateShipmentStatusPayload,\r\n CancelShipmentPayload,\r\n ProviderName,\r\n} from \"../types/logistics\";\r\n\r\n// ==================== Request Options ====================\r\n\r\ntype FetchOptions = Omit<RequestOptions, 'token' | 'organizationId'>;\r\n\r\n// ==================== Logistics API ====================\r\n\r\n/**\r\n * Logistics API\r\n *\r\n * Manages shipments and delivery charge calculation.\r\n *\r\n * NOTE: For area data (divisions, districts, areas), use @classytic/bd-areas directly:\r\n * ```typescript\r\n * import { searchAreas, getAreasByDistrict, getArea } from '@classytic/bd-areas';\r\n * ```\r\n *\r\n * Public Endpoints:\r\n * - GET /logistics/charge - Calculate delivery charge via provider (RedX)\r\n *\r\n * Shipment Endpoints (Admin/Store Manager):\r\n * - POST /logistics/shipments - Create shipment\r\n * - GET /logistics/shipments/:id - Get shipment\r\n * - GET /logistics/shipments/:id/track - Track shipment\r\n * - PATCH /logistics/shipments/:id/status - Update status manually\r\n * - POST /logistics/shipments/:id/cancel - Cancel shipment\r\n *\r\n * Admin Endpoints:\r\n * - GET /logistics/config - Get config (read-only)\r\n * - GET /logistics/pickup-stores - List pickup stores\r\n * - GET /logistics/health/circuit-status - Get circuit breaker status\r\n * - POST /logistics/health/circuit-reset/:provider - Reset circuit breaker\r\n */\r\nclass LogisticsApi extends BaseApi<Shipment, CreateShipmentPayload> {\r\n constructor(config = {}) {\r\n super('logistics', config);\r\n }\r\n\r\n // ============================================\r\n // CHARGE CALCULATION (Public)\r\n // ============================================\r\n\r\n /**\r\n * Calculate delivery charge via provider API (e.g., RedX)\r\n * GET /logistics/charge\r\n *\r\n * Use this to get real-time delivery charges from the logistics provider\r\n * before creating an order.\r\n *\r\n * @param deliveryAreaId - Area internalId from @classytic/bd-areas\r\n * @param amount - COD amount in BDT (use 0 for prepaid orders)\r\n * @param weight - Parcel weight in grams (default: 500g)\r\n *\r\n * @example\r\n * import { searchAreas } from '@classytic/bd-areas';\r\n *\r\n * // 1. User selects area\r\n * const areas = searchAreas('mohamm');\r\n * const selectedArea = areas[0]; // { internalId: 1206, name: 'Mohammadpur', ... }\r\n *\r\n * // 2. Calculate delivery charge\r\n * const { data } = await logisticsApi.calculateCharge({\r\n * deliveryAreaId: selectedArea.internalId,\r\n * amount: isCOD ? cartTotal : 0,\r\n * });\r\n * // { deliveryCharge: 60, codCharge: 15, totalCharge: 75 }\r\n */\r\n async calculateCharge({\r\n deliveryAreaId,\r\n pickupAreaId,\r\n amount,\r\n weight,\r\n provider,\r\n options = {},\r\n }: {\r\n deliveryAreaId: number;\r\n pickupAreaId?: number;\r\n amount: number;\r\n weight?: number;\r\n provider?: ProviderName;\r\n options?: FetchOptions;\r\n }): Promise<ApiResponse<ProviderCharges>> {\r\n if (!deliveryAreaId || amount === undefined) {\r\n throw new Error(\"deliveryAreaId and amount are required\");\r\n }\r\n\r\n const queryString = this.createQueryString({\r\n deliveryAreaId,\r\n pickupAreaId,\r\n amount,\r\n weight,\r\n provider,\r\n });\r\n\r\n return handleApiRequest(\"GET\", `${this.baseUrl}/charge?${queryString}`, {\r\n cache: \"no-store\",\r\n ...options,\r\n });\r\n }\r\n\r\n // ============================================\r\n // CONFIG ENDPOINTS (Admin - Read-only)\r\n // ============================================\r\n\r\n /**\r\n * Get logistics configuration (read-only from .env)\r\n * GET /logistics/config\r\n *\r\n * NOTE: Configuration is managed via environment variables.\r\n * To change settings, update .env file and restart server.\r\n */\r\n async getConfig({\r\n token,\r\n options = {},\r\n }: {\r\n token: string;\r\n options?: FetchOptions;\r\n }): Promise<ApiResponse<LogisticsConfig>> {\r\n return handleApiRequest(\"GET\", `${this.baseUrl}/config`, {\r\n token,\r\n cache: \"no-store\",\r\n ...options,\r\n });\r\n }\r\n\r\n // ============================================\r\n // PICKUP STORES (Admin)\r\n // ============================================\r\n\r\n /**\r\n * Get pickup stores from RedX API\r\n * GET /logistics/pickup-stores\r\n *\r\n * Pickup stores are created by admin in RedX dashboard.\r\n * Use this to list available pickup locations when creating shipments.\r\n *\r\n * @example\r\n * // Admin: List pickup stores for shipment creation\r\n * const { data: stores } = await logisticsApi.getPickupStores({ token });\r\n *\r\n * // Display in dropdown for admin to select\r\n * stores.forEach(store => {\r\n * console.log(`${store.name} - ${store.areaName} (ID: ${store.id})`);\r\n * });\r\n *\r\n * // Use selected store when creating shipment\r\n * await logisticsApi.createShipment({\r\n * token,\r\n * data: {\r\n * orderId: order._id,\r\n * pickupStoreId: selectedStore.id, // From dropdown\r\n * },\r\n * });\r\n */\r\n async getPickupStores({\r\n token,\r\n provider,\r\n options = {},\r\n }: {\r\n token: string;\r\n provider?: string;\r\n options?: FetchOptions;\r\n }): Promise<ApiResponse<PickupStore[]>> {\r\n const queryString = provider ? `?provider=${provider}` : '';\r\n return handleApiRequest(\r\n \"GET\",\r\n `${this.baseUrl}/pickup-stores${queryString}`,\r\n {\r\n token,\r\n cache: \"no-store\",\r\n ...options,\r\n }\r\n );\r\n }\r\n\r\n // ============================================\r\n // SHIPMENT ENDPOINTS (Admin/Store Manager)\r\n // ============================================\r\n\r\n /**\r\n * Create shipment for an order via RedX API\r\n * POST /logistics/shipments\r\n *\r\n * This creates a parcel in RedX and updates the order with tracking info.\r\n *\r\n * @example\r\n * // Basic: Create shipment with default pickup store\r\n * const shipment = await logisticsApi.createShipment({\r\n * token,\r\n * data: { orderId: order._id },\r\n * });\r\n *\r\n * @example\r\n * // With specific pickup store (from getPickupStores)\r\n * const { data: stores } = await logisticsApi.getPickupStores({ token });\r\n * const shipment = await logisticsApi.createShipment({\r\n * token,\r\n * data: {\r\n * orderId: order._id,\r\n * pickupStoreId: stores[0].id, // Select pickup location\r\n * weight: 500, // Parcel weight in grams\r\n * instructions: 'Handle with care',\r\n * },\r\n * });\r\n *\r\n * // Response includes tracking ID\r\n * console.log(`Tracking: ${shipment.data.trackingId}`);\r\n */\r\n async createShipment({\r\n token,\r\n data,\r\n options = {},\r\n }: {\r\n token: string;\r\n data: CreateShipmentPayload;\r\n options?: FetchOptions;\r\n }): Promise<ApiResponse<Shipment>> {\r\n if (!data?.orderId) throw new Error(\"Order ID is required\");\r\n\r\n return handleApiRequest(\"POST\", `${this.baseUrl}/shipments`, {\r\n token,\r\n body: data,\r\n ...options,\r\n });\r\n }\r\n\r\n /**\r\n * Get shipment by ID\r\n * GET /logistics/shipments/:id\r\n */\r\n async getShipment({\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<Shipment>> {\r\n if (!id) throw new Error(\"Shipment ID is required\");\r\n\r\n return handleApiRequest(\"GET\", `${this.baseUrl}/shipments/${id}`, {\r\n token,\r\n cache: \"no-store\",\r\n ...options,\r\n });\r\n }\r\n\r\n /**\r\n * Track shipment (fetch latest from provider)\r\n * GET /logistics/shipments/:id/track\r\n */\r\n async trackShipment({\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<TrackingResult>> {\r\n if (!id) throw new Error(\"Shipment ID is required\");\r\n\r\n return handleApiRequest(\"GET\", `${this.baseUrl}/shipments/${id}/track`, {\r\n token,\r\n cache: \"no-store\",\r\n ...options,\r\n });\r\n }\r\n\r\n /**\r\n * Update shipment status manually\r\n * PATCH /logistics/shipments/:id/status\r\n */\r\n async updateShipmentStatus({\r\n token,\r\n id,\r\n data,\r\n options = {},\r\n }: {\r\n token: string;\r\n id: string;\r\n data: UpdateShipmentStatusPayload;\r\n options?: FetchOptions;\r\n }): Promise<ApiResponse<Shipment>> {\r\n if (!id) throw new Error(\"Shipment ID is required\");\r\n if (!data?.status) throw new Error(\"Status is required\");\r\n\r\n return handleApiRequest(\"PATCH\", `${this.baseUrl}/shipments/${id}/status`, {\r\n token,\r\n body: data,\r\n ...options,\r\n });\r\n }\r\n\r\n /**\r\n * Cancel shipment\r\n * POST /logistics/shipments/:id/cancel\r\n */\r\n async cancelShipment({\r\n token,\r\n id,\r\n data,\r\n options = {},\r\n }: {\r\n token: string;\r\n id: string;\r\n data?: CancelShipmentPayload;\r\n options?: FetchOptions;\r\n }): Promise<ApiResponse<Shipment>> {\r\n if (!id) throw new Error(\"Shipment ID is required\");\r\n\r\n return handleApiRequest(\"POST\", `${this.baseUrl}/shipments/${id}/cancel`, {\r\n token,\r\n body: data || {},\r\n ...options,\r\n });\r\n }\r\n\r\n // ============================================\r\n // HEALTH & MONITORING (Admin)\r\n // ============================================\r\n\r\n /**\r\n * Get circuit breaker status for all providers\r\n * GET /logistics/health/circuit-status\r\n */\r\n async getCircuitStatus({\r\n token,\r\n options = {},\r\n }: {\r\n token: string;\r\n options?: FetchOptions;\r\n }): Promise<ApiResponse<Record<string, { state: string; failureCount: number }>>> {\r\n return handleApiRequest(\"GET\", `${this.baseUrl}/health/circuit-status`, {\r\n token,\r\n cache: \"no-store\",\r\n ...options,\r\n });\r\n }\r\n\r\n /**\r\n * Reset circuit breaker for a provider\r\n * POST /logistics/health/circuit-reset/:provider\r\n */\r\n async resetProviderCircuit({\r\n token,\r\n provider,\r\n options = {},\r\n }: {\r\n token: string;\r\n provider: string;\r\n options?: FetchOptions;\r\n }): Promise<ApiResponse<{ message: string }>> {\r\n if (!provider) throw new Error(\"Provider name is required\");\r\n\r\n return handleApiRequest(\r\n \"POST\",\r\n `${this.baseUrl}/health/circuit-reset/${provider}`,\r\n {\r\n token,\r\n body: {},\r\n ...options,\r\n }\r\n );\r\n }\r\n}\r\n\r\n// Create and export singleton instance\r\nexport const logisticsApi = new LogisticsApi();\r\n\r\n// Export class for custom configurations\r\nexport { LogisticsApi };\r\n","\"use client\";\n\nimport { useQuery, useMutation, useQueryClient } from \"@tanstack/react-query\";\nimport { logisticsApi } from \"../api/logistics\";\nimport { getToastHandler } from \"../../core/react/mutation.factory\";\nimport type {\n Shipment,\n PickupStore,\n TrackingResult,\n CreateShipmentPayload,\n ProviderCharges,\n ProviderName,\n} from \"../types/logistics\";\n\n// ============================================\n// Query Keys\n// ============================================\n\nexport const LOGISTICS_KEYS = {\n all: [\"logistics\"] as const,\n pickupStores: (provider?: string) => [...LOGISTICS_KEYS.all, \"pickup-stores\", provider] as const,\n shipment: (id: string) => [...LOGISTICS_KEYS.all, \"shipment\", id] as const,\n tracking: (id: string) => [...LOGISTICS_KEYS.all, \"tracking\", id] as const,\n charge: (params: { deliveryAreaId: number; amount: number; weight?: number }) =>\n [...LOGISTICS_KEYS.all, \"charge\", params] as const,\n config: () => [...LOGISTICS_KEYS.all, \"config\"] as const,\n};\n\n// ============================================\n// Types\n// ============================================\n\ninterface QueryOptions {\n enabled?: boolean;\n staleTime?: number;\n refetchInterval?: number | false;\n}\n\ninterface ChargeParams {\n deliveryAreaId: number;\n pickupAreaId?: number;\n amount: number;\n weight?: number;\n provider?: ProviderName;\n}\n\ninterface UseDeliveryChargeParams {\n deliveryAreaId: number | null | undefined;\n amount: number;\n weight?: number;\n enabled?: boolean;\n}\n\nexport interface UseDeliveryChargeReturn {\n charges: ProviderCharges | null;\n deliveryCharge: number;\n codCharge: number;\n totalCharge: number;\n isLoading: boolean;\n isFetching: boolean;\n error: Error | null;\n refetch: () => void;\n}\n\nexport interface UseLogisticsActionsReturn {\n createShipment: (data: CreateShipmentPayload) => Promise<Shipment | undefined>;\n isCreatingShipment: boolean;\n cancelShipment: (params: { shipmentId: string; reason?: string }) => Promise<Shipment | undefined>;\n isCancellingShipment: boolean;\n updateShipmentStatus: (params: { shipmentId: string; status: string; message?: string }) => Promise<Shipment | undefined>;\n isUpdatingStatus: boolean;\n isLoading: boolean;\n}\n\n// ============================================\n// Query Hooks\n// ============================================\n\n/**\n * Fetch pickup stores from logistics provider\n *\n * @param token - Auth token (admin required)\n * @param provider - Optional provider filter\n * @param options - Query options\n *\n * @example\n * ```tsx\n * function PickupStoreSelect() {\n * const { data: stores, isLoading } = usePickupStores(token);\n *\n * return (\n * <Select>\n * {stores?.map(store => (\n * <SelectItem key={store.id} value={store.id.toString()}>\n * {store.name} - {store.areaName}\n * </SelectItem>\n * ))}\n * </Select>\n * );\n * }\n * ```\n */\nexport function usePickupStores(\n token: string,\n provider?: string,\n options: QueryOptions = {}\n) {\n return useQuery({\n queryKey: LOGISTICS_KEYS.pickupStores(provider),\n queryFn: async (): Promise<PickupStore[]> => {\n const response = await logisticsApi.getPickupStores({ token, provider });\n return response.data || [];\n },\n enabled: options.enabled !== false && !!token,\n staleTime: options.staleTime ?? 5 * 60 * 1000,\n });\n}\n\n/**\n * Calculate delivery charge via provider API\n *\n * @param token - Auth token (optional for public)\n * @param params - Charge calculation parameters\n * @param options - Query options\n *\n * @example\n * ```tsx\n * const { data: charges } = useDeliveryChargeCalculation(token, {\n * deliveryAreaId: 1206,\n * amount: isCOD ? cartTotal : 0,\n * });\n * ```\n */\nexport function useDeliveryChargeCalculation(\n token: string | null,\n params: ChargeParams | null,\n options: QueryOptions = {}\n) {\n const hasValidParams = !!params?.deliveryAreaId && params?.amount !== undefined;\n\n return useQuery({\n queryKey: LOGISTICS_KEYS.charge(\n params\n ? { deliveryAreaId: params.deliveryAreaId, amount: params.amount, weight: params.weight }\n : { deliveryAreaId: 0, amount: 0 }\n ),\n queryFn: async (): Promise<ProviderCharges> => {\n if (!params) throw new Error(\"Params required\");\n const response = await logisticsApi.calculateCharge({\n deliveryAreaId: params.deliveryAreaId,\n pickupAreaId: params.pickupAreaId,\n amount: params.amount,\n weight: params.weight,\n provider: params.provider,\n });\n if (!response.data) throw new Error(\"No charge data returned\");\n return response.data;\n },\n enabled: options.enabled !== false && hasValidParams,\n staleTime: options.staleTime ?? 60 * 1000,\n });\n}\n\n/**\n * Convenience hook for delivery charge with extracted values\n *\n * @param params - Delivery charge parameters\n *\n * @example\n * ```tsx\n * function CheckoutDelivery({ areaId, subtotal, isCOD }) {\n * const { deliveryCharge, isLoading } = useDeliveryCharge({\n * deliveryAreaId: areaId,\n * amount: isCOD ? subtotal : 0,\n * });\n *\n * return (\n * <p>Delivery: {isLoading ? \"...\" : `৳${deliveryCharge}`}</p>\n * );\n * }\n * ```\n */\nexport function useDeliveryCharge({\n deliveryAreaId,\n amount,\n weight = 500,\n enabled = true,\n}: UseDeliveryChargeParams): UseDeliveryChargeReturn {\n const { data, isLoading, isFetching, error, refetch } = useQuery<ProviderCharges | null>({\n queryKey: LOGISTICS_KEYS.charge({\n deliveryAreaId: deliveryAreaId || 0,\n amount,\n weight,\n }),\n queryFn: async () => {\n if (!deliveryAreaId) return null;\n\n const response = await logisticsApi.calculateCharge({\n deliveryAreaId,\n amount,\n weight,\n });\n\n return response.data || null;\n },\n enabled: enabled && !!deliveryAreaId,\n staleTime: 5 * 60 * 1000,\n gcTime: 10 * 60 * 1000,\n retry: 1,\n });\n\n return {\n charges: data || null,\n deliveryCharge: data?.deliveryCharge ?? 0,\n codCharge: data?.codCharge ?? 0,\n totalCharge: data?.totalCharge ?? 0,\n isLoading,\n isFetching,\n error: error as Error | null,\n refetch,\n };\n}\n\n/**\n * Get shipment by ID\n *\n * @param token - Auth token\n * @param shipmentId - Shipment ID\n * @param options - Query options\n */\nexport function useShipment(\n token: string,\n shipmentId: string | null,\n options: QueryOptions = {}\n) {\n return useQuery({\n queryKey: LOGISTICS_KEYS.shipment(shipmentId || \"\"),\n queryFn: async (): Promise<Shipment> => {\n if (!shipmentId) throw new Error(\"Shipment ID required\");\n const response = await logisticsApi.getShipment({ token, id: shipmentId });\n if (!response.data) throw new Error(\"Shipment not found\");\n return response.data;\n },\n enabled: options.enabled !== false && !!token && !!shipmentId,\n staleTime: options.staleTime ?? 30 * 1000,\n });\n}\n\n/**\n * Track shipment - fetches latest status from provider\n *\n * @param token - Auth token\n * @param shipmentId - Shipment ID\n * @param options - Query options (supports refetchInterval for auto-refresh)\n *\n * @example\n * ```tsx\n * function ShipmentTracker({ shipmentId }) {\n * const { data, isLoading } = useTrackShipment(token, shipmentId, {\n * refetchInterval: 5 * 60 * 1000, // Auto-refresh every 5 minutes\n * });\n *\n * return (\n * <Timeline events={data?.tracking?.timeline || []} />\n * );\n * }\n * ```\n */\nexport function useTrackShipment(\n token: string,\n shipmentId: string | null,\n options: QueryOptions = {}\n) {\n return useQuery({\n queryKey: LOGISTICS_KEYS.tracking(shipmentId || \"\"),\n queryFn: async (): Promise<TrackingResult> => {\n if (!shipmentId) throw new Error(\"Shipment ID required\");\n const response = await logisticsApi.trackShipment({ token, id: shipmentId });\n if (!response.data) throw new Error(\"Tracking data not found\");\n return response.data;\n },\n enabled: options.enabled !== false && !!token && !!shipmentId,\n staleTime: options.staleTime ?? 60 * 1000,\n refetchInterval: options.refetchInterval ?? 5 * 60 * 1000,\n });\n}\n\n// ============================================\n// Mutation Hooks\n// ============================================\n\n/**\n * Create shipment mutation\n *\n * @param token - Auth token\n *\n * @example\n * ```tsx\n * function CreateShipmentButton({ order }) {\n * const { mutate, isPending } = useCreateShipment(token);\n *\n * return (\n * <Button\n * onClick={() => mutate({ orderId: order._id })}\n * disabled={isPending}\n * >\n * Create Shipment\n * </Button>\n * );\n * }\n * ```\n */\nexport function useCreateShipment(token: string) {\n const queryClient = useQueryClient();\n const toast = getToastHandler();\n\n return useMutation({\n mutationFn: async (data: CreateShipmentPayload) => {\n const response = await logisticsApi.createShipment({ token, data });\n return response.data;\n },\n onSuccess: () => {\n toast.success(\"Shipment created successfully\");\n queryClient.invalidateQueries({ queryKey: [\"orders\"] });\n queryClient.invalidateQueries({ queryKey: LOGISTICS_KEYS.all });\n },\n onError: (error: Error) => {\n toast.error(error.message || \"Failed to create shipment\");\n },\n });\n}\n\n/**\n * Cancel shipment mutation\n *\n * @param token - Auth token\n */\nexport function useCancelShipment(token: string) {\n const queryClient = useQueryClient();\n const toast = getToastHandler();\n\n return useMutation({\n mutationFn: async ({ shipmentId, reason }: { shipmentId: string; reason?: string }) => {\n const response = await logisticsApi.cancelShipment({\n token,\n id: shipmentId,\n data: { reason },\n });\n return response.data;\n },\n onSuccess: () => {\n toast.success(\"Shipment cancelled\");\n queryClient.invalidateQueries({ queryKey: [\"orders\"] });\n queryClient.invalidateQueries({ queryKey: LOGISTICS_KEYS.all });\n },\n onError: (error: Error) => {\n toast.error(error.message || \"Failed to cancel shipment\");\n },\n });\n}\n\n/**\n * Update shipment status mutation\n *\n * @param token - Auth token\n */\nexport function useUpdateShipmentStatus(token: string) {\n const queryClient = useQueryClient();\n const toast = getToastHandler();\n\n return useMutation({\n mutationFn: async ({\n shipmentId,\n status,\n message,\n }: {\n shipmentId: string;\n status: string;\n message?: string;\n }) => {\n const response = await logisticsApi.updateShipmentStatus({\n token,\n id: shipmentId,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n data: { status: status as any, message },\n });\n return response.data;\n },\n onSuccess: () => {\n toast.success(\"Shipment status updated\");\n queryClient.invalidateQueries({ queryKey: [\"orders\"] });\n queryClient.invalidateQueries({ queryKey: LOGISTICS_KEYS.all });\n },\n onError: (error: Error) => {\n toast.error(error.message || \"Failed to update status\");\n },\n });\n}\n\n/**\n * Combined hook for all logistics mutations\n *\n * @param token - Auth token\n *\n * @example\n * ```tsx\n * function ShipmentActions({ order }) {\n * const {\n * createShipment,\n * cancelShipment,\n * isLoading,\n * } = useLogisticsActions(token);\n *\n * return (\n * <>\n * <Button onClick={() => createShipment({ orderId: order._id })}>\n * Create Shipment\n * </Button>\n * <Button onClick={() => cancelShipment({ shipmentId: order.shipment._id })}>\n * Cancel\n * </Button>\n * </>\n * );\n * }\n * ```\n */\nexport function useLogisticsActions(token: string): UseLogisticsActionsReturn {\n const createShipmentMutation = useCreateShipment(token);\n const cancelShipmentMutation = useCancelShipment(token);\n const updateStatusMutation = useUpdateShipmentStatus(token);\n\n return {\n createShipment: createShipmentMutation.mutateAsync,\n isCreatingShipment: createShipmentMutation.isPending,\n cancelShipment: cancelShipmentMutation.mutateAsync,\n isCancellingShipment: cancelShipmentMutation.isPending,\n updateShipmentStatus: updateStatusMutation.mutateAsync,\n isUpdatingStatus: updateStatusMutation.isPending,\n isLoading:\n createShipmentMutation.isPending ||\n cancelShipmentMutation.isPending ||\n updateStatusMutation.isPending,\n };\n}\n"]}
|