@paro.io/expert-shared-components 1.14.66 → 1.14.67
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 +0 -1
- package/lib/components/TaxAxis/TaxAxisShell.js +5 -80
- package/lib/components/shared/UploadClient.d.ts +2 -1
- package/lib/components/shared/UploadClient.js +6 -2
- package/lib/index.d.ts +1 -13
- package/lib/index.js +1 -27
- 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/Methodology.js +2 -2
- 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 +5 -2
- package/lib/tax-axis/components/clientReport/TaxAxisClientReport.js +9 -7
- package/lib/tax-axis/components/dashboard/DashboardActions.js +6 -5
- package/lib/tax-axis/components/dashboard/DashboardSummary.d.ts +6 -1
- package/lib/tax-axis/components/dashboard/DashboardSummary.js +19 -10
- package/lib/tax-axis/components/dashboard/StrategyDetailPanel.d.ts +1 -1
- package/lib/tax-axis/components/dashboard/StrategyDetailPanel.js +122 -95
- package/lib/tax-axis/components/dashboard/TaxAxisDashboard.d.ts +58 -4
- package/lib/tax-axis/components/dashboard/TaxAxisDashboard.js +375 -56
- package/lib/tax-axis/components/documents/DocumentCard.d.ts +6 -3
- package/lib/tax-axis/components/documents/DocumentCard.js +72 -15
- package/lib/tax-axis/components/documents/DocumentReviewModal.d.ts +3 -2
- package/lib/tax-axis/components/documents/DocumentReviewModal.js +109 -295
- package/lib/tax-axis/components/documents/DocumentTier.d.ts +5 -4
- package/lib/tax-axis/components/documents/DocumentTier.js +2 -2
- package/lib/tax-axis/components/documents/TaxAxisDocuments.d.ts +28 -8
- package/lib/tax-axis/components/documents/TaxAxisDocuments.js +335 -172
- package/lib/tax-axis/components/documents/qbo/QboAvailableReportsModal.d.ts +13 -0
- package/lib/tax-axis/components/documents/qbo/QboAvailableReportsModal.js +180 -0
- package/lib/tax-axis/components/documents/qbo/QboClientSelectorModal.d.ts +10 -0
- package/lib/tax-axis/components/documents/qbo/QboClientSelectorModal.js +155 -0
- package/lib/tax-axis/components/documents/qbo/QboConnectBanner.d.ts +9 -0
- package/lib/tax-axis/components/documents/qbo/QboConnectBanner.js +55 -0
- package/lib/tax-axis/components/documents/qbo/QboDocumentMappingModal.d.ts +10 -0
- package/lib/tax-axis/components/documents/qbo/QboDocumentMappingModal.js +202 -0
- package/lib/tax-axis/components/documents/qbo/QboImportingModal.d.ts +8 -0
- package/lib/tax-axis/components/documents/qbo/QboImportingModal.js +75 -0
- package/lib/tax-axis/components/documents/qbo/QboPermissionsModal.d.ts +8 -0
- package/lib/tax-axis/components/documents/qbo/QboPermissionsModal.js +126 -0
- package/lib/tax-axis/components/documents/qbo/index.d.ts +8 -0
- package/lib/tax-axis/components/documents/qbo/index.js +17 -0
- package/lib/tax-axis/components/documents/qbo/qboConstants.d.ts +24 -0
- package/lib/tax-axis/components/documents/qbo/qboConstants.js +71 -0
- package/lib/tax-axis/components/documents/qbo/types.d.ts +43 -0
- package/lib/tax-axis/components/documents/qbo/types.js +3 -0
- package/lib/tax-axis/components/documents/qbo/useQboFlow.d.ts +19 -0
- package/lib/tax-axis/components/documents/qbo/useQboFlow.js +207 -0
- package/lib/tax-axis/components/intake/ClientParametersSection.js +14 -30
- package/lib/tax-axis/components/intake/CpaIntakeQuestionsSection.js +3 -3
- package/lib/tax-axis/components/intake/IntakeCtaCards.d.ts +1 -2
- package/lib/tax-axis/components/intake/IntakeCtaCards.js +6 -13
- package/lib/tax-axis/components/intake/RefineAnalysisSection.js +7 -7
- package/lib/tax-axis/components/intake/TaxAxisIntake.js +7 -95
- package/lib/tax-axis/components/intake/intakeSchema.d.ts +0 -3
- package/lib/tax-axis/components/intake/intakeSchema.js +2 -4
- package/lib/tax-axis/components/preparerWorkpaper/TaxAxisPreparerWorkpaper.d.ts +23 -4
- package/lib/tax-axis/components/preparerWorkpaper/TaxAxisPreparerWorkpaper.js +15 -4
- package/lib/tax-axis/components/processing/TaxAxisProcessing.d.ts +2 -1
- package/lib/tax-axis/components/processing/TaxAxisProcessing.js +102 -31
- package/lib/tax-axis/components/prospectReport/ProspectPrintView.js +0 -2
- package/lib/tax-axis/components/prospectReport/ProspectStrategyCard.d.ts +1 -8
- package/lib/tax-axis/components/prospectReport/ProspectStrategyCard.js +5 -5
- package/lib/tax-axis/components/prospectReport/TaxAxisProspectReport.d.ts +1 -27
- package/lib/tax-axis/components/prospectReport/TaxAxisProspectReport.js +25 -43
- package/lib/tax-axis/index.d.ts +3 -1
- package/lib/tax-axis/index.js +4 -3
- package/lib/tax-axis/lib/adapters/useEngineOutput.d.ts +138 -13
- package/lib/tax-axis/lib/adapters/useEngineOutput.js +156 -7
- 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/data/strategies.js +9 -9
- package/lib/tax-axis/lib/documentFieldCatalog.d.ts +7 -12
- package/lib/tax-axis/lib/documentFieldCatalog.js +805 -8
- package/lib/tax-axis/lib/types/index.d.ts +13 -1
- package/package.json +1 -1
- package/lib/README.md +0 -2
- package/lib/package.json +0 -68
|
@@ -26,14 +26,214 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
26
26
|
exports.TaxAxisDashboard = TaxAxisDashboard;
|
|
27
27
|
const react_1 = __importStar(require("react"));
|
|
28
28
|
const data_1 = require("../../lib/data");
|
|
29
|
+
const strategyNarrative_1 = require("../../lib/data/strategyNarrative");
|
|
29
30
|
const compute_1 = require("../../lib/compute");
|
|
31
|
+
const useEngineOutput_1 = require("../../lib/adapters/useEngineOutput");
|
|
30
32
|
const TaxAxisButton_1 = require("../shared/TaxAxisButton");
|
|
31
33
|
const TaxAxisBadge_1 = require("../shared/TaxAxisBadge");
|
|
32
34
|
const DashboardSummary_1 = require("./DashboardSummary");
|
|
33
|
-
const DashboardTopBar_1 = require("./DashboardTopBar");
|
|
34
35
|
const DashboardActions_1 = require("./DashboardActions");
|
|
35
36
|
const StrategyTile_1 = require("./StrategyTile");
|
|
36
37
|
const StrategyDetailPanel_1 = require("./StrategyDetailPanel");
|
|
38
|
+
const STRATEGY_TYPE_LABELS = {
|
|
39
|
+
ENTITY_RESTRUCTURING: "Entity Restructuring",
|
|
40
|
+
QBI_199A_OPTIMIZATION: "QBI §199A Optimization",
|
|
41
|
+
DOCUMENTATION_GAP_REMEDIATION: "Documentation Gap Remediation",
|
|
42
|
+
RETIREMENT_PLAN: "Retirement Plan Optimization",
|
|
43
|
+
DEPRECIATION_ACCELERATION: "Depreciation Acceleration",
|
|
44
|
+
COST_SEGREGATION: "Cost Segregation",
|
|
45
|
+
RD_CREDIT: "R&D Tax Credit",
|
|
46
|
+
HSA_MAXIMIZATION: "HSA Maximization",
|
|
47
|
+
SALT_PTE: "SALT / PTE Optimization",
|
|
48
|
+
WOTC: "Work Opportunity Tax Credit",
|
|
49
|
+
INCOME_DEFERRAL: "Income Deferral",
|
|
50
|
+
CHARITABLE_GIVING: "Charitable Giving Strategy",
|
|
51
|
+
FAMILY_EMPLOYMENT: "Family Employment",
|
|
52
|
+
MEALS_DEDUCTIONS: "Business Meals Deduction",
|
|
53
|
+
OPPORTUNITY_ZONE: "Opportunity Zone Investment",
|
|
54
|
+
ACCOUNTING_METHOD: "Accounting Method Change",
|
|
55
|
+
BONUS_DEPRECIATION: "Bonus Depreciation §168(k)",
|
|
56
|
+
SECTION_179: "Section 179 Expensing",
|
|
57
|
+
};
|
|
58
|
+
function humanizeStrategyType(raw) {
|
|
59
|
+
if (STRATEGY_TYPE_LABELS[raw])
|
|
60
|
+
return STRATEGY_TYPE_LABELS[raw];
|
|
61
|
+
return raw
|
|
62
|
+
.replace(/_/g, " ")
|
|
63
|
+
.replace(/\b\w/g, (c) => c.toUpperCase());
|
|
64
|
+
}
|
|
65
|
+
// Build a lookup from strategy_id → strategy_name using engineOutput.strategy_analysis
|
|
66
|
+
function buildEngineNameLookup(llm) {
|
|
67
|
+
var _a;
|
|
68
|
+
const map = new Map();
|
|
69
|
+
const analysis = (_a = llm.engineOutput) === null || _a === void 0 ? void 0 : _a.strategy_analysis;
|
|
70
|
+
if (Array.isArray(analysis)) {
|
|
71
|
+
for (const a of analysis) {
|
|
72
|
+
if (a.strategy_id && a.strategy_name)
|
|
73
|
+
map.set(a.strategy_id, a.strategy_name);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return map;
|
|
77
|
+
}
|
|
78
|
+
// Build a lookup from strategy_id → roadmap bucket using engineOutput.implementation_roadmap
|
|
79
|
+
function buildRoadmapBucketLookup(llm) {
|
|
80
|
+
var _a, _b;
|
|
81
|
+
const map = new Map();
|
|
82
|
+
const roadmap = (_a = llm.engineOutput) === null || _a === void 0 ? void 0 : _a.implementation_roadmap;
|
|
83
|
+
if (!roadmap)
|
|
84
|
+
return map;
|
|
85
|
+
const bucketKeys = [
|
|
86
|
+
{ key: "quick_wins", bucket: "now" },
|
|
87
|
+
{ key: "immediate", bucket: "now" },
|
|
88
|
+
{ key: "thirty_day", bucket: "30d" },
|
|
89
|
+
{ key: "ninety_day", bucket: "90d" },
|
|
90
|
+
{ key: "annual", bucket: "filing" },
|
|
91
|
+
];
|
|
92
|
+
for (const { key, bucket } of bucketKeys) {
|
|
93
|
+
for (const item of (_b = roadmap[key]) !== null && _b !== void 0 ? _b : []) {
|
|
94
|
+
if (item.strategy_id)
|
|
95
|
+
map.set(item.strategy_id, bucket);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return map;
|
|
99
|
+
}
|
|
100
|
+
// LLM sometimes emits these literal placeholder strings as why_it_applies / next_step
|
|
101
|
+
// content. When detected, we fall back to STRATEGY_NARRATIVE static content.
|
|
102
|
+
const PLACEHOLDER_WHY = "This strategy may apply based on your financial profile.";
|
|
103
|
+
const PLACEHOLDER_NEXT = "Discuss with your CPA to evaluate and implement this strategy.";
|
|
104
|
+
function isMissingOrPlaceholder(value, knownPlaceholder) {
|
|
105
|
+
if (!value)
|
|
106
|
+
return true;
|
|
107
|
+
const trimmed = value.trim();
|
|
108
|
+
if (trimmed === "")
|
|
109
|
+
return true;
|
|
110
|
+
if (trimmed === knownPlaceholder)
|
|
111
|
+
return true;
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
// Parse "S10" -> 10. Returns null if strategyId doesn't match the SN pattern.
|
|
115
|
+
function parseStrategyNumber(strategyId) {
|
|
116
|
+
if (!strategyId)
|
|
117
|
+
return null;
|
|
118
|
+
const match = strategyId.match(/^S(\d+)$/);
|
|
119
|
+
if (!match)
|
|
120
|
+
return null;
|
|
121
|
+
return parseInt(match[1], 10);
|
|
122
|
+
}
|
|
123
|
+
// Build a strategy_id -> client_summary entry lookup using strategy_analysis as the join table.
|
|
124
|
+
function buildClientSummaryLookup(llm) {
|
|
125
|
+
var _a, _b, _c, _d;
|
|
126
|
+
const lookup = new Map();
|
|
127
|
+
const engineOutput = (_a = llm.engineOutput) !== null && _a !== void 0 ? _a : llm.rawOutput;
|
|
128
|
+
if (!engineOutput)
|
|
129
|
+
return lookup;
|
|
130
|
+
const strategyAnalysis = (_b = engineOutput.strategy_analysis) !== null && _b !== void 0 ? _b : [];
|
|
131
|
+
const clientSummaryStrategies = (_d = (_c = engineOutput.client_summary) === null || _c === void 0 ? void 0 : _c.strategies) !== null && _d !== void 0 ? _d : [];
|
|
132
|
+
// strategy_name -> client_summary entry
|
|
133
|
+
const byName = new Map();
|
|
134
|
+
for (const cs of clientSummaryStrategies) {
|
|
135
|
+
if (cs.strategy_name) {
|
|
136
|
+
byName.set(cs.strategy_name, cs);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
// strategy_id -> client_summary entry (via strategy_analysis name lookup)
|
|
140
|
+
for (const sa of strategyAnalysis) {
|
|
141
|
+
if (sa.strategy_id && sa.strategy_name) {
|
|
142
|
+
const cs = byName.get(sa.strategy_name);
|
|
143
|
+
if (cs) {
|
|
144
|
+
lookup.set(sa.strategy_id, cs);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return lookup;
|
|
149
|
+
}
|
|
150
|
+
function mapLlmToStrategies(llm, profile) {
|
|
151
|
+
const nameLookup = buildEngineNameLookup(llm);
|
|
152
|
+
const bucketLookup = buildRoadmapBucketLookup(llm);
|
|
153
|
+
const clientSummaryLookup = buildClientSummaryLookup(llm);
|
|
154
|
+
return llm.strategies
|
|
155
|
+
.filter((s) => s.applicable)
|
|
156
|
+
.map((s, idx) => {
|
|
157
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
158
|
+
const id = (_a = s.strategyId) !== null && _a !== void 0 ? _a : s.strategyType;
|
|
159
|
+
const name = (_b = nameLookup.get(id)) !== null && _b !== void 0 ? _b : humanizeStrategyType(s.strategyType);
|
|
160
|
+
const timelineBucket = (_c = bucketLookup.get(id)) !== null && _c !== void 0 ? _c : (s.priority === "HIGH" ? "now" : "90d");
|
|
161
|
+
const weightedScore = (_d = s.weightedScore) !== null && _d !== void 0 ? _d : (s.priority === "HIGH" ? 85 : s.priority === "MEDIUM" ? 70 : 55);
|
|
162
|
+
// Lookup the client_summary entry for this strategy (top-3 strategies only)
|
|
163
|
+
const csEntry = clientSummaryLookup.get(id);
|
|
164
|
+
const llmWhy = csEntry === null || csEntry === void 0 ? void 0 : csEntry.why_it_applies;
|
|
165
|
+
const llmNext = csEntry === null || csEntry === void 0 ? void 0 : csEntry.next_step;
|
|
166
|
+
// Strategy number for STRATEGY_NARRATIVE static lookup (e.g. "S10" -> 10)
|
|
167
|
+
const strategyNumber = parseStrategyNumber(id);
|
|
168
|
+
const staticNarrative = strategyNumber !== null ? strategyNarrative_1.STRATEGY_NARRATIVE[strategyNumber] : undefined;
|
|
169
|
+
// clientBrief: prefer LLM why_it_applies, fall back to static, then neutral default
|
|
170
|
+
let clientBrief;
|
|
171
|
+
if (!isMissingOrPlaceholder(llmWhy, PLACEHOLDER_WHY)) {
|
|
172
|
+
clientBrief = llmWhy;
|
|
173
|
+
}
|
|
174
|
+
else if (staticNarrative === null || staticNarrative === void 0 ? void 0 : staticNarrative.whyMatters) {
|
|
175
|
+
clientBrief = staticNarrative.whyMatters(profile);
|
|
176
|
+
}
|
|
177
|
+
else {
|
|
178
|
+
clientBrief = "Your preparer will review this strategy and include the analysis in your engagement report.";
|
|
179
|
+
}
|
|
180
|
+
// action: prefer LLM next_step, fall back to static nextSteps, then implementationSteps[0]
|
|
181
|
+
let action;
|
|
182
|
+
if (!isMissingOrPlaceholder(llmNext, PLACEHOLDER_NEXT)) {
|
|
183
|
+
action = llmNext;
|
|
184
|
+
}
|
|
185
|
+
else if (staticNarrative === null || staticNarrative === void 0 ? void 0 : staticNarrative.nextSteps) {
|
|
186
|
+
action = staticNarrative.nextSteps;
|
|
187
|
+
}
|
|
188
|
+
else if ((_e = s.implementationSteps) === null || _e === void 0 ? void 0 : _e[0]) {
|
|
189
|
+
action = s.implementationSteps[0];
|
|
190
|
+
}
|
|
191
|
+
else {
|
|
192
|
+
action = "Work with your CPA to implement this strategy.";
|
|
193
|
+
}
|
|
194
|
+
// Pull calculation_trace fields. Defensive about shape.
|
|
195
|
+
const ct = ((_f = s.calculationTrace) !== null && _f !== void 0 ? _f : {});
|
|
196
|
+
const sourceDocuments = Array.isArray(ct.source_documents) ? ct.source_documents : undefined;
|
|
197
|
+
const specialistNote = typeof ct.specialist_note === "string" && ct.specialist_note.trim() !== ""
|
|
198
|
+
? ct.specialist_note
|
|
199
|
+
: ((_g = staticNarrative === null || staticNarrative === void 0 ? void 0 : staticNarrative.whySpecialist) !== null && _g !== void 0 ? _g : undefined);
|
|
200
|
+
const positionStrength = typeof ct.position_strength === "string" ? ct.position_strength : undefined;
|
|
201
|
+
const authority = typeof ct.irs_cite === "string" ? ct.irs_cite : undefined;
|
|
202
|
+
const formsFromTrace = Array.isArray(ct.forms_required) ? ct.forms_required.join(", ") : undefined;
|
|
203
|
+
return {
|
|
204
|
+
rank: idx + 1,
|
|
205
|
+
code: id,
|
|
206
|
+
name,
|
|
207
|
+
cat: "income",
|
|
208
|
+
priority: (s.priority || "MEDIUM").toUpperCase(),
|
|
209
|
+
score: Math.round(weightedScore),
|
|
210
|
+
entities: [],
|
|
211
|
+
lo: s.estimatedSavings.min,
|
|
212
|
+
hi: s.estimatedSavings.max,
|
|
213
|
+
timeline: timelineBucket === "now" ? "Act now" : timelineBucket === "30d" ? "Within 30 days" : "Within 90 days",
|
|
214
|
+
timelineBucket,
|
|
215
|
+
clientBrief,
|
|
216
|
+
action,
|
|
217
|
+
forms: formsFromTrace !== null && formsFromTrace !== void 0 ? formsFromTrace : s.requiredForms.join(", "),
|
|
218
|
+
abstract: s.summary,
|
|
219
|
+
sources: [],
|
|
220
|
+
trace: [],
|
|
221
|
+
cost: undefined,
|
|
222
|
+
sourceDocuments,
|
|
223
|
+
specialistNote,
|
|
224
|
+
positionStrength,
|
|
225
|
+
authority,
|
|
226
|
+
quickWin: s.quickWin,
|
|
227
|
+
};
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
function buildLlmComputed(strategies) {
|
|
231
|
+
const map = new Map();
|
|
232
|
+
for (const s of strategies) {
|
|
233
|
+
map.set(s.rank, { lo: s.lo, hi: s.hi, sources: s.sources, trace: s.trace });
|
|
234
|
+
}
|
|
235
|
+
return map;
|
|
236
|
+
}
|
|
37
237
|
// ─── Formatting helper ──────────────────────────────────────────
|
|
38
238
|
const fmtK = (n) => `$${(n / 1000).toFixed(n % 1000 ? 1 : 0)}K`;
|
|
39
239
|
// ─── Timeline buckets for Client Summary ────────────────────────
|
|
@@ -42,21 +242,66 @@ const BUCKETS = [
|
|
|
42
242
|
{ key: "30d", label: "Within 30 Days", desc: "Documentation or payroll changes" },
|
|
43
243
|
{ key: "90d", label: "Within 90 Days", desc: "Structural changes — new accounts or plan setup" },
|
|
44
244
|
];
|
|
45
|
-
function TaxAxisDashboard({ profile, onDownloadClient, onDownloadPreparer, onPresent, onSend, onReset, onReviewData, onUploadMore, userContext: _userContext = "expert", }) {
|
|
245
|
+
function TaxAxisDashboard({ profile, llmResult, parsedDocuments, onDownloadClient, onDownloadPreparer, onPresent, onSend, onReset, onReviewData, onUploadMore, userContext: _userContext = "expert", }) {
|
|
246
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u;
|
|
247
|
+
const hasLlm = !!((_a = llmResult === null || llmResult === void 0 ? void 0 : llmResult.strategies) === null || _a === void 0 ? void 0 : _a.length);
|
|
248
|
+
// All live fields from rawOutput — nothing hardcoded
|
|
249
|
+
const rawOutput = (_c = (_b = llmResult === null || llmResult === void 0 ? void 0 : llmResult.rawOutput) !== null && _b !== void 0 ? _b : llmResult === null || llmResult === void 0 ? void 0 : llmResult.engineOutput) !== null && _c !== void 0 ? _c : null;
|
|
250
|
+
const businessProfile = (_d = rawOutput === null || rawOutput === void 0 ? void 0 : rawOutput.business_profile) !== null && _d !== void 0 ? _d : null;
|
|
251
|
+
const dataQualityFlags = (_e = businessProfile === null || businessProfile === void 0 ? void 0 : businessProfile.data_quality_flags) !== null && _e !== void 0 ? _e : [];
|
|
252
|
+
const riskDisclosures = (_f = rawOutput === null || rawOutput === void 0 ? void 0 : rawOutput.risk_disclosures) !== null && _f !== void 0 ? _f : [];
|
|
253
|
+
const nexusFlags = (_g = rawOutput === null || rawOutput === void 0 ? void 0 : rawOutput.nexus_flags) !== null && _g !== void 0 ? _g : [];
|
|
254
|
+
const engagementRecs = (_j = (_h = rawOutput === null || rawOutput === void 0 ? void 0 : rawOutput.cpa_workflow) === null || _h === void 0 ? void 0 : _h.engagement_recommendations) !== null && _j !== void 0 ? _j : [];
|
|
255
|
+
const excludedStrategies = (_l = (_k = rawOutput === null || rawOutput === void 0 ? void 0 : rawOutput.eligibility_screening) === null || _k === void 0 ? void 0 : _k.excluded_strategies) !== null && _l !== void 0 ? _l : [];
|
|
256
|
+
const clientSummaryOpening = (_o = (_m = rawOutput === null || rawOutput === void 0 ? void 0 : rawOutput.client_summary) === null || _m === void 0 ? void 0 : _m.opening) !== null && _o !== void 0 ? _o : "";
|
|
257
|
+
const clientSummaryClosing = (_q = (_p = rawOutput === null || rawOutput === void 0 ? void 0 : rawOutput.client_summary) === null || _p === void 0 ? void 0 : _p.closing) !== null && _q !== void 0 ? _q : "";
|
|
258
|
+
const dataQualityNote = (_s = (_r = rawOutput === null || rawOutput === void 0 ? void 0 : rawOutput.client_summary) === null || _r === void 0 ? void 0 : _r.data_quality_note) !== null && _s !== void 0 ? _s : "";
|
|
259
|
+
const interactionWarning = (_u = (_t = rawOutput === null || rawOutput === void 0 ? void 0 : rawOutput.client_summary) === null || _t === void 0 ? void 0 : _t.interaction_warning) !== null && _u !== void 0 ? _u : null;
|
|
260
|
+
// Extracted documents: live from session if provided, otherwise empty (no mock fallback)
|
|
261
|
+
const extractionDocs = parsedDocuments !== null && parsedDocuments !== void 0 ? parsedDocuments : [];
|
|
46
262
|
// ─── Derived data ──────────────────────────────────────────────
|
|
47
|
-
|
|
48
|
-
|
|
263
|
+
// Prefer useEngineOutput (full rich data: sourceDocuments, positionStrength,
|
|
264
|
+
// clientBrief from why_it_applies, etc.) over the thin mapLlmToStrategies fallback.
|
|
265
|
+
// engineOutput is at llmResult.engineOutput or llmResult.rawOutput (both present).
|
|
266
|
+
const engineOutputForAdapter = (0, react_1.useMemo)(() => { var _a, _b; return (_b = (_a = llmResult === null || llmResult === void 0 ? void 0 : llmResult.engineOutput) !== null && _a !== void 0 ? _a : llmResult === null || llmResult === void 0 ? void 0 : llmResult.rawOutput) !== null && _b !== void 0 ? _b : null; }, [llmResult]);
|
|
267
|
+
const adapted = (0, useEngineOutput_1.useEngineOutput)(engineOutputForAdapter);
|
|
268
|
+
const llmStrategies = (0, react_1.useMemo)(() => {
|
|
269
|
+
var _a;
|
|
270
|
+
if (!hasLlm)
|
|
271
|
+
return [];
|
|
272
|
+
// Use adapted strategies when available — they carry the full engine data.
|
|
273
|
+
if ((_a = adapted === null || adapted === void 0 ? void 0 : adapted.strategies) === null || _a === void 0 ? void 0 : _a.length)
|
|
274
|
+
return adapted.strategies;
|
|
275
|
+
// Fallback to thin mapping for old payload shapes without engineOutput.
|
|
276
|
+
return mapLlmToStrategies(llmResult, profile);
|
|
277
|
+
}, [hasLlm, adapted, llmResult, profile]);
|
|
278
|
+
const llmComputed = (0, react_1.useMemo)(() => {
|
|
279
|
+
var _a;
|
|
280
|
+
if (!hasLlm)
|
|
281
|
+
return new Map();
|
|
282
|
+
if ((_a = adapted === null || adapted === void 0 ? void 0 : adapted.computedMap) === null || _a === void 0 ? void 0 : _a.size)
|
|
283
|
+
return adapted.computedMap;
|
|
284
|
+
return buildLlmComputed(llmStrategies);
|
|
285
|
+
}, [hasLlm, adapted, llmStrategies]);
|
|
286
|
+
const computed = (0, react_1.useMemo)(() => (hasLlm ? llmComputed : (0, compute_1.computeAllStrategies)(profile)), [hasLlm, llmComputed, profile]);
|
|
287
|
+
const dashEligible = (0, react_1.useMemo)(() => (hasLlm ? llmStrategies : (0, compute_1.filterEligibleStrategies)(profile)), [hasLlm, llmStrategies, profile]);
|
|
49
288
|
const maxSavings = Math.max(...dashEligible.map((s) => { var _a, _b; return (_b = (_a = computed.get(s.rank)) === null || _a === void 0 ? void 0 : _a.hi) !== null && _b !== void 0 ? _b : s.hi; }), 1);
|
|
50
289
|
// ─── State ─────────────────────────────────────────────────────
|
|
51
|
-
|
|
290
|
+
// When LLM result is present, land directly on the Intelligence Report tab
|
|
291
|
+
const [topTab, setTopTab] = (0, react_1.useState)(hasLlm ? "report" : "extraction");
|
|
52
292
|
const [reportTab, setReportTab] = (0, react_1.useState)("report");
|
|
53
293
|
const [chartExpanded, setChartExpanded] = (0, react_1.useState)(false);
|
|
54
294
|
const [selected, setSelected] = (0, react_1.useState)(null);
|
|
55
|
-
|
|
295
|
+
// When LLM result is present, data is implicitly confirmed — skip the gate
|
|
296
|
+
const [dataConfirmed, setDataConfirmed] = (0, react_1.useState)(hasLlm);
|
|
56
297
|
const [reviewStatus, setReviewStatus] = (0, react_1.useState)({
|
|
57
|
-
unreviewed:
|
|
298
|
+
unreviewed: extractionDocs.reduce((a, d) => a + d.flagCount, 0),
|
|
58
299
|
edits: 0,
|
|
59
300
|
});
|
|
301
|
+
// Keep review count in sync when live docs arrive after initial render
|
|
302
|
+
(0, react_1.useEffect)(() => {
|
|
303
|
+
setReviewStatus((prev) => (Object.assign(Object.assign({}, prev), { unreviewed: extractionDocs.reduce((a, d) => a + d.flagCount, 0) })));
|
|
304
|
+
}, [extractionDocs]);
|
|
60
305
|
// Restore confirmed state on mount — flag persists until session reset
|
|
61
306
|
(0, react_1.useEffect)(() => {
|
|
62
307
|
if (typeof window !== "undefined" && sessionStorage.getItem("taxAxisDataConfirmed") === "true") {
|
|
@@ -94,13 +339,37 @@ function TaxAxisDashboard({ profile, onDownloadClient, onDownloadPreparer, onPre
|
|
|
94
339
|
return map;
|
|
95
340
|
}, [uncalculated]);
|
|
96
341
|
const [uncalcExpanded, setUncalcExpanded] = (0, react_1.useState)(false);
|
|
342
|
+
const [excludedExpanded, setExcludedExpanded] = (0, react_1.useState)(false);
|
|
343
|
+
const [riskExpanded, setRiskExpanded] = (0, react_1.useState)(false);
|
|
97
344
|
return (react_1.default.createElement("div", null,
|
|
98
|
-
react_1.default.createElement(
|
|
99
|
-
|
|
100
|
-
|
|
345
|
+
react_1.default.createElement("style", null, `
|
|
346
|
+
@media print {
|
|
347
|
+
* { print-color-adjust: exact; -webkit-print-color-adjust: exact; }
|
|
348
|
+
.MuiDrawer-root, .MuiDrawer-paper, .MuiDrawer-permanent,
|
|
349
|
+
.MuiAppBar-root { display: none !important; }
|
|
350
|
+
.tax-axis-no-print { display: none !important; }
|
|
351
|
+
body { background: white !important; }
|
|
352
|
+
.min-h-screen.bg-tax-axis-navy { background: white !important; }
|
|
353
|
+
.flex.flex-col.w-full { margin-top: 0 !important; margin-left: 0 !important; }
|
|
354
|
+
main.w-full { width: 100% !important; margin: 0 !important; padding: 0 !important; }
|
|
355
|
+
.rounded-\\[14px\\] { page-break-inside: avoid; break-inside: avoid; }
|
|
356
|
+
.rounded-2xl { page-break-inside: avoid; break-inside: avoid; }
|
|
357
|
+
}
|
|
358
|
+
`),
|
|
359
|
+
react_1.default.createElement(DashboardSummary_1.DashboardSummary, { profile: profile, dashEligible: dashEligible, computed: computed, dataConfirmed: dataConfirmed, reviewUnreviewed: reviewStatus.unreviewed, liveSavingsMin: hasLlm ? llmResult.summary.estimatedSavingsMin : undefined, liveSavingsMax: hasLlm ? llmResult.summary.estimatedSavingsMax : undefined, liveStrategyCount: hasLlm ? llmResult.summary.applicableCount : undefined, confidenceTier: businessProfile === null || businessProfile === void 0 ? void 0 : businessProfile.confidence_tier, dataYears: businessProfile === null || businessProfile === void 0 ? void 0 : businessProfile.data_years }),
|
|
360
|
+
false && (react_1.default.createElement("div", null,
|
|
361
|
+
dataQualityFlags.length > 0 && (react_1.default.createElement("div", { className: "rounded-[14px] mb-4", style: { background: "rgba(251,154,29,0.04)", border: "1px solid rgba(251,154,29,0.2)", padding: "16px 20px" } },
|
|
362
|
+
react_1.default.createElement("div", { className: "text-[11px] font-bold text-white uppercase tracking-widest font-tax-axis-mono mb-2.5 flex items-center gap-2" },
|
|
363
|
+
react_1.default.createElement("svg", { width: "12", height: "12", viewBox: "0 0 12 12", fill: "none" },
|
|
364
|
+
react_1.default.createElement("path", { d: "M6 1.5l5 9H1L6 1.5z", stroke: "#FB9A1D", strokeWidth: "1.2", fill: "none" }),
|
|
365
|
+
react_1.default.createElement("path", { d: "M6 5v2.5M6 9h.005", stroke: "#FB9A1D", strokeWidth: "1.2", strokeLinecap: "round" })),
|
|
366
|
+
"Data Quality Flags"),
|
|
367
|
+
dataQualityFlags.map((flag, i) => (react_1.default.createElement("div", { key: i, className: "text-[11px] text-tax-axis-text-2 font-tax-axis-body py-1.5", style: { borderTop: i > 0 ? "1px solid rgba(251,154,29,0.1)" : "none" } }, flag))))),
|
|
101
368
|
react_1.default.createElement("div", { className: "rounded-[14px] mb-4", style: { background: "#0E1132", border: "1px solid rgba(36,131,132,0.12)", padding: "20px 24px" } },
|
|
102
369
|
react_1.default.createElement("div", { className: "text-[13px] font-bold text-white uppercase tracking-widest font-tax-axis-head mb-3" }, "Document Extraction Summary"),
|
|
103
|
-
|
|
370
|
+
extractionDocs.length === 0 ? (react_1.default.createElement("div", { className: "text-[12px] text-tax-axis-text-3 font-tax-axis-body py-2" }, hasLlm
|
|
371
|
+
? "Parsed document data is loading..."
|
|
372
|
+
: "No documents have been parsed yet.")) : (extractionDocs.map((doc) => (react_1.default.createElement("div", { key: doc.docId, className: "flex items-center justify-between py-2.5", style: { borderTop: "1px solid rgba(36,131,132,0.08)" } },
|
|
104
373
|
react_1.default.createElement("div", { className: "flex items-center gap-3" },
|
|
105
374
|
react_1.default.createElement("span", { className: "text-[11px] font-tax-axis-mono text-tax-axis-teal-light bg-tax-axis-teal-bg px-2 py-0.5 rounded" }, doc.code),
|
|
106
375
|
react_1.default.createElement("span", { className: "text-[13px] text-tax-axis-text font-tax-axis-body" }, doc.docName)),
|
|
@@ -108,9 +377,8 @@ function TaxAxisDashboard({ profile, onDownloadClient, onDownloadPreparer, onPre
|
|
|
108
377
|
react_1.default.createElement("span", { className: "text-[11px] font-tax-axis-mono text-tax-axis-text-3" },
|
|
109
378
|
doc.fields.length,
|
|
110
379
|
" fields"),
|
|
111
|
-
doc.flagCount > 0
|
|
112
|
-
|
|
113
|
-
react_1.default.createElement("path", { d: "M2.5 6l3 3 4.5-5", stroke: "#0F6E56", strokeWidth: "1.5", strokeLinecap: "round" })))))))),
|
|
380
|
+
doc.flagCount > 0 ? (react_1.default.createElement("span", { className: "text-[10px] font-semibold font-tax-axis-mono rounded-full min-w-[18px] text-center px-1.5 py-0.5", style: { color: "#FB9A1D", background: "rgba(251,154,29,0.06)" } }, doc.flagCount)) : (react_1.default.createElement("svg", { width: "12", height: "12", viewBox: "0 0 12 12", fill: "none" },
|
|
381
|
+
react_1.default.createElement("path", { d: "M2.5 6l3 3 4.5-5", stroke: "#0F6E56", strokeWidth: "1.5", strokeLinecap: "round" }))))))))),
|
|
114
382
|
!dataConfirmed ? (react_1.default.createElement("div", { className: "rounded-[14px]", style: {
|
|
115
383
|
background: "linear-gradient(135deg, rgba(36,131,132,0.12), rgba(36,131,132,0.06))",
|
|
116
384
|
border: "1px solid rgba(36,131,132,0.3)",
|
|
@@ -142,8 +410,8 @@ function TaxAxisDashboard({ profile, onDownloadClient, onDownloadPreparer, onPre
|
|
|
142
410
|
border: "1px solid rgba(15,110,86,0.25)",
|
|
143
411
|
color: "#0F6E56",
|
|
144
412
|
} }, "View Report"))))),
|
|
145
|
-
|
|
146
|
-
react_1.default.createElement("div", { className: "flex gap-0 mb-5", style: { borderBottom: "1px solid rgba(36,131,132,0.12)" } }, [["report", "Preparer Report"], ["client", "Client Summary"]].map(([id, lbl]) => (react_1.default.createElement("button", { key: id, onClick: () => setReportTab(id), className: "bg-transparent border-0 font-tax-axis-body mr-6", style: {
|
|
413
|
+
(react_1.default.createElement("div", null,
|
|
414
|
+
react_1.default.createElement("div", { className: "flex gap-0 mb-5 tax-axis-no-print", style: { borderBottom: "1px solid rgba(36,131,132,0.12)" } }, [["report", "Preparer Report"], ["client", "Client Summary"]].map(([id, lbl]) => (react_1.default.createElement("button", { key: id, onClick: () => setReportTab(id), className: "bg-transparent border-0 font-tax-axis-body mr-6", style: {
|
|
147
415
|
padding: "10px 0",
|
|
148
416
|
fontSize: 14,
|
|
149
417
|
fontWeight: reportTab === id ? 600 : 400,
|
|
@@ -193,20 +461,14 @@ function TaxAxisDashboard({ profile, onDownloadClient, onDownloadPreparer, onPre
|
|
|
193
461
|
const clo = (_d = (_c = computed.get(s.rank)) === null || _c === void 0 ? void 0 : _c.lo) !== null && _d !== void 0 ? _d : s.lo;
|
|
194
462
|
const w = (chi / maxSavings) * 100;
|
|
195
463
|
return (react_1.default.createElement("div", { key: s.rank, className: "flex items-center gap-3 cursor-pointer", style: { marginBottom: chartExpanded ? 14 : 10 }, onClick: () => setSelected(s) },
|
|
196
|
-
react_1.default.createElement("span", { className:
|
|
197
|
-
fontSize: chartExpanded ? 13 : 12,
|
|
198
|
-
width: chartExpanded ? 180 : 140,
|
|
199
|
-
} }, s.name),
|
|
464
|
+
react_1.default.createElement("span", { className: `text-tax-axis-text font-tax-axis-body flex-shrink-0 overflow-hidden text-ellipsis whitespace-nowrap ${chartExpanded ? "w-[100px] sm:w-[180px] text-[13px]" : "w-[100px] sm:w-[140px] text-[12px]"}` }, s.name),
|
|
200
465
|
react_1.default.createElement("div", { className: "flex-1 bg-tax-axis-surface-2 rounded-sm overflow-hidden", style: { height: chartExpanded ? 10 : 6 } },
|
|
201
466
|
react_1.default.createElement("div", { className: "h-full rounded-sm", style: {
|
|
202
467
|
width: `${w}%`,
|
|
203
468
|
background: "linear-gradient(90deg, #248384, #A1E5E6)",
|
|
204
469
|
transition: "width 0.8s cubic-bezier(.16,1,.3,1)",
|
|
205
470
|
} })),
|
|
206
|
-
react_1.default.createElement("span", { className:
|
|
207
|
-
fontSize: chartExpanded ? 13 : 12,
|
|
208
|
-
width: chartExpanded ? 100 : 80,
|
|
209
|
-
} },
|
|
471
|
+
react_1.default.createElement("span", { className: `font-semibold text-tax-axis-teal-light font-tax-axis-mono flex-shrink-0 text-right ${chartExpanded ? "w-[60px] sm:w-[100px] text-[13px]" : "w-[60px] sm:w-[80px] text-[12px]"}` },
|
|
210
472
|
fmtK(clo),
|
|
211
473
|
"\u2013",
|
|
212
474
|
fmtK(chi))));
|
|
@@ -221,15 +483,34 @@ function TaxAxisDashboard({ profile, onDownloadClient, onDownloadPreparer, onPre
|
|
|
221
483
|
" strategies \u2014 click to collapse"))),
|
|
222
484
|
react_1.default.createElement("div", { className: "text-[13px] font-bold text-white uppercase tracking-widest mb-2.5 font-tax-axis-head flex justify-between items-center" },
|
|
223
485
|
react_1.default.createElement("span", null,
|
|
224
|
-
|
|
486
|
+
dashEligible.length,
|
|
225
487
|
" Strategies"),
|
|
226
488
|
react_1.default.createElement("span", { className: "font-normal normal-case tracking-normal text-tax-axis-text-2 text-xs font-tax-axis-body" }, "Click to explore")),
|
|
227
|
-
react_1.default.createElement("div", { className: "grid grid-cols-2 gap-2.5 mb-4" },
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
489
|
+
react_1.default.createElement("div", { className: "grid grid-cols-1 sm:grid-cols-2 gap-2.5 mb-4" },
|
|
490
|
+
calculable.map((s, i) => {
|
|
491
|
+
var _a, _b;
|
|
492
|
+
const c = computed.get(s.rank);
|
|
493
|
+
return (react_1.default.createElement(StrategyTile_1.StrategyTile, { key: s.rank, s: Object.assign(Object.assign({}, s), { lo: (_a = c === null || c === void 0 ? void 0 : c.lo) !== null && _a !== void 0 ? _a : s.lo, hi: (_b = c === null || c === void 0 ? void 0 : c.hi) !== null && _b !== void 0 ? _b : s.hi }), delay: 0.2 + i * 0.06, onClick: () => setSelected(s), maxSavings: maxSavings }));
|
|
494
|
+
}),
|
|
495
|
+
hasLlm && uncalculated.map((s, i) => (react_1.default.createElement("div", { key: s.rank, onClick: () => setSelected(s), className: "rounded-[14px] p-4 cursor-pointer", style: {
|
|
496
|
+
background: "#0E1132",
|
|
497
|
+
border: "1px solid rgba(36,131,132,0.12)",
|
|
498
|
+
boxShadow: "0 2px 8px rgba(6,8,33,0.3)",
|
|
499
|
+
animationDelay: `${0.2 + (calculable.length + i) * 0.06}s`,
|
|
500
|
+
} },
|
|
501
|
+
react_1.default.createElement("div", { className: "flex items-start justify-between gap-2 mb-2" },
|
|
502
|
+
react_1.default.createElement("div", { className: "flex items-center gap-2 flex-wrap" },
|
|
503
|
+
react_1.default.createElement("span", { className: "text-[10px] font-semibold font-tax-axis-mono px-2 py-0.5 rounded", style: { background: "rgba(36,131,132,0.12)", color: "#A1E5E6", border: "1px solid rgba(36,131,132,0.2)" } }, s.code),
|
|
504
|
+
react_1.default.createElement("span", { className: "text-[10px] font-semibold font-tax-axis-mono px-2 py-0.5 rounded", style: { background: "rgba(148,152,184,0.1)", color: "#9498B8", border: "1px solid rgba(148,152,184,0.15)" } }, "Qualitative")),
|
|
505
|
+
react_1.default.createElement("div", { className: "w-8 h-8 rounded-full flex items-center justify-center text-[12px] font-bold font-tax-axis-mono flex-shrink-0", style: {
|
|
506
|
+
background: "conic-gradient(#248384 0%, #248384 55%, #1A1D3A 55%)",
|
|
507
|
+
color: "#A1E5E6",
|
|
508
|
+
} }, s.score)),
|
|
509
|
+
react_1.default.createElement("div", { className: "text-[14px] font-semibold text-white font-tax-axis-head mb-1 leading-tight" }, s.name),
|
|
510
|
+
react_1.default.createElement("div", { className: "text-[12px] text-tax-axis-teal-light font-tax-axis-mono mb-2" }, s.timeline),
|
|
511
|
+
react_1.default.createElement("div", { className: "h-0.5 w-full rounded-sm mb-2", style: { background: "rgba(36,131,132,0.2)" } }),
|
|
512
|
+
react_1.default.createElement("p", { className: "text-[11px] text-tax-axis-text-2 font-tax-axis-body leading-relaxed line-clamp-2" }, s.abstract || s.clientBrief))))),
|
|
513
|
+
uncalculated.length > 0 && !hasLlm && (react_1.default.createElement("div", { className: "rounded-[14px] overflow-hidden mb-4", style: {
|
|
233
514
|
background: "#0E1132",
|
|
234
515
|
border: "1px solid rgba(251,154,29,0.15)",
|
|
235
516
|
boxShadow: "0 2px 8px rgba(6,8,33,0.3)",
|
|
@@ -238,31 +519,29 @@ function TaxAxisDashboard({ profile, onDownloadClient, onDownloadPreparer, onPre
|
|
|
238
519
|
react_1.default.createElement("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", className: "flex-shrink-0" },
|
|
239
520
|
react_1.default.createElement("circle", { cx: "7", cy: "7", r: "5.5", stroke: "#FB9A1D", strokeWidth: "1.2" }),
|
|
240
521
|
react_1.default.createElement("path", { d: "M7 4.5v3M7 9.5h.005", stroke: "#FB9A1D", strokeWidth: "1.2", strokeLinecap: "round" })),
|
|
241
|
-
react_1.default.createElement("span", { className: "text-[13px] font-semibold text-white font-tax-axis-body flex-1" },
|
|
242
|
-
uncalculated.length
|
|
243
|
-
|
|
244
|
-
uncalculated.length > 1 ? "ies" : "y",
|
|
245
|
-
" need more data to calculate savings"),
|
|
522
|
+
react_1.default.createElement("span", { className: "text-[13px] font-semibold text-white font-tax-axis-body flex-1" }, hasLlm
|
|
523
|
+
? `${uncalculated.length} qualitative strateg${uncalculated.length > 1 ? "ies" : "y"} — CPA review recommended`
|
|
524
|
+
: `${uncalculated.length} strateg${uncalculated.length > 1 ? "ies" : "y"} need more data to calculate savings`),
|
|
246
525
|
react_1.default.createElement("svg", { width: "12", height: "12", viewBox: "0 0 12 12", fill: "none", style: {
|
|
247
526
|
transform: uncalcExpanded ? "rotate(180deg)" : "none",
|
|
248
527
|
transition: "transform .2s",
|
|
249
528
|
} },
|
|
250
529
|
react_1.default.createElement("path", { d: "M3 4.5l3 3 3-3", stroke: "#9498B8", strokeWidth: "1.5", strokeLinecap: "round" }))),
|
|
251
530
|
uncalcExpanded && (react_1.default.createElement("div", { style: { borderTop: "1px solid rgba(251,154,29,0.12)", padding: "12px 20px" } },
|
|
252
|
-
uncalculated.map((s, i) => (react_1.default.createElement("div", { key: s.rank, className: "py-2.5", style: {
|
|
531
|
+
uncalculated.map((s, i) => (react_1.default.createElement("div", { key: s.rank, className: "py-2.5 cursor-pointer", style: {
|
|
253
532
|
borderBottom: i < uncalculated.length - 1
|
|
254
533
|
? "1px solid rgba(36,131,132,0.08)"
|
|
255
534
|
: "none",
|
|
256
|
-
} },
|
|
535
|
+
}, onClick: () => setSelected(s) },
|
|
257
536
|
react_1.default.createElement("div", { className: "flex items-center gap-2.5 mb-1" },
|
|
258
537
|
react_1.default.createElement("span", { className: "text-[11px] font-tax-axis-mono px-2 py-0.5 rounded", style: { color: "#FB9A1D", background: "rgba(251,154,29,0.08)", border: "1px solid rgba(251,154,29,0.15)" } }, s.code),
|
|
259
538
|
react_1.default.createElement("span", { className: "text-[13px] text-white font-tax-axis-body font-semibold" }, s.name)),
|
|
260
|
-
react_1.default.createElement("div", { className: "text-[11px] text-tax-axis-text-2 font-tax-axis-body pl-0.5" },
|
|
261
|
-
"
|
|
262
|
-
(strategyDocNeeds.get(s.name) || ["Upload additional documents"]).join(", "))))),
|
|
263
|
-
onUploadMore && (react_1.default.createElement("div", { className: "pt-3 mt-1", style: { borderTop: "1px solid rgba(251,154,29,0.12)" } },
|
|
539
|
+
react_1.default.createElement("div", { className: "text-[11px] text-tax-axis-text-2 font-tax-axis-body pl-0.5" }, hasLlm
|
|
540
|
+
? (s.abstract || s.clientBrief || "See CPA for details")
|
|
541
|
+
: `Needs: ${(strategyDocNeeds.get(s.name) || ["Upload additional documents"]).join(", ")}`)))),
|
|
542
|
+
!hasLlm && onUploadMore && (react_1.default.createElement("div", { className: "pt-3 mt-1", style: { borderTop: "1px solid rgba(251,154,29,0.12)" } },
|
|
264
543
|
react_1.default.createElement(TaxAxisButton_1.TaxAxisButton, { variant: "secondary", onClick: onUploadMore }, "Upload Documents"))))))),
|
|
265
|
-
react_1.default.createElement("div", { className: "rounded-[14px] overflow-hidden mb-4", style: {
|
|
544
|
+
!hasLlm && (react_1.default.createElement("div", { className: "rounded-[14px] overflow-hidden mb-4", style: {
|
|
266
545
|
background: "#0E1132",
|
|
267
546
|
border: "1px solid rgba(36,131,132,0.12)",
|
|
268
547
|
boxShadow: "0 2px 8px rgba(6,8,33,0.3)",
|
|
@@ -275,19 +554,50 @@ function TaxAxisDashboard({ profile, onDownloadClient, onDownloadPreparer, onPre
|
|
|
275
554
|
react_1.default.createElement("span", { className: "text-[13px] text-tax-axis-text" }, a.name),
|
|
276
555
|
react_1.default.createElement("div", { className: "flex items-center gap-2.5" },
|
|
277
556
|
react_1.default.createElement("span", { className: "text-[11px] font-tax-axis-mono text-tax-axis-text-2" }, a.savings),
|
|
278
|
-
react_1.default.createElement(TaxAxisBadge_1.TaxAxisBadge, { color: a.priority === "MEDIUM" ? "orange" : "neutral", size: "xs" }, a.priority)))))),
|
|
279
|
-
react_1.default.createElement("div", { className: "
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
557
|
+
react_1.default.createElement(TaxAxisBadge_1.TaxAxisBadge, { color: a.priority === "MEDIUM" ? "orange" : "neutral", size: "xs" }, a.priority))))))),
|
|
558
|
+
engagementRecs.length > 0 && (react_1.default.createElement("div", { className: "mb-4" },
|
|
559
|
+
react_1.default.createElement("div", { className: "text-[13px] font-bold text-white uppercase tracking-widest font-tax-axis-head mb-3" }, "CPA Engagement Notes"),
|
|
560
|
+
react_1.default.createElement("div", { className: "flex flex-col gap-3" }, engagementRecs.map((rec, i) => {
|
|
561
|
+
const colonIdx = rec.indexOf(":");
|
|
562
|
+
const hasLabel = colonIdx > 0 && colonIdx < 60;
|
|
563
|
+
const label = hasLabel ? rec.slice(0, colonIdx).trim() : null;
|
|
564
|
+
const body = hasLabel ? rec.slice(colonIdx + 1).trim() : rec;
|
|
565
|
+
return (react_1.default.createElement("div", { key: i, className: "rounded-[10px] p-4", style: {
|
|
566
|
+
background: "#0E1132",
|
|
567
|
+
border: "1px solid rgba(36,131,132,0.12)",
|
|
568
|
+
borderLeft: "3px solid rgba(36,131,132,0.4)",
|
|
569
|
+
} },
|
|
570
|
+
label && (react_1.default.createElement("div", { className: "text-xs font-semibold tracking-wide text-tax-axis-teal-light font-tax-axis-mono mb-1.5 uppercase" }, label)),
|
|
571
|
+
react_1.default.createElement("div", { className: "text-[12px] text-tax-axis-text leading-[1.7] font-tax-axis-body" }, body)));
|
|
572
|
+
})))),
|
|
573
|
+
nexusFlags.length > 0 && (react_1.default.createElement("div", { className: "rounded-[14px] mb-4", style: { background: "#0E1132", border: "1px solid rgba(36,131,132,0.12)", padding: "16px 20px" } },
|
|
574
|
+
react_1.default.createElement("div", { className: "text-[11px] font-bold text-white uppercase tracking-widest font-tax-axis-mono mb-2" }, "State Nexus"),
|
|
575
|
+
nexusFlags.map((f, i) => (react_1.default.createElement("div", { key: i, className: "text-[12px] text-tax-axis-text-2 font-tax-axis-body py-1.5", style: { borderTop: i > 0 ? "1px solid rgba(36,131,132,0.08)" : "none" } },
|
|
576
|
+
react_1.default.createElement("span", { className: "font-semibold text-tax-axis-teal-light mr-2" }, f.state),
|
|
577
|
+
f.flag_text))))),
|
|
578
|
+
riskDisclosures.length > 0 && (react_1.default.createElement("div", { className: "rounded-[14px] mb-4 overflow-hidden", style: { background: "rgba(251,154,29,0.04)", border: "1px solid rgba(251,154,29,0.15)" } },
|
|
579
|
+
react_1.default.createElement("div", { className: "px-5 py-3.5 flex items-center justify-between cursor-pointer", onClick: () => setRiskExpanded(p => !p) },
|
|
580
|
+
react_1.default.createElement("span", { className: "text-[13px] text-tax-axis-text-2 font-tax-axis-body" }, "Risk disclosures & IRC \u00A76694 notices"),
|
|
581
|
+
react_1.default.createElement("svg", { width: "12", height: "12", viewBox: "0 0 12 12", fill: "none", style: { transform: riskExpanded ? "rotate(180deg)" : "none", transition: "transform .2s" } },
|
|
582
|
+
react_1.default.createElement("path", { d: "M3 4.5l3 3 3-3", stroke: "#9498B8", strokeWidth: "1.5", strokeLinecap: "round" }))),
|
|
583
|
+
riskExpanded && (react_1.default.createElement("div", { style: { borderTop: "1px solid rgba(251,154,29,0.12)", padding: "12px 20px" } }, riskDisclosures.map((r, i) => (react_1.default.createElement("div", { key: i, className: "text-[11px] text-tax-axis-text-2 font-tax-axis-body py-1.5", style: { borderTop: i > 0 ? "1px solid rgba(251,154,29,0.08)" : "none" } }, r))))))),
|
|
584
|
+
excludedStrategies.length > 0 && (react_1.default.createElement("div", { className: "rounded-[14px] mb-4 overflow-hidden", style: { background: "#0E1132", border: "1px solid rgba(148,152,184,0.15)" } },
|
|
585
|
+
react_1.default.createElement("div", { className: "px-5 py-3.5 flex items-center justify-between cursor-pointer", onClick: () => setExcludedExpanded(p => !p) },
|
|
586
|
+
react_1.default.createElement("span", { className: "text-[13px] text-tax-axis-text-2 font-tax-axis-body" },
|
|
587
|
+
excludedStrategies.length,
|
|
588
|
+
" strategies screened \u2014 not applicable to this client"),
|
|
589
|
+
react_1.default.createElement("svg", { width: "12", height: "12", viewBox: "0 0 12 12", fill: "none", style: { transform: excludedExpanded ? "rotate(180deg)" : "none", transition: "transform .2s" } },
|
|
590
|
+
react_1.default.createElement("path", { d: "M3 4.5l3 3 3-3", stroke: "#9498B8", strokeWidth: "1.5", strokeLinecap: "round" }))),
|
|
591
|
+
excludedExpanded && (react_1.default.createElement("div", { style: { borderTop: "1px solid rgba(148,152,184,0.1)" } }, excludedStrategies.map((ex, i) => (react_1.default.createElement("div", { key: i, className: "px-5 py-2.5 flex items-start gap-3", style: { borderTop: i > 0 ? "1px solid rgba(148,152,184,0.08)" : "none" } },
|
|
592
|
+
react_1.default.createElement("span", { className: "text-[10px] font-semibold font-tax-axis-mono text-tax-axis-text-3 bg-tax-axis-surface px-2 py-0.5 rounded flex-shrink-0 mt-0.5" }, ex.strategy_id),
|
|
593
|
+
react_1.default.createElement("div", { className: "flex-1" },
|
|
594
|
+
react_1.default.createElement("div", { className: "text-[11px] text-tax-axis-text-2 font-tax-axis-body" }, ex.reason),
|
|
595
|
+
ex.irs_cite && (react_1.default.createElement("div", { className: "text-[10px] text-tax-axis-text-3 font-tax-axis-mono mt-0.5" }, ex.irs_cite)))))))))),
|
|
596
|
+
react_1.default.createElement("div", { className: "tax-axis-no-print" },
|
|
287
597
|
react_1.default.createElement(TaxAxisButton_1.TaxAxisButton, { onClick: onDownloadPreparer, className: "w-full" }, "Download Full Preparer Report")))) : (
|
|
288
598
|
/* ═══ CLIENT SUMMARY — Timeline View ═══ */
|
|
289
599
|
react_1.default.createElement("div", null,
|
|
290
|
-
react_1.default.createElement("p", { className: "text-sm text-tax-axis-text leading-[1.7] mb-6 font-tax-axis-body" },
|
|
600
|
+
clientSummaryOpening ? (react_1.default.createElement("div", { className: "rounded-[10px] mb-5 text-[12px] text-tax-axis-text leading-[1.7] font-tax-axis-body", style: { background: "rgba(36,131,132,0.04)", border: "1px solid rgba(36,131,132,0.1)", padding: "14px 16px" } }, clientSummaryOpening)) : (react_1.default.createElement("p", { className: "text-sm text-tax-axis-text leading-[1.7] mb-6 font-tax-axis-body" },
|
|
291
601
|
profile.bizName || "Client",
|
|
292
602
|
", here's your action plan organized by urgency.",
|
|
293
603
|
" ",
|
|
@@ -295,7 +605,13 @@ function TaxAxisDashboard({ profile, onDownloadClient, onDownloadPreparer, onPre
|
|
|
295
605
|
dashEligible.length,
|
|
296
606
|
" strategies"),
|
|
297
607
|
" ",
|
|
298
|
-
"identified."),
|
|
608
|
+
"identified.")),
|
|
609
|
+
dataQualityNote && (react_1.default.createElement("div", { className: "rounded-[10px] mb-5 text-[11px] text-tax-axis-text-2 font-tax-axis-body flex items-start gap-2", style: { background: "rgba(251,154,29,0.04)", border: "1px solid rgba(251,154,29,0.15)", padding: "10px 14px" } },
|
|
610
|
+
react_1.default.createElement("svg", { width: "12", height: "12", viewBox: "0 0 12 12", fill: "none", className: "flex-shrink-0 mt-0.5" },
|
|
611
|
+
react_1.default.createElement("circle", { cx: "6", cy: "6", r: "5", stroke: "#FB9A1D", strokeWidth: "1" }),
|
|
612
|
+
react_1.default.createElement("path", { d: "M6 4v2.5M6 8h.005", stroke: "#FB9A1D", strokeWidth: "1", strokeLinecap: "round" })),
|
|
613
|
+
dataQualityNote)),
|
|
614
|
+
interactionWarning && (react_1.default.createElement("div", { className: "rounded-[10px] mb-5 text-[11px] text-tax-axis-text-2 font-tax-axis-body", style: { background: "rgba(251,154,29,0.04)", border: "1px solid rgba(251,154,29,0.15)", padding: "10px 14px" } }, interactionWarning)),
|
|
299
615
|
BUCKETS.map(({ key, label, desc }) => {
|
|
300
616
|
const items = dashEligible.filter((s) => s.timelineBucket === key);
|
|
301
617
|
if (!items.length)
|
|
@@ -344,7 +660,10 @@ function TaxAxisDashboard({ profile, onDownloadClient, onDownloadPreparer, onPre
|
|
|
344
660
|
s.cost && s.cost !== "$0" && (react_1.default.createElement("span", { className: "text-[11px] font-semibold font-tax-axis-mono", style: { color: "#FB9A1D" } }, s.cost)))));
|
|
345
661
|
})));
|
|
346
662
|
}),
|
|
347
|
-
react_1.default.createElement(
|
|
348
|
-
|
|
663
|
+
react_1.default.createElement("div", { className: "tax-axis-no-print" },
|
|
664
|
+
react_1.default.createElement(TaxAxisButton_1.TaxAxisButton, { onClick: onDownloadClient, className: "w-full mt-1.5" }, "Download Client Summary")),
|
|
665
|
+
clientSummaryClosing && (react_1.default.createElement("div", { className: "mt-4 text-[11px] text-tax-axis-text-3 leading-[1.65] font-tax-axis-body", style: { borderTop: "1px solid rgba(36,131,132,0.08)", paddingTop: 14 } }, clientSummaryClosing)))),
|
|
666
|
+
react_1.default.createElement("div", { className: "tax-axis-no-print" },
|
|
667
|
+
react_1.default.createElement(DashboardActions_1.DashboardActions, { profile: profile, dashEligible: dashEligible, computed: computed, onDownloadPreparer: onDownloadPreparer, onPresent: onPresent, onSend: onSend, onReset: onReset })))),
|
|
349
668
|
enrichedSelected && (react_1.default.createElement(StrategyDetailPanel_1.StrategyDetailPanel, { s: enrichedSelected, profile: profile, computed: computed, onClose: () => setSelected(null) }))));
|
|
350
669
|
}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { DocSpec } from "../../lib/types";
|
|
3
|
-
export type DocStatus = "empty" | "validating" | "valid";
|
|
3
|
+
export type DocStatus = "empty" | "validating" | "parsing" | "failed" | "valid";
|
|
4
4
|
export interface DocState extends DocSpec {
|
|
5
5
|
status: DocStatus;
|
|
6
6
|
fileName: string | null;
|
|
7
|
+
parseError?: string | null;
|
|
8
|
+
qboSource?: boolean;
|
|
7
9
|
}
|
|
8
10
|
interface DocumentCardProps {
|
|
9
11
|
doc: DocState;
|
|
@@ -12,9 +14,10 @@ interface DocumentCardProps {
|
|
|
12
14
|
tierBadgeText: string;
|
|
13
15
|
helpOverride?: string;
|
|
14
16
|
fieldCount?: number;
|
|
15
|
-
onUpload: () => void;
|
|
17
|
+
onUpload: (file: File) => void;
|
|
16
18
|
onClear: () => void;
|
|
19
|
+
onRemove?: () => void;
|
|
17
20
|
onReview?: () => void;
|
|
18
21
|
}
|
|
19
|
-
export declare function DocumentCard({ doc, tierBorderColor, tierBadgeColor, tierBadgeText, helpOverride, fieldCount, onUpload, onClear, onReview, }: DocumentCardProps): React.JSX.Element;
|
|
22
|
+
export declare function DocumentCard({ doc, tierBorderColor, tierBadgeColor, tierBadgeText, helpOverride, fieldCount, onUpload, onClear, onRemove, onReview, }: DocumentCardProps): React.JSX.Element;
|
|
20
23
|
export {};
|