medusajs-documents-plugin 1.1.59 → 1.1.61
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.
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsxs, jsx } from "react/jsx-runtime";
|
|
2
2
|
import { defineRouteConfig } from "@medusajs/admin-sdk";
|
|
3
3
|
import { Container, Heading, Text, Button, Input, Select, Tooltip, IconButton, Switch, Label, Table, Badge, DropdownMenu, Textarea, FocusModal } from "@medusajs/ui";
|
|
4
|
-
import { useState, useEffect, useMemo, Fragment } from "react";
|
|
4
|
+
import { useState, useRef, useEffect, useMemo, useCallback, Fragment } from "react";
|
|
5
5
|
import { DocumentText, ArrowPath, Plus, Sparkles, ChevronDown, ChevronRight, ArrowDownTray, PencilSquare, Envelope, Trash } from "@medusajs/icons";
|
|
6
6
|
function extractBaseReference(displayId) {
|
|
7
7
|
if (!displayId) return "";
|
|
@@ -409,6 +409,10 @@ const DocumentsPage = () => {
|
|
|
409
409
|
const [zohoLiveDocs, setZohoLiveDocs] = useState([]);
|
|
410
410
|
const [loadingZoho, setLoadingZoho] = useState(false);
|
|
411
411
|
const [isSyncingRepairs, setIsSyncingRepairs] = useState(false);
|
|
412
|
+
const [displayLimit, setDisplayLimit] = useState(100);
|
|
413
|
+
const [totalBackendCount, setTotalBackendCount] = useState(0);
|
|
414
|
+
const [isLoadingMore, setIsLoadingMore] = useState(false);
|
|
415
|
+
const sentinelRef = useRef(null);
|
|
412
416
|
const [groupByJob, setGroupByJob] = useState(true);
|
|
413
417
|
const [expandedGroups, setExpandedGroups] = useState({});
|
|
414
418
|
const toggleGroup = (groupId) => {
|
|
@@ -728,10 +732,16 @@ const DocumentsPage = () => {
|
|
|
728
732
|
custom_message: "",
|
|
729
733
|
subject: ""
|
|
730
734
|
});
|
|
731
|
-
const loadDocuments = () => {
|
|
735
|
+
const loadDocuments = (resetLimit = true) => {
|
|
732
736
|
setLoading(true);
|
|
733
|
-
fetch("/admin/documents", { credentials: "include" }).then((res) => res.json()).then((data) => {
|
|
737
|
+
fetch("/admin/documents?take=100&skip=0", { credentials: "include" }).then((res) => res.json()).then((data) => {
|
|
734
738
|
setDocuments(data.documents || []);
|
|
739
|
+
if (data.count != null) {
|
|
740
|
+
setTotalBackendCount(Number(data.count));
|
|
741
|
+
}
|
|
742
|
+
if (resetLimit) {
|
|
743
|
+
setDisplayLimit(100);
|
|
744
|
+
}
|
|
735
745
|
}).catch((err) => console.error("Error loading documents:", err)).finally(() => setLoading(false));
|
|
736
746
|
};
|
|
737
747
|
const loadSettings = () => {
|
|
@@ -1200,6 +1210,71 @@ const DocumentsPage = () => {
|
|
|
1200
1210
|
return true;
|
|
1201
1211
|
});
|
|
1202
1212
|
}, [documents, sourceFilter, typeFilter, searchTerm]);
|
|
1213
|
+
const totalItemCount = groupByJob ? documentGroups.length : filteredDocs.length;
|
|
1214
|
+
const hasMoreLocally = displayLimit < totalItemCount;
|
|
1215
|
+
const hasMoreBackend = documents.length < totalBackendCount;
|
|
1216
|
+
const canLoadMore = hasMoreLocally || hasMoreBackend;
|
|
1217
|
+
const handleLoadMore = useCallback(async () => {
|
|
1218
|
+
if (isLoadingMore || loading) return;
|
|
1219
|
+
if (hasMoreLocally) {
|
|
1220
|
+
setDisplayLimit((prev) => prev + 100);
|
|
1221
|
+
return;
|
|
1222
|
+
}
|
|
1223
|
+
if (hasMoreBackend) {
|
|
1224
|
+
setIsLoadingMore(true);
|
|
1225
|
+
try {
|
|
1226
|
+
const nextSkip = documents.length;
|
|
1227
|
+
const res = await fetch(`/admin/documents?take=100&skip=${nextSkip}`, { credentials: "include" });
|
|
1228
|
+
const data = await res.json();
|
|
1229
|
+
if (data.documents && data.documents.length > 0) {
|
|
1230
|
+
setDocuments((prev) => {
|
|
1231
|
+
const existingIds = new Set(prev.map((d) => d.id));
|
|
1232
|
+
const newUnique = data.documents.filter((d) => !existingIds.has(d.id));
|
|
1233
|
+
return [...prev, ...newUnique];
|
|
1234
|
+
});
|
|
1235
|
+
if (data.count != null) {
|
|
1236
|
+
setTotalBackendCount(Number(data.count));
|
|
1237
|
+
}
|
|
1238
|
+
setDisplayLimit((prev) => prev + 100);
|
|
1239
|
+
} else {
|
|
1240
|
+
setTotalBackendCount(documents.length);
|
|
1241
|
+
}
|
|
1242
|
+
} catch (err) {
|
|
1243
|
+
console.error("Error loading more documents:", err);
|
|
1244
|
+
} finally {
|
|
1245
|
+
setIsLoadingMore(false);
|
|
1246
|
+
}
|
|
1247
|
+
}
|
|
1248
|
+
}, [isLoadingMore, loading, hasMoreLocally, hasMoreBackend, documents.length, totalBackendCount]);
|
|
1249
|
+
useEffect(() => {
|
|
1250
|
+
setDisplayLimit(100);
|
|
1251
|
+
}, [searchTerm, typeFilter, sourceFilter, groupByJob]);
|
|
1252
|
+
useEffect(() => {
|
|
1253
|
+
const el = sentinelRef.current;
|
|
1254
|
+
if (!el || !canLoadMore || isLoadingMore || loading) return;
|
|
1255
|
+
const observer = new IntersectionObserver(
|
|
1256
|
+
(entries) => {
|
|
1257
|
+
if (entries[0].isIntersecting) {
|
|
1258
|
+
handleLoadMore();
|
|
1259
|
+
}
|
|
1260
|
+
},
|
|
1261
|
+
{ rootMargin: "300px" }
|
|
1262
|
+
);
|
|
1263
|
+
observer.observe(el);
|
|
1264
|
+
return () => observer.disconnect();
|
|
1265
|
+
}, [handleLoadMore, canLoadMore, isLoadingMore, loading]);
|
|
1266
|
+
useEffect(() => {
|
|
1267
|
+
const handleScroll = () => {
|
|
1268
|
+
if (!canLoadMore || isLoadingMore || loading) return;
|
|
1269
|
+
const scrollPosition = window.innerHeight + window.scrollY;
|
|
1270
|
+
const threshold = document.documentElement.scrollHeight - 350;
|
|
1271
|
+
if (scrollPosition >= threshold) {
|
|
1272
|
+
handleLoadMore();
|
|
1273
|
+
}
|
|
1274
|
+
};
|
|
1275
|
+
window.addEventListener("scroll", handleScroll, { passive: true });
|
|
1276
|
+
return () => window.removeEventListener("scroll", handleScroll);
|
|
1277
|
+
}, [handleLoadMore, canLoadMore, isLoadingMore, loading]);
|
|
1203
1278
|
return /* @__PURE__ */ jsxs(Container, { className: "p-0", children: [
|
|
1204
1279
|
/* @__PURE__ */ jsxs("div", { className: "flex flex-col md:flex-row md:items-center justify-between p-6 border-b border-ui-border-base gap-4 bg-ui-bg-base", children: [
|
|
1205
1280
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
|
|
@@ -1363,340 +1438,183 @@ const DocumentsPage = () => {
|
|
|
1363
1438
|
loading ? /* @__PURE__ */ jsx("div", { className: "py-12 text-center text-ui-fg-muted text-sm", children: "Loading documents..." }) : (groupByJob ? documentGroups.length === 0 : filteredDocs.length === 0) ? /* @__PURE__ */ jsxs("div", { className: "py-12 text-center text-ui-fg-muted border border-dashed border-ui-border-base rounded-lg", children: [
|
|
1364
1439
|
/* @__PURE__ */ jsx(Text, { className: "text-sm", children: "No documents found." }),
|
|
1365
1440
|
/* @__PURE__ */ jsx(Text, { className: "text-xs text-ui-fg-subtle mt-1", children: "Create a manual invoice or process an order to generate your first document." })
|
|
1366
|
-
] }) : /* @__PURE__ */ jsxs(
|
|
1367
|
-
/* @__PURE__ */
|
|
1368
|
-
/* @__PURE__ */ jsx(Table.
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
/* @__PURE__ */ jsxs(
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
{
|
|
1393
|
-
type: "button",
|
|
1394
|
-
onClick: () => toggleGroup(group.groupId),
|
|
1395
|
-
className: "p-1 rounded hover:bg-ui-bg-base text-ui-fg-subtle hover:text-ui-fg-base cursor-pointer transition-colors",
|
|
1396
|
-
title: isExpanded ? "Collapse related documents" : `Expand ${group.documents.length} related documents`,
|
|
1397
|
-
children: isExpanded ? /* @__PURE__ */ jsx(ChevronDown, { className: "w-4 h-4 text-purple-600" }) : /* @__PURE__ */ jsx(ChevronRight, { className: "w-4 h-4 text-ui-fg-subtle" })
|
|
1398
|
-
}
|
|
1399
|
-
) : /* @__PURE__ */ jsx("span", { className: "w-5 inline-block" }),
|
|
1400
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 flex-wrap", children: [
|
|
1401
|
-
/* @__PURE__ */ jsx(
|
|
1441
|
+
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1442
|
+
/* @__PURE__ */ jsxs(Table, { children: [
|
|
1443
|
+
/* @__PURE__ */ jsx(Table.Header, { children: /* @__PURE__ */ jsxs(Table.Row, { children: [
|
|
1444
|
+
/* @__PURE__ */ jsx(Table.HeaderCell, { children: "Reference" }),
|
|
1445
|
+
/* @__PURE__ */ jsx(Table.HeaderCell, { children: "Type" }),
|
|
1446
|
+
/* @__PURE__ */ jsx(Table.HeaderCell, { children: "Recipient" }),
|
|
1447
|
+
/* @__PURE__ */ jsx(Table.HeaderCell, { children: "Amount" }),
|
|
1448
|
+
/* @__PURE__ */ jsx(Table.HeaderCell, { children: "Status" }),
|
|
1449
|
+
/* @__PURE__ */ jsx(Table.HeaderCell, { children: "Source" }),
|
|
1450
|
+
/* @__PURE__ */ jsx(Table.HeaderCell, { children: "Date" }),
|
|
1451
|
+
/* @__PURE__ */ jsx(Table.HeaderCell, { className: "text-right", children: "Actions" })
|
|
1452
|
+
] }) }),
|
|
1453
|
+
/* @__PURE__ */ jsx(Table.Body, { children: groupByJob ? documentGroups.slice(0, displayLimit).map((group) => {
|
|
1454
|
+
const isExpanded = !!expandedGroups[group.groupId];
|
|
1455
|
+
const doc = group.primaryDoc;
|
|
1456
|
+
const isPaid = doc.payment_status === "paid" || doc.status === "paid";
|
|
1457
|
+
const isZoho = doc.source === "zoho";
|
|
1458
|
+
const hasMultiple = group.documents.length > 1;
|
|
1459
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1460
|
+
/* @__PURE__ */ jsxs(
|
|
1461
|
+
Table.Row,
|
|
1462
|
+
{
|
|
1463
|
+
className: `transition-colors ${isExpanded ? "bg-ui-bg-subtle" : "hover:bg-ui-bg-subtle-hover"}`,
|
|
1464
|
+
children: [
|
|
1465
|
+
/* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
|
|
1466
|
+
hasMultiple ? /* @__PURE__ */ jsx(
|
|
1402
1467
|
"button",
|
|
1403
1468
|
{
|
|
1404
1469
|
type: "button",
|
|
1405
|
-
onClick: () => handleViewDocument(doc.id, doc.display_id),
|
|
1406
|
-
className: "font-medium text-ui-fg-interactive hover:underline text-left cursor-pointer bg-transparent border-0 p-0",
|
|
1407
|
-
children: doc.display_id
|
|
1408
|
-
}
|
|
1409
|
-
),
|
|
1410
|
-
hasMultiple && /* @__PURE__ */ jsxs(
|
|
1411
|
-
Badge,
|
|
1412
|
-
{
|
|
1413
|
-
size: "2xsmall",
|
|
1414
|
-
color: "purple",
|
|
1415
|
-
className: "cursor-pointer hover:opacity-80 transition-opacity",
|
|
1416
1470
|
onClick: () => toggleGroup(group.groupId),
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
]
|
|
1471
|
+
className: "p-1 rounded hover:bg-ui-bg-base text-ui-fg-subtle hover:text-ui-fg-base cursor-pointer transition-colors",
|
|
1472
|
+
title: isExpanded ? "Collapse related documents" : `Expand ${group.documents.length} related documents`,
|
|
1473
|
+
children: isExpanded ? /* @__PURE__ */ jsx(ChevronDown, { className: "w-4 h-4 text-purple-600" }) : /* @__PURE__ */ jsx(ChevronRight, { className: "w-4 h-4 text-ui-fg-subtle" })
|
|
1421
1474
|
}
|
|
1422
|
-
)
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
hasMultiple && /* @__PURE__ */ jsxs(DropdownMenu, { children: [
|
|
1442
|
-
/* @__PURE__ */ jsx(DropdownMenu.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs(
|
|
1443
|
-
"button",
|
|
1444
|
-
{
|
|
1445
|
-
type: "button",
|
|
1446
|
-
className: "flex items-center gap-1 text-[11px] font-medium px-2 py-1 rounded bg-ui-bg-subtle hover:bg-ui-bg-base border border-ui-border-base text-ui-fg-base transition-colors",
|
|
1447
|
-
title: "View all related documents for this job/order",
|
|
1448
|
-
children: [
|
|
1449
|
-
/* @__PURE__ */ jsx(DocumentText, { className: "w-3.5 h-3.5 text-purple-600" }),
|
|
1450
|
-
/* @__PURE__ */ jsxs("span", { children: [
|
|
1451
|
-
"Docs (",
|
|
1475
|
+
) : /* @__PURE__ */ jsx("span", { className: "w-5 inline-block" }),
|
|
1476
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 flex-wrap", children: [
|
|
1477
|
+
/* @__PURE__ */ jsx(
|
|
1478
|
+
"button",
|
|
1479
|
+
{
|
|
1480
|
+
type: "button",
|
|
1481
|
+
onClick: () => handleViewDocument(doc.id, doc.display_id),
|
|
1482
|
+
className: "font-medium text-ui-fg-interactive hover:underline text-left cursor-pointer bg-transparent border-0 p-0",
|
|
1483
|
+
children: doc.display_id
|
|
1484
|
+
}
|
|
1485
|
+
),
|
|
1486
|
+
hasMultiple && /* @__PURE__ */ jsxs(
|
|
1487
|
+
Badge,
|
|
1488
|
+
{
|
|
1489
|
+
size: "2xsmall",
|
|
1490
|
+
color: "purple",
|
|
1491
|
+
className: "cursor-pointer hover:opacity-80 transition-opacity",
|
|
1492
|
+
onClick: () => toggleGroup(group.groupId),
|
|
1493
|
+
children: [
|
|
1452
1494
|
group.documents.length,
|
|
1453
|
-
"
|
|
1454
|
-
]
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1495
|
+
" docs"
|
|
1496
|
+
]
|
|
1497
|
+
}
|
|
1498
|
+
)
|
|
1499
|
+
] })
|
|
1500
|
+
] }) }),
|
|
1501
|
+
/* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
|
|
1502
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs font-semibold text-ui-fg-base", children: doc.title }),
|
|
1503
|
+
hasMultiple && /* @__PURE__ */ jsxs("span", { className: "text-[11px] text-ui-fg-subtle truncate max-w-[220px]", title: group.includedTypesSummary, children: [
|
|
1504
|
+
"Includes: ",
|
|
1505
|
+
group.includedTypesSummary
|
|
1506
|
+
] })
|
|
1507
|
+
] }) }),
|
|
1508
|
+
/* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
|
|
1509
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs font-medium", children: group.customerName || "Guest" }),
|
|
1510
|
+
/* @__PURE__ */ jsx("span", { className: "text-[11px] text-ui-fg-subtle", children: group.customerEmail || group.customerPhone || "-" })
|
|
1511
|
+
] }) }),
|
|
1512
|
+
/* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx("span", { className: "text-xs font-semibold", children: formatCurrency(group.totalAmount, group.currencyCode) }) }),
|
|
1513
|
+
/* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(Badge, { color: isPaid ? "green" : doc.payment_status === "unpaid" ? "red" : "blue", size: "small", children: doc.payment_status || doc.status }) }),
|
|
1514
|
+
/* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(Badge, { color: isZoho ? "purple" : "grey", size: "small", children: isZoho ? "Zoho Books" : "PDFKit" }) }),
|
|
1515
|
+
/* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx("span", { className: "text-xs text-ui-fg-subtle", children: new Date(group.latestCreatedAt).toLocaleDateString() }) }),
|
|
1516
|
+
/* @__PURE__ */ jsx(Table.Cell, { className: "text-right", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-1.5", children: [
|
|
1517
|
+
hasMultiple && /* @__PURE__ */ jsxs(DropdownMenu, { children: [
|
|
1518
|
+
/* @__PURE__ */ jsx(DropdownMenu.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs(
|
|
1519
|
+
"button",
|
|
1468
1520
|
{
|
|
1469
|
-
|
|
1470
|
-
className: "flex items-center
|
|
1521
|
+
type: "button",
|
|
1522
|
+
className: "flex items-center gap-1 text-[11px] font-medium px-2 py-1 rounded bg-ui-bg-subtle hover:bg-ui-bg-base border border-ui-border-base text-ui-fg-base transition-colors",
|
|
1523
|
+
title: "View all related documents for this job/order",
|
|
1471
1524
|
children: [
|
|
1472
|
-
/* @__PURE__ */
|
|
1473
|
-
|
|
1474
|
-
|
|
1525
|
+
/* @__PURE__ */ jsx(DocumentText, { className: "w-3.5 h-3.5 text-purple-600" }),
|
|
1526
|
+
/* @__PURE__ */ jsxs("span", { children: [
|
|
1527
|
+
"Docs (",
|
|
1528
|
+
group.documents.length,
|
|
1529
|
+
")"
|
|
1475
1530
|
] }),
|
|
1476
|
-
/* @__PURE__ */
|
|
1477
|
-
/* @__PURE__ */ jsx("span", { className: "text-[11px] font-semibold text-ui-fg-base", children: subDoc.total_amount != null && Number(subDoc.total_amount) > 0 ? formatCurrency(subDoc.total_amount, subDoc.currency_code) : "—" }),
|
|
1478
|
-
/* @__PURE__ */ jsx(ArrowDownTray, { className: "w-3.5 h-3.5 text-ui-fg-subtle" })
|
|
1479
|
-
] })
|
|
1531
|
+
/* @__PURE__ */ jsx(ChevronDown, { className: "w-3 h-3 text-ui-fg-subtle" })
|
|
1480
1532
|
]
|
|
1481
|
-
},
|
|
1482
|
-
subDoc.id
|
|
1483
|
-
))
|
|
1484
|
-
] })
|
|
1485
|
-
] }),
|
|
1486
|
-
/* @__PURE__ */ jsx(
|
|
1487
|
-
"button",
|
|
1488
|
-
{
|
|
1489
|
-
type: "button",
|
|
1490
|
-
onClick: () => handleViewDocument(doc.id, doc.display_id),
|
|
1491
|
-
className: "p-1.5 rounded hover:bg-ui-bg-subtle text-ui-fg-subtle hover:text-ui-fg-base cursor-pointer",
|
|
1492
|
-
title: "View / Download PDF",
|
|
1493
|
-
children: /* @__PURE__ */ jsx(ArrowDownTray, { className: "w-4 h-4" })
|
|
1494
|
-
}
|
|
1495
|
-
),
|
|
1496
|
-
(doc.type === "invoice" || doc.type === "estimate" || doc.type === "quote") && /* @__PURE__ */ jsx(
|
|
1497
|
-
"button",
|
|
1498
|
-
{
|
|
1499
|
-
type: "button",
|
|
1500
|
-
onClick: () => handleOpenEditModal(doc),
|
|
1501
|
-
className: "p-1.5 rounded hover:bg-ui-bg-subtle text-ui-fg-subtle hover:text-purple-600 cursor-pointer",
|
|
1502
|
-
title: "Edit Quote / Invoice & Sync with Zoho Books",
|
|
1503
|
-
children: /* @__PURE__ */ jsx(PencilSquare, { className: "w-4 h-4" })
|
|
1504
|
-
}
|
|
1505
|
-
),
|
|
1506
|
-
/* @__PURE__ */ jsx(
|
|
1507
|
-
"button",
|
|
1508
|
-
{
|
|
1509
|
-
onClick: () => {
|
|
1510
|
-
setSelectedDoc(doc);
|
|
1511
|
-
setSendForm({
|
|
1512
|
-
channels: ["email"],
|
|
1513
|
-
custom_message: "",
|
|
1514
|
-
subject: `${settings.company_name}: ${doc.title} #${doc.display_id}`
|
|
1515
|
-
});
|
|
1516
|
-
setSendModalOpen(true);
|
|
1517
|
-
},
|
|
1518
|
-
className: "p-1.5 rounded hover:bg-ui-bg-subtle text-ui-fg-subtle hover:text-ui-fg-base",
|
|
1519
|
-
title: "Send via Email / SMS / WhatsApp",
|
|
1520
|
-
children: /* @__PURE__ */ jsx(Envelope, { className: "w-4 h-4" })
|
|
1521
|
-
}
|
|
1522
|
-
),
|
|
1523
|
-
!isZoho && settings.zoho_books_enabled && (doc.type === "invoice" || doc.type === "estimate") && Number(doc.total_amount || 0) > 0 && /* @__PURE__ */ jsx(
|
|
1524
|
-
Button,
|
|
1525
|
-
{
|
|
1526
|
-
variant: "transparent",
|
|
1527
|
-
size: "small",
|
|
1528
|
-
onClick: () => handleSyncToZoho(doc.id),
|
|
1529
|
-
className: "text-xs text-purple-600 hover:text-purple-700",
|
|
1530
|
-
children: "Push Zoho"
|
|
1531
|
-
}
|
|
1532
|
-
),
|
|
1533
|
-
doc.short_payment_link && /* @__PURE__ */ jsx(
|
|
1534
|
-
"button",
|
|
1535
|
-
{
|
|
1536
|
-
onClick: () => {
|
|
1537
|
-
navigator.clipboard.writeText(doc.short_payment_link);
|
|
1538
|
-
alert("Short payment link copied to clipboard!");
|
|
1539
|
-
},
|
|
1540
|
-
className: "text-[11px] text-ui-fg-interactive hover:underline px-1.5 py-1",
|
|
1541
|
-
title: "Copy Short Payment Link",
|
|
1542
|
-
children: "Copy Link"
|
|
1543
|
-
}
|
|
1544
|
-
),
|
|
1545
|
-
/* @__PURE__ */ jsx(
|
|
1546
|
-
"button",
|
|
1547
|
-
{
|
|
1548
|
-
type: "button",
|
|
1549
|
-
onClick: () => {
|
|
1550
|
-
if (doc.repair_ticket_id) {
|
|
1551
|
-
handleDeleteRepairDocuments(doc.repair_ticket_id);
|
|
1552
|
-
} else {
|
|
1553
|
-
handleDeleteDocument(doc.id);
|
|
1554
1533
|
}
|
|
1555
|
-
},
|
|
1556
|
-
className: "p-1.5
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
children: [
|
|
1584
|
-
/* @__PURE__ */ jsx(Trash, { className: "w-3 h-3" }),
|
|
1585
|
-
" Reset / Delete Job Documents"
|
|
1586
|
-
]
|
|
1587
|
-
}
|
|
1588
|
-
),
|
|
1589
|
-
/* @__PURE__ */ jsx(
|
|
1590
|
-
"button",
|
|
1591
|
-
{
|
|
1592
|
-
type: "button",
|
|
1593
|
-
onClick: () => toggleGroup(group.groupId),
|
|
1594
|
-
className: "text-[11px] text-ui-fg-interactive hover:underline",
|
|
1595
|
-
children: "Collapse"
|
|
1596
|
-
}
|
|
1597
|
-
)
|
|
1598
|
-
] })
|
|
1599
|
-
] }),
|
|
1600
|
-
/* @__PURE__ */ jsx("div", { className: "overflow-x-auto rounded border border-ui-border-base bg-ui-bg-base", children: /* @__PURE__ */ jsxs("table", { className: "w-full text-left border-collapse", children: [
|
|
1601
|
-
/* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { className: "border-b border-ui-border-base bg-ui-bg-subtle text-[11px] text-ui-fg-muted font-medium", children: [
|
|
1602
|
-
/* @__PURE__ */ jsx("th", { className: "py-1.5 px-3", children: "Document Type" }),
|
|
1603
|
-
/* @__PURE__ */ jsx("th", { className: "py-1.5 px-3", children: "Reference" }),
|
|
1604
|
-
/* @__PURE__ */ jsx("th", { className: "py-1.5 px-3", children: "Amount" }),
|
|
1605
|
-
/* @__PURE__ */ jsx("th", { className: "py-1.5 px-3", children: "Status" }),
|
|
1606
|
-
/* @__PURE__ */ jsx("th", { className: "py-1.5 px-3", children: "Source" }),
|
|
1607
|
-
/* @__PURE__ */ jsx("th", { className: "py-1.5 px-3", children: "Created Date" }),
|
|
1608
|
-
/* @__PURE__ */ jsx("th", { className: "py-1.5 px-3 text-right", children: "Actions" })
|
|
1609
|
-
] }) }),
|
|
1610
|
-
/* @__PURE__ */ jsx("tbody", { className: "divide-y divide-ui-border-base text-xs", children: group.documents.map((subDoc) => {
|
|
1611
|
-
const subIsPaid = subDoc.payment_status === "paid" || subDoc.status === "paid";
|
|
1612
|
-
const subIsZoho = subDoc.source === "zoho";
|
|
1613
|
-
return /* @__PURE__ */ jsxs("tr", { className: "hover:bg-ui-bg-subtle-hover transition-colors", children: [
|
|
1614
|
-
/* @__PURE__ */ jsx("td", { className: "py-2 px-3", children: /* @__PURE__ */ jsx(
|
|
1615
|
-
Badge,
|
|
1616
|
-
{
|
|
1617
|
-
size: "2xsmall",
|
|
1618
|
-
color: subDoc.type === "invoice" ? "green" : subDoc.type === "estimate" ? "blue" : subDoc.type === "job_card" ? "orange" : subDoc.type === "receipt" ? "purple" : "grey",
|
|
1619
|
-
children: subDoc.title
|
|
1620
|
-
}
|
|
1621
|
-
) }),
|
|
1622
|
-
/* @__PURE__ */ jsx("td", { className: "py-2 px-3 font-medium", children: /* @__PURE__ */ jsx(
|
|
1623
|
-
"button",
|
|
1624
|
-
{
|
|
1625
|
-
type: "button",
|
|
1626
|
-
onClick: () => handleViewDocument(subDoc.id, subDoc.display_id),
|
|
1627
|
-
className: "text-ui-fg-interactive hover:underline text-left cursor-pointer bg-transparent border-0 p-0 font-medium",
|
|
1628
|
-
children: subDoc.display_id
|
|
1629
|
-
}
|
|
1630
|
-
) }),
|
|
1631
|
-
/* @__PURE__ */ jsx("td", { className: "py-2 px-3 font-semibold text-ui-fg-base", children: subDoc.total_amount != null && Number(subDoc.total_amount) > 0 ? formatCurrency(subDoc.total_amount, subDoc.currency_code) : "—" }),
|
|
1632
|
-
/* @__PURE__ */ jsx("td", { className: "py-2 px-3", children: /* @__PURE__ */ jsx(
|
|
1633
|
-
Badge,
|
|
1634
|
-
{
|
|
1635
|
-
size: "2xsmall",
|
|
1636
|
-
color: subIsPaid ? "green" : subDoc.payment_status === "unpaid" ? "red" : "blue",
|
|
1637
|
-
children: subDoc.payment_status || subDoc.status
|
|
1638
|
-
}
|
|
1639
|
-
) }),
|
|
1640
|
-
/* @__PURE__ */ jsx("td", { className: "py-2 px-3", children: /* @__PURE__ */ jsx(Badge, { size: "2xsmall", color: subIsZoho ? "purple" : "grey", children: subIsZoho ? "Zoho Books" : "PDFKit" }) }),
|
|
1641
|
-
/* @__PURE__ */ jsx("td", { className: "py-2 px-3 text-ui-fg-subtle text-[11px]", children: new Date(subDoc.created_at).toLocaleString() }),
|
|
1642
|
-
/* @__PURE__ */ jsx("td", { className: "py-2 px-3 text-right", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-1.5", children: [
|
|
1534
|
+
) }),
|
|
1535
|
+
/* @__PURE__ */ jsxs(DropdownMenu.Content, { align: "end", className: "w-72 p-1.5 z-50", children: [
|
|
1536
|
+
/* @__PURE__ */ jsxs(DropdownMenu.Label, { className: "text-xs font-semibold px-2 py-1.5 text-ui-fg-muted", children: [
|
|
1537
|
+
"Related Documents (",
|
|
1538
|
+
group.documents.length,
|
|
1539
|
+
")"
|
|
1540
|
+
] }),
|
|
1541
|
+
/* @__PURE__ */ jsx(DropdownMenu.Separator, {}),
|
|
1542
|
+
group.documents.map((subDoc) => /* @__PURE__ */ jsxs(
|
|
1543
|
+
DropdownMenu.Item,
|
|
1544
|
+
{
|
|
1545
|
+
onClick: () => handleViewDocument(subDoc.id, subDoc.display_id),
|
|
1546
|
+
className: "flex items-center justify-between px-2 py-2 cursor-pointer hover:bg-ui-bg-subtle-hover rounded text-xs transition-colors",
|
|
1547
|
+
children: [
|
|
1548
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col text-left", children: [
|
|
1549
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium text-ui-fg-base", children: subDoc.title }),
|
|
1550
|
+
/* @__PURE__ */ jsx("span", { className: "text-[10px] text-ui-fg-subtle", children: subDoc.display_id })
|
|
1551
|
+
] }),
|
|
1552
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
1553
|
+
/* @__PURE__ */ jsx("span", { className: "text-[11px] font-semibold text-ui-fg-base", children: subDoc.total_amount != null && Number(subDoc.total_amount) > 0 ? formatCurrency(subDoc.total_amount, subDoc.currency_code) : "—" }),
|
|
1554
|
+
/* @__PURE__ */ jsx(ArrowDownTray, { className: "w-3.5 h-3.5 text-ui-fg-subtle" })
|
|
1555
|
+
] })
|
|
1556
|
+
]
|
|
1557
|
+
},
|
|
1558
|
+
subDoc.id
|
|
1559
|
+
))
|
|
1560
|
+
] })
|
|
1561
|
+
] }),
|
|
1643
1562
|
/* @__PURE__ */ jsx(
|
|
1644
1563
|
"button",
|
|
1645
1564
|
{
|
|
1646
1565
|
type: "button",
|
|
1647
|
-
onClick: () => handleViewDocument(
|
|
1648
|
-
className: "p-1 rounded hover:bg-ui-bg-subtle text-ui-fg-subtle hover:text-ui-fg-base",
|
|
1566
|
+
onClick: () => handleViewDocument(doc.id, doc.display_id),
|
|
1567
|
+
className: "p-1.5 rounded hover:bg-ui-bg-subtle text-ui-fg-subtle hover:text-ui-fg-base cursor-pointer",
|
|
1649
1568
|
title: "View / Download PDF",
|
|
1650
|
-
children: /* @__PURE__ */ jsx(ArrowDownTray, { className: "w-
|
|
1569
|
+
children: /* @__PURE__ */ jsx(ArrowDownTray, { className: "w-4 h-4" })
|
|
1651
1570
|
}
|
|
1652
1571
|
),
|
|
1653
|
-
(
|
|
1572
|
+
(doc.type === "invoice" || doc.type === "estimate" || doc.type === "quote") && /* @__PURE__ */ jsx(
|
|
1654
1573
|
"button",
|
|
1655
1574
|
{
|
|
1656
1575
|
type: "button",
|
|
1657
|
-
onClick: () => handleOpenEditModal(
|
|
1658
|
-
className: "p-1 rounded hover:bg-ui-bg-subtle text-ui-fg-subtle hover:text-purple-600",
|
|
1576
|
+
onClick: () => handleOpenEditModal(doc),
|
|
1577
|
+
className: "p-1.5 rounded hover:bg-ui-bg-subtle text-ui-fg-subtle hover:text-purple-600 cursor-pointer",
|
|
1659
1578
|
title: "Edit Quote / Invoice & Sync with Zoho Books",
|
|
1660
|
-
children: /* @__PURE__ */ jsx(PencilSquare, { className: "w-
|
|
1579
|
+
children: /* @__PURE__ */ jsx(PencilSquare, { className: "w-4 h-4" })
|
|
1661
1580
|
}
|
|
1662
1581
|
),
|
|
1663
1582
|
/* @__PURE__ */ jsx(
|
|
1664
1583
|
"button",
|
|
1665
1584
|
{
|
|
1666
|
-
type: "button",
|
|
1667
1585
|
onClick: () => {
|
|
1668
|
-
setSelectedDoc(
|
|
1586
|
+
setSelectedDoc(doc);
|
|
1669
1587
|
setSendForm({
|
|
1670
1588
|
channels: ["email"],
|
|
1671
1589
|
custom_message: "",
|
|
1672
|
-
subject: `${settings.company_name}: ${
|
|
1590
|
+
subject: `${settings.company_name}: ${doc.title} #${doc.display_id}`
|
|
1673
1591
|
});
|
|
1674
1592
|
setSendModalOpen(true);
|
|
1675
1593
|
},
|
|
1676
|
-
className: "p-1 rounded hover:bg-ui-bg-subtle text-ui-fg-subtle hover:text-ui-fg-base",
|
|
1677
|
-
title: "Send
|
|
1678
|
-
children: /* @__PURE__ */ jsx(Envelope, { className: "w-
|
|
1594
|
+
className: "p-1.5 rounded hover:bg-ui-bg-subtle text-ui-fg-subtle hover:text-ui-fg-base",
|
|
1595
|
+
title: "Send via Email / SMS / WhatsApp",
|
|
1596
|
+
children: /* @__PURE__ */ jsx(Envelope, { className: "w-4 h-4" })
|
|
1679
1597
|
}
|
|
1680
1598
|
),
|
|
1681
|
-
!
|
|
1599
|
+
!isZoho && settings.zoho_books_enabled && (doc.type === "invoice" || doc.type === "estimate") && Number(doc.total_amount || 0) > 0 && /* @__PURE__ */ jsx(
|
|
1682
1600
|
Button,
|
|
1683
1601
|
{
|
|
1684
1602
|
variant: "transparent",
|
|
1685
1603
|
size: "small",
|
|
1686
|
-
onClick: () => handleSyncToZoho(
|
|
1687
|
-
className: "text-
|
|
1604
|
+
onClick: () => handleSyncToZoho(doc.id),
|
|
1605
|
+
className: "text-xs text-purple-600 hover:text-purple-700",
|
|
1688
1606
|
children: "Push Zoho"
|
|
1689
1607
|
}
|
|
1690
1608
|
),
|
|
1691
|
-
|
|
1609
|
+
doc.short_payment_link && /* @__PURE__ */ jsx(
|
|
1692
1610
|
"button",
|
|
1693
1611
|
{
|
|
1694
1612
|
onClick: () => {
|
|
1695
|
-
navigator.clipboard.writeText(
|
|
1613
|
+
navigator.clipboard.writeText(doc.short_payment_link);
|
|
1696
1614
|
alert("Short payment link copied to clipboard!");
|
|
1697
1615
|
},
|
|
1698
|
-
className: "text-[
|
|
1699
|
-
title: "Copy Short Link",
|
|
1616
|
+
className: "text-[11px] text-ui-fg-interactive hover:underline px-1.5 py-1",
|
|
1617
|
+
title: "Copy Short Payment Link",
|
|
1700
1618
|
children: "Copy Link"
|
|
1701
1619
|
}
|
|
1702
1620
|
),
|
|
@@ -1705,124 +1623,319 @@ const DocumentsPage = () => {
|
|
|
1705
1623
|
{
|
|
1706
1624
|
type: "button",
|
|
1707
1625
|
onClick: () => {
|
|
1708
|
-
if (
|
|
1709
|
-
handleDeleteRepairDocuments(
|
|
1626
|
+
if (doc.repair_ticket_id) {
|
|
1627
|
+
handleDeleteRepairDocuments(doc.repair_ticket_id);
|
|
1710
1628
|
} else {
|
|
1711
|
-
handleDeleteDocument(
|
|
1629
|
+
handleDeleteDocument(doc.id);
|
|
1712
1630
|
}
|
|
1713
1631
|
},
|
|
1714
|
-
className: "p-1 rounded hover:bg-ui-bg-subtle text-ui-fg-subtle hover:text-red-600 transition-colors",
|
|
1715
|
-
title:
|
|
1716
|
-
children: /* @__PURE__ */ jsx(Trash, { className: "w-
|
|
1632
|
+
className: "p-1.5 rounded hover:bg-ui-bg-subtle text-ui-fg-subtle hover:text-red-600 transition-colors",
|
|
1633
|
+
title: doc.repair_ticket_id ? "Delete / Reset All Documents for this Repair Ticket (including in Zoho Books)" : "Delete Document Record",
|
|
1634
|
+
children: /* @__PURE__ */ jsx(Trash, { className: "w-4 h-4 text-red-500 hover:text-red-700" })
|
|
1717
1635
|
}
|
|
1718
1636
|
)
|
|
1719
1637
|
] }) })
|
|
1720
|
-
]
|
|
1721
|
-
}) })
|
|
1722
|
-
] }) })
|
|
1723
|
-
] }) }) })
|
|
1724
|
-
] }, group.groupId);
|
|
1725
|
-
}) : filteredDocs.map((doc) => {
|
|
1726
|
-
const isPaid = doc.payment_status === "paid" || doc.status === "paid";
|
|
1727
|
-
const isZoho = doc.source === "zoho";
|
|
1728
|
-
return /* @__PURE__ */ jsxs(Table.Row, { className: "hover:bg-ui-bg-subtle-hover transition-colors", children: [
|
|
1729
|
-
/* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(
|
|
1730
|
-
"button",
|
|
1731
|
-
{
|
|
1732
|
-
type: "button",
|
|
1733
|
-
onClick: () => handleViewDocument(doc.id, doc.display_id),
|
|
1734
|
-
className: "font-medium text-ui-fg-interactive hover:underline text-left cursor-pointer bg-transparent border-0 p-0",
|
|
1735
|
-
children: doc.display_id
|
|
1736
|
-
}
|
|
1737
|
-
) }),
|
|
1738
|
-
/* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-ui-fg-base", children: doc.title }) }),
|
|
1739
|
-
/* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
|
|
1740
|
-
/* @__PURE__ */ jsx("span", { className: "text-xs font-medium", children: doc.customer_name || "Guest" }),
|
|
1741
|
-
/* @__PURE__ */ jsx("span", { className: "text-[11px] text-ui-fg-subtle", children: doc.customer_email || doc.customer_phone || "-" })
|
|
1742
|
-
] }) }),
|
|
1743
|
-
/* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx("span", { className: "text-xs font-semibold", children: formatCurrency(doc.total_amount, doc.currency_code) }) }),
|
|
1744
|
-
/* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(Badge, { color: isPaid ? "green" : doc.payment_status === "unpaid" ? "red" : "blue", size: "small", children: doc.payment_status || doc.status }) }),
|
|
1745
|
-
/* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(Badge, { color: isZoho ? "purple" : "grey", size: "small", children: isZoho ? "Zoho Books" : "PDFKit" }) }),
|
|
1746
|
-
/* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx("span", { className: "text-xs text-ui-fg-subtle", children: new Date(doc.created_at).toLocaleDateString() }) }),
|
|
1747
|
-
/* @__PURE__ */ jsx(Table.Cell, { className: "text-right", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-1.5", children: [
|
|
1748
|
-
/* @__PURE__ */ jsx(
|
|
1749
|
-
"button",
|
|
1750
|
-
{
|
|
1751
|
-
type: "button",
|
|
1752
|
-
onClick: () => handleViewDocument(doc.id, doc.display_id),
|
|
1753
|
-
className: "p-1.5 rounded hover:bg-ui-bg-subtle text-ui-fg-subtle hover:text-ui-fg-base cursor-pointer",
|
|
1754
|
-
title: "View / Download PDF",
|
|
1755
|
-
children: /* @__PURE__ */ jsx(ArrowDownTray, { className: "w-4 h-4" })
|
|
1756
|
-
}
|
|
1757
|
-
),
|
|
1758
|
-
(doc.type === "invoice" || doc.type === "estimate" || doc.type === "quote") && /* @__PURE__ */ jsx(
|
|
1759
|
-
"button",
|
|
1760
|
-
{
|
|
1761
|
-
type: "button",
|
|
1762
|
-
onClick: () => handleOpenEditModal(doc),
|
|
1763
|
-
className: "p-1.5 rounded hover:bg-ui-bg-subtle text-ui-fg-subtle hover:text-purple-600 cursor-pointer",
|
|
1764
|
-
title: "Edit Quote / Invoice & Sync with Zoho Books",
|
|
1765
|
-
children: /* @__PURE__ */ jsx(PencilSquare, { className: "w-4 h-4" })
|
|
1766
|
-
}
|
|
1767
|
-
),
|
|
1768
|
-
/* @__PURE__ */ jsx(
|
|
1769
|
-
"button",
|
|
1770
|
-
{
|
|
1771
|
-
onClick: () => {
|
|
1772
|
-
setSelectedDoc(doc);
|
|
1773
|
-
setSendForm({
|
|
1774
|
-
channels: ["email"],
|
|
1775
|
-
custom_message: "",
|
|
1776
|
-
subject: `${settings.company_name}: ${doc.title} #${doc.display_id}`
|
|
1777
|
-
});
|
|
1778
|
-
setSendModalOpen(true);
|
|
1779
|
-
},
|
|
1780
|
-
className: "p-1.5 rounded hover:bg-ui-bg-subtle text-ui-fg-subtle hover:text-ui-fg-base",
|
|
1781
|
-
title: "Send via Email / SMS / WhatsApp",
|
|
1782
|
-
children: /* @__PURE__ */ jsx(Envelope, { className: "w-4 h-4" })
|
|
1783
|
-
}
|
|
1784
|
-
),
|
|
1785
|
-
!isZoho && settings.zoho_books_enabled && (doc.type === "invoice" || doc.type === "estimate") && Number(doc.total_amount || 0) > 0 && /* @__PURE__ */ jsx(
|
|
1786
|
-
Button,
|
|
1787
|
-
{
|
|
1788
|
-
variant: "transparent",
|
|
1789
|
-
size: "small",
|
|
1790
|
-
onClick: () => handleSyncToZoho(doc.id),
|
|
1791
|
-
className: "text-xs text-purple-600 hover:text-purple-700",
|
|
1792
|
-
children: "Push Zoho"
|
|
1793
|
-
}
|
|
1794
|
-
),
|
|
1795
|
-
doc.short_payment_link && /* @__PURE__ */ jsx(
|
|
1796
|
-
"button",
|
|
1797
|
-
{
|
|
1798
|
-
onClick: () => {
|
|
1799
|
-
navigator.clipboard.writeText(doc.short_payment_link);
|
|
1800
|
-
alert("Short payment link copied to clipboard!");
|
|
1801
|
-
},
|
|
1802
|
-
className: "text-[11px] text-ui-fg-interactive hover:underline px-1.5 py-1",
|
|
1803
|
-
title: "Copy Short Payment Link",
|
|
1804
|
-
children: "Copy Link"
|
|
1638
|
+
]
|
|
1805
1639
|
}
|
|
1806
1640
|
),
|
|
1807
|
-
/* @__PURE__ */ jsx(
|
|
1641
|
+
isExpanded && hasMultiple && /* @__PURE__ */ jsx(Table.Row, { className: "bg-ui-bg-subtle hover:bg-ui-bg-subtle border-b border-ui-border-base", children: /* @__PURE__ */ jsx(Table.Cell, { colSpan: 8, className: "p-0", children: /* @__PURE__ */ jsxs("div", { className: "py-3 px-6 bg-ui-bg-subtle/80 border-l-4 border-l-purple-500 my-1 mx-2 rounded-r-md", children: [
|
|
1642
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between mb-2", children: [
|
|
1643
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
1644
|
+
/* @__PURE__ */ jsx(DocumentText, { className: "w-4 h-4 text-purple-600" }),
|
|
1645
|
+
/* @__PURE__ */ jsxs("span", { className: "text-xs font-semibold text-ui-fg-base", children: [
|
|
1646
|
+
"Related Documents for this Job / Order (",
|
|
1647
|
+
group.documents.length,
|
|
1648
|
+
")"
|
|
1649
|
+
] })
|
|
1650
|
+
] }),
|
|
1651
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
|
|
1652
|
+
group.repair_ticket_id && /* @__PURE__ */ jsxs(
|
|
1653
|
+
"button",
|
|
1654
|
+
{
|
|
1655
|
+
type: "button",
|
|
1656
|
+
onClick: () => handleDeleteRepairDocuments(group.repair_ticket_id),
|
|
1657
|
+
className: "text-[11px] text-red-600 hover:text-red-700 hover:underline flex items-center gap-1 font-medium",
|
|
1658
|
+
title: "Delete all generated documents for this repair job in database & Zoho Books to allow clean regeneration",
|
|
1659
|
+
children: [
|
|
1660
|
+
/* @__PURE__ */ jsx(Trash, { className: "w-3 h-3" }),
|
|
1661
|
+
" Reset / Delete Job Documents"
|
|
1662
|
+
]
|
|
1663
|
+
}
|
|
1664
|
+
),
|
|
1665
|
+
/* @__PURE__ */ jsx(
|
|
1666
|
+
"button",
|
|
1667
|
+
{
|
|
1668
|
+
type: "button",
|
|
1669
|
+
onClick: () => toggleGroup(group.groupId),
|
|
1670
|
+
className: "text-[11px] text-ui-fg-interactive hover:underline",
|
|
1671
|
+
children: "Collapse"
|
|
1672
|
+
}
|
|
1673
|
+
)
|
|
1674
|
+
] })
|
|
1675
|
+
] }),
|
|
1676
|
+
/* @__PURE__ */ jsx("div", { className: "overflow-x-auto rounded border border-ui-border-base bg-ui-bg-base", children: /* @__PURE__ */ jsxs("table", { className: "w-full text-left border-collapse", children: [
|
|
1677
|
+
/* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { className: "border-b border-ui-border-base bg-ui-bg-subtle text-[11px] text-ui-fg-muted font-medium", children: [
|
|
1678
|
+
/* @__PURE__ */ jsx("th", { className: "py-1.5 px-3", children: "Document Type" }),
|
|
1679
|
+
/* @__PURE__ */ jsx("th", { className: "py-1.5 px-3", children: "Reference" }),
|
|
1680
|
+
/* @__PURE__ */ jsx("th", { className: "py-1.5 px-3", children: "Amount" }),
|
|
1681
|
+
/* @__PURE__ */ jsx("th", { className: "py-1.5 px-3", children: "Status" }),
|
|
1682
|
+
/* @__PURE__ */ jsx("th", { className: "py-1.5 px-3", children: "Source" }),
|
|
1683
|
+
/* @__PURE__ */ jsx("th", { className: "py-1.5 px-3", children: "Created Date" }),
|
|
1684
|
+
/* @__PURE__ */ jsx("th", { className: "py-1.5 px-3 text-right", children: "Actions" })
|
|
1685
|
+
] }) }),
|
|
1686
|
+
/* @__PURE__ */ jsx("tbody", { className: "divide-y divide-ui-border-base text-xs", children: group.documents.map((subDoc) => {
|
|
1687
|
+
const subIsPaid = subDoc.payment_status === "paid" || subDoc.status === "paid";
|
|
1688
|
+
const subIsZoho = subDoc.source === "zoho";
|
|
1689
|
+
return /* @__PURE__ */ jsxs("tr", { className: "hover:bg-ui-bg-subtle-hover transition-colors", children: [
|
|
1690
|
+
/* @__PURE__ */ jsx("td", { className: "py-2 px-3", children: /* @__PURE__ */ jsx(
|
|
1691
|
+
Badge,
|
|
1692
|
+
{
|
|
1693
|
+
size: "2xsmall",
|
|
1694
|
+
color: subDoc.type === "invoice" ? "green" : subDoc.type === "estimate" ? "blue" : subDoc.type === "job_card" ? "orange" : subDoc.type === "receipt" ? "purple" : "grey",
|
|
1695
|
+
children: subDoc.title
|
|
1696
|
+
}
|
|
1697
|
+
) }),
|
|
1698
|
+
/* @__PURE__ */ jsx("td", { className: "py-2 px-3 font-medium", children: /* @__PURE__ */ jsx(
|
|
1699
|
+
"button",
|
|
1700
|
+
{
|
|
1701
|
+
type: "button",
|
|
1702
|
+
onClick: () => handleViewDocument(subDoc.id, subDoc.display_id),
|
|
1703
|
+
className: "text-ui-fg-interactive hover:underline text-left cursor-pointer bg-transparent border-0 p-0 font-medium",
|
|
1704
|
+
children: subDoc.display_id
|
|
1705
|
+
}
|
|
1706
|
+
) }),
|
|
1707
|
+
/* @__PURE__ */ jsx("td", { className: "py-2 px-3 font-semibold text-ui-fg-base", children: subDoc.total_amount != null && Number(subDoc.total_amount) > 0 ? formatCurrency(subDoc.total_amount, subDoc.currency_code) : "—" }),
|
|
1708
|
+
/* @__PURE__ */ jsx("td", { className: "py-2 px-3", children: /* @__PURE__ */ jsx(
|
|
1709
|
+
Badge,
|
|
1710
|
+
{
|
|
1711
|
+
size: "2xsmall",
|
|
1712
|
+
color: subIsPaid ? "green" : subDoc.payment_status === "unpaid" ? "red" : "blue",
|
|
1713
|
+
children: subDoc.payment_status || subDoc.status
|
|
1714
|
+
}
|
|
1715
|
+
) }),
|
|
1716
|
+
/* @__PURE__ */ jsx("td", { className: "py-2 px-3", children: /* @__PURE__ */ jsx(Badge, { size: "2xsmall", color: subIsZoho ? "purple" : "grey", children: subIsZoho ? "Zoho Books" : "PDFKit" }) }),
|
|
1717
|
+
/* @__PURE__ */ jsx("td", { className: "py-2 px-3 text-ui-fg-subtle text-[11px]", children: new Date(subDoc.created_at).toLocaleString() }),
|
|
1718
|
+
/* @__PURE__ */ jsx("td", { className: "py-2 px-3 text-right", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-1.5", children: [
|
|
1719
|
+
/* @__PURE__ */ jsx(
|
|
1720
|
+
"button",
|
|
1721
|
+
{
|
|
1722
|
+
type: "button",
|
|
1723
|
+
onClick: () => handleViewDocument(subDoc.id, subDoc.display_id),
|
|
1724
|
+
className: "p-1 rounded hover:bg-ui-bg-subtle text-ui-fg-subtle hover:text-ui-fg-base",
|
|
1725
|
+
title: "View / Download PDF",
|
|
1726
|
+
children: /* @__PURE__ */ jsx(ArrowDownTray, { className: "w-3.5 h-3.5" })
|
|
1727
|
+
}
|
|
1728
|
+
),
|
|
1729
|
+
(subDoc.type === "invoice" || subDoc.type === "estimate" || subDoc.type === "quote") && /* @__PURE__ */ jsx(
|
|
1730
|
+
"button",
|
|
1731
|
+
{
|
|
1732
|
+
type: "button",
|
|
1733
|
+
onClick: () => handleOpenEditModal(subDoc),
|
|
1734
|
+
className: "p-1 rounded hover:bg-ui-bg-subtle text-ui-fg-subtle hover:text-purple-600",
|
|
1735
|
+
title: "Edit Quote / Invoice & Sync with Zoho Books",
|
|
1736
|
+
children: /* @__PURE__ */ jsx(PencilSquare, { className: "w-3.5 h-3.5" })
|
|
1737
|
+
}
|
|
1738
|
+
),
|
|
1739
|
+
/* @__PURE__ */ jsx(
|
|
1740
|
+
"button",
|
|
1741
|
+
{
|
|
1742
|
+
type: "button",
|
|
1743
|
+
onClick: () => {
|
|
1744
|
+
setSelectedDoc(subDoc);
|
|
1745
|
+
setSendForm({
|
|
1746
|
+
channels: ["email"],
|
|
1747
|
+
custom_message: "",
|
|
1748
|
+
subject: `${settings.company_name}: ${subDoc.title} #${subDoc.display_id}`
|
|
1749
|
+
});
|
|
1750
|
+
setSendModalOpen(true);
|
|
1751
|
+
},
|
|
1752
|
+
className: "p-1 rounded hover:bg-ui-bg-subtle text-ui-fg-subtle hover:text-ui-fg-base",
|
|
1753
|
+
title: "Send Document",
|
|
1754
|
+
children: /* @__PURE__ */ jsx(Envelope, { className: "w-3.5 h-3.5" })
|
|
1755
|
+
}
|
|
1756
|
+
),
|
|
1757
|
+
!subIsZoho && settings.zoho_books_enabled && (subDoc.type === "invoice" || subDoc.type === "estimate") && Number(subDoc.total_amount || 0) > 0 && /* @__PURE__ */ jsx(
|
|
1758
|
+
Button,
|
|
1759
|
+
{
|
|
1760
|
+
variant: "transparent",
|
|
1761
|
+
size: "small",
|
|
1762
|
+
onClick: () => handleSyncToZoho(subDoc.id),
|
|
1763
|
+
className: "text-[11px] text-purple-600 hover:text-purple-700 py-0.5 px-1.5",
|
|
1764
|
+
children: "Push Zoho"
|
|
1765
|
+
}
|
|
1766
|
+
),
|
|
1767
|
+
subDoc.short_payment_link && /* @__PURE__ */ jsx(
|
|
1768
|
+
"button",
|
|
1769
|
+
{
|
|
1770
|
+
onClick: () => {
|
|
1771
|
+
navigator.clipboard.writeText(subDoc.short_payment_link);
|
|
1772
|
+
alert("Short payment link copied to clipboard!");
|
|
1773
|
+
},
|
|
1774
|
+
className: "text-[10px] text-ui-fg-interactive hover:underline px-1 py-0.5",
|
|
1775
|
+
title: "Copy Short Link",
|
|
1776
|
+
children: "Copy Link"
|
|
1777
|
+
}
|
|
1778
|
+
),
|
|
1779
|
+
/* @__PURE__ */ jsx(
|
|
1780
|
+
"button",
|
|
1781
|
+
{
|
|
1782
|
+
type: "button",
|
|
1783
|
+
onClick: () => {
|
|
1784
|
+
if (subDoc.repair_ticket_id) {
|
|
1785
|
+
handleDeleteRepairDocuments(subDoc.repair_ticket_id);
|
|
1786
|
+
} else {
|
|
1787
|
+
handleDeleteDocument(subDoc.id);
|
|
1788
|
+
}
|
|
1789
|
+
},
|
|
1790
|
+
className: "p-1 rounded hover:bg-ui-bg-subtle text-ui-fg-subtle hover:text-red-600 transition-colors",
|
|
1791
|
+
title: subDoc.repair_ticket_id ? "Delete / Reset All Documents for this Repair Ticket (including in Zoho Books)" : "Delete Document Record",
|
|
1792
|
+
children: /* @__PURE__ */ jsx(Trash, { className: "w-3.5 h-3.5 text-red-500 hover:text-red-700" })
|
|
1793
|
+
}
|
|
1794
|
+
)
|
|
1795
|
+
] }) })
|
|
1796
|
+
] }, subDoc.id);
|
|
1797
|
+
}) })
|
|
1798
|
+
] }) })
|
|
1799
|
+
] }) }) })
|
|
1800
|
+
] }, group.groupId);
|
|
1801
|
+
}) : filteredDocs.slice(0, displayLimit).map((doc) => {
|
|
1802
|
+
const isPaid = doc.payment_status === "paid" || doc.status === "paid";
|
|
1803
|
+
const isZoho = doc.source === "zoho";
|
|
1804
|
+
return /* @__PURE__ */ jsxs(Table.Row, { className: "hover:bg-ui-bg-subtle-hover transition-colors", children: [
|
|
1805
|
+
/* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(
|
|
1808
1806
|
"button",
|
|
1809
1807
|
{
|
|
1810
1808
|
type: "button",
|
|
1811
|
-
onClick: () =>
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
} else {
|
|
1815
|
-
handleDeleteDocument(doc.id);
|
|
1816
|
-
}
|
|
1817
|
-
},
|
|
1818
|
-
className: "p-1.5 rounded hover:bg-ui-bg-subtle text-ui-fg-subtle hover:text-red-600 transition-colors",
|
|
1819
|
-
title: doc.repair_ticket_id ? "Delete / Reset All Documents for this Repair Ticket (including in Zoho Books)" : "Delete Document Record",
|
|
1820
|
-
children: /* @__PURE__ */ jsx(Trash, { className: "w-4 h-4 text-red-500 hover:text-red-700" })
|
|
1809
|
+
onClick: () => handleViewDocument(doc.id, doc.display_id),
|
|
1810
|
+
className: "font-medium text-ui-fg-interactive hover:underline text-left cursor-pointer bg-transparent border-0 p-0",
|
|
1811
|
+
children: doc.display_id
|
|
1821
1812
|
}
|
|
1822
|
-
)
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1813
|
+
) }),
|
|
1814
|
+
/* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-ui-fg-base", children: doc.title }) }),
|
|
1815
|
+
/* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
|
|
1816
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs font-medium", children: doc.customer_name || "Guest" }),
|
|
1817
|
+
/* @__PURE__ */ jsx("span", { className: "text-[11px] text-ui-fg-subtle", children: doc.customer_email || doc.customer_phone || "-" })
|
|
1818
|
+
] }) }),
|
|
1819
|
+
/* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx("span", { className: "text-xs font-semibold", children: formatCurrency(doc.total_amount, doc.currency_code) }) }),
|
|
1820
|
+
/* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(Badge, { color: isPaid ? "green" : doc.payment_status === "unpaid" ? "red" : "blue", size: "small", children: doc.payment_status || doc.status }) }),
|
|
1821
|
+
/* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(Badge, { color: isZoho ? "purple" : "grey", size: "small", children: isZoho ? "Zoho Books" : "PDFKit" }) }),
|
|
1822
|
+
/* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx("span", { className: "text-xs text-ui-fg-subtle", children: new Date(doc.created_at).toLocaleDateString() }) }),
|
|
1823
|
+
/* @__PURE__ */ jsx(Table.Cell, { className: "text-right", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-1.5", children: [
|
|
1824
|
+
/* @__PURE__ */ jsx(
|
|
1825
|
+
"button",
|
|
1826
|
+
{
|
|
1827
|
+
type: "button",
|
|
1828
|
+
onClick: () => handleViewDocument(doc.id, doc.display_id),
|
|
1829
|
+
className: "p-1.5 rounded hover:bg-ui-bg-subtle text-ui-fg-subtle hover:text-ui-fg-base cursor-pointer",
|
|
1830
|
+
title: "View / Download PDF",
|
|
1831
|
+
children: /* @__PURE__ */ jsx(ArrowDownTray, { className: "w-4 h-4" })
|
|
1832
|
+
}
|
|
1833
|
+
),
|
|
1834
|
+
(doc.type === "invoice" || doc.type === "estimate" || doc.type === "quote") && /* @__PURE__ */ jsx(
|
|
1835
|
+
"button",
|
|
1836
|
+
{
|
|
1837
|
+
type: "button",
|
|
1838
|
+
onClick: () => handleOpenEditModal(doc),
|
|
1839
|
+
className: "p-1.5 rounded hover:bg-ui-bg-subtle text-ui-fg-subtle hover:text-purple-600 cursor-pointer",
|
|
1840
|
+
title: "Edit Quote / Invoice & Sync with Zoho Books",
|
|
1841
|
+
children: /* @__PURE__ */ jsx(PencilSquare, { className: "w-4 h-4" })
|
|
1842
|
+
}
|
|
1843
|
+
),
|
|
1844
|
+
/* @__PURE__ */ jsx(
|
|
1845
|
+
"button",
|
|
1846
|
+
{
|
|
1847
|
+
onClick: () => {
|
|
1848
|
+
setSelectedDoc(doc);
|
|
1849
|
+
setSendForm({
|
|
1850
|
+
channels: ["email"],
|
|
1851
|
+
custom_message: "",
|
|
1852
|
+
subject: `${settings.company_name}: ${doc.title} #${doc.display_id}`
|
|
1853
|
+
});
|
|
1854
|
+
setSendModalOpen(true);
|
|
1855
|
+
},
|
|
1856
|
+
className: "p-1.5 rounded hover:bg-ui-bg-subtle text-ui-fg-subtle hover:text-ui-fg-base",
|
|
1857
|
+
title: "Send via Email / SMS / WhatsApp",
|
|
1858
|
+
children: /* @__PURE__ */ jsx(Envelope, { className: "w-4 h-4" })
|
|
1859
|
+
}
|
|
1860
|
+
),
|
|
1861
|
+
!isZoho && settings.zoho_books_enabled && (doc.type === "invoice" || doc.type === "estimate") && Number(doc.total_amount || 0) > 0 && /* @__PURE__ */ jsx(
|
|
1862
|
+
Button,
|
|
1863
|
+
{
|
|
1864
|
+
variant: "transparent",
|
|
1865
|
+
size: "small",
|
|
1866
|
+
onClick: () => handleSyncToZoho(doc.id),
|
|
1867
|
+
className: "text-xs text-purple-600 hover:text-purple-700",
|
|
1868
|
+
children: "Push Zoho"
|
|
1869
|
+
}
|
|
1870
|
+
),
|
|
1871
|
+
doc.short_payment_link && /* @__PURE__ */ jsx(
|
|
1872
|
+
"button",
|
|
1873
|
+
{
|
|
1874
|
+
onClick: () => {
|
|
1875
|
+
navigator.clipboard.writeText(doc.short_payment_link);
|
|
1876
|
+
alert("Short payment link copied to clipboard!");
|
|
1877
|
+
},
|
|
1878
|
+
className: "text-[11px] text-ui-fg-interactive hover:underline px-1.5 py-1",
|
|
1879
|
+
title: "Copy Short Payment Link",
|
|
1880
|
+
children: "Copy Link"
|
|
1881
|
+
}
|
|
1882
|
+
),
|
|
1883
|
+
/* @__PURE__ */ jsx(
|
|
1884
|
+
"button",
|
|
1885
|
+
{
|
|
1886
|
+
type: "button",
|
|
1887
|
+
onClick: () => {
|
|
1888
|
+
if (doc.repair_ticket_id) {
|
|
1889
|
+
handleDeleteRepairDocuments(doc.repair_ticket_id);
|
|
1890
|
+
} else {
|
|
1891
|
+
handleDeleteDocument(doc.id);
|
|
1892
|
+
}
|
|
1893
|
+
},
|
|
1894
|
+
className: "p-1.5 rounded hover:bg-ui-bg-subtle text-ui-fg-subtle hover:text-red-600 transition-colors",
|
|
1895
|
+
title: doc.repair_ticket_id ? "Delete / Reset All Documents for this Repair Ticket (including in Zoho Books)" : "Delete Document Record",
|
|
1896
|
+
children: /* @__PURE__ */ jsx(Trash, { className: "w-4 h-4 text-red-500 hover:text-red-700" })
|
|
1897
|
+
}
|
|
1898
|
+
)
|
|
1899
|
+
] }) })
|
|
1900
|
+
] }, doc.id);
|
|
1901
|
+
}) })
|
|
1902
|
+
] }),
|
|
1903
|
+
/* @__PURE__ */ jsx("div", { ref: sentinelRef, className: "h-6 w-full pointer-events-none" }),
|
|
1904
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col sm:flex-row items-center justify-between p-4 border-t border-ui-border-base bg-ui-bg-subtle text-xs text-ui-fg-subtle gap-3", children: [
|
|
1905
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 flex-wrap", children: [
|
|
1906
|
+
/* @__PURE__ */ jsxs("span", { children: [
|
|
1907
|
+
"Showing ",
|
|
1908
|
+
/* @__PURE__ */ jsx("strong", { className: "font-semibold text-ui-fg-base", children: Math.min(displayLimit, totalItemCount) }),
|
|
1909
|
+
" of",
|
|
1910
|
+
" ",
|
|
1911
|
+
/* @__PURE__ */ jsx("strong", { className: "font-semibold text-ui-fg-base", children: totalItemCount }),
|
|
1912
|
+
" ",
|
|
1913
|
+
groupByJob ? "jobs/orders" : "documents"
|
|
1914
|
+
] }),
|
|
1915
|
+
totalBackendCount > documents.length && /* @__PURE__ */ jsxs(Badge, { size: "2xsmall", color: "grey", children: [
|
|
1916
|
+
totalBackendCount,
|
|
1917
|
+
" total in database"
|
|
1918
|
+
] }),
|
|
1919
|
+
/* @__PURE__ */ jsx("span", { className: "text-ui-fg-muted", children: "(capped at 100 per scroll batch)" })
|
|
1920
|
+
] }),
|
|
1921
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
1922
|
+
isLoadingMore && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-purple-600 font-medium", children: [
|
|
1923
|
+
/* @__PURE__ */ jsx(ArrowPath, { className: "w-3.5 h-3.5 animate-spin" }),
|
|
1924
|
+
/* @__PURE__ */ jsx("span", { children: "Loading next batch..." })
|
|
1925
|
+
] }),
|
|
1926
|
+
canLoadMore && !isLoadingMore && /* @__PURE__ */ jsx(
|
|
1927
|
+
Button,
|
|
1928
|
+
{
|
|
1929
|
+
variant: "secondary",
|
|
1930
|
+
size: "small",
|
|
1931
|
+
onClick: handleLoadMore,
|
|
1932
|
+
className: "text-xs h-7",
|
|
1933
|
+
children: "Load More (+100)"
|
|
1934
|
+
}
|
|
1935
|
+
),
|
|
1936
|
+
!canLoadMore && totalItemCount > 0 && /* @__PURE__ */ jsx("span", { className: "text-ui-fg-muted", children: "All documents loaded" })
|
|
1937
|
+
] })
|
|
1938
|
+
] })
|
|
1826
1939
|
] })
|
|
1827
1940
|
] }),
|
|
1828
1941
|
activeTab === "templates" && /* @__PURE__ */ jsxs("div", { className: "p-6 w-full flex flex-col gap-6", children: [
|