@paro.io/expert-shared-components 1.14.52 → 1.14.54

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.
Files changed (31) hide show
  1. package/lib/components/DocumentCenter/MultiFileUploadSection.js +220 -121
  2. package/lib/components/TaxAxis/TaxAxisApi.d.ts +1 -0
  3. package/lib/components/TaxAxis/TaxAxisShell.js +80 -17
  4. package/lib/index.d.ts +1 -14
  5. package/lib/index.js +1 -27
  6. package/lib/tax-axis/components/clientReport/TaxAxisClientReport.d.ts +6 -2
  7. package/lib/tax-axis/components/clientReport/TaxAxisClientReport.js +5 -3
  8. package/lib/tax-axis/components/dashboard/TaxAxisDashboard.d.ts +2 -1
  9. package/lib/tax-axis/components/dashboard/TaxAxisDashboard.js +163 -34
  10. package/lib/tax-axis/components/documents/DocumentCard.d.ts +3 -1
  11. package/lib/tax-axis/components/documents/DocumentCard.js +17 -5
  12. package/lib/tax-axis/components/documents/DocumentReviewModal.d.ts +13 -0
  13. package/lib/tax-axis/components/documents/DocumentReviewModal.js +248 -0
  14. package/lib/tax-axis/components/documents/DocumentTier.d.ts +3 -1
  15. package/lib/tax-axis/components/documents/DocumentTier.js +2 -2
  16. package/lib/tax-axis/components/documents/TaxAxisDocuments.d.ts +5 -1
  17. package/lib/tax-axis/components/documents/TaxAxisDocuments.js +86 -5
  18. package/lib/tax-axis/components/extractionReview/TaxAxisExtractionReview.js +17 -17
  19. package/lib/tax-axis/components/intake/ClientParametersSection.js +1 -1
  20. package/lib/tax-axis/components/intake/intakeSchema.js +1 -1
  21. package/lib/tax-axis/components/preparerWorkpaper/TaxAxisPreparerWorkpaper.d.ts +6 -2
  22. package/lib/tax-axis/components/preparerWorkpaper/TaxAxisPreparerWorkpaper.js +5 -3
  23. package/lib/tax-axis/index.d.ts +4 -0
  24. package/lib/tax-axis/index.js +6 -1
  25. package/lib/tax-axis/lib/adapters/useEngineOutput.d.ts +144 -0
  26. package/lib/tax-axis/lib/adapters/useEngineOutput.js +156 -0
  27. package/lib/tax-axis/lib/data/documents.d.ts +1 -0
  28. package/lib/tax-axis/lib/data/documents.js +5 -0
  29. package/lib/tax-axis/lib/documentFieldCatalog.d.ts +13 -0
  30. package/lib/tax-axis/lib/documentFieldCatalog.js +808 -0
  31. 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
  }
@@ -21,6 +21,10 @@ export interface TaxAxisDocumentsProps extends TaxAxisScreenProps {
21
21
  documentType?: string | null;
22
22
  parseError?: string | null;
23
23
  updatedAt?: string | null;
24
+ parsedData?: Record<string, unknown> | null;
24
25
  }>>;
26
+ parsedFieldCounts?: Record<string, number>;
27
+ jobId?: string;
28
+ onSaveReviewedField?: (documentId: string, reviewedData: Record<string, unknown>) => Promise<void>;
25
29
  }
