@paro.io/expert-shared-components 1.14.51 → 1.14.53
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/lib/components/DocumentCenter/MultiFileUploadSection.js +220 -121
- package/lib/components/TaxAxis/TaxAxisApi.d.ts +1 -0
- package/lib/components/TaxAxis/TaxAxisShell.js +55 -12
- package/lib/index.d.ts +1 -14
- package/lib/index.js +1 -27
- package/lib/tax-axis/components/clientReport/TaxAxisClientReport.d.ts +6 -2
- package/lib/tax-axis/components/clientReport/TaxAxisClientReport.js +5 -3
- package/lib/tax-axis/components/dashboard/TaxAxisDashboard.d.ts +2 -1
- package/lib/tax-axis/components/dashboard/TaxAxisDashboard.js +163 -34
- package/lib/tax-axis/components/documents/DocumentCard.d.ts +3 -1
- package/lib/tax-axis/components/documents/DocumentCard.js +17 -5
- package/lib/tax-axis/components/documents/DocumentReviewModal.d.ts +13 -0
- package/lib/tax-axis/components/documents/DocumentReviewModal.js +248 -0
- package/lib/tax-axis/components/documents/DocumentTier.d.ts +3 -1
- package/lib/tax-axis/components/documents/DocumentTier.js +2 -2
- package/lib/tax-axis/components/documents/TaxAxisDocuments.d.ts +7 -1
- package/lib/tax-axis/components/documents/TaxAxisDocuments.js +116 -53
- package/lib/tax-axis/components/extractionReview/TaxAxisExtractionReview.js +17 -17
- package/lib/tax-axis/components/intake/ClientParametersSection.js +1 -1
- package/lib/tax-axis/components/intake/intakeSchema.js +1 -1
- package/lib/tax-axis/components/preparerWorkpaper/TaxAxisPreparerWorkpaper.d.ts +6 -2
- package/lib/tax-axis/components/preparerWorkpaper/TaxAxisPreparerWorkpaper.js +5 -3
- package/lib/tax-axis/index.d.ts +4 -0
- package/lib/tax-axis/index.js +6 -1
- package/lib/tax-axis/lib/adapters/useEngineOutput.d.ts +144 -0
- package/lib/tax-axis/lib/adapters/useEngineOutput.js +155 -0
- package/lib/tax-axis/lib/data/documents.d.ts +3 -2
- package/lib/tax-axis/lib/data/documents.js +225 -25
- package/lib/tax-axis/lib/documentFieldCatalog.d.ts +13 -0
- package/lib/tax-axis/lib/documentFieldCatalog.js +808 -0
- package/lib/tax-axis/lib/types/index.d.ts +3 -0
- package/package.json +1 -1
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
26
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
27
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
28
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
29
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
30
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
31
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
32
|
+
});
|
|
33
|
+
};
|
|
34
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
35
|
+
exports.SAVE_FIELD_EDIT_MUTATION = exports.EXTRACTED_FIELDS_QUERY = void 0;
|
|
36
|
+
exports.DocumentReviewModal = DocumentReviewModal;
|
|
37
|
+
const react_1 = __importStar(require("react"));
|
|
38
|
+
const extractedData_1 = require("../../lib/data/extractedData");
|
|
39
|
+
const documentFieldCatalog_1 = require("../../lib/documentFieldCatalog");
|
|
40
|
+
// ── GraphQL contracts (for consuming apps to use once resolvers land) ──
|
|
41
|
+
exports.EXTRACTED_FIELDS_QUERY = `
|
|
42
|
+
query ExtractedDocumentFields($jobId: ID!, $documentId: ID!) {
|
|
43
|
+
extractedDocumentFields(jobId: $jobId, documentId: $documentId) {
|
|
44
|
+
documentId
|
|
45
|
+
documentName
|
|
46
|
+
fileName
|
|
47
|
+
sections {
|
|
48
|
+
head
|
|
49
|
+
fields {
|
|
50
|
+
key
|
|
51
|
+
label
|
|
52
|
+
value
|
|
53
|
+
sourceRef
|
|
54
|
+
confidence
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
`;
|
|
60
|
+
exports.SAVE_FIELD_EDIT_MUTATION = `
|
|
61
|
+
mutation SaveExtractedFieldEdit($jobId: ID!, $documentId: ID!, $fieldKey: String!, $value: String!) {
|
|
62
|
+
saveExtractedFieldEdit(jobId: $jobId, documentId: $documentId, fieldKey: $fieldKey, value: $value) {
|
|
63
|
+
success
|
|
64
|
+
fieldKey
|
|
65
|
+
savedValue
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
`;
|
|
69
|
+
// ── Format a raw value for display ──
|
|
70
|
+
function formatValue(v) {
|
|
71
|
+
if (v === null || v === undefined)
|
|
72
|
+
return "";
|
|
73
|
+
if (typeof v === "number")
|
|
74
|
+
return `$${v.toLocaleString()}`;
|
|
75
|
+
if (typeof v === "boolean")
|
|
76
|
+
return v ? "Yes" : "No";
|
|
77
|
+
return String(v);
|
|
78
|
+
}
|
|
79
|
+
// ── Build ReviewSection[] from real parsedData using the catalog ──
|
|
80
|
+
function buildSectionsFromCatalog(documentType, fields) {
|
|
81
|
+
const catalog = documentFieldCatalog_1.DOCUMENT_FIELD_CATALOG[documentType];
|
|
82
|
+
if (!catalog) {
|
|
83
|
+
// Unknown doc type — render all non-null scalar fields in one flat section
|
|
84
|
+
const flatFields = Object.entries(fields)
|
|
85
|
+
.filter(([, v]) => v !== null && v !== undefined && typeof v !== "object")
|
|
86
|
+
.map(([key, val]) => ({
|
|
87
|
+
key,
|
|
88
|
+
label: key.replace(/_/g, " ").replace(/\b\w/g, (c) => c.toUpperCase()),
|
|
89
|
+
value: formatValue(val),
|
|
90
|
+
sourceRef: "",
|
|
91
|
+
confidence: 0.9,
|
|
92
|
+
}));
|
|
93
|
+
return flatFields.length > 0 ? [{ head: "Extracted Fields", fields: flatFields }] : [];
|
|
94
|
+
}
|
|
95
|
+
return catalog.sections
|
|
96
|
+
.map((section) => {
|
|
97
|
+
const sectionFields = section.fields
|
|
98
|
+
.filter((key) => {
|
|
99
|
+
const v = fields[key];
|
|
100
|
+
// Include all scalar fields from the catalog — show empty string for null/undefined.
|
|
101
|
+
// Skip only object/array values (dicts, arrays) which can't be inline-edited.
|
|
102
|
+
return typeof v !== "object" || v === null || v === undefined;
|
|
103
|
+
})
|
|
104
|
+
.map((key) => {
|
|
105
|
+
var _a, _b;
|
|
106
|
+
const def = catalog.fields[key];
|
|
107
|
+
return {
|
|
108
|
+
key,
|
|
109
|
+
label: (_a = def === null || def === void 0 ? void 0 : def.label) !== null && _a !== void 0 ? _a : key.replace(/_/g, " ").replace(/\b\w/g, (c) => c.toUpperCase()),
|
|
110
|
+
value: formatValue(fields[key]),
|
|
111
|
+
sourceRef: (_b = def === null || def === void 0 ? void 0 : def.sourceRef) !== null && _b !== void 0 ? _b : "",
|
|
112
|
+
confidence: 0.9,
|
|
113
|
+
};
|
|
114
|
+
});
|
|
115
|
+
return { head: section.head, fields: sectionFields };
|
|
116
|
+
})
|
|
117
|
+
.filter((s) => s.fields.length > 0);
|
|
118
|
+
}
|
|
119
|
+
// ── Stub fallback when no real parsedData is available ──
|
|
120
|
+
function getStubSections(documentId) {
|
|
121
|
+
const doc = extractedData_1.EXTRACTED_DATA.find((d) => d.docId === documentId);
|
|
122
|
+
if (!doc)
|
|
123
|
+
return [];
|
|
124
|
+
return [
|
|
125
|
+
{
|
|
126
|
+
head: doc.docName,
|
|
127
|
+
fields: doc.fields.map((f, i) => ({
|
|
128
|
+
key: `${documentId}-${i}`,
|
|
129
|
+
label: f.field,
|
|
130
|
+
value: f.value,
|
|
131
|
+
sourceRef: f.line,
|
|
132
|
+
confidence: f.status === "pass" ? 0.92 : 0.65,
|
|
133
|
+
})),
|
|
134
|
+
},
|
|
135
|
+
];
|
|
136
|
+
}
|
|
137
|
+
function getTotalFieldCount(sections) {
|
|
138
|
+
return sections.reduce((sum, s) => sum + s.fields.length, 0);
|
|
139
|
+
}
|
|
140
|
+
// ── Component ──
|
|
141
|
+
function DocumentReviewModal({ documentId, documentName, fileName, jobId: _jobId, parsedData, onSaveReviewedData, onClose, }) {
|
|
142
|
+
const [loading, setLoading] = (0, react_1.useState)(true);
|
|
143
|
+
const [sections, setSections] = (0, react_1.useState)([]);
|
|
144
|
+
const [saveStatus, setSaveStatus] = (0, react_1.useState)("idle");
|
|
145
|
+
const debounceTimers = (0, react_1.useRef)({});
|
|
146
|
+
(0, react_1.useEffect)(() => {
|
|
147
|
+
var _a;
|
|
148
|
+
if (parsedData && typeof parsedData === "object") {
|
|
149
|
+
const fields = ((_a = parsedData.fields) !== null && _a !== void 0 ? _a : parsedData);
|
|
150
|
+
const documentType = parsedData.documentType || documentId;
|
|
151
|
+
setSections(buildSectionsFromCatalog(documentType, fields));
|
|
152
|
+
setLoading(false);
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
// Fallback: stub loading delay
|
|
156
|
+
const t = setTimeout(() => {
|
|
157
|
+
setSections(getStubSections(documentId));
|
|
158
|
+
setLoading(false);
|
|
159
|
+
}, 400);
|
|
160
|
+
return () => clearTimeout(t);
|
|
161
|
+
}, [documentId, parsedData]);
|
|
162
|
+
const handleFieldChange = (0, react_1.useCallback)((sectionIdx, fieldIdx, newValue) => {
|
|
163
|
+
setSections((prev) => prev.map((sec, si) => si === sectionIdx
|
|
164
|
+
? Object.assign(Object.assign({}, sec), { fields: sec.fields.map((f, fi) => fi === fieldIdx ? Object.assign(Object.assign({}, f), { value: newValue }) : f) }) : sec));
|
|
165
|
+
const timerKey = `${sectionIdx}-${fieldIdx}`;
|
|
166
|
+
clearTimeout(debounceTimers.current[timerKey]);
|
|
167
|
+
setSaveStatus("saving");
|
|
168
|
+
debounceTimers.current[timerKey] = setTimeout(() => {
|
|
169
|
+
setSaveStatus("saved");
|
|
170
|
+
setTimeout(() => setSaveStatus("idle"), 1500);
|
|
171
|
+
}, 900);
|
|
172
|
+
}, [sections]);
|
|
173
|
+
const handleDone = (0, react_1.useCallback)(() => __awaiter(this, void 0, void 0, function* () {
|
|
174
|
+
if (onSaveReviewedData && sections.length > 0) {
|
|
175
|
+
const allFields = {};
|
|
176
|
+
sections.forEach((sec) => sec.fields.forEach((f) => { allFields[f.key] = f.value; }));
|
|
177
|
+
try {
|
|
178
|
+
yield onSaveReviewedData(allFields);
|
|
179
|
+
}
|
|
180
|
+
catch ( /* non-fatal */_a) { /* non-fatal */ }
|
|
181
|
+
}
|
|
182
|
+
onClose();
|
|
183
|
+
}), [onSaveReviewedData, sections, onClose]);
|
|
184
|
+
(0, react_1.useEffect)(() => {
|
|
185
|
+
const timers = debounceTimers.current;
|
|
186
|
+
return () => { Object.values(timers).forEach(clearTimeout); };
|
|
187
|
+
}, []);
|
|
188
|
+
const totalFields = getTotalFieldCount(sections);
|
|
189
|
+
const isFlagged = (f) => f.confidence < 0.8;
|
|
190
|
+
return (react_1.default.createElement("div", { onClick: onClose, style: { position: "fixed", inset: 0, zIndex: 9999, background: "rgba(0,0,0,0.65)", display: "flex", alignItems: "center", justifyContent: "center" } },
|
|
191
|
+
react_1.default.createElement("div", { onClick: (e) => e.stopPropagation(), style: { width: 520, maxHeight: "85vh", background: "#111827", border: "1px solid #1f2937", borderRadius: 16, display: "flex", flexDirection: "column", boxShadow: "0 25px 60px rgba(0,0,0,0.5)" } },
|
|
192
|
+
react_1.default.createElement("div", { style: { padding: "20px 24px 16px", borderBottom: "1px solid #1f2937", display: "flex", alignItems: "flex-start", gap: 14 } },
|
|
193
|
+
react_1.default.createElement("div", { style: { width: 40, height: 40, borderRadius: 10, background: "rgba(99,102,241,0.12)", border: "1px solid rgba(99,102,241,0.25)", display: "flex", alignItems: "center", justifyContent: "center", flexShrink: 0 } },
|
|
194
|
+
react_1.default.createElement("svg", { width: "18", height: "18", viewBox: "0 0 18 18", fill: "none" },
|
|
195
|
+
react_1.default.createElement("rect", { x: "3", y: "2", width: "12", height: "14", rx: "2", stroke: "#818cf8", strokeWidth: "1.5" }),
|
|
196
|
+
react_1.default.createElement("path", { d: "M6 6h6M6 9h6M6 12h4", stroke: "#818cf8", strokeWidth: "1.2", strokeLinecap: "round" }))),
|
|
197
|
+
react_1.default.createElement("div", { style: { flex: 1, minWidth: 0 } },
|
|
198
|
+
react_1.default.createElement("div", { className: "font-tax-axis-body", style: { fontSize: 15, fontWeight: 600, color: "#f3f4f6", marginBottom: 3 } },
|
|
199
|
+
documentName,
|
|
200
|
+
" \u2014 Extracted Fields"),
|
|
201
|
+
react_1.default.createElement("div", { className: "font-tax-axis-body", style: { fontSize: 12, color: "#9ca3af" } },
|
|
202
|
+
fileName,
|
|
203
|
+
!loading && react_1.default.createElement(react_1.default.Fragment, null,
|
|
204
|
+
" ",
|
|
205
|
+
"\u00B7 ",
|
|
206
|
+
totalFields,
|
|
207
|
+
" fields \u00B7 Review and correct parsed values"))),
|
|
208
|
+
react_1.default.createElement("button", { onClick: onClose, style: { background: "transparent", border: "none", color: "#6b7280", fontSize: 20, cursor: "pointer", padding: "2px 6px", lineHeight: 1 } }, "\u00D7")),
|
|
209
|
+
react_1.default.createElement("div", { style: { flex: 1, overflowY: "auto", padding: "16px 24px 8px" } }, loading ? (react_1.default.createElement(LoadingSkeleton, null)) : sections.length === 0 ? (react_1.default.createElement("div", { style: { color: "#6b7280", fontSize: 13, textAlign: "center", padding: "32px 0" } }, "No extracted fields available for this document.")) : (sections.map((section, si) => (react_1.default.createElement("div", { key: section.head, style: { marginBottom: 20 } },
|
|
210
|
+
react_1.default.createElement("div", { style: { display: "flex", alignItems: "center", gap: 10, marginBottom: 10 } },
|
|
211
|
+
react_1.default.createElement("span", { className: "font-tax-axis-mono", style: { fontSize: 10, fontWeight: 700, letterSpacing: "0.08em", textTransform: "uppercase", color: "#6b7280" } }, section.head),
|
|
212
|
+
react_1.default.createElement("div", { style: { flex: 1, height: 1, background: "#1f2937" } })),
|
|
213
|
+
react_1.default.createElement("div", { style: { background: "#0d1117", borderRadius: 10, border: "1px solid #1f2937", overflow: "hidden" } }, section.fields.map((field, fi) => {
|
|
214
|
+
const flagged = isFlagged(field);
|
|
215
|
+
return (react_1.default.createElement("div", { key: field.key, style: { display: "grid", gridTemplateColumns: "160px 1fr auto", alignItems: "center", padding: "10px 14px", borderBottom: fi < section.fields.length - 1 ? "1px solid #1f2937" : "none", gap: 12 } },
|
|
216
|
+
react_1.default.createElement("span", { className: "font-tax-axis-body", style: { fontSize: 12, color: flagged ? "#fbbf24" : "#9ca3af", display: "flex", alignItems: "center", gap: 5 } },
|
|
217
|
+
flagged && (react_1.default.createElement("svg", { width: "12", height: "12", viewBox: "0 0 12 12", fill: "none" },
|
|
218
|
+
react_1.default.createElement("path", { d: "M6 1L11 10H1L6 1Z", stroke: "#fbbf24", strokeWidth: "1.2", strokeLinejoin: "round" }),
|
|
219
|
+
react_1.default.createElement("path", { d: "M6 4.5V6.5M6 8V8.01", stroke: "#fbbf24", strokeWidth: "1.1", strokeLinecap: "round" }))),
|
|
220
|
+
field.label),
|
|
221
|
+
react_1.default.createElement("input", { type: "text", value: field.value, onChange: (e) => handleFieldChange(si, fi, e.target.value), style: { background: "#0d1117", border: `1px solid ${flagged ? "rgba(251,191,36,0.4)" : "#1f2937"}`, borderRadius: 6, padding: "7px 10px", color: "#e5e7eb", fontSize: 13, fontFamily: "monospace", outline: "none", width: "100%", boxSizing: "border-box" } }),
|
|
222
|
+
react_1.default.createElement("span", { className: "font-tax-axis-mono", style: { fontSize: 11, color: flagged ? "#fbbf24" : "#4ade80", whiteSpace: "nowrap", display: "flex", alignItems: "center", gap: 4 } },
|
|
223
|
+
field.sourceRef || "",
|
|
224
|
+
" ",
|
|
225
|
+
flagged ? react_1.default.createElement("span", { style: { fontSize: 10 } }, "\u25B2") : react_1.default.createElement("span", { style: { fontSize: 12 } }, "\u2713"))));
|
|
226
|
+
}))))))),
|
|
227
|
+
react_1.default.createElement("div", { style: { padding: "14px 24px", borderTop: "1px solid #1f2937", display: "flex", alignItems: "center", justifyContent: "space-between" } },
|
|
228
|
+
react_1.default.createElement("span", { className: "font-tax-axis-body", style: { fontSize: 11, color: "#6b7280", display: "flex", alignItems: "center", gap: 6 } },
|
|
229
|
+
saveStatus === "idle" && (react_1.default.createElement(react_1.default.Fragment, null,
|
|
230
|
+
react_1.default.createElement("svg", { width: "12", height: "12", viewBox: "0 0 12 12", fill: "none" },
|
|
231
|
+
react_1.default.createElement("circle", { cx: "6", cy: "6", r: "5", stroke: "#6b7280", strokeWidth: "1.2" }),
|
|
232
|
+
react_1.default.createElement("path", { d: "M6 3.5V6.5L8 7.5", stroke: "#6b7280", strokeWidth: "1.1", strokeLinecap: "round" })),
|
|
233
|
+
"Changes save automatically")),
|
|
234
|
+
saveStatus === "saving" && (react_1.default.createElement(react_1.default.Fragment, null,
|
|
235
|
+
react_1.default.createElement("div", { style: { width: 10, height: 10, borderRadius: "50%", border: "2px solid transparent", borderTopColor: "#818cf8", animation: "spin 0.6s linear infinite" } }),
|
|
236
|
+
"Saving\u2026")),
|
|
237
|
+
saveStatus === "saved" && react_1.default.createElement("span", { style: { color: "#4ade80" } }, "Saved \u2713")),
|
|
238
|
+
react_1.default.createElement("button", { onClick: handleDone, className: "font-tax-axis-body", style: { background: "rgba(99,102,241,0.9)", border: "none", borderRadius: 8, padding: "9px 28px", color: "#fff", fontSize: 13, fontWeight: 600, cursor: "pointer" } }, "Done"))),
|
|
239
|
+
react_1.default.createElement("style", null, `@keyframes spin { to { transform: rotate(360deg); } }`)));
|
|
240
|
+
}
|
|
241
|
+
function LoadingSkeleton() {
|
|
242
|
+
return (react_1.default.createElement("div", null, [1, 2].map((i) => (react_1.default.createElement("div", { key: i, style: { marginBottom: 20 } },
|
|
243
|
+
react_1.default.createElement("div", { style: { width: 100, height: 10, background: "#1f2937", borderRadius: 4, marginBottom: 10 } }),
|
|
244
|
+
react_1.default.createElement("div", { style: { background: "#0d1117", borderRadius: 10, border: "1px solid #1f2937", padding: 14 } }, [1, 2, 3].map((j) => (react_1.default.createElement("div", { key: j, style: { display: "grid", gridTemplateColumns: "160px 1fr 60px", gap: 12, marginBottom: j < 3 ? 12 : 0 } },
|
|
245
|
+
react_1.default.createElement("div", { style: { height: 14, background: "#1f2937", borderRadius: 4 } }),
|
|
246
|
+
react_1.default.createElement("div", { style: { height: 32, background: "#1f2937", borderRadius: 6 } }),
|
|
247
|
+
react_1.default.createElement("div", { style: { height: 14, background: "#1f2937", borderRadius: 4 } }))))))))));
|
|
248
|
+
}
|
|
@@ -14,9 +14,11 @@ interface DocumentTierProps {
|
|
|
14
14
|
tier: TierDef;
|
|
15
15
|
docs: DocState[];
|
|
16
16
|
helpOverrides: Record<string, string>;
|
|
17
|
+
fieldCounts?: Record<string, number>;
|
|
17
18
|
onUpload: (idx: number, file: File) => void;
|
|
18
19
|
onClear: (idx: number) => void;
|
|
19
20
|
onRemove?: (idx: number) => void;
|
|
21
|
+
onReview?: (docId: string) => void;
|
|
20
22
|
}
|
|
21
|
-
export declare function DocumentTier({ tier, docs, helpOverrides, onUpload, onClear, onRemove, }: DocumentTierProps): React.JSX.Element | null;
|
|
23
|
+
export declare function DocumentTier({ tier, docs, helpOverrides, fieldCounts, onUpload, onClear, onRemove, onReview, }: DocumentTierProps): React.JSX.Element | null;
|
|
22
24
|
export {};
|
|
@@ -6,7 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.DocumentTier = DocumentTier;
|
|
7
7
|
const react_1 = __importDefault(require("react"));
|
|
8
8
|
const DocumentCard_1 = require("./DocumentCard");
|
|
9
|
-
function DocumentTier({ tier, docs, helpOverrides, onUpload, onClear, onRemove, }) {
|
|
9
|
+
function DocumentTier({ tier, docs, helpOverrides, fieldCounts, onUpload, onClear, onRemove, onReview, }) {
|
|
10
10
|
const tierDocs = tier.ids
|
|
11
11
|
.map((id) => {
|
|
12
12
|
const idx = docs.findIndex((d) => d.id === id);
|
|
@@ -19,5 +19,5 @@ function DocumentTier({ tier, docs, helpOverrides, onUpload, onClear, onRemove,
|
|
|
19
19
|
react_1.default.createElement("div", { className: "flex items-center gap-2 mb-2" },
|
|
20
20
|
react_1.default.createElement("span", { className: "text-[10px] font-bold uppercase tracking-widest font-tax-axis-mono", style: { color: tier.labelColor } }, tier.label),
|
|
21
21
|
react_1.default.createElement("span", { className: "text-[10px] text-tax-axis-text-4 font-tax-axis-body" }, tier.sublabel)),
|
|
22
|
-
react_1.default.createElement("div", { className: "grid gap-1.5" }, tierDocs.map(({ doc, idx }) => (react_1.default.createElement(DocumentCard_1.DocumentCard, { key: doc.id, doc: doc, tierBorderColor: tier.borderColor, tierBadgeColor: tier.badgeColor, tierBadgeText: tier.badgeText, helpOverride: helpOverrides[doc.id], onUpload: (file) => onUpload(idx, file), onClear: () => onClear(idx), onRemove: onRemove ? () => onRemove(idx) : undefined }))))));
|
|
22
|
+
react_1.default.createElement("div", { className: "grid gap-1.5" }, tierDocs.map(({ doc, idx }) => (react_1.default.createElement(DocumentCard_1.DocumentCard, { key: doc.id, doc: doc, tierBorderColor: tier.borderColor, tierBadgeColor: tier.badgeColor, tierBadgeText: tier.badgeText, helpOverride: helpOverrides[doc.id], fieldCount: fieldCounts === null || fieldCounts === void 0 ? void 0 : fieldCounts[doc.id], onUpload: (file) => onUpload(idx, file), onClear: () => onClear(idx), onRemove: onRemove ? () => onRemove(idx) : undefined, onReview: onReview ? () => onReview(doc.id) : undefined }))))));
|
|
23
23
|
}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { ClientProfile, TaxAxisScreenProps } from "../../lib/types";
|
|
3
|
+
import { TaxAxisEntityTypeKey } from "../../lib/data/documents";
|
|
3
4
|
import { DocState } from "./DocumentCard";
|
|
4
5
|
export interface TaxAxisDocumentsProps extends TaxAxisScreenProps {
|
|
5
6
|
profile: ClientProfile;
|
|
7
|
+
entityType?: TaxAxisEntityTypeKey | string | null;
|
|
6
8
|
onContinue: () => void;
|
|
7
9
|
onBack: () => void;
|
|
8
10
|
onUploadDocument?: (doc: DocState, file: File) => Promise<void | {
|
|
@@ -19,6 +21,10 @@ export interface TaxAxisDocumentsProps extends TaxAxisScreenProps {
|
|
|
19
21
|
documentType?: string | null;
|
|
20
22
|
parseError?: string | null;
|
|
21
23
|
updatedAt?: string | null;
|
|
24
|
+
parsedData?: Record<string, unknown> | null;
|
|
22
25
|
}>>;
|
|
26
|
+
parsedFieldCounts?: Record<string, number>;
|
|
27
|
+
jobId?: string;
|
|
28
|
+
onSaveReviewedField?: (documentId: string, reviewedData: Record<string, unknown>) => Promise<void>;
|
|
23
29
|
}
|
|
24
|
-
export declare function TaxAxisDocuments({ profile, onContinue, onBack, onUploadDocument, onDeleteDocument, fetchUploadedDocuments, userContext: _userContext, }: TaxAxisDocumentsProps): React.JSX.Element;
|
|
30
|
+
export declare function TaxAxisDocuments({ profile, entityType, onContinue, onBack, onUploadDocument, onDeleteDocument, fetchUploadedDocuments, parsedFieldCounts, jobId, onSaveReviewedField, userContext: _userContext, }: TaxAxisDocumentsProps): React.JSX.Element;
|
|
@@ -37,24 +37,7 @@ const react_1 = __importStar(require("react"));
|
|
|
37
37
|
const documents_1 = require("../../lib/data/documents");
|
|
38
38
|
const TaxAxisButton_1 = require("../shared/TaxAxisButton");
|
|
39
39
|
const DocumentTier_1 = require("./DocumentTier");
|
|
40
|
-
const
|
|
41
|
-
"1120s": "2025_1120S.pdf",
|
|
42
|
-
"state-return": "2025_State_Return.pdf",
|
|
43
|
-
"payroll": "2025_Payroll.xlsx",
|
|
44
|
-
"pnl": "QBO_PnL_2025.pdf",
|
|
45
|
-
"balance": "QBO_BS_2025.pdf",
|
|
46
|
-
"cashflow": "QBO_CashFlow_2025.pdf",
|
|
47
|
-
"fixed-assets": "Fixed_Assets.xlsx",
|
|
48
|
-
"prior-returns": "Prior_Returns.pdf",
|
|
49
|
-
};
|
|
50
|
-
const HELP_OVERRIDES = {
|
|
51
|
-
"1120s": "Improves accuracy of every strategy",
|
|
52
|
-
"payroll": "Critical for Entity Structure and QBI calculations",
|
|
53
|
-
"fixed-assets": "Unlocks Cost Segregation (potential $15K\u201385K)",
|
|
54
|
-
"state-return": "If client operates in income-tax states",
|
|
55
|
-
"cashflow": "Helps with income deferral and timing strategies",
|
|
56
|
-
"prior-returns": "Improves confidence intervals (more years = tighter estimates)",
|
|
57
|
-
};
|
|
40
|
+
const DocumentReviewModal_1 = require("./DocumentReviewModal");
|
|
58
41
|
const TIER_DEFS = [
|
|
59
42
|
{
|
|
60
43
|
key: "required",
|
|
@@ -64,7 +47,7 @@ const TIER_DEFS = [
|
|
|
64
47
|
labelColor: "#C53030",
|
|
65
48
|
badgeColor: "red",
|
|
66
49
|
badgeText: "REQUIRED",
|
|
67
|
-
ids: [
|
|
50
|
+
ids: [],
|
|
68
51
|
},
|
|
69
52
|
{
|
|
70
53
|
key: "recommended",
|
|
@@ -74,7 +57,7 @@ const TIER_DEFS = [
|
|
|
74
57
|
labelColor: "#FB9A1D",
|
|
75
58
|
badgeColor: "orange",
|
|
76
59
|
badgeText: "RECOMMENDED",
|
|
77
|
-
ids: [
|
|
60
|
+
ids: [],
|
|
78
61
|
},
|
|
79
62
|
{
|
|
80
63
|
key: "conditional",
|
|
@@ -84,16 +67,49 @@ const TIER_DEFS = [
|
|
|
84
67
|
labelColor: "#C8CCE5",
|
|
85
68
|
badgeColor: "neutral",
|
|
86
69
|
badgeText: "CONDITIONAL",
|
|
87
|
-
ids: [
|
|
70
|
+
ids: [],
|
|
88
71
|
},
|
|
89
72
|
];
|
|
90
|
-
function TaxAxisDocuments({ profile, onContinue, onBack, onUploadDocument, onDeleteDocument, fetchUploadedDocuments, userContext: _userContext = "expert", }) {
|
|
91
|
-
|
|
92
|
-
const docSpecs = (0, react_1.useMemo)(() => (0, documents_1.getDocSpecs)(
|
|
73
|
+
function TaxAxisDocuments({ profile, entityType, onContinue, onBack, onUploadDocument, onDeleteDocument, fetchUploadedDocuments, parsedFieldCounts, jobId = "stub-job-id", onSaveReviewedField, userContext: _userContext = "expert", }) {
|
|
74
|
+
var _a, _b, _c;
|
|
75
|
+
const docSpecs = (0, react_1.useMemo)(() => (0, documents_1.getDocSpecs)(entityType !== null && entityType !== void 0 ? entityType : undefined), [entityType]);
|
|
76
|
+
// Build tier defs dynamically from the doc spec list so they're always in sync.
|
|
77
|
+
const tierDefs = (0, react_1.useMemo)(() => {
|
|
78
|
+
return TIER_DEFS.map((def) => (Object.assign(Object.assign({}, def), { ids: docSpecs
|
|
79
|
+
.filter((s) => s.tier === def.key)
|
|
80
|
+
.map((s) => s.id) })));
|
|
81
|
+
}, [docSpecs]);
|
|
93
82
|
const [docs, setDocs] = (0, react_1.useState)(() => docSpecs.map((s) => (Object.assign(Object.assign({}, s), { status: "empty", fileName: null, parseError: null }))));
|
|
94
83
|
const [uploadedDocIds, setUploadedDocIds] = (0, react_1.useState)({});
|
|
95
84
|
const [continueError, setContinueError] = (0, react_1.useState)(null);
|
|
96
|
-
const
|
|
85
|
+
const [reviewDocId, setReviewDocId] = (0, react_1.useState)(null);
|
|
86
|
+
// parsedData keyed by documentType (e.g. "profit_loss") — populated from poll results
|
|
87
|
+
const [parsedDataByDocType, setParsedDataByDocType] = (0, react_1.useState)({});
|
|
88
|
+
// On mount, fetch any already-parsed docs so the review modal has real data
|
|
89
|
+
(0, react_1.useEffect)(() => {
|
|
90
|
+
if (!fetchUploadedDocuments)
|
|
91
|
+
return;
|
|
92
|
+
fetchUploadedDocuments().then((uploaded) => {
|
|
93
|
+
const byType = {};
|
|
94
|
+
for (const doc of uploaded) {
|
|
95
|
+
if (doc.parsedData && doc.documentType) {
|
|
96
|
+
byType[doc.documentType] = doc.parsedData;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
if (Object.keys(byType).length > 0) {
|
|
100
|
+
setParsedDataByDocType(byType);
|
|
101
|
+
}
|
|
102
|
+
}).catch(() => { });
|
|
103
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
104
|
+
}, []);
|
|
105
|
+
const reviewDoc = reviewDocId
|
|
106
|
+
? (_a = docs.find((d) => d.id === reviewDocId)) !== null && _a !== void 0 ? _a : null
|
|
107
|
+
: null;
|
|
108
|
+
// The real parsedData for the document currently open in the review modal
|
|
109
|
+
const reviewParsedData = reviewDoc
|
|
110
|
+
? ((_c = (_b = parsedDataByDocType[reviewDoc.documentType || reviewDoc.id]) !== null && _b !== void 0 ? _b : parsedDataByDocType[reviewDoc.id]) !== null && _c !== void 0 ? _c : null)
|
|
111
|
+
: null;
|
|
112
|
+
const pollForParseStatus = (idx, fileName, documentType) => __awaiter(this, void 0, void 0, function* () {
|
|
97
113
|
if (!fetchUploadedDocuments)
|
|
98
114
|
return;
|
|
99
115
|
const maxAttempts = 80;
|
|
@@ -101,11 +117,11 @@ function TaxAxisDocuments({ profile, onContinue, onBack, onUploadDocument, onDel
|
|
|
101
117
|
for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
|
|
102
118
|
try {
|
|
103
119
|
const uploaded = yield fetchUploadedDocuments();
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
const
|
|
108
|
-
const candidates =
|
|
120
|
+
// Match by documentType first (exact lowercase key), fall back to fileName.
|
|
121
|
+
const typeMatch = uploaded.filter((doc) => doc.fileName === fileName &&
|
|
122
|
+
String(doc.documentType || "").toLowerCase() === documentType.toLowerCase());
|
|
123
|
+
const nameMatch = uploaded.filter((doc) => doc.fileName === fileName);
|
|
124
|
+
const candidates = typeMatch.length > 0 ? typeMatch : nameMatch;
|
|
109
125
|
const match = candidates
|
|
110
126
|
.slice()
|
|
111
127
|
.sort((a, b) => new Date(String(b.updatedAt || "")).getTime() -
|
|
@@ -120,6 +136,9 @@ function TaxAxisDocuments({ profile, onContinue, onBack, onUploadDocument, onDel
|
|
|
120
136
|
if (status === "PARSED") {
|
|
121
137
|
setDocs((prev) => prev.map((d, i) => i === idx
|
|
122
138
|
? Object.assign(Object.assign({}, d), { status: "valid", fileName, parseError: null }) : d));
|
|
139
|
+
if (match.parsedData && documentType) {
|
|
140
|
+
setParsedDataByDocType((prev) => (Object.assign(Object.assign({}, prev), { [documentType]: match.parsedData })));
|
|
141
|
+
}
|
|
123
142
|
return;
|
|
124
143
|
}
|
|
125
144
|
if (status === "PARSING" || status === "UPLOADED") {
|
|
@@ -128,7 +147,7 @@ function TaxAxisDocuments({ profile, onContinue, onBack, onUploadDocument, onDel
|
|
|
128
147
|
}
|
|
129
148
|
}
|
|
130
149
|
}
|
|
131
|
-
catch (
|
|
150
|
+
catch (_pollError) {
|
|
132
151
|
// keep polling
|
|
133
152
|
}
|
|
134
153
|
yield new Promise((resolve) => setTimeout(resolve, pollIntervalMs));
|
|
@@ -141,13 +160,14 @@ function TaxAxisDocuments({ profile, onContinue, onBack, onUploadDocument, onDel
|
|
|
141
160
|
return;
|
|
142
161
|
setContinueError(null);
|
|
143
162
|
setDocs((prev) => prev.map((d, i) => i === idx
|
|
144
|
-
? Object.assign(Object.assign({}, d), { status: "validating", fileName: file.name
|
|
163
|
+
? Object.assign(Object.assign({}, d), { status: "validating", fileName: file.name, parseError: null }) : d));
|
|
145
164
|
try {
|
|
146
165
|
const uploadResult = onUploadDocument
|
|
147
166
|
? yield onUploadDocument(selectedDoc, file)
|
|
148
167
|
: undefined;
|
|
149
|
-
const nextFileName = file.name
|
|
150
|
-
|
|
168
|
+
const nextFileName = file.name;
|
|
169
|
+
// Use the canonical documentType from the catalog entry.
|
|
170
|
+
const documentType = selectedDoc.documentType;
|
|
151
171
|
const immediateStatus = String((uploadResult === null || uploadResult === void 0 ? void 0 : uploadResult.status) || "").toUpperCase();
|
|
152
172
|
if (uploadResult === null || uploadResult === void 0 ? void 0 : uploadResult.documentId) {
|
|
153
173
|
setUploadedDocIds((prev) => (Object.assign(Object.assign({}, prev), { [idx]: uploadResult.documentId })));
|
|
@@ -155,6 +175,19 @@ function TaxAxisDocuments({ profile, onContinue, onBack, onUploadDocument, onDel
|
|
|
155
175
|
if (immediateStatus === "PARSED") {
|
|
156
176
|
setDocs((prev) => prev.map((d, i) => i === idx
|
|
157
177
|
? Object.assign(Object.assign({}, d), { status: "valid", fileName: (uploadResult === null || uploadResult === void 0 ? void 0 : uploadResult.fileName) || nextFileName, parseError: null }) : d));
|
|
178
|
+
// parsedData is not on the upload mutation response — fetch it now via one poll call.
|
|
179
|
+
if (fetchUploadedDocuments && documentType) {
|
|
180
|
+
try {
|
|
181
|
+
const uploaded = yield fetchUploadedDocuments();
|
|
182
|
+
const match = uploaded.find((d) => String(d.documentType || "").toLowerCase() === documentType.toLowerCase());
|
|
183
|
+
if (match === null || match === void 0 ? void 0 : match.parsedData) {
|
|
184
|
+
setParsedDataByDocType((prev) => (Object.assign(Object.assign({}, prev), { [documentType]: match.parsedData })));
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
catch (_a) {
|
|
188
|
+
// non-fatal — user can still open modal, will show empty state
|
|
189
|
+
}
|
|
190
|
+
}
|
|
158
191
|
return;
|
|
159
192
|
}
|
|
160
193
|
if (immediateStatus === "FAILED") {
|
|
@@ -162,9 +195,8 @@ function TaxAxisDocuments({ profile, onContinue, onBack, onUploadDocument, onDel
|
|
|
162
195
|
? Object.assign(Object.assign({}, d), { status: "failed", fileName: (uploadResult === null || uploadResult === void 0 ? void 0 : uploadResult.fileName) || nextFileName, parseError: (uploadResult === null || uploadResult === void 0 ? void 0 : uploadResult.parseError) || "Parsing failed. Please upload a correct document." }) : d));
|
|
163
196
|
return;
|
|
164
197
|
}
|
|
165
|
-
setDocs((prev) => prev.map((d, i) => i === idx
|
|
166
|
-
|
|
167
|
-
yield pollForParseStatus(idx, nextFileName, expectedDocumentType);
|
|
198
|
+
setDocs((prev) => prev.map((d, i) => i === idx ? Object.assign(Object.assign({}, d), { status: "parsing", fileName: nextFileName }) : d));
|
|
199
|
+
yield pollForParseStatus(idx, nextFileName, documentType);
|
|
168
200
|
}
|
|
169
201
|
catch (uploadError) {
|
|
170
202
|
const errorMessage = uploadError instanceof Error
|
|
@@ -185,8 +217,8 @@ function TaxAxisDocuments({ profile, onContinue, onBack, onUploadDocument, onDel
|
|
|
185
217
|
try {
|
|
186
218
|
yield onDeleteDocument(docId);
|
|
187
219
|
}
|
|
188
|
-
catch (
|
|
189
|
-
//
|
|
220
|
+
catch (_deleteError) {
|
|
221
|
+
// clear from UI even if backend delete fails
|
|
190
222
|
}
|
|
191
223
|
}
|
|
192
224
|
setUploadedDocIds((prev) => {
|
|
@@ -196,7 +228,7 @@ function TaxAxisDocuments({ profile, onContinue, onBack, onUploadDocument, onDel
|
|
|
196
228
|
});
|
|
197
229
|
handleClear(idx);
|
|
198
230
|
});
|
|
199
|
-
const handleContinue = () => {
|
|
231
|
+
const handleContinue = () => __awaiter(this, void 0, void 0, function* () {
|
|
200
232
|
const failedDocs = docs.filter((d) => d.status === "failed");
|
|
201
233
|
if (failedDocs.length > 0) {
|
|
202
234
|
const names = failedDocs.map((d) => d.name).join(", ");
|
|
@@ -204,21 +236,45 @@ function TaxAxisDocuments({ profile, onContinue, onBack, onUploadDocument, onDel
|
|
|
204
236
|
return;
|
|
205
237
|
}
|
|
206
238
|
setContinueError(null);
|
|
239
|
+
// For every parsed doc that was not manually reviewed, persist parsedData.fields
|
|
240
|
+
// as reviewedData so the engine always has a reviewedData record to read from.
|
|
241
|
+
if (onSaveReviewedField) {
|
|
242
|
+
const validDocs = docs.filter((d) => d.status === "valid");
|
|
243
|
+
yield Promise.all(validDocs.map((doc) => __awaiter(this, void 0, void 0, function* () {
|
|
244
|
+
var _a;
|
|
245
|
+
const idx = docs.indexOf(doc);
|
|
246
|
+
const documentId = uploadedDocIds[idx];
|
|
247
|
+
if (!documentId)
|
|
248
|
+
return;
|
|
249
|
+
const parsed = parsedDataByDocType[doc.documentType || doc.id];
|
|
250
|
+
if (!parsed)
|
|
251
|
+
return;
|
|
252
|
+
const fields = ((_a = parsed.fields) !== null && _a !== void 0 ? _a : parsed);
|
|
253
|
+
// Convert all scalar values to strings for reviewedData
|
|
254
|
+
const reviewedFields = {};
|
|
255
|
+
for (const [k, v] of Object.entries(fields)) {
|
|
256
|
+
if (v !== null && v !== undefined && typeof v !== "object") {
|
|
257
|
+
reviewedFields[k] = v;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
if (Object.keys(reviewedFields).length > 0) {
|
|
261
|
+
try {
|
|
262
|
+
yield onSaveReviewedField(documentId, reviewedFields);
|
|
263
|
+
}
|
|
264
|
+
catch ( /* non-fatal */_b) { /* non-fatal */ }
|
|
265
|
+
}
|
|
266
|
+
})));
|
|
267
|
+
}
|
|
207
268
|
onContinue();
|
|
208
|
-
};
|
|
269
|
+
});
|
|
209
270
|
const validCount = docs.filter((d) => d.status === "valid").length;
|
|
210
271
|
const failedCount = docs.filter((d) => d.status === "failed").length;
|
|
211
272
|
const busyCount = docs.filter((d) => d.status === "validating" || d.status === "parsing").length;
|
|
212
|
-
const coveragePct = validCount === 0
|
|
213
|
-
?
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
? 60
|
|
218
|
-
: validCount <= 4
|
|
219
|
-
? 75
|
|
220
|
-
: validCount <= 6
|
|
221
|
-
? 90
|
|
273
|
+
const coveragePct = validCount === 0 ? 32
|
|
274
|
+
: validCount === 1 ? 50
|
|
275
|
+
: validCount === 2 ? 60
|
|
276
|
+
: validCount <= 4 ? 75
|
|
277
|
+
: validCount <= 6 ? 90
|
|
222
278
|
: 100;
|
|
223
279
|
const strategiesCovered = Math.round((25 * coveragePct) / 100);
|
|
224
280
|
return (react_1.default.createElement("div", { className: "max-w-[580px] mx-auto" },
|
|
@@ -262,12 +318,19 @@ function TaxAxisDocuments({ profile, onContinue, onBack, onUploadDocument, onDel
|
|
|
262
318
|
border: "1px solid rgba(197,48,48,0.3)",
|
|
263
319
|
color: "#FEB2B2",
|
|
264
320
|
} }, continueError)),
|
|
265
|
-
|
|
321
|
+
tierDefs.map((tier) => (react_1.default.createElement(DocumentTier_1.DocumentTier, { key: tier.key, tier: tier, docs: docs, helpOverrides: {}, fieldCounts: parsedFieldCounts, onUpload: handleUpload, onClear: handleClear, onRemove: handleRemove, onReview: (docId) => setReviewDocId(docId) }))),
|
|
266
322
|
react_1.default.createElement("div", { className: "flex gap-3 mt-6" },
|
|
267
323
|
react_1.default.createElement(TaxAxisButton_1.TaxAxisButton, { variant: "secondary", onClick: onBack }, "Back"),
|
|
268
324
|
react_1.default.createElement(TaxAxisButton_1.TaxAxisButton, { onClick: handleContinue, className: "flex-1", disabled: busyCount > 0 }, busyCount > 0
|
|
269
325
|
? "Processing..."
|
|
270
326
|
: failedCount > 0
|
|
271
327
|
? `Continue (${failedCount} failed)`
|
|
272
|
-
: "Continue"))
|
|
328
|
+
: "Continue")),
|
|
329
|
+
reviewDoc && (react_1.default.createElement(DocumentReviewModal_1.DocumentReviewModal, { documentId: reviewDoc.id, documentName: reviewDoc.name, fileName: reviewDoc.fileName || "", jobId: jobId, parsedData: reviewParsedData, onSaveReviewedData: onSaveReviewedField
|
|
330
|
+
? (fields) => __awaiter(this, void 0, void 0, function* () {
|
|
331
|
+
const docId = uploadedDocIds[docs.indexOf(reviewDoc)];
|
|
332
|
+
if (docId)
|
|
333
|
+
yield onSaveReviewedField(docId, fields);
|
|
334
|
+
})
|
|
335
|
+
: undefined, onClose: () => setReviewDocId(null) }))));
|
|
273
336
|
}
|
|
@@ -89,6 +89,22 @@ function TaxAxisExtractionReview({ onStatusChange, onConfirmAndUnlock, onBack, }
|
|
|
89
89
|
return (react_1.default.createElement("div", null,
|
|
90
90
|
react_1.default.createElement("style", null, `@keyframes spin{to{transform:rotate(360deg)}}`),
|
|
91
91
|
react_1.default.createElement(PurposeBlock_1.PurposeBlock, { totalFields: totalFields, totalDocs: data_1.EXTRACTED_DATA.length }),
|
|
92
|
+
onConfirmAndUnlock && (react_1.default.createElement("div", { style: {
|
|
93
|
+
marginBottom: 16,
|
|
94
|
+
background: "linear-gradient(135deg, rgba(36,131,132,0.12), rgba(36,131,132,0.06))",
|
|
95
|
+
border: "1px solid rgba(36,131,132,0.3)",
|
|
96
|
+
borderRadius: 12,
|
|
97
|
+
padding: "18px 20px",
|
|
98
|
+
} },
|
|
99
|
+
react_1.default.createElement("div", { className: "flex items-center gap-4" },
|
|
100
|
+
react_1.default.createElement("div", { className: "flex-1" },
|
|
101
|
+
react_1.default.createElement("div", { className: "text-[15px] font-bold text-white font-tax-axis-head mb-1" }, "Ready to view your report?"),
|
|
102
|
+
react_1.default.createElement("div", { className: "text-[13px] text-tax-axis-text leading-relaxed font-tax-axis-body" }, totalFlags - totalEdits > 0
|
|
103
|
+
? (totalFlags - totalEdits) + " value" + (totalFlags - totalEdits > 1 ? "s" : "") + " still flagged. You can confirm now or correct values first."
|
|
104
|
+
: "All extracted values look good. Confirm to unlock the Intelligence Report.")),
|
|
105
|
+
react_1.default.createElement("div", { className: "flex gap-2.5" },
|
|
106
|
+
onBack && (react_1.default.createElement(TaxAxisButton_1.TaxAxisButton, { variant: "secondary", onClick: onBack }, "Back to Dashboard")),
|
|
107
|
+
react_1.default.createElement(TaxAxisButton_1.TaxAxisButton, { onClick: onConfirmAndUnlock }, totalFlags - totalEdits > 0 ? "Confirm & Unlock Report" : "Confirm & View Report"))))),
|
|
92
108
|
react_1.default.createElement("div", { style: { display: "flex", alignItems: "center", gap: 10, marginBottom: 12 } },
|
|
93
109
|
react_1.default.createElement("div", { style: {
|
|
94
110
|
width: 8,
|
|
@@ -166,21 +182,5 @@ function TaxAxisExtractionReview({ onStatusChange, onConfirmAndUnlock, onBack, }
|
|
|
166
182
|
borderRadius: 4,
|
|
167
183
|
border: "1px solid #2E3160",
|
|
168
184
|
} }, d.code))))))),
|
|
169
|
-
react_1.default.createElement(RerunFooter_1.RerunFooter, { totalEdits: totalEdits, rerunning: rerunning, onRerun: handleRerun })
|
|
170
|
-
onConfirmAndUnlock && (react_1.default.createElement("div", { style: {
|
|
171
|
-
marginTop: 16,
|
|
172
|
-
background: "linear-gradient(135deg, rgba(36,131,132,0.12), rgba(36,131,132,0.06))",
|
|
173
|
-
border: "1px solid rgba(36,131,132,0.3)",
|
|
174
|
-
borderRadius: 12,
|
|
175
|
-
padding: "18px 20px",
|
|
176
|
-
} },
|
|
177
|
-
react_1.default.createElement("div", { className: "flex items-center gap-4" },
|
|
178
|
-
react_1.default.createElement("div", { className: "flex-1" },
|
|
179
|
-
react_1.default.createElement("div", { className: "text-[15px] font-bold text-white font-tax-axis-head mb-1" }, "Ready to view your report?"),
|
|
180
|
-
react_1.default.createElement("div", { className: "text-[13px] text-tax-axis-text leading-relaxed font-tax-axis-body" }, totalFlags - totalEdits > 0
|
|
181
|
-
? (totalFlags - totalEdits) + " value" + (totalFlags - totalEdits > 1 ? "s" : "") + " still flagged. You can confirm now or correct values first."
|
|
182
|
-
: "All extracted values look good. Confirm to unlock the Intelligence Report.")),
|
|
183
|
-
react_1.default.createElement("div", { className: "flex gap-2.5" },
|
|
184
|
-
onBack && (react_1.default.createElement(TaxAxisButton_1.TaxAxisButton, { variant: "secondary", onClick: onBack }, "Back to Dashboard")),
|
|
185
|
-
react_1.default.createElement(TaxAxisButton_1.TaxAxisButton, { onClick: onConfirmAndUnlock }, totalFlags - totalEdits > 0 ? "Confirm & Unlock Report" : "Confirm & View Report")))))));
|
|
185
|
+
react_1.default.createElement(RerunFooter_1.RerunFooter, { totalEdits: totalEdits, rerunning: rerunning, onRerun: handleRerun })));
|
|
186
186
|
}
|