@paro.io/expert-shared-components 1.14.53 → 1.14.55
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/TaxAxis/TaxAxisApi.d.ts +2 -0
- package/lib/components/TaxAxis/TaxAxisShell.js +138 -13
- package/lib/tax-axis/components/clientReport/ExecutiveSummary.d.ts +4 -1
- package/lib/tax-axis/components/clientReport/ExecutiveSummary.js +10 -6
- package/lib/tax-axis/components/clientReport/RecommendedStrategies.d.ts +6 -1
- package/lib/tax-axis/components/clientReport/RecommendedStrategies.js +26 -24
- package/lib/tax-axis/components/clientReport/StrategyCard.d.ts +1 -1
- package/lib/tax-axis/components/clientReport/StrategyCard.js +39 -23
- package/lib/tax-axis/components/clientReport/TaxAxisClientReport.d.ts +3 -1
- package/lib/tax-axis/components/clientReport/TaxAxisClientReport.js +4 -4
- package/lib/tax-axis/components/dashboard/DashboardSummary.d.ts +6 -1
- package/lib/tax-axis/components/dashboard/DashboardSummary.js +14 -4
- package/lib/tax-axis/components/dashboard/StrategyDetailPanel.d.ts +1 -1
- package/lib/tax-axis/components/dashboard/StrategyDetailPanel.js +123 -91
- package/lib/tax-axis/components/dashboard/TaxAxisDashboard.d.ts +3 -2
- package/lib/tax-axis/components/dashboard/TaxAxisDashboard.js +67 -19
- package/lib/tax-axis/components/documents/TaxAxisDocuments.d.ts +2 -0
- package/lib/tax-axis/components/documents/TaxAxisDocuments.js +46 -10
- package/lib/tax-axis/components/preparerWorkpaper/TaxAxisPreparerWorkpaper.d.ts +21 -1
- package/lib/tax-axis/components/preparerWorkpaper/TaxAxisPreparerWorkpaper.js +10 -1
- package/lib/tax-axis/components/processing/TaxAxisProcessing.d.ts +3 -1
- package/lib/tax-axis/components/processing/TaxAxisProcessing.js +77 -31
- package/lib/tax-axis/lib/adapters/useEngineOutput.d.ts +7 -0
- package/lib/tax-axis/lib/adapters/useEngineOutput.js +10 -4
- package/lib/tax-axis/lib/types/index.d.ts +10 -1
- package/package.json +1 -1
|
@@ -71,7 +71,7 @@ const TIER_DEFS = [
|
|
|
71
71
|
},
|
|
72
72
|
];
|
|
73
73
|
function TaxAxisDocuments({ profile, entityType, onContinue, onBack, onUploadDocument, onDeleteDocument, fetchUploadedDocuments, parsedFieldCounts, jobId = "stub-job-id", onSaveReviewedField, userContext: _userContext = "expert", }) {
|
|
74
|
-
var _a, _b, _c;
|
|
74
|
+
var _a, _b, _c, _d, _e;
|
|
75
75
|
const docSpecs = (0, react_1.useMemo)(() => (0, documents_1.getDocSpecs)(entityType !== null && entityType !== void 0 ? entityType : undefined), [entityType]);
|
|
76
76
|
// Build tier defs dynamically from the doc spec list so they're always in sync.
|
|
77
77
|
const tierDefs = (0, react_1.useMemo)(() => {
|
|
@@ -85,29 +85,62 @@ function TaxAxisDocuments({ profile, entityType, onContinue, onBack, onUploadDoc
|
|
|
85
85
|
const [reviewDocId, setReviewDocId] = (0, react_1.useState)(null);
|
|
86
86
|
// parsedData keyed by documentType (e.g. "profit_loss") — populated from poll results
|
|
87
87
|
const [parsedDataByDocType, setParsedDataByDocType] = (0, react_1.useState)({});
|
|
88
|
-
//
|
|
88
|
+
// reviewedData keyed by documentType — populated after CPA saves corrections; takes priority over parsedData in modal
|
|
89
|
+
const [reviewedDataByDocType, setReviewedDataByDocType] = (0, react_1.useState)({});
|
|
90
|
+
// On mount, restore card state from any already-uploaded documents in this session.
|
|
91
|
+
// This runs whenever the user re-enters the DOCUMENT_UPLOAD step (e.g. after an
|
|
92
|
+
// eval failure) so previously uploaded files appear as valid/failed instead of empty.
|
|
89
93
|
(0, react_1.useEffect)(() => {
|
|
90
94
|
if (!fetchUploadedDocuments)
|
|
91
95
|
return;
|
|
92
96
|
fetchUploadedDocuments().then((uploaded) => {
|
|
93
|
-
|
|
97
|
+
if (!uploaded.length)
|
|
98
|
+
return;
|
|
99
|
+
const parsedByType = {};
|
|
100
|
+
const reviewedByType = {};
|
|
101
|
+
const nextDocIds = {};
|
|
102
|
+
setDocs((prev) => prev.map((docState, idx) => {
|
|
103
|
+
// Match by documentType (canonical key) — find the most recently updated upload
|
|
104
|
+
const candidates = uploaded.filter((u) => String(u.documentType || '').toLowerCase() === (docState.documentType || docState.id).toLowerCase());
|
|
105
|
+
const match = candidates.sort((a, b) => new Date(String(b.updatedAt || 0)).getTime() - new Date(String(a.updatedAt || 0)).getTime())[0];
|
|
106
|
+
if (!match)
|
|
107
|
+
return docState;
|
|
108
|
+
// Populate uploadedDocIds for delete/review actions
|
|
109
|
+
if (match.documentId) {
|
|
110
|
+
nextDocIds[idx] = match.documentId;
|
|
111
|
+
}
|
|
112
|
+
const apiStatus = String(match.status || '').toUpperCase();
|
|
113
|
+
const nextStatus = apiStatus === 'PARSED' ? 'valid' :
|
|
114
|
+
apiStatus === 'FAILED' ? 'failed' :
|
|
115
|
+
apiStatus === 'PARSING' || apiStatus === 'UPLOADED' ? 'parsing' :
|
|
116
|
+
docState.status;
|
|
117
|
+
return Object.assign(Object.assign({}, docState), { status: nextStatus, fileName: match.fileName || docState.fileName, parseError: match.parseError || null });
|
|
118
|
+
}));
|
|
119
|
+
// Populate document ID map in one batch
|
|
120
|
+
setUploadedDocIds((prev) => (Object.assign(Object.assign({}, prev), nextDocIds)));
|
|
121
|
+
// Populate review modal data
|
|
94
122
|
for (const doc of uploaded) {
|
|
95
|
-
if (doc.
|
|
96
|
-
|
|
123
|
+
if (!doc.documentType)
|
|
124
|
+
continue;
|
|
125
|
+
if (doc.parsedData)
|
|
126
|
+
parsedByType[doc.documentType] = doc.parsedData;
|
|
127
|
+
if (doc.reviewedData && Object.keys(doc.reviewedData).length > 0) {
|
|
128
|
+
reviewedByType[doc.documentType] = doc.reviewedData;
|
|
97
129
|
}
|
|
98
130
|
}
|
|
99
|
-
if (Object.keys(
|
|
100
|
-
setParsedDataByDocType(
|
|
101
|
-
|
|
131
|
+
if (Object.keys(parsedByType).length > 0)
|
|
132
|
+
setParsedDataByDocType(parsedByType);
|
|
133
|
+
if (Object.keys(reviewedByType).length > 0)
|
|
134
|
+
setReviewedDataByDocType(reviewedByType);
|
|
102
135
|
}).catch(() => { });
|
|
103
136
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
104
137
|
}, []);
|
|
105
138
|
const reviewDoc = reviewDocId
|
|
106
139
|
? (_a = docs.find((d) => d.id === reviewDocId)) !== null && _a !== void 0 ? _a : null
|
|
107
140
|
: null;
|
|
108
|
-
//
|
|
141
|
+
// Prefer reviewedData (CPA-corrected) over parsedData (raw LLM extraction)
|
|
109
142
|
const reviewParsedData = reviewDoc
|
|
110
|
-
? ((_c = (_b =
|
|
143
|
+
? ((_e = (_d = (_c = (_b = reviewedDataByDocType[reviewDoc.documentType || reviewDoc.id]) !== null && _b !== void 0 ? _b : reviewedDataByDocType[reviewDoc.id]) !== null && _c !== void 0 ? _c : parsedDataByDocType[reviewDoc.documentType || reviewDoc.id]) !== null && _d !== void 0 ? _d : parsedDataByDocType[reviewDoc.id]) !== null && _e !== void 0 ? _e : null)
|
|
111
144
|
: null;
|
|
112
145
|
const pollForParseStatus = (idx, fileName, documentType) => __awaiter(this, void 0, void 0, function* () {
|
|
113
146
|
if (!fetchUploadedDocuments)
|
|
@@ -331,6 +364,9 @@ function TaxAxisDocuments({ profile, entityType, onContinue, onBack, onUploadDoc
|
|
|
331
364
|
const docId = uploadedDocIds[docs.indexOf(reviewDoc)];
|
|
332
365
|
if (docId)
|
|
333
366
|
yield onSaveReviewedField(docId, fields);
|
|
367
|
+
// Store locally so reopening the modal shows corrected values
|
|
368
|
+
const docTypeKey = reviewDoc.documentType || reviewDoc.id;
|
|
369
|
+
setReviewedDataByDocType((prev) => (Object.assign(Object.assign({}, prev), { [docTypeKey]: fields })));
|
|
334
370
|
})
|
|
335
371
|
: undefined, onClose: () => setReviewDocId(null) }))));
|
|
336
372
|
}
|
|
@@ -9,5 +9,25 @@ export interface TaxAxisPreparerWorkpaperProps extends TaxAxisScreenProps {
|
|
|
9
9
|
liveStrategies?: Strategy[];
|
|
10
10
|
/** When provided, bypasses local computeAllStrategies. Must accompany liveStrategies. */
|
|
11
11
|
liveComputedMap?: ComputedMap;
|
|
12
|
+
/** Live cpa_workflow from engine output */
|
|
13
|
+
cpaWorkflow?: {
|
|
14
|
+
workpaper_codes?: string[] | null;
|
|
15
|
+
section_6694_notices?: Array<{
|
|
16
|
+
strategy_id: string;
|
|
17
|
+
position_strength: string;
|
|
18
|
+
notice: string;
|
|
19
|
+
}>;
|
|
20
|
+
prior_year_flags?: string[];
|
|
21
|
+
engagement_recommendations?: string[];
|
|
22
|
+
};
|
|
23
|
+
/** Live risk disclosures from engine output */
|
|
24
|
+
riskDisclosures?: string[];
|
|
25
|
+
/** Live business profile from engine output */
|
|
26
|
+
businessProfile?: {
|
|
27
|
+
confidence_tier?: string;
|
|
28
|
+
data_years?: number;
|
|
29
|
+
data_quality_flags?: string[];
|
|
30
|
+
effective_tax_rate?: number;
|
|
31
|
+
};
|
|
12
32
|
}
|
|
13
|
-
export declare function TaxAxisPreparerWorkpaper({ profile, onBack, onToggleToClient, liveStrategies, liveComputedMap }: TaxAxisPreparerWorkpaperProps): React.JSX.Element;
|
|
33
|
+
export declare function TaxAxisPreparerWorkpaper({ profile, onBack, onToggleToClient, liveStrategies, liveComputedMap, cpaWorkflow, riskDisclosures, businessProfile }: TaxAxisPreparerWorkpaperProps): React.JSX.Element;
|
|
@@ -32,7 +32,7 @@ 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, liveStrategies, liveComputedMap }) {
|
|
35
|
+
function TaxAxisPreparerWorkpaper({ profile, onBack, onToggleToClient, liveStrategies, liveComputedMap, cpaWorkflow, riskDisclosures, businessProfile }) {
|
|
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] })));
|
|
@@ -168,6 +168,15 @@ function TaxAxisPreparerWorkpaper({ profile, onBack, onToggleToClient, liveStrat
|
|
|
168
168
|
"$" + interactionAdj.toLocaleString() + " ",
|
|
169
169
|
react_1.default.createElement("span", { style: { fontWeight: 400, fontSize: 10 } }, "(\u221215%)")),
|
|
170
170
|
react_1.default.createElement("td", { colSpan: 2 })))))),
|
|
171
|
+
(cpaWorkflow === null || cpaWorkflow === void 0 ? void 0 : cpaWorkflow.engagement_recommendations) && cpaWorkflow.engagement_recommendations.length > 0 && (react_1.default.createElement("div", { style: Object.assign(Object.assign({}, card), { marginBottom: 24 }) },
|
|
172
|
+
react_1.default.createElement("div", { style: sectionTitle }, "CPA ENGAGEMENT NOTES"),
|
|
173
|
+
cpaWorkflow.engagement_recommendations.map((rec, i) => (react_1.default.createElement("div", { key: i, style: { fontSize: 12, color: palette_1.P.gray700, lineHeight: 1.7, fontFamily: palette_1.P.body, padding: '8px 0', borderTop: i > 0 ? '1px solid ' + palette_1.P.gray100 : 'none' } }, rec))))),
|
|
174
|
+
riskDisclosures && riskDisclosures.length > 0 && (react_1.default.createElement("div", { style: Object.assign(Object.assign({}, card), { marginBottom: 24, borderColor: '#FDBA74' }) },
|
|
175
|
+
react_1.default.createElement("div", { style: Object.assign(Object.assign({}, sectionTitle), { color: palette_1.P.orange }) }, "RISK DISCLOSURES"),
|
|
176
|
+
riskDisclosures.map((r, i) => (react_1.default.createElement("div", { key: i, style: { fontSize: 11, color: palette_1.P.gray600, lineHeight: 1.65, fontFamily: palette_1.P.body, padding: '6px 0', borderTop: i > 0 ? '1px solid ' + palette_1.P.gray100 : 'none' } }, r))))),
|
|
177
|
+
(businessProfile === null || businessProfile === void 0 ? void 0 : businessProfile.data_quality_flags) && businessProfile.data_quality_flags.length > 0 && (react_1.default.createElement("div", { style: Object.assign(Object.assign({}, card), { marginBottom: 24, borderColor: '#FDBA74' }) },
|
|
178
|
+
react_1.default.createElement("div", { style: Object.assign(Object.assign({}, sectionTitle), { color: palette_1.P.orange }) }, "DATA QUALITY FLAGS"),
|
|
179
|
+
businessProfile.data_quality_flags.map((f, i) => (react_1.default.createElement("div", { key: i, style: { fontSize: 11, color: palette_1.P.gray600, padding: '4px 0', fontFamily: palette_1.P.body } }, f))))),
|
|
171
180
|
react_1.default.createElement("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center", padding: "12px 0", borderTop: "1px solid " + palette_1.P.gray200, fontSize: 11, color: palette_1.P.gray500, fontFamily: palette_1.P.body } },
|
|
172
181
|
react_1.default.createElement("div", { style: { display: "flex", alignItems: "center", gap: 6 } },
|
|
173
182
|
react_1.default.createElement("div", { style: { width: 16, height: 16, borderRadius: 4, background: palette_1.P.navy, display: "flex", alignItems: "center", justifyContent: "center" } },
|
|
@@ -3,5 +3,7 @@ import { ClientProfile, TaxAxisScreenProps } from "../../lib/types";
|
|
|
3
3
|
export interface TaxAxisProcessingProps extends TaxAxisScreenProps {
|
|
4
4
|
onComplete: () => void;
|
|
5
5
|
profile?: ClientProfile;
|
|
6
|
+
/** Set to true by the shell poller when stage===REPORT_READY is detected. */
|
|
7
|
+
reportReady?: boolean;
|
|
6
8
|
}
|
|
7
|
-
export declare function TaxAxisProcessing({ onComplete, profile, userContext: _userContext, }: TaxAxisProcessingProps): React.JSX.Element;
|
|
9
|
+
export declare function TaxAxisProcessing({ onComplete, profile, reportReady, userContext: _userContext, }: TaxAxisProcessingProps): React.JSX.Element;
|
|
@@ -26,21 +26,25 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
26
26
|
exports.TaxAxisProcessing = TaxAxisProcessing;
|
|
27
27
|
const react_1 = __importStar(require("react"));
|
|
28
28
|
const ProcessingStages_1 = require("./ProcessingStages");
|
|
29
|
+
const CRAWL_CEILING = 80; // hold here until reportReady
|
|
30
|
+
const CRAWL_TICK_MS = 180; // interval between crawl ticks
|
|
31
|
+
const CRAWL_STEP = 0.35; // % added each tick (reaches 80% in ~41s)
|
|
32
|
+
const FINISH_MS = 600; // ms to animate from current% → 100% once ready
|
|
33
|
+
const STAGE_ADVANCE_MS = 3200; // how often the displayed stage advances
|
|
29
34
|
function buildStages(profile) {
|
|
30
35
|
var _a;
|
|
31
36
|
if (!profile) {
|
|
32
37
|
return [
|
|
33
38
|
"Parsing source documents",
|
|
34
39
|
"Injecting IRS 2026 parameters",
|
|
35
|
-
"Screening
|
|
40
|
+
"Screening eligible strategies",
|
|
36
41
|
"Computing deterministic tax math",
|
|
37
42
|
"Generating IRS citations",
|
|
38
43
|
];
|
|
39
44
|
}
|
|
40
|
-
const entity = profile.entity || "your";
|
|
45
|
+
const entity = profile.entity || "your business";
|
|
41
46
|
const stateCount = ((_a = profile.states) === null || _a === void 0 ? void 0 : _a.length) || 1;
|
|
42
47
|
const bizName = profile.bizName || "your business";
|
|
43
|
-
// Verbatim from mock (App.jsx:1473-1477)
|
|
44
48
|
const base = [
|
|
45
49
|
"Parsing source documents",
|
|
46
50
|
"Injecting IRS 2026 parameters",
|
|
@@ -53,53 +57,95 @@ function buildStages(profile) {
|
|
|
53
57
|
if (entity === "S-Corporation") {
|
|
54
58
|
base.push("Benchmarking officer salary against BLS data");
|
|
55
59
|
}
|
|
56
|
-
base.push("Screening
|
|
60
|
+
base.push("Screening 30 eligible strategies", "Computing deterministic tax math", "Cross-validating source documents", "Generating IRS citations", `Assembling TaxAxis report for ${bizName}`);
|
|
57
61
|
return base;
|
|
58
62
|
}
|
|
59
|
-
function TaxAxisProcessing({ onComplete, profile, userContext: _userContext = "expert", }) {
|
|
63
|
+
function TaxAxisProcessing({ onComplete, profile, reportReady = false, userContext: _userContext = "expert", }) {
|
|
60
64
|
const stages = (0, react_1.useMemo)(() => buildStages(profile), [profile]);
|
|
61
65
|
const [progress, setProgress] = (0, react_1.useState)(0);
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
//
|
|
66
|
-
|
|
66
|
+
const [stageIdx, setStageIdx] = (0, react_1.useState)(0);
|
|
67
|
+
const finishingRef = (0, react_1.useRef)(false);
|
|
68
|
+
const completedRef = (0, react_1.useRef)(false);
|
|
69
|
+
// Track current progress in a ref so the finish animation can read it synchronously
|
|
70
|
+
// without relying on the async functional-updater pattern.
|
|
71
|
+
const progressRef = (0, react_1.useRef)(0);
|
|
72
|
+
const setProgressSync = (v) => {
|
|
73
|
+
progressRef.current = v;
|
|
74
|
+
setProgress(v);
|
|
75
|
+
};
|
|
76
|
+
// ── Crawl: 0 → 80% — skipped entirely if reportReady already true on mount ──
|
|
67
77
|
(0, react_1.useEffect)(() => {
|
|
68
|
-
|
|
69
|
-
|
|
78
|
+
if (reportReady || finishingRef.current)
|
|
79
|
+
return;
|
|
70
80
|
const iv = setInterval(() => {
|
|
71
|
-
|
|
72
|
-
setProgress(i);
|
|
73
|
-
if (i >= stages.length) {
|
|
81
|
+
if (finishingRef.current) {
|
|
74
82
|
clearInterval(iv);
|
|
75
|
-
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
const next = Math.min(progressRef.current + CRAWL_STEP, CRAWL_CEILING);
|
|
86
|
+
setProgressSync(next);
|
|
87
|
+
if (next >= CRAWL_CEILING)
|
|
88
|
+
clearInterval(iv);
|
|
89
|
+
}, CRAWL_TICK_MS);
|
|
90
|
+
return () => clearInterval(iv);
|
|
91
|
+
// reportReady intentionally in deps: if it arrives before mount effect runs, skip crawl
|
|
92
|
+
}, [reportReady]);
|
|
93
|
+
// ── Stage labels: advance every STAGE_ADVANCE_MS ─────────────────
|
|
94
|
+
(0, react_1.useEffect)(() => {
|
|
95
|
+
const iv = setInterval(() => {
|
|
96
|
+
setStageIdx((i) => (i + 1 < stages.length ? i + 1 : i));
|
|
97
|
+
}, STAGE_ADVANCE_MS);
|
|
98
|
+
return () => clearInterval(iv);
|
|
99
|
+
}, [stages.length]);
|
|
100
|
+
// ── Finish: reportReady → fast fill to 100%, then onComplete ─────
|
|
101
|
+
(0, react_1.useEffect)(() => {
|
|
102
|
+
if (!reportReady || finishingRef.current || completedRef.current)
|
|
103
|
+
return;
|
|
104
|
+
finishingRef.current = true;
|
|
105
|
+
setStageIdx(stages.length - 1);
|
|
106
|
+
// Read current progress synchronously from ref — not from stale state closure
|
|
107
|
+
const startPct = progressRef.current;
|
|
108
|
+
const startTime = Date.now();
|
|
109
|
+
const frame = () => {
|
|
110
|
+
const elapsed = Date.now() - startTime;
|
|
111
|
+
const t = Math.min(elapsed / FINISH_MS, 1);
|
|
112
|
+
const eased = t < 1 ? t * (2 - t) : 1;
|
|
113
|
+
setProgressSync(startPct + (100 - startPct) * eased);
|
|
114
|
+
if (t < 1) {
|
|
115
|
+
requestAnimationFrame(frame);
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
setProgressSync(100);
|
|
119
|
+
if (!completedRef.current) {
|
|
120
|
+
completedRef.current = true;
|
|
121
|
+
setTimeout(onComplete, 150);
|
|
122
|
+
}
|
|
76
123
|
}
|
|
77
|
-
}, stageInterval);
|
|
78
|
-
return () => {
|
|
79
|
-
clearInterval(iv);
|
|
80
|
-
if (navTimer !== null)
|
|
81
|
-
clearTimeout(navTimer);
|
|
82
124
|
};
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
125
|
+
requestAnimationFrame(frame);
|
|
126
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
127
|
+
}, [reportReady, stages.length]);
|
|
128
|
+
const pct = Math.round(progress);
|
|
129
|
+
const title = (profile === null || profile === void 0 ? void 0 : profile.bizName) ? `Analyzing ${profile.bizName}` : "Running Analysis";
|
|
130
|
+
const isFinishing = finishingRef.current;
|
|
88
131
|
return (react_1.default.createElement("div", { className: "pt-[60px] text-center" },
|
|
89
132
|
react_1.default.createElement("div", { className: "relative w-[72px] h-[72px] mx-auto mb-7" },
|
|
90
133
|
react_1.default.createElement("div", { className: "absolute inset-0 rounded-full animate-ping", style: {
|
|
91
134
|
background: "radial-gradient(circle, #248384, transparent 70%)",
|
|
92
135
|
opacity: 0.15,
|
|
136
|
+
animationDuration: isFinishing ? "0.4s" : "1.4s",
|
|
93
137
|
} }),
|
|
94
138
|
react_1.default.createElement("div", { className: "absolute inset-0 w-[72px] h-[72px] rounded-full bg-tax-axis-surface flex items-center justify-center", style: { border: "2px solid rgba(36,131,132,0.4)" } },
|
|
95
|
-
react_1.default.createElement("span", { className: "
|
|
139
|
+
react_1.default.createElement("span", { className: "font-bold text-tax-axis-teal-light font-tax-axis-mono", style: { fontSize: pct === 100 ? 20 : 28 } }, pct === 100 ? "✓" : pct))),
|
|
96
140
|
react_1.default.createElement("h2", { className: "text-[22px] font-bold text-white font-tax-axis-head mb-1" }, title),
|
|
97
|
-
react_1.default.createElement("p", { className: "text-[13px] text-tax-axis-text-3 font-tax-axis-body mb-7" }, "Deterministic
|
|
141
|
+
react_1.default.createElement("p", { className: "text-[13px] text-tax-axis-text-3 font-tax-axis-body mb-7" }, isFinishing ? "Report ready — loading your results…" : "Deterministic · Temperature 0 · IRS-cited"),
|
|
98
142
|
react_1.default.createElement("div", { className: "max-w-[360px] mx-auto mb-6 h-0.5 bg-tax-axis-surface-2 rounded-sm overflow-hidden" },
|
|
99
|
-
react_1.default.createElement("div", { className: "h-full rounded-sm
|
|
100
|
-
width: `${
|
|
143
|
+
react_1.default.createElement("div", { className: "h-full rounded-sm", style: {
|
|
144
|
+
width: `${progress}%`,
|
|
101
145
|
background: "linear-gradient(90deg, #248384, #A1E5E6)",
|
|
102
146
|
boxShadow: "0 0 8px #248384",
|
|
147
|
+
transition: isFinishing ? "none" : "width 0.18s linear",
|
|
103
148
|
} })),
|
|
104
|
-
react_1.default.createElement(ProcessingStages_1.ProcessingStages, { stages: stages, progress:
|
|
149
|
+
react_1.default.createElement(ProcessingStages_1.ProcessingStages, { stages: stages, progress: stageIdx + 1 }),
|
|
150
|
+
pct >= CRAWL_CEILING && !isFinishing && (react_1.default.createElement("p", { className: "text-[11px] text-tax-axis-text-4 font-tax-axis-mono mt-4 animate-pulse" }, "Finalizing analysis\u2026"))));
|
|
105
151
|
}
|
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
import type { Strategy, ComputedMap } from "../types";
|
|
2
|
+
export interface SourceDocumentRef {
|
|
3
|
+
field_label: string;
|
|
4
|
+
value_display: string;
|
|
5
|
+
source_hint: string;
|
|
6
|
+
}
|
|
2
7
|
export interface EngineCalculationTrace {
|
|
3
8
|
strategy_id: string;
|
|
4
9
|
branch_executed: string | null;
|
|
@@ -16,6 +21,8 @@ export interface EngineCalculationTrace {
|
|
|
16
21
|
forms_required: string[];
|
|
17
22
|
deadline_flag: string | null;
|
|
18
23
|
amt_flag: boolean;
|
|
24
|
+
source_documents?: SourceDocumentRef[];
|
|
25
|
+
specialist_note?: string | null;
|
|
19
26
|
}
|
|
20
27
|
export interface EngineStrategyAnalysis {
|
|
21
28
|
strategy_id: string;
|
|
@@ -71,6 +71,7 @@ function resolveTimelineBucket(strategyId, roadmap) {
|
|
|
71
71
|
}
|
|
72
72
|
// ── CalculationTrace → StrategyTraceStep[] ───────────────────────────
|
|
73
73
|
function traceFromEngine(trace) {
|
|
74
|
+
var _a, _b;
|
|
74
75
|
const steps = [];
|
|
75
76
|
// Emit formula as step 1
|
|
76
77
|
if (trace.formula) {
|
|
@@ -83,7 +84,7 @@ function traceFromEngine(trace) {
|
|
|
83
84
|
});
|
|
84
85
|
}
|
|
85
86
|
// Emit confidence interval as step 2 when present
|
|
86
|
-
if (trace.confidence_interval) {
|
|
87
|
+
if (((_a = trace.confidence_interval) === null || _a === void 0 ? void 0 : _a.low) != null && ((_b = trace.confidence_interval) === null || _b === void 0 ? void 0 : _b.high) != null) {
|
|
87
88
|
steps.push({
|
|
88
89
|
n: 2,
|
|
89
90
|
step: "Confidence range",
|
|
@@ -95,7 +96,7 @@ function traceFromEngine(trace) {
|
|
|
95
96
|
return steps;
|
|
96
97
|
}
|
|
97
98
|
function adaptEngineOutput(engineOutput) {
|
|
98
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s;
|
|
99
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t;
|
|
99
100
|
const strategies = [];
|
|
100
101
|
const computedMap = new Map();
|
|
101
102
|
for (const analysis of engineOutput.strategy_analysis) {
|
|
@@ -108,6 +109,7 @@ function adaptEngineOutput(engineOutput) {
|
|
|
108
109
|
const lo = (_b = (_a = ci === null || ci === void 0 ? void 0 : ci.low) !== null && _a !== void 0 ? _a : template === null || template === void 0 ? void 0 : template.lo) !== null && _b !== void 0 ? _b : 0;
|
|
109
110
|
const hi = (_d = (_c = ci === null || ci === void 0 ? void 0 : ci.high) !== null && _c !== void 0 ? _c : template === null || template === void 0 ? void 0 : template.hi) !== null && _d !== void 0 ? _d : 0;
|
|
110
111
|
const timelineBucket = resolveTimelineBucket(analysis.strategy_id, engineOutput.implementation_roadmap);
|
|
112
|
+
const clientSummaryEntry = engineOutput.client_summary.strategies.find((cs) => cs.strategy_name === analysis.strategy_name);
|
|
111
113
|
const strategy = {
|
|
112
114
|
rank: rank !== null && rank !== void 0 ? rank : 99,
|
|
113
115
|
code: (_e = template === null || template === void 0 ? void 0 : template.code) !== null && _e !== void 0 ? _e : analysis.strategy_id,
|
|
@@ -131,8 +133,12 @@ function adaptEngineOutput(engineOutput) {
|
|
|
131
133
|
preferIndustry: template === null || template === void 0 ? void 0 : template.preferIndustry,
|
|
132
134
|
minEmployees: template === null || template === void 0 ? void 0 : template.minEmployees,
|
|
133
135
|
needsOwnerComp: template === null || template === void 0 ? void 0 : template.needsOwnerComp,
|
|
134
|
-
clientBrief: (
|
|
135
|
-
action: (
|
|
136
|
+
clientBrief: (_p = clientSummaryEntry === null || clientSummaryEntry === void 0 ? void 0 : clientSummaryEntry.why_it_applies) !== null && _p !== void 0 ? _p : template === null || template === void 0 ? void 0 : template.clientBrief,
|
|
137
|
+
action: (_q = clientSummaryEntry === null || clientSummaryEntry === void 0 ? void 0 : clientSummaryEntry.next_step) !== null && _q !== void 0 ? _q : template === null || template === void 0 ? void 0 : template.action,
|
|
138
|
+
sourceDocuments: (_r = trace === null || trace === void 0 ? void 0 : trace.source_documents) !== null && _r !== void 0 ? _r : [],
|
|
139
|
+
quickWin: analysis.quick_win,
|
|
140
|
+
positionStrength: (_s = trace === null || trace === void 0 ? void 0 : trace.position_strength) !== null && _s !== void 0 ? _s : undefined,
|
|
141
|
+
specialistNote: (_t = trace === null || trace === void 0 ? void 0 : trace.specialist_note) !== null && _t !== void 0 ? _t : undefined,
|
|
136
142
|
};
|
|
137
143
|
strategies.push(strategy);
|
|
138
144
|
computedMap.set(strategy.rank, {
|
|
@@ -12,6 +12,11 @@ export interface StrategySource {
|
|
|
12
12
|
value: string;
|
|
13
13
|
field: string;
|
|
14
14
|
}
|
|
15
|
+
export interface SourceDocumentRef {
|
|
16
|
+
field_label: string;
|
|
17
|
+
value_display: string;
|
|
18
|
+
source_hint: string;
|
|
19
|
+
}
|
|
15
20
|
export interface StrategyTraceStep {
|
|
16
21
|
n: number;
|
|
17
22
|
step: string;
|
|
@@ -38,14 +43,18 @@ export interface Strategy {
|
|
|
38
43
|
needsOwnerComp?: boolean;
|
|
39
44
|
clientBrief?: string;
|
|
40
45
|
action?: string;
|
|
46
|
+
abstract?: string;
|
|
41
47
|
authority?: string;
|
|
42
48
|
forms?: string;
|
|
43
49
|
warning?: string | null;
|
|
44
|
-
abstract?: string;
|
|
45
50
|
sources?: StrategySource[];
|
|
46
51
|
trace?: StrategyTraceStep[];
|
|
47
52
|
cost?: string;
|
|
48
53
|
timelineBucket?: string;
|
|
54
|
+
sourceDocuments?: SourceDocumentRef[];
|
|
55
|
+
quickWin?: boolean;
|
|
56
|
+
positionStrength?: string;
|
|
57
|
+
specialistNote?: string;
|
|
49
58
|
}
|
|
50
59
|
export interface ClientProfile {
|
|
51
60
|
bizName: string;
|