26
- export declare function TaxAxisDocuments({ profile, entityType, 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,6 +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 DocumentReviewModal_1 = require("./DocumentReviewModal");
40
41
  const TIER_DEFS = [
41
42
  {
42
43
  key: "required",
@@ -69,7 +70,8 @@ const TIER_DEFS = [
69
70
  ids: [],
70
71
  },
71
72
  ];
72
- function TaxAxisDocuments({ profile, entityType, onContinue, onBack, onUploadDocument, onDeleteDocument, fetchUploadedDocuments, userContext: _userContext = "expert", }) {
73
+ function TaxAxisDocuments({ profile, entityType, onContinue, onBack, onUploadDocument, onDeleteDocument, fetchUploadedDocuments, parsedFieldCounts, jobId = "stub-job-id", onSaveReviewedField, userContext: _userContext = "expert", }) {
74
+ var _a, _b, _c;
73
75
  const docSpecs = (0, react_1.useMemo)(() => (0, documents_1.getDocSpecs)(entityType !== null && entityType !== void 0 ? entityType : undefined), [entityType]);
74
76
  // Build tier defs dynamically from the doc spec list so they're always in sync.
75
77
  const tierDefs = (0, react_1.useMemo)(() => {
@@ -80,6 +82,33 @@ function TaxAxisDocuments({ profile, entityType, onContinue, onBack, onUploadDoc
80
82
  const [docs, setDocs] = (0, react_1.useState)(() => docSpecs.map((s) => (Object.assign(Object.assign({}, s), { status: "empty", fileName: null, parseError: null }))));
81
83
  const [uploadedDocIds, setUploadedDocIds] = (0, react_1.useState)({});
82
84
  const [continueError, setContinueError] = (0, react_1.useState)(null);
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;
83
112
  const pollForParseStatus = (idx, fileName, documentType) => __awaiter(this, void 0, void 0, function* () {
84
113
  if (!fetchUploadedDocuments)
85
114
  return;
@@ -107,6 +136,9 @@ function TaxAxisDocuments({ profile, entityType, onContinue, onBack, onUploadDoc
107
136
  if (status === "PARSED") {
108
137
  setDocs((prev) => prev.map((d, i) => i === idx
109
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
+ }
110
142
  return;
111
143
  }
112
144
  if (status === "PARSING" || status === "UPLOADED") {
@@ -143,6 +175,19 @@ function TaxAxisDocuments({ profile, entityType, onContinue, onBack, onUploadDoc
143
175
  if (immediateStatus === "PARSED") {
144
176
  setDocs((prev) => prev.map((d, i) => i === idx
145
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
+ }
146
191
  return;
147
192
  }
148
193
  if (immediateStatus === "FAILED") {
@@ -183,7 +228,7 @@ function TaxAxisDocuments({ profile, entityType, onContinue, onBack, onUploadDoc
183
228
  });
184
229
  handleClear(idx);
185
230
  });
186
- const handleContinue = () => {
231
+ const handleContinue = () => __awaiter(this, void 0, void 0, function* () {
187
232
  const failedDocs = docs.filter((d) => d.status === "failed");
188
233
  if (failedDocs.length > 0) {
189
234
  const names = failedDocs.map((d) => d.name).join(", ");
@@ -191,8 +236,37 @@ function TaxAxisDocuments({ profile, entityType, onContinue, onBack, onUploadDoc
191
236
  return;
192
237
  }
193
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
+ }
194
268
  onContinue();
195
- };
269
+ });
196
270
  const validCount = docs.filter((d) => d.status === "valid").length;
197
271
  const failedCount = docs.filter((d) => d.status === "failed").length;
198
272
  const busyCount = docs.filter((d) => d.status === "validating" || d.status === "parsing").length;
@@ -244,12 +318,19 @@ function TaxAxisDocuments({ profile, entityType, onContinue, onBack, onUploadDoc
244
318
  border: "1px solid rgba(197,48,48,0.3)",
245
319
  color: "#FEB2B2",
246
320
  } }, continueError)),
247
- tierDefs.map((tier) => (react_1.default.createElement(DocumentTier_1.DocumentTier, { key: tier.key, tier: tier, docs: docs, helpOverrides: {}, onUpload: handleUpload, onClear: handleClear, onRemove: handleRemove }))),
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) }))),
248
322
  react_1.default.createElement("div", { className: "flex gap-3 mt-6" },
249
323
  react_1.default.createElement(TaxAxisButton_1.TaxAxisButton, { variant: "secondary", onClick: onBack }, "Back"),
250
324
  react_1.default.createElement(TaxAxisButton_1.TaxAxisButton, { onClick: handleContinue, className: "flex-1", disabled: busyCount > 0 }, busyCount > 0
251
325
  ? "Processing..."
252
326
  : failedCount > 0
253
327
  ? `Continue (${failedCount} failed)`
254
- : "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) }))));
255
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
  }
@@ -49,8 +49,8 @@ const Chevron = () => (react_1.default.createElement("svg", { className: "absolu
49
49
  react_1.default.createElement("path", { d: "M3 4.5l3 3 3-3", stroke: "#E6E8F5", strokeWidth: "1.5", strokeLinecap: "round" })));
50
50
  /* ═══ Option lists (spec-canonical) ═══ */
51
51
  const ENTITY_OPTIONS = [
52
- "S-Corporation",
53
52
  "C-Corporation",
53
+ "S-Corporation",
54
54
  "LLC",
55
55
  "Partnership",
56
56
  "Sole Proprietor",
@@ -60,7 +60,7 @@ exports.intakeSchema = Yup.object().shape({
60
60
  exports.intakeDefaultValues = {
61
61
  bizName: "",
62
62
  cpaName: "",
63
- entity: "S-Corporation",
63
+ entity: "C-Corporation",
64
64
  industry: "Professional Services",
65
65
  revenue: "",
66
66
  netIncome: "",
@@ -1,9 +1,13 @@
1
1
  import React from "react";
2
- import type { ClientProfile } from "../../lib/types";
2
+ import type { ClientProfile, Strategy, ComputedMap } from "../../lib/types";
3
3
  import type { TaxAxisScreenProps } from "../../lib/types";
4
4
  export interface TaxAxisPreparerWorkpaperProps extends TaxAxisScreenProps {
5
5
  profile: ClientProfile;
6
6
  onBack: () => void;
7
7
  onToggleToClient?: () => void;
8
+ /** When provided, bypasses local filterEligibleStrategies + computeAllStrategies. */
9
+ liveStrategies?: Strategy[];
10
+ /** When provided, bypasses local computeAllStrategies. Must accompany liveStrategies. */
11
+ liveComputedMap?: ComputedMap;
8
12
  }
9
- export declare function TaxAxisPreparerWorkpaper({ profile, onBack, onToggleToClient }: TaxAxisPreparerWorkpaperProps): React.JSX.Element;
13
+ export declare function TaxAxisPreparerWorkpaper({ profile, onBack, onToggleToClient, liveStrategies, liveComputedMap }: TaxAxisPreparerWorkpaperProps): React.JSX.Element;
@@ -32,12 +32,14 @@ const ReportToolbar_1 = require("../shared/ReportToolbar");
32
32
  const EngagementHeader_1 = require("./EngagementHeader");
33
33
  const Section6694Summary_1 = require("./Section6694Summary");
34
34
  const PriorityGroup_1 = require("./PriorityGroup");
35
- function TaxAxisPreparerWorkpaper({ profile, onBack, onToggleToClient }) {
35
+ function TaxAxisPreparerWorkpaper({ profile, onBack, onToggleToClient, liveStrategies, liveComputedMap }) {
36
36
  const [expanded, setExpanded] = (0, react_1.useState)({});
37
37
  const [printMode, setPrintMode] = (0, react_1.useState)(false);
38
38
  const toggle = (rank, section) => setExpanded(prev => (Object.assign(Object.assign({}, prev), { [rank + "-" + section]: !prev[rank + "-" + section] })));
39
- const eligible = (0, react_1.useMemo)(() => (0, compute_1.filterEligibleStrategies)(profile), [profile]);
40
- const computed = (0, react_1.useMemo)(() => (0, compute_1.computeAllStrategies)(profile), [profile]);
39
+ const staticEligible = (0, react_1.useMemo)(() => (0, compute_1.filterEligibleStrategies)(profile), [profile]);
40
+ const staticComputed = (0, react_1.useMemo)(() => (0, compute_1.computeAllStrategies)(profile), [profile]);
41
+ const eligible = liveStrategies !== null && liveStrategies !== void 0 ? liveStrategies : staticEligible;
42
+ const computed = liveComputedMap !== null && liveComputedMap !== void 0 ? liveComputedMap : staticComputed;
41
43
  const states = profile.states || [];
42
44
  const bizName = profile.bizName || "Client";
43
45
  const rev = parseInt((profile.revenue || "0").replace(/,/g, "")) || 0;
@@ -5,10 +5,14 @@ export { SectionHeader } from "./components/shared/SectionHeader";
5
5
  export * from "./lib/types";
6
6
  export * from "./lib/data";
7
7
  export * from "./lib/compute";
8
+ export { useEngineOutput } from "./lib/adapters/useEngineOutput";
9
+ export type { EngineOutput, EngineOutputAdapterResult, EngineStrategyAnalysis, EngineCpaWorkflow } from "./lib/adapters/useEngineOutput";
8
10
  export { TaxAxisIntake } from "./components/intake/TaxAxisIntake";
9
11
  export type { TaxAxisIntakeProps } from "./components/intake/TaxAxisIntake";
10
12
  export { TaxAxisDocuments } from "./components/documents/TaxAxisDocuments";
11
13
  export type { TaxAxisDocumentsProps } from "./components/documents/TaxAxisDocuments";
14
+ export { DocumentReviewModal } from "./components/documents/DocumentReviewModal";
15
+ export type { DocumentReviewModalProps } from "./components/documents/DocumentReviewModal";
12
16
  export { TaxAxisProcessing } from "./components/processing/TaxAxisProcessing";
13
17
  export type { TaxAxisProcessingProps } from "./components/processing/TaxAxisProcessing";
14
18
  export { TaxAxisDashboard } from "./components/dashboard/TaxAxisDashboard";
@@ -14,7 +14,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
- exports.TaxAxisPresentationMode = exports.TaxAxisProspectReport = exports.TaxAxisExtractionReview = exports.TaxAxisPreparerWorkpaper = exports.TaxAxisClientReport = exports.TaxAxisDashboard = exports.TaxAxisProcessing = exports.TaxAxisDocuments = exports.TaxAxisIntake = exports.SectionHeader = exports.TaxAxisButton = exports.TaxAxisBadge = exports.TaxAxisCard = void 0;
17
+ exports.TaxAxisPresentationMode = exports.TaxAxisProspectReport = exports.TaxAxisExtractionReview = exports.TaxAxisPreparerWorkpaper = exports.TaxAxisClientReport = exports.TaxAxisDashboard = exports.TaxAxisProcessing = exports.DocumentReviewModal = exports.TaxAxisDocuments = exports.TaxAxisIntake = exports.useEngineOutput = exports.SectionHeader = exports.TaxAxisButton = exports.TaxAxisBadge = exports.TaxAxisCard = void 0;
18
18
  // Shared primitives
19
19
  var TaxAxisCard_1 = require("./components/shared/TaxAxisCard");
20
20
  Object.defineProperty(exports, "TaxAxisCard", { enumerable: true, get: function () { return TaxAxisCard_1.TaxAxisCard; } });
@@ -30,11 +30,16 @@ __exportStar(require("./lib/types"), exports);
30
30
  __exportStar(require("./lib/data"), exports);
31
31
  // Compute
32
32
  __exportStar(require("./lib/compute"), exports);
33
+ // Adapters
34
+ var useEngineOutput_1 = require("./lib/adapters/useEngineOutput");
35
+ Object.defineProperty(exports, "useEngineOutput", { enumerable: true, get: function () { return useEngineOutput_1.useEngineOutput; } });
33
36
  // Screens
34
37
  var TaxAxisIntake_1 = require("./components/intake/TaxAxisIntake");
35
38
  Object.defineProperty(exports, "TaxAxisIntake", { enumerable: true, get: function () { return TaxAxisIntake_1.TaxAxisIntake; } });
36
39
  var TaxAxisDocuments_1 = require("./components/documents/TaxAxisDocuments");
37
40
  Object.defineProperty(exports, "TaxAxisDocuments", { enumerable: true, get: function () { return TaxAxisDocuments_1.TaxAxisDocuments; } });
41
+ var DocumentReviewModal_1 = require("./components/documents/DocumentReviewModal");
42
+ Object.defineProperty(exports, "DocumentReviewModal", { enumerable: true, get: function () { return DocumentReviewModal_1.DocumentReviewModal; } });
38
43
  var TaxAxisProcessing_1 = require("./components/processing/TaxAxisProcessing");
39
44
  Object.defineProperty(exports, "TaxAxisProcessing", { enumerable: true, get: function () { return TaxAxisProcessing_1.TaxAxisProcessing; } });
40
45
  var TaxAxisDashboard_1 = require("./components/dashboard/TaxAxisDashboard");