@lodashventure/medusa-quotation 1.4.19 → 1.4.21
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.
- package/.medusa/server/src/admin/index.js +300 -69
- package/.medusa/server/src/admin/index.mjs +301 -70
- package/.medusa/server/src/api/admin/quotes/[id]/approve/route.js +22 -0
- package/.medusa/server/src/api/admin/quotes/[id]/route.js +13 -2
- package/.medusa/server/src/api/admin/quotes/[id]/void/route.js +22 -0
- package/.medusa/server/src/modules/quote/migrations/Migration20251028120000.js +18 -0
- package/.medusa/server/src/modules/quote/types/quote-status.enum.js +3 -1
- package/.medusa/server/src/workflows/merchant-approve-quote.js +30 -0
- package/.medusa/server/src/workflows/merchant-delete-quote.js +24 -0
- package/.medusa/server/src/workflows/merchant-void-quote.js +30 -0
- package/.medusa/server/src/workflows/steps/delete-quotes.js +13 -0
- package/.medusa/server/src/workflows/steps/validate-quote-can-approve.js +17 -0
- package/.medusa/server/src/workflows/steps/validate-quote-can-delete.js +17 -0
- package/.medusa/server/src/workflows/steps/validate-quote-can-void.js +12 -0
- package/.medusa/server/src/workflows/steps/validate-quote-not-accepted.js +7 -1
- package/package.json +1 -1
|
@@ -17,20 +17,26 @@ const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
|
|
|
17
17
|
const Medusa__default = /* @__PURE__ */ _interopDefault(Medusa);
|
|
18
18
|
const pdfMake__default = /* @__PURE__ */ _interopDefault(pdfMake);
|
|
19
19
|
const StatusTitles = {
|
|
20
|
+
approved: "Approved",
|
|
20
21
|
accepted: "Accepted",
|
|
21
22
|
customer_rejected: "Customer Rejected",
|
|
22
23
|
merchant_rejected: "Merchant Rejected",
|
|
23
24
|
pending_merchant: "Pending Merchant",
|
|
24
|
-
pending_customer: "Pending Customer"
|
|
25
|
+
pending_customer: "Pending Customer",
|
|
26
|
+
voided: "Voided"
|
|
25
27
|
};
|
|
26
28
|
const getStatusColor = (statusKey) => {
|
|
27
29
|
switch (statusKey) {
|
|
28
30
|
case "accepted":
|
|
29
31
|
return "bg-green-100 text-green-800";
|
|
32
|
+
case "approved":
|
|
33
|
+
return "bg-emerald-100 text-emerald-800";
|
|
30
34
|
case "pending_merchant":
|
|
31
35
|
return "bg-blue-100 text-blue-800";
|
|
32
36
|
case "customer_rejected":
|
|
33
37
|
return "bg-red-100 text-red-800";
|
|
38
|
+
case "voided":
|
|
39
|
+
return "bg-gray-100 text-gray-800";
|
|
34
40
|
default:
|
|
35
41
|
return "bg-gray-100 text-gray-800";
|
|
36
42
|
}
|
|
@@ -47,6 +53,10 @@ const getStatusIcon = (statusKey) => {
|
|
|
47
53
|
return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.XCircle, { className: "h-4 w-4 text-red-600" });
|
|
48
54
|
case "customer_rejected":
|
|
49
55
|
return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.XCircle, { className: "h-4 w-4 text-red-600" });
|
|
56
|
+
case "approved":
|
|
57
|
+
return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CheckCircle, { className: "h-4 w-4 text-emerald-600" });
|
|
58
|
+
case "voided":
|
|
59
|
+
return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.XCircle, { className: "h-4 w-4 text-gray-600" });
|
|
50
60
|
default:
|
|
51
61
|
return null;
|
|
52
62
|
}
|
|
@@ -151,7 +161,7 @@ const useAddQuoteItem = (id, options) => {
|
|
|
151
161
|
setIsPending(false);
|
|
152
162
|
}
|
|
153
163
|
};
|
|
154
|
-
return { mutate, isPending, error };
|
|
164
|
+
return { mutate, mutateAsync: mutate, isPending, error };
|
|
155
165
|
};
|
|
156
166
|
const useUpdateQuoteItem = (id, options) => {
|
|
157
167
|
const [isPending, setIsPending] = react.useState(false);
|
|
@@ -175,7 +185,7 @@ const useUpdateQuoteItem = (id, options) => {
|
|
|
175
185
|
setIsPending(false);
|
|
176
186
|
}
|
|
177
187
|
};
|
|
178
|
-
return { mutate, isPending, error };
|
|
188
|
+
return { mutate, mutateAsync: mutate, isPending, error };
|
|
179
189
|
};
|
|
180
190
|
const useRemoveQuoteItem = (id, options) => {
|
|
181
191
|
const [isPending, setIsPending] = react.useState(false);
|
|
@@ -195,7 +205,7 @@ const useRemoveQuoteItem = (id, options) => {
|
|
|
195
205
|
setIsPending(false);
|
|
196
206
|
}
|
|
197
207
|
};
|
|
198
|
-
return { mutate, isPending, error };
|
|
208
|
+
return { mutate, mutateAsync: mutate, isPending, error };
|
|
199
209
|
};
|
|
200
210
|
const useConfirmQuote = (id, options) => {
|
|
201
211
|
const [isPending, setIsPending] = react.useState(false);
|
|
@@ -215,7 +225,7 @@ const useConfirmQuote = (id, options) => {
|
|
|
215
225
|
setIsPending(false);
|
|
216
226
|
}
|
|
217
227
|
};
|
|
218
|
-
return { mutate, isPending, error };
|
|
228
|
+
return { mutate, mutateAsync: mutate, isPending, error };
|
|
219
229
|
};
|
|
220
230
|
const useSendQuote = (id, options) => {
|
|
221
231
|
const [isPending, setIsPending] = react.useState(false);
|
|
@@ -223,22 +233,49 @@ const useSendQuote = (id, options) => {
|
|
|
223
233
|
const sendQuote = async (id2) => sdk.client.fetch(`/admin/quotes/${id2}/send`, {
|
|
224
234
|
method: "POST"
|
|
225
235
|
});
|
|
226
|
-
const mutate = async () => {
|
|
227
|
-
var _a;
|
|
236
|
+
const mutate = async (_, mutateOptions) => {
|
|
237
|
+
var _a, _b, _c;
|
|
228
238
|
try {
|
|
229
239
|
setIsPending(true);
|
|
230
240
|
setError(null);
|
|
231
241
|
const data = await sendQuote(id);
|
|
232
242
|
(_a = options == null ? void 0 : options.onSuccess) == null ? void 0 : _a.call(options, data);
|
|
243
|
+
(_b = mutateOptions == null ? void 0 : mutateOptions.onSuccess) == null ? void 0 : _b.call(mutateOptions, data);
|
|
233
244
|
return data;
|
|
234
245
|
} catch (err) {
|
|
235
246
|
setError(err);
|
|
247
|
+
(_c = mutateOptions == null ? void 0 : mutateOptions.onError) == null ? void 0 : _c.call(mutateOptions, err);
|
|
236
248
|
throw err;
|
|
237
249
|
} finally {
|
|
238
250
|
setIsPending(false);
|
|
239
251
|
}
|
|
240
252
|
};
|
|
241
|
-
return { mutate, isPending, error };
|
|
253
|
+
return { mutate, mutateAsync: mutate, isPending, error };
|
|
254
|
+
};
|
|
255
|
+
const useApproveQuote = (id, options) => {
|
|
256
|
+
const [isPending, setIsPending] = react.useState(false);
|
|
257
|
+
const [error, setError] = react.useState(null);
|
|
258
|
+
const approveQuote = async (quoteId) => sdk.client.fetch(`/admin/quotes/${quoteId}/approve`, {
|
|
259
|
+
method: "POST"
|
|
260
|
+
});
|
|
261
|
+
const mutate = async (_, mutateOptions) => {
|
|
262
|
+
var _a, _b, _c;
|
|
263
|
+
try {
|
|
264
|
+
setIsPending(true);
|
|
265
|
+
setError(null);
|
|
266
|
+
const data = await approveQuote(id);
|
|
267
|
+
(_a = options == null ? void 0 : options.onSuccess) == null ? void 0 : _a.call(options, data);
|
|
268
|
+
(_b = mutateOptions == null ? void 0 : mutateOptions.onSuccess) == null ? void 0 : _b.call(mutateOptions, data);
|
|
269
|
+
return data;
|
|
270
|
+
} catch (err) {
|
|
271
|
+
setError(err);
|
|
272
|
+
(_c = mutateOptions == null ? void 0 : mutateOptions.onError) == null ? void 0 : _c.call(mutateOptions, err);
|
|
273
|
+
throw err;
|
|
274
|
+
} finally {
|
|
275
|
+
setIsPending(false);
|
|
276
|
+
}
|
|
277
|
+
};
|
|
278
|
+
return { mutate, mutateAsync: mutate, isPending, error };
|
|
242
279
|
};
|
|
243
280
|
const useRejectQuote = (id, options) => {
|
|
244
281
|
const [isPending, setIsPending] = react.useState(false);
|
|
@@ -246,22 +283,96 @@ const useRejectQuote = (id, options) => {
|
|
|
246
283
|
const rejectQuote = async (id2) => sdk.client.fetch(`/admin/quotes/${id2}/reject`, {
|
|
247
284
|
method: "POST"
|
|
248
285
|
});
|
|
249
|
-
const mutate = async () => {
|
|
250
|
-
var _a;
|
|
286
|
+
const mutate = async (_, mutateOptions) => {
|
|
287
|
+
var _a, _b, _c;
|
|
251
288
|
try {
|
|
252
289
|
setIsPending(true);
|
|
253
290
|
setError(null);
|
|
254
291
|
const data = await rejectQuote(id);
|
|
255
292
|
(_a = options == null ? void 0 : options.onSuccess) == null ? void 0 : _a.call(options, data);
|
|
293
|
+
(_b = mutateOptions == null ? void 0 : mutateOptions.onSuccess) == null ? void 0 : _b.call(mutateOptions, data);
|
|
256
294
|
return data;
|
|
257
295
|
} catch (err) {
|
|
258
296
|
setError(err);
|
|
297
|
+
(_c = mutateOptions == null ? void 0 : mutateOptions.onError) == null ? void 0 : _c.call(mutateOptions, err);
|
|
259
298
|
throw err;
|
|
260
299
|
} finally {
|
|
261
300
|
setIsPending(false);
|
|
262
301
|
}
|
|
263
302
|
};
|
|
264
|
-
return { mutate, isPending, error };
|
|
303
|
+
return { mutate, mutateAsync: mutate, isPending, error };
|
|
304
|
+
};
|
|
305
|
+
const useVoidQuote = (id, options) => {
|
|
306
|
+
const [isPending, setIsPending] = react.useState(false);
|
|
307
|
+
const [error, setError] = react.useState(null);
|
|
308
|
+
const voidQuote = async (quoteId) => sdk.client.fetch(`/admin/quotes/${quoteId}/void`, {
|
|
309
|
+
method: "POST"
|
|
310
|
+
});
|
|
311
|
+
const mutate = async (_, mutateOptions) => {
|
|
312
|
+
var _a, _b, _c;
|
|
313
|
+
try {
|
|
314
|
+
setIsPending(true);
|
|
315
|
+
setError(null);
|
|
316
|
+
const data = await voidQuote(id);
|
|
317
|
+
(_a = options == null ? void 0 : options.onSuccess) == null ? void 0 : _a.call(options, data);
|
|
318
|
+
(_b = mutateOptions == null ? void 0 : mutateOptions.onSuccess) == null ? void 0 : _b.call(mutateOptions, data);
|
|
319
|
+
return data;
|
|
320
|
+
} catch (err) {
|
|
321
|
+
setError(err);
|
|
322
|
+
(_c = mutateOptions == null ? void 0 : mutateOptions.onError) == null ? void 0 : _c.call(mutateOptions, err);
|
|
323
|
+
throw err;
|
|
324
|
+
} finally {
|
|
325
|
+
setIsPending(false);
|
|
326
|
+
}
|
|
327
|
+
};
|
|
328
|
+
return { mutate, mutateAsync: mutate, isPending, error };
|
|
329
|
+
};
|
|
330
|
+
const useDeleteQuote = (id, options) => {
|
|
331
|
+
const [isPending, setIsPending] = react.useState(false);
|
|
332
|
+
const [error, setError] = react.useState(null);
|
|
333
|
+
const deleteQuote = async () => {
|
|
334
|
+
const response = await fetch(`/admin/quotes/${id}`, {
|
|
335
|
+
method: "DELETE",
|
|
336
|
+
headers: {
|
|
337
|
+
"Content-Type": "application/json"
|
|
338
|
+
},
|
|
339
|
+
credentials: "include"
|
|
340
|
+
});
|
|
341
|
+
if (!response.ok) {
|
|
342
|
+
const errorText = await response.text();
|
|
343
|
+
let errorMessage = errorText;
|
|
344
|
+
try {
|
|
345
|
+
const errorJson = JSON.parse(errorText);
|
|
346
|
+
errorMessage = errorJson.message || errorText;
|
|
347
|
+
} catch {
|
|
348
|
+
}
|
|
349
|
+
throw new Error(errorMessage || `HTTP ${response.status}`);
|
|
350
|
+
}
|
|
351
|
+
if (response.status === 204) {
|
|
352
|
+
return;
|
|
353
|
+
}
|
|
354
|
+
const contentType = response.headers.get("content-type");
|
|
355
|
+
if (contentType && contentType.includes("application/json")) {
|
|
356
|
+
return response.json();
|
|
357
|
+
}
|
|
358
|
+
};
|
|
359
|
+
const mutate = async (_, mutateOptions) => {
|
|
360
|
+
var _a, _b, _c;
|
|
361
|
+
try {
|
|
362
|
+
setIsPending(true);
|
|
363
|
+
setError(null);
|
|
364
|
+
await deleteQuote();
|
|
365
|
+
(_a = options == null ? void 0 : options.onSuccess) == null ? void 0 : _a.call(options);
|
|
366
|
+
(_b = mutateOptions == null ? void 0 : mutateOptions.onSuccess) == null ? void 0 : _b.call(mutateOptions);
|
|
367
|
+
} catch (err) {
|
|
368
|
+
setError(err);
|
|
369
|
+
(_c = mutateOptions == null ? void 0 : mutateOptions.onError) == null ? void 0 : _c.call(mutateOptions, err);
|
|
370
|
+
throw err;
|
|
371
|
+
} finally {
|
|
372
|
+
setIsPending(false);
|
|
373
|
+
}
|
|
374
|
+
};
|
|
375
|
+
return { mutate, mutateAsync: mutate, isPending, error };
|
|
265
376
|
};
|
|
266
377
|
const useQuoteStore = () => {
|
|
267
378
|
const [data, setData] = react.useState(void 0);
|
|
@@ -1181,7 +1292,7 @@ const StoreConfig = () => {
|
|
|
1181
1292
|
const onSubmit = async (data) => {
|
|
1182
1293
|
try {
|
|
1183
1294
|
setIsLoading(true);
|
|
1184
|
-
await updateQuoteStore.
|
|
1295
|
+
await updateQuoteStore.mutate(data);
|
|
1185
1296
|
ui.toast.success("Company information saved successfully");
|
|
1186
1297
|
setOpen(false);
|
|
1187
1298
|
} catch (error) {
|
|
@@ -1678,11 +1789,15 @@ const TotalsBreakdown = ({ order }) => {
|
|
|
1678
1789
|
})
|
|
1679
1790
|
] });
|
|
1680
1791
|
};
|
|
1681
|
-
const useOrderPreview = (id, query) => {
|
|
1792
|
+
const useOrderPreview = (id, query, options) => {
|
|
1682
1793
|
const [data, setData] = react.useState(void 0);
|
|
1683
1794
|
const [isLoading, setIsLoading] = react.useState(true);
|
|
1684
1795
|
const [error, setError] = react.useState(null);
|
|
1796
|
+
const enabled = (options == null ? void 0 : options.enabled) ?? true;
|
|
1685
1797
|
const fetchOrderPreview = react.useCallback(async () => {
|
|
1798
|
+
if (!id || !enabled) {
|
|
1799
|
+
return;
|
|
1800
|
+
}
|
|
1686
1801
|
try {
|
|
1687
1802
|
setIsLoading(true);
|
|
1688
1803
|
setError(null);
|
|
@@ -1693,10 +1808,14 @@ const useOrderPreview = (id, query) => {
|
|
|
1693
1808
|
} finally {
|
|
1694
1809
|
setIsLoading(false);
|
|
1695
1810
|
}
|
|
1696
|
-
}, [id, JSON.stringify(query)]);
|
|
1811
|
+
}, [id, enabled, JSON.stringify(query)]);
|
|
1697
1812
|
react.useEffect(() => {
|
|
1813
|
+
if (!id || !enabled) {
|
|
1814
|
+
setIsLoading(false);
|
|
1815
|
+
return;
|
|
1816
|
+
}
|
|
1698
1817
|
fetchOrderPreview();
|
|
1699
|
-
}, [fetchOrderPreview]);
|
|
1818
|
+
}, [fetchOrderPreview, id, enabled]);
|
|
1700
1819
|
return {
|
|
1701
1820
|
...data,
|
|
1702
1821
|
isLoading,
|
|
@@ -1756,13 +1875,17 @@ const DEFAULT_RELATIONS = [
|
|
|
1756
1875
|
const DEFAULT_ORDER_FIELDS = `${DEFAULT_PROPERTIES.join(
|
|
1757
1876
|
","
|
|
1758
1877
|
)},${DEFAULT_RELATIONS.join(",")}`;
|
|
1759
|
-
const useOrder = (id, query) => {
|
|
1878
|
+
const useOrder = (id, query, options) => {
|
|
1760
1879
|
const [data, setData] = react.useState(
|
|
1761
1880
|
void 0
|
|
1762
1881
|
);
|
|
1763
1882
|
const [isLoading, setIsLoading] = react.useState(true);
|
|
1764
1883
|
const [error, setError] = react.useState(null);
|
|
1884
|
+
const enabled = (options == null ? void 0 : options.enabled) ?? true;
|
|
1765
1885
|
const fetchOrder = react.useCallback(async () => {
|
|
1886
|
+
if (!id || !enabled) {
|
|
1887
|
+
return;
|
|
1888
|
+
}
|
|
1766
1889
|
try {
|
|
1767
1890
|
setIsLoading(true);
|
|
1768
1891
|
setError(null);
|
|
@@ -1773,10 +1896,14 @@ const useOrder = (id, query) => {
|
|
|
1773
1896
|
} finally {
|
|
1774
1897
|
setIsLoading(false);
|
|
1775
1898
|
}
|
|
1776
|
-
}, [id, JSON.stringify(query)]);
|
|
1899
|
+
}, [id, enabled, JSON.stringify(query)]);
|
|
1777
1900
|
react.useEffect(() => {
|
|
1901
|
+
if (!id || !enabled) {
|
|
1902
|
+
setIsLoading(false);
|
|
1903
|
+
return;
|
|
1904
|
+
}
|
|
1778
1905
|
fetchOrder();
|
|
1779
|
-
}, [fetchOrder]);
|
|
1906
|
+
}, [fetchOrder, id, enabled]);
|
|
1780
1907
|
return {
|
|
1781
1908
|
...data,
|
|
1782
1909
|
isLoading,
|
|
@@ -2148,77 +2275,150 @@ const QuoteDetails = () => {
|
|
|
2148
2275
|
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
2149
2276
|
const { id } = reactRouterDom.useParams();
|
|
2150
2277
|
const navigate = reactRouterDom.useNavigate();
|
|
2151
|
-
const { quote, isLoading } = useQuote(id, {
|
|
2278
|
+
const { quote, isLoading, refetch: refetchQuote } = useQuote(id, {
|
|
2152
2279
|
fields: "*draft_order,*draft_order.customer,*draft_order.shipping_address,*draft_order.billing_address"
|
|
2153
2280
|
});
|
|
2154
2281
|
const { generatePdf, downloadPdf, pdfUrl } = useQuotePdf();
|
|
2155
2282
|
const { store } = useQuoteStore();
|
|
2283
|
+
const draftOrderId = quote == null ? void 0 : quote.draft_order_id;
|
|
2156
2284
|
const { order: preview, isLoading: isPreviewLoading } = useOrderPreview(
|
|
2157
|
-
|
|
2285
|
+
draftOrderId,
|
|
2158
2286
|
{
|
|
2159
2287
|
fields: DEFAULT_ORDER_FIELDS
|
|
2160
2288
|
},
|
|
2161
|
-
{ enabled: !!
|
|
2289
|
+
{ enabled: !!draftOrderId }
|
|
2290
|
+
);
|
|
2291
|
+
useOrder(
|
|
2292
|
+
draftOrderId,
|
|
2293
|
+
{
|
|
2294
|
+
fields: DEFAULT_ORDER_FIELDS
|
|
2295
|
+
},
|
|
2296
|
+
{ enabled: !!draftOrderId }
|
|
2162
2297
|
);
|
|
2163
|
-
const { order } = useOrder(quote == null ? void 0 : quote.draft_order_id, {
|
|
2164
|
-
fields: DEFAULT_ORDER_FIELDS
|
|
2165
|
-
});
|
|
2166
|
-
console.log(order);
|
|
2167
2298
|
const prompt = ui.usePrompt();
|
|
2168
2299
|
const { mutateAsync: rejectQuote, isPending: isRejectingQuote } = useRejectQuote(id);
|
|
2169
|
-
const [showRejectQuote, setShowRejectQuote] = react.useState(false);
|
|
2170
2300
|
const { mutateAsync: sendQuote, isPending: isSendingQuote } = useSendQuote(
|
|
2171
2301
|
id
|
|
2172
2302
|
);
|
|
2173
|
-
const
|
|
2174
|
-
const
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2303
|
+
const { mutateAsync: approveQuote, isPending: isApprovingQuote } = useApproveQuote(id);
|
|
2304
|
+
const { mutateAsync: voidQuote, isPending: isVoidingQuote } = useVoidQuote(
|
|
2305
|
+
id
|
|
2306
|
+
);
|
|
2307
|
+
const { mutateAsync: deleteQuote, isPending: isDeletingQuote } = useDeleteQuote(id);
|
|
2308
|
+
const quoteStatus = (quote == null ? void 0 : quote.status) ?? "";
|
|
2309
|
+
const canApproveQuote = [
|
|
2310
|
+
"pending_merchant",
|
|
2311
|
+
"pending_customer",
|
|
2312
|
+
"customer_rejected"
|
|
2313
|
+
].includes(quoteStatus);
|
|
2314
|
+
const canRejectQuote = ["pending_merchant", "pending_customer"].includes(
|
|
2315
|
+
quoteStatus
|
|
2316
|
+
);
|
|
2317
|
+
const canSendQuote = ["pending_merchant", "customer_rejected"].includes(
|
|
2318
|
+
quoteStatus
|
|
2319
|
+
);
|
|
2320
|
+
const canManageQuote = ["pending_merchant", "customer_rejected"].includes(
|
|
2321
|
+
quoteStatus
|
|
2322
|
+
);
|
|
2323
|
+
const canDeleteQuote = !["accepted", "approved", "converted"].includes(
|
|
2324
|
+
quoteStatus
|
|
2325
|
+
);
|
|
2326
|
+
const canVoidQuote = quoteStatus === "approved";
|
|
2327
|
+
const isMutatingQuote = isRejectingQuote || isSendingQuote || isApprovingQuote || isVoidingQuote || isDeletingQuote;
|
|
2328
|
+
const getErrorMessage = (error) => error instanceof Error ? error.message : "Something went wrong";
|
|
2194
2329
|
const handleRejectQuote = async () => {
|
|
2195
|
-
const
|
|
2330
|
+
const confirmed = await prompt({
|
|
2196
2331
|
title: "Reject quote?",
|
|
2197
2332
|
description: "You are about to reject this customer's quote. Do you want to continue?",
|
|
2198
|
-
confirmText: "
|
|
2333
|
+
confirmText: "Reject",
|
|
2199
2334
|
cancelText: "Cancel",
|
|
2200
2335
|
variant: "confirmation"
|
|
2201
2336
|
});
|
|
2202
|
-
if (
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2337
|
+
if (!confirmed) {
|
|
2338
|
+
return;
|
|
2339
|
+
}
|
|
2340
|
+
try {
|
|
2341
|
+
await rejectQuote();
|
|
2342
|
+
await refetchQuote();
|
|
2343
|
+
ui.toast.success("Successfully rejected customer's quote");
|
|
2344
|
+
} catch (error) {
|
|
2345
|
+
ui.toast.error(getErrorMessage(error));
|
|
2207
2346
|
}
|
|
2208
2347
|
};
|
|
2209
2348
|
const handleSendQuote = async () => {
|
|
2210
|
-
const
|
|
2349
|
+
const confirmed = await prompt({
|
|
2211
2350
|
title: "Send quote?",
|
|
2212
2351
|
description: "You are about to send this quote to the customer. Do you want to continue?",
|
|
2213
|
-
confirmText: "
|
|
2352
|
+
confirmText: "Send",
|
|
2214
2353
|
cancelText: "Cancel",
|
|
2215
2354
|
variant: "confirmation"
|
|
2216
2355
|
});
|
|
2217
|
-
if (
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2356
|
+
if (!confirmed) {
|
|
2357
|
+
return;
|
|
2358
|
+
}
|
|
2359
|
+
try {
|
|
2360
|
+
await sendQuote();
|
|
2361
|
+
await refetchQuote();
|
|
2362
|
+
ui.toast.success("Successfully sent quote to customer");
|
|
2363
|
+
} catch (error) {
|
|
2364
|
+
ui.toast.error(getErrorMessage(error));
|
|
2365
|
+
}
|
|
2366
|
+
};
|
|
2367
|
+
const handleApproveQuote = async () => {
|
|
2368
|
+
const confirmed = await prompt({
|
|
2369
|
+
title: "Approve quote?",
|
|
2370
|
+
description: "Approving the quote makes it ready for processing. Continue?",
|
|
2371
|
+
confirmText: "Approve",
|
|
2372
|
+
cancelText: "Cancel",
|
|
2373
|
+
variant: "confirmation"
|
|
2374
|
+
});
|
|
2375
|
+
if (!confirmed) {
|
|
2376
|
+
return;
|
|
2377
|
+
}
|
|
2378
|
+
try {
|
|
2379
|
+
await approveQuote();
|
|
2380
|
+
await refetchQuote();
|
|
2381
|
+
ui.toast.success("Quote approved");
|
|
2382
|
+
} catch (error) {
|
|
2383
|
+
ui.toast.error(getErrorMessage(error));
|
|
2384
|
+
}
|
|
2385
|
+
};
|
|
2386
|
+
const handleVoidQuote = async () => {
|
|
2387
|
+
const confirmed = await prompt({
|
|
2388
|
+
title: "Void approved quote?",
|
|
2389
|
+
description: "Voiding will move the quote out of the approved state. Continue?",
|
|
2390
|
+
confirmText: "Void",
|
|
2391
|
+
cancelText: "Cancel",
|
|
2392
|
+
variant: "confirmation"
|
|
2393
|
+
});
|
|
2394
|
+
if (!confirmed) {
|
|
2395
|
+
return;
|
|
2396
|
+
}
|
|
2397
|
+
try {
|
|
2398
|
+
await voidQuote();
|
|
2399
|
+
await refetchQuote();
|
|
2400
|
+
ui.toast.success("Quote voided");
|
|
2401
|
+
} catch (error) {
|
|
2402
|
+
ui.toast.error(getErrorMessage(error));
|
|
2403
|
+
}
|
|
2404
|
+
};
|
|
2405
|
+
const handleDeleteQuote = async () => {
|
|
2406
|
+
const confirmed = await prompt({
|
|
2407
|
+
title: "Delete quote?",
|
|
2408
|
+
description: "This will remove the quote permanently. This action cannot be undone.",
|
|
2409
|
+
confirmText: "Delete",
|
|
2410
|
+
cancelText: "Cancel",
|
|
2411
|
+
variant: "danger"
|
|
2412
|
+
});
|
|
2413
|
+
if (!confirmed) {
|
|
2414
|
+
return;
|
|
2415
|
+
}
|
|
2416
|
+
try {
|
|
2417
|
+
await deleteQuote();
|
|
2418
|
+
ui.toast.success("Quote deleted");
|
|
2419
|
+
navigate("/quotes");
|
|
2420
|
+
} catch (error) {
|
|
2421
|
+
ui.toast.error(getErrorMessage(error));
|
|
2222
2422
|
}
|
|
2223
2423
|
};
|
|
2224
2424
|
const parseToPdfData = () => {
|
|
@@ -2357,33 +2557,64 @@ const QuoteDetails = () => {
|
|
|
2357
2557
|
)
|
|
2358
2558
|
] })
|
|
2359
2559
|
] }),
|
|
2360
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-ui-bg-subtle flex items-center justify-end gap-
|
|
2361
|
-
|
|
2560
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-ui-bg-subtle flex flex-wrap items-center justify-end gap-2 rounded-b-xl px-4 py-4", children: [
|
|
2561
|
+
canDeleteQuote && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2562
|
+
ui.Button,
|
|
2563
|
+
{
|
|
2564
|
+
size: "small",
|
|
2565
|
+
variant: "danger",
|
|
2566
|
+
onClick: handleDeleteQuote,
|
|
2567
|
+
disabled: isMutatingQuote,
|
|
2568
|
+
children: "Delete Quote"
|
|
2569
|
+
}
|
|
2570
|
+
),
|
|
2571
|
+
canVoidQuote && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2572
|
+
ui.Button,
|
|
2573
|
+
{
|
|
2574
|
+
size: "small",
|
|
2575
|
+
variant: "secondary",
|
|
2576
|
+
onClick: handleVoidQuote,
|
|
2577
|
+
disabled: isMutatingQuote,
|
|
2578
|
+
children: "Void Quote"
|
|
2579
|
+
}
|
|
2580
|
+
),
|
|
2581
|
+
canRejectQuote && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2362
2582
|
ui.Button,
|
|
2363
2583
|
{
|
|
2364
2584
|
size: "small",
|
|
2365
2585
|
variant: "secondary",
|
|
2366
|
-
onClick:
|
|
2367
|
-
disabled:
|
|
2586
|
+
onClick: handleRejectQuote,
|
|
2587
|
+
disabled: isMutatingQuote,
|
|
2368
2588
|
children: "Reject Quote"
|
|
2369
2589
|
}
|
|
2370
2590
|
),
|
|
2371
|
-
|
|
2591
|
+
canApproveQuote && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2592
|
+
ui.Button,
|
|
2593
|
+
{
|
|
2594
|
+
size: "small",
|
|
2595
|
+
variant: "primary",
|
|
2596
|
+
onClick: handleApproveQuote,
|
|
2597
|
+
disabled: isMutatingQuote,
|
|
2598
|
+
children: "Approve Quote"
|
|
2599
|
+
}
|
|
2600
|
+
),
|
|
2601
|
+
canSendQuote && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2372
2602
|
ui.Button,
|
|
2373
2603
|
{
|
|
2374
2604
|
size: "small",
|
|
2375
2605
|
variant: "secondary",
|
|
2376
|
-
onClick:
|
|
2377
|
-
disabled:
|
|
2606
|
+
onClick: handleSendQuote,
|
|
2607
|
+
disabled: isMutatingQuote,
|
|
2378
2608
|
children: "Send Quote"
|
|
2379
2609
|
}
|
|
2380
2610
|
),
|
|
2381
|
-
|
|
2611
|
+
canManageQuote && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2382
2612
|
ui.Button,
|
|
2383
2613
|
{
|
|
2384
2614
|
size: "small",
|
|
2385
2615
|
variant: "secondary",
|
|
2386
2616
|
onClick: () => navigate(`/quotes/${quote.id}/manage`),
|
|
2617
|
+
disabled: isMutatingQuote,
|
|
2387
2618
|
children: "Manage Quote"
|
|
2388
2619
|
}
|
|
2389
2620
|
)
|