@paro.io/expert-shared-components 1.14.56 → 1.14.59
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 +1 -0
- package/lib/components/TaxAxis/TaxAxisShell.d.ts +1 -1
- package/lib/components/TaxAxis/TaxAxisShell.js +52 -2
- package/lib/components/TaxAxis/types.d.ts +5 -0
- package/lib/tax-axis/components/clientReport/Methodology.js +2 -2
- package/lib/tax-axis/components/dashboard/DashboardActions.js +4 -4
- package/lib/tax-axis/components/dashboard/DashboardSummary.js +5 -6
- package/lib/tax-axis/components/dashboard/StrategyDetailPanel.js +2 -4
- package/lib/tax-axis/components/dashboard/TaxAxisDashboard.js +162 -57
- package/lib/tax-axis/components/documents/DocumentCard.d.ts +1 -0
- package/lib/tax-axis/components/documents/DocumentCard.js +19 -3
- package/lib/tax-axis/components/documents/TaxAxisDocuments.d.ts +12 -1
- package/lib/tax-axis/components/documents/TaxAxisDocuments.js +110 -48
- 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 +1 -1
- package/lib/tax-axis/components/intake/CpaIntakeQuestionsSection.js +3 -3
- package/lib/tax-axis/components/intake/IntakeCtaCards.js +1 -1
- package/lib/tax-axis/components/intake/RefineAnalysisSection.js +7 -7
- package/lib/tax-axis/components/intake/TaxAxisIntake.js +2 -2
- package/lib/tax-axis/components/processing/TaxAxisProcessing.js +30 -5
- package/package.json +1 -1
|
@@ -54,4 +54,5 @@ export type TaxAxisApi = {
|
|
|
54
54
|
updateReport: (reportId: string, reviewedReport: Record<string, unknown>) => Promise<any>;
|
|
55
55
|
generatePdf: (sessionId: string) => Promise<any>;
|
|
56
56
|
getArtifacts: (sessionId: string) => Promise<any[]>;
|
|
57
|
+
importQboReport?: (sessionId: string, expertId: string, year: number, reportType: string) => Promise<any>;
|
|
57
58
|
};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { TaxAxisShellProps } from './types';
|
|
2
|
-
export declare const TaxAxisShell: ({ taxAxisApi, userContext, initialSessionId, initialProfile, onSessionChange, documentUploadUrl, uploadBucketName, sessionDefaults, }: TaxAxisShellProps) => JSX.Element;
|
|
2
|
+
export declare const TaxAxisShell: ({ taxAxisApi, userContext, initialSessionId, initialProfile, onSessionChange, documentUploadUrl, uploadBucketName, sessionDefaults, qboAuthorizeUrl, expertId, qboConnected, qboCompanyName, }: TaxAxisShellProps) => JSX.Element;
|
|
3
3
|
export default TaxAxisShell;
|
|
@@ -135,7 +135,7 @@ function ShellContainer({ children, fullWidth = false, }) {
|
|
|
135
135
|
return (react_1.default.createElement("div", { className: 'min-h-screen bg-tax-axis-navy text-white font-tax-axis-body' },
|
|
136
136
|
react_1.default.createElement("div", { className: 'max-w-[960px] mx-auto px-5 py-7' }, children)));
|
|
137
137
|
}
|
|
138
|
-
const TaxAxisShell = ({ taxAxisApi, userContext = 'expert', initialSessionId, initialProfile, onSessionChange, documentUploadUrl, uploadBucketName, sessionDefaults, }) => {
|
|
138
|
+
const TaxAxisShell = ({ taxAxisApi, userContext = 'expert', initialSessionId, initialProfile, onSessionChange, documentUploadUrl, uploadBucketName, sessionDefaults, qboAuthorizeUrl, expertId, qboConnected, qboCompanyName, }) => {
|
|
139
139
|
const [step, setStep] = (0, react_1.useState)('SESSION_SETUP');
|
|
140
140
|
const [profile, setProfile] = (0, react_1.useState)(initialProfile ? Object.assign({}, initialProfile) : null);
|
|
141
141
|
const [sessionId, setSessionId] = (0, react_1.useState)(initialSessionId || null);
|
|
@@ -147,6 +147,12 @@ const TaxAxisShell = ({ taxAxisApi, userContext = 'expert', initialSessionId, in
|
|
|
147
147
|
const [busyMessage, setBusyMessage] = (0, react_1.useState)('Syncing Tax Axis session...');
|
|
148
148
|
const [reportReady, setReportReady] = (0, react_1.useState)(false);
|
|
149
149
|
const isPollingRef = react_1.default.useRef(false);
|
|
150
|
+
// QBO state driven by EPS props — not localStorage
|
|
151
|
+
const [qboConnectedState, setQboConnectedState] = (0, react_1.useState)(!!qboConnected);
|
|
152
|
+
const [qboCompanyNameState, setQboCompanyNameState] = (0, react_1.useState)(qboCompanyName !== null && qboCompanyName !== void 0 ? qboCompanyName : null);
|
|
153
|
+
// Sync if parent re-fetches EPS data
|
|
154
|
+
react_1.default.useEffect(() => { setQboConnectedState(!!qboConnected); }, [qboConnected]);
|
|
155
|
+
react_1.default.useEffect(() => { setQboCompanyNameState(qboCompanyName !== null && qboCompanyName !== void 0 ? qboCompanyName : null); }, [qboCompanyName]);
|
|
150
156
|
// Derive live strategies from engineOutput so CLIENT_REPORT and PREPARER_WORKPAPER
|
|
151
157
|
// render real engine data instead of the static STRATEGIES catalog.
|
|
152
158
|
const engineOutput = (0, react_1.useMemo)(() => { var _a; return (_a = llmResult === null || llmResult === void 0 ? void 0 : llmResult.engineOutput) !== null && _a !== void 0 ? _a : null; }, [llmResult]);
|
|
@@ -300,6 +306,17 @@ const TaxAxisShell = ({ taxAxisApi, userContext = 'expert', initialSessionId, in
|
|
|
300
306
|
const handleDeleteDocument = (0, react_1.useCallback)((documentId) => __awaiter(void 0, void 0, void 0, function* () {
|
|
301
307
|
yield taxAxisApi.deleteDocument(documentId);
|
|
302
308
|
}), [taxAxisApi]);
|
|
309
|
+
const handleImportQboReport = (0, react_1.useCallback)((sid, _realmId, reportType, _accountingMethod, year) => __awaiter(void 0, void 0, void 0, function* () {
|
|
310
|
+
var _a;
|
|
311
|
+
if (!taxAxisApi.importQboReport) {
|
|
312
|
+
throw new Error('QBO import is not available.');
|
|
313
|
+
}
|
|
314
|
+
if (!expertId) {
|
|
315
|
+
throw new Error('Expert ID is required for QBO import.');
|
|
316
|
+
}
|
|
317
|
+
const taxYear = (_a = year !== null && year !== void 0 ? year : Number(profile === null || profile === void 0 ? void 0 : profile.year)) !== null && _a !== void 0 ? _a : new Date().getFullYear();
|
|
318
|
+
return taxAxisApi.importQboReport(sid, expertId, taxYear, reportType);
|
|
319
|
+
}), [taxAxisApi, expertId, profile]);
|
|
303
320
|
const pollForResult = (0, react_1.useCallback)((sid) => __awaiter(void 0, void 0, void 0, function* () {
|
|
304
321
|
const POLL_INTERVAL_MS = 4000;
|
|
305
322
|
const MAX_ATTEMPTS = 4500; // 300 minutes max
|
|
@@ -409,6 +426,28 @@ const TaxAxisShell = ({ taxAxisApi, userContext = 'expert', initialSessionId, in
|
|
|
409
426
|
react_1.default.createElement(TaxAxisProspectReport_1.TaxAxisProspectReport, { profile: profile, userContext: userContext, onUpgrade: () => setStep('DOCUMENT_UPLOAD'), onPresent: () => setStep('PRESENTATION'), onReset: handleReset })));
|
|
410
427
|
case 'DOCUMENT_UPLOAD':
|
|
411
428
|
return (react_1.default.createElement(ShellContainer, null,
|
|
429
|
+
react_1.default.createElement("div", { className: "flex items-center justify-between rounded-lg px-4 py-3 mb-5", style: {
|
|
430
|
+
background: '#1A1F3A',
|
|
431
|
+
border: '1px solid #2E3160',
|
|
432
|
+
} },
|
|
433
|
+
react_1.default.createElement("div", { className: "flex items-center gap-3 min-w-0" },
|
|
434
|
+
react_1.default.createElement("span", { className: "text-[14px] font-semibold text-white font-tax-axis-body truncate max-w-[160px] sm:max-w-none" }, profile.bizName || 'Untitled Client'),
|
|
435
|
+
profile.entity && (react_1.default.createElement("span", { className: "text-[10px] font-semibold font-tax-axis-mono flex-shrink-0", style: {
|
|
436
|
+
padding: '2px 8px',
|
|
437
|
+
borderRadius: 4,
|
|
438
|
+
background: 'rgba(36,131,132,0.10)',
|
|
439
|
+
border: '1px solid rgba(36,131,132,0.25)',
|
|
440
|
+
color: '#A1E5E6',
|
|
441
|
+
letterSpacing: '0.03em',
|
|
442
|
+
} }, profile.entity)),
|
|
443
|
+
profile.year && (react_1.default.createElement("span", { className: "hidden sm:inline text-[12px] text-tax-axis-text-3 font-tax-axis-body flex-shrink-0" },
|
|
444
|
+
"TY ",
|
|
445
|
+
profile.year))),
|
|
446
|
+
react_1.default.createElement("button", { onClick: () => isProspectFlow ? setStep('PROSPECT_REPORT') : setStep('SESSION_SETUP'), className: "text-[11px] font-semibold font-tax-axis-mono cursor-pointer flex-shrink-0 rounded-md px-3 py-1", style: {
|
|
447
|
+
background: 'rgba(99,102,241,0.12)',
|
|
448
|
+
border: '1px solid rgba(99,102,241,0.30)',
|
|
449
|
+
color: '#a5b4fc',
|
|
450
|
+
} }, "Edit")),
|
|
412
451
|
react_1.default.createElement(TaxAxisDocuments_1.TaxAxisDocuments, { key: sessionId || 'new', profile: profile, entityType: entityTypeKey(profile.entity), userContext: userContext, onUploadDocument: handleUploadDocument, onDeleteDocument: handleDeleteDocument, fetchUploadedDocuments: () => __awaiter(void 0, void 0, void 0, function* () {
|
|
413
452
|
const ensuredSessionId = sessionId || (profile ? yield createSessionIfNeeded(profile) : null);
|
|
414
453
|
if (!ensuredSessionId) {
|
|
@@ -430,7 +469,13 @@ const TaxAxisShell = ({ taxAxisApi, userContext = 'expert', initialSessionId, in
|
|
|
430
469
|
});
|
|
431
470
|
}), jobId: sessionId || undefined, onSaveReviewedField: (documentId, reviewedData) => __awaiter(void 0, void 0, void 0, function* () {
|
|
432
471
|
yield taxAxisApi.saveReviewedData(documentId, reviewedData);
|
|
433
|
-
}), onContinue: handleAnalyzeDocuments, onBack: () => isProspectFlow ? setStep('PROSPECT_REPORT') : setStep('SESSION_SETUP')
|
|
472
|
+
}), onContinue: handleAnalyzeDocuments, onBack: () => isProspectFlow ? setStep('PROSPECT_REPORT') : setStep('SESSION_SETUP'), qboConnected: qboConnectedState, qboCompanyName: qboCompanyNameState, qboAuthorizeUrl: qboAuthorizeUrl, qboClientConfirmed: qboConnectedState, onImportQboReport: taxAxisApi.importQboReport ? handleImportQboReport : undefined, onQboConnected: (companyName) => {
|
|
473
|
+
setQboConnectedState(true);
|
|
474
|
+
setQboCompanyNameState(companyName);
|
|
475
|
+
}, onQboDisconnected: () => {
|
|
476
|
+
setQboConnectedState(false);
|
|
477
|
+
setQboCompanyNameState(null);
|
|
478
|
+
} })));
|
|
434
479
|
case 'PROCESSING':
|
|
435
480
|
return (react_1.default.createElement(ShellContainer, null,
|
|
436
481
|
react_1.default.createElement(TaxAxisProcessing_1.TaxAxisProcessing, { profile: profile, userContext: userContext, reportReady: reportReady, onComplete: () => setStep('DASHBOARD') })));
|
|
@@ -469,6 +514,11 @@ const TaxAxisShell = ({ taxAxisApi, userContext = 'expert', initialSessionId, in
|
|
|
469
514
|
adapted,
|
|
470
515
|
reportReady,
|
|
471
516
|
parsedDocuments,
|
|
517
|
+
qboConnectedState,
|
|
518
|
+
qboCompanyNameState,
|
|
519
|
+
qboAuthorizeUrl,
|
|
520
|
+
expertId,
|
|
521
|
+
handleImportQboReport,
|
|
472
522
|
]);
|
|
473
523
|
return (react_1.default.createElement(react_1.default.Fragment, null,
|
|
474
524
|
error && (react_1.default.createElement("div", { className: 'fixed right-4 top-4 z-[200] max-w-sm rounded-lg border border-red-500/30 bg-tax-axis-surface px-4 py-3 text-xs text-red-200 shadow-lg' },
|
|
@@ -10,13 +10,13 @@ const SectionOpener_1 = require("./SectionOpener");
|
|
|
10
10
|
function Methodology({ profile, eligible, palette }) {
|
|
11
11
|
return (react_1.default.createElement(react_1.default.Fragment, null,
|
|
12
12
|
react_1.default.createElement(SectionOpener_1.SectionOpener, { number: "04", eyebrow: "METHODOLOGY", headline: "How TaxAxis arrives at these numbers.", bullets: [
|
|
13
|
-
"25 federal strategies evaluated against your profile
|
|
13
|
+
"25 federal strategies evaluated against your profile through a two-stage AI and deterministic pipeline \u2014 every recommendation traces to a specific IRC section, revenue ruling, or OBBBA provision.",
|
|
14
14
|
"Confidence bands reflect data quality: \u00B130% on single-year data, narrowing to \u00B115% with multi-year history.",
|
|
15
15
|
"Aggregate savings on the cover chart are adjusted by an interaction-discount factor reflecting strategy stacking, marginal-rate exhaustion, and \u00A76694 reasonableness.",
|
|
16
16
|
], palette: palette }),
|
|
17
17
|
react_1.default.createElement("div", { style: { marginBottom: 28 } },
|
|
18
18
|
react_1.default.createElement("div", { style: { fontSize: 10, fontWeight: 700, textTransform: "uppercase", letterSpacing: "0.12em", color: palette.gray400, fontFamily: palette.mono, marginBottom: 8 } }, "EVAL PIPELINE"),
|
|
19
|
-
react_1.default.createElement("div", { style: { fontSize: 13, color: palette.gray700, lineHeight: 1.8, fontFamily: palette.body } }, "TaxAxis evaluates 25 federal tax strategies against each client profile.
|
|
19
|
+
react_1.default.createElement("div", { style: { fontSize: 13, color: palette.gray700, lineHeight: 1.8, fontFamily: palette.body } }, "TaxAxis evaluates 25 federal tax strategies against each client profile through a two-stage pipeline. An AI model (Claude Sonnet 4.5 via AWS Bedrock) reads your financial documents, identifies applicable strategies, and drafts narrative content. A deterministic post-processing engine then recomputes savings ranges against IRC-cited rules, corrects confidence bands based on data quality, and validates every output through an 8-gate compliance check \u2014 covering schema integrity, strategy coverage, profile consistency, mathematical accuracy, business rules, \u00A76694 compliance, narrative quality, and entity eligibility. Every recommendation is reviewed by a qualified tax professional before the report is issued.")),
|
|
20
20
|
react_1.default.createElement("div", { style: { marginBottom: 28 } },
|
|
21
21
|
react_1.default.createElement("div", { style: { fontSize: 10, fontWeight: 700, textTransform: "uppercase", letterSpacing: "0.12em", color: palette.gray400, fontFamily: palette.mono, marginBottom: 8 } }, "CONFIDENCE BANDS"),
|
|
22
22
|
react_1.default.createElement("div", { style: { fontSize: 13, color: palette.gray700, lineHeight: 1.8, fontFamily: palette.body, marginBottom: 12 } }, "Savings ranges reflect data quality. Clients who provide multiple years of financial history receive tighter bands of \u00B115%, because multi-year data reveals trends and reduces estimation variance. Single-year data widens the bands to \u00B130%. Within each band, the low estimate uses conservative inputs at the minimum applicable rate, while the high estimate uses full applicable inputs at the client's marginal rate."),
|
|
@@ -70,10 +70,10 @@ function DashboardActions({ profile, dashEligible, computed, onDownloadPreparer,
|
|
|
70
70
|
"across ",
|
|
71
71
|
dashEligible.length,
|
|
72
72
|
" strategies \u2014 use this to close the engagement or expand scope."),
|
|
73
|
-
react_1.default.createElement("div", { className: "flex gap-2.5 flex-wrap" },
|
|
74
|
-
react_1.default.createElement(TaxAxisButton_1.TaxAxisButton, { variant: "orange", onClick: onSend }, "Send Report to Client"),
|
|
75
|
-
react_1.default.createElement(TaxAxisButton_1.TaxAxisButton, { onClick: onPresent }, "Present to Client"),
|
|
76
|
-
react_1.default.createElement(TaxAxisButton_1.TaxAxisButton, { variant: "secondary" }, "Generate Engagement Letter")))),
|
|
73
|
+
react_1.default.createElement("div", { className: "flex flex-col sm:flex-row gap-2.5 flex-wrap" },
|
|
74
|
+
react_1.default.createElement(TaxAxisButton_1.TaxAxisButton, { variant: "orange", onClick: onSend, className: "w-full sm:w-auto" }, "Send Report to Client"),
|
|
75
|
+
react_1.default.createElement(TaxAxisButton_1.TaxAxisButton, { onClick: onPresent, className: "w-full sm:w-auto" }, "Present to Client"),
|
|
76
|
+
react_1.default.createElement(TaxAxisButton_1.TaxAxisButton, { variant: "secondary", className: "w-full sm:w-auto" }, "Generate Engagement Letter")))),
|
|
77
77
|
react_1.default.createElement("div", { className: "flex gap-4 mt-4 pt-3.5", style: { borderTop: "1px solid rgba(36,131,132,0.15)" } }, [
|
|
78
78
|
{ v: "3x", l: "Faster than Manual" },
|
|
79
79
|
{ v: String(dashEligible.length), l: "Strategies Found" },
|
|
@@ -23,10 +23,9 @@ function DashboardSummary({ profile, dashEligible, computed, dataConfirmed, revi
|
|
|
23
23
|
const fmtHero = (k) => k >= 1000 ? "$" + (k / 1000).toFixed(1) + "M" : "$" + k + "K";
|
|
24
24
|
const riskVal = parseInt(profile.riskTolerance) || 3;
|
|
25
25
|
const riskLabels = ["", "Very Conservative", "Conservative", "Moderate", "Aggressive", "Very Aggressive"];
|
|
26
|
-
return (react_1.default.createElement("div", { className: "relative overflow-hidden rounded-2xl mb-5", style: {
|
|
26
|
+
return (react_1.default.createElement("div", { className: "relative overflow-hidden rounded-2xl mb-5 p-4 sm:p-8", style: {
|
|
27
27
|
background: "radial-gradient(ellipse at 30% 0%, rgba(36,131,132,0.08) 0%, transparent 60%), #0E1132",
|
|
28
28
|
border: "1px solid rgba(36,131,132,0.12)",
|
|
29
|
-
padding: "32px 32px 28px",
|
|
30
29
|
boxShadow: "0 4px 20px rgba(6,8,33,0.3)",
|
|
31
30
|
} },
|
|
32
31
|
react_1.default.createElement("div", { className: "absolute inset-0 opacity-[0.02]", style: {
|
|
@@ -79,13 +78,13 @@ function DashboardSummary({ profile, dashEligible, computed, dataConfirmed, revi
|
|
|
79
78
|
profile.cpaName && (react_1.default.createElement("div", { className: "text-xs text-tax-axis-text-3 mt-1" },
|
|
80
79
|
"Preparer: ",
|
|
81
80
|
profile.cpaName)),
|
|
82
|
-
react_1.default.createElement("div", { className: "flex gap-6 mt-[22px] pt-[18px]", style: { borderTop: "1px solid rgba(36,131,132,0.12)" } }, [
|
|
83
|
-
{ v:
|
|
81
|
+
react_1.default.createElement("div", { className: "grid grid-cols-2 gap-4 sm:flex sm:gap-6 mt-[22px] pt-[18px]", style: { borderTop: "1px solid rgba(36,131,132,0.12)" } }, [
|
|
82
|
+
{ v: confidenceTier ? confidenceTier.replace(/-DATA$/, "").replace(/-/g, " ") : "—", u: "", l: "Confidence Tier", warn: false, ok: !!confidenceTier },
|
|
84
83
|
{ v: String(strategyCount), u: "", l: "Strategies Identified", warn: false, ok: false },
|
|
85
84
|
{
|
|
86
|
-
v: dataConfirmed ? "
|
|
85
|
+
v: dataConfirmed ? "Verified" : String(reviewUnreviewed),
|
|
87
86
|
u: "",
|
|
88
|
-
l:
|
|
87
|
+
l: "Data Quality",
|
|
89
88
|
warn: !dataConfirmed && reviewUnreviewed > 0,
|
|
90
89
|
ok: dataConfirmed,
|
|
91
90
|
},
|
|
@@ -103,13 +103,11 @@ function StrategyDetailPanel({ s, profile: _profile, computed, onClose }) {
|
|
|
103
103
|
const { savingsSection, cpaSection } = splitEngagementText(s.abstract || "");
|
|
104
104
|
return (react_1.default.createElement(react_1.default.Fragment, null,
|
|
105
105
|
react_1.default.createElement("div", { onClick: onClose, className: "fixed inset-0 z-[200]", style: { background: "rgba(6,8,33,0.7)", backdropFilter: "blur(4px)" } }),
|
|
106
|
-
react_1.default.createElement("div", { className: "fixed top-0 right-0 bottom-0 z-[201] flex flex-col", style: {
|
|
107
|
-
width: 520,
|
|
108
|
-
maxWidth: "calc(100vw - 24px)",
|
|
106
|
+
react_1.default.createElement("div", { className: "fixed bottom-0 left-0 right-0 md:top-0 md:left-auto md:right-0 md:bottom-0 z-[201] flex flex-col w-full md:w-[520px] max-h-[85vh] md:max-h-none overflow-y-auto border-t border-tax-axis-border md:border-t-0 md:border-l", style: {
|
|
109
107
|
background: "#0E1132",
|
|
110
|
-
borderLeft: "1px solid rgba(36,131,132,0.12)",
|
|
111
108
|
boxShadow: "-8px 0 40px rgba(6,8,33,0.6)",
|
|
112
109
|
} },
|
|
110
|
+
react_1.default.createElement("div", { className: "w-10 h-1 rounded-full bg-tax-axis-text-4 mx-auto my-2 md:hidden" }),
|
|
113
111
|
react_1.default.createElement("div", { className: "px-6 py-5 flex-shrink-0", style: { borderBottom: "1px solid rgba(36,131,132,0.12)" } },
|
|
114
112
|
react_1.default.createElement("div", { className: "flex justify-between items-start mb-3" },
|
|
115
113
|
react_1.default.createElement("div", null,
|
|
@@ -26,12 +26,12 @@ 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");
|
|
30
31
|
const useEngineOutput_1 = require("../../lib/adapters/useEngineOutput");
|
|
31
32
|
const TaxAxisButton_1 = require("../shared/TaxAxisButton");
|
|
32
33
|
const TaxAxisBadge_1 = require("../shared/TaxAxisBadge");
|
|
33
34
|
const DashboardSummary_1 = require("./DashboardSummary");
|
|
34
|
-
const DashboardTopBar_1 = require("./DashboardTopBar");
|
|
35
35
|
const DashboardActions_1 = require("./DashboardActions");
|
|
36
36
|
const StrategyTile_1 = require("./StrategyTile");
|
|
37
37
|
const StrategyDetailPanel_1 = require("./StrategyDetailPanel");
|
|
@@ -97,18 +97,109 @@ function buildRoadmapBucketLookup(llm) {
|
|
|
97
97
|
}
|
|
98
98
|
return map;
|
|
99
99
|
}
|
|
100
|
-
|
|
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) {
|
|
101
151
|
const nameLookup = buildEngineNameLookup(llm);
|
|
102
152
|
const bucketLookup = buildRoadmapBucketLookup(llm);
|
|
153
|
+
const clientSummaryLookup = buildClientSummaryLookup(llm);
|
|
103
154
|
return llm.strategies
|
|
104
155
|
.filter((s) => s.applicable)
|
|
105
156
|
.map((s, idx) => {
|
|
106
|
-
var _a, _b, _c, _d, _e;
|
|
157
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
107
158
|
const id = (_a = s.strategyId) !== null && _a !== void 0 ? _a : s.strategyType;
|
|
108
|
-
// Prefer the real strategy_name from engineOutput, fall back to humanized strategyType
|
|
109
159
|
const name = (_b = nameLookup.get(id)) !== null && _b !== void 0 ? _b : humanizeStrategyType(s.strategyType);
|
|
110
160
|
const timelineBucket = (_c = bucketLookup.get(id)) !== null && _c !== void 0 ? _c : (s.priority === "HIGH" ? "now" : "90d");
|
|
111
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;
|
|
112
203
|
return {
|
|
113
204
|
rank: idx + 1,
|
|
114
205
|
code: id,
|
|
@@ -121,13 +212,18 @@ function mapLlmToStrategies(llm) {
|
|
|
121
212
|
hi: s.estimatedSavings.max,
|
|
122
213
|
timeline: timelineBucket === "now" ? "Act now" : timelineBucket === "30d" ? "Within 30 days" : "Within 90 days",
|
|
123
214
|
timelineBucket,
|
|
124
|
-
clientBrief
|
|
125
|
-
action
|
|
126
|
-
forms: s.requiredForms.join(", "),
|
|
215
|
+
clientBrief,
|
|
216
|
+
action,
|
|
217
|
+
forms: formsFromTrace !== null && formsFromTrace !== void 0 ? formsFromTrace : s.requiredForms.join(", "),
|
|
127
218
|
abstract: s.summary,
|
|
128
219
|
sources: [],
|
|
129
220
|
trace: [],
|
|
130
221
|
cost: undefined,
|
|
222
|
+
sourceDocuments,
|
|
223
|
+
specialistNote,
|
|
224
|
+
positionStrength,
|
|
225
|
+
authority,
|
|
226
|
+
quickWin: s.quickWin,
|
|
131
227
|
};
|
|
132
228
|
});
|
|
133
229
|
}
|
|
@@ -147,7 +243,7 @@ const BUCKETS = [
|
|
|
147
243
|
{ key: "90d", label: "Within 90 Days", desc: "Structural changes — new accounts or plan setup" },
|
|
148
244
|
];
|
|
149
245
|
function TaxAxisDashboard({ profile, llmResult, parsedDocuments, onDownloadClient, onDownloadPreparer, onPresent, onSend, onReset, onReviewData, onUploadMore, userContext: _userContext = "expert", }) {
|
|
150
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u
|
|
246
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u;
|
|
151
247
|
const hasLlm = !!((_a = llmResult === null || llmResult === void 0 ? void 0 : llmResult.strategies) === null || _a === void 0 ? void 0 : _a.length);
|
|
152
248
|
// All live fields from rawOutput — nothing hardcoded
|
|
153
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;
|
|
@@ -177,8 +273,8 @@ function TaxAxisDashboard({ profile, llmResult, parsedDocuments, onDownloadClien
|
|
|
177
273
|
if ((_a = adapted === null || adapted === void 0 ? void 0 : adapted.strategies) === null || _a === void 0 ? void 0 : _a.length)
|
|
178
274
|
return adapted.strategies;
|
|
179
275
|
// Fallback to thin mapping for old payload shapes without engineOutput.
|
|
180
|
-
return mapLlmToStrategies(llmResult);
|
|
181
|
-
}, [hasLlm, adapted, llmResult]);
|
|
276
|
+
return mapLlmToStrategies(llmResult, profile);
|
|
277
|
+
}, [hasLlm, adapted, llmResult, profile]);
|
|
182
278
|
const llmComputed = (0, react_1.useMemo)(() => {
|
|
183
279
|
var _a;
|
|
184
280
|
if (!hasLlm)
|
|
@@ -243,29 +339,25 @@ function TaxAxisDashboard({ profile, llmResult, parsedDocuments, onDownloadClien
|
|
|
243
339
|
return map;
|
|
244
340
|
}, [uncalculated]);
|
|
245
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);
|
|
246
344
|
return (react_1.default.createElement("div", null,
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
react_1.default.createElement("span", { className: "text-tax-axis-text-4" }, (() => {
|
|
262
|
-
var _a, _b;
|
|
263
|
-
const tokens = (_b = (_a = llmResult.meta.totalTokens) !== null && _a !== void 0 ? _a : llmResult.meta.tokenCount) !== null && _b !== void 0 ? _b : 0;
|
|
264
|
-
return tokens > 0 ? `${tokens} tokens` : "";
|
|
265
|
-
})()))),
|
|
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
|
+
`),
|
|
266
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 }),
|
|
267
|
-
react_1.default.createElement(
|
|
268
|
-
topTab === "extraction" && (react_1.default.createElement("div", null,
|
|
360
|
+
false && (react_1.default.createElement("div", null,
|
|
269
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" } },
|
|
270
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" },
|
|
271
363
|
react_1.default.createElement("svg", { width: "12", height: "12", viewBox: "0 0 12 12", fill: "none" },
|
|
@@ -318,8 +410,8 @@ function TaxAxisDashboard({ profile, llmResult, parsedDocuments, onDownloadClien
|
|
|
318
410
|
border: "1px solid rgba(15,110,86,0.25)",
|
|
319
411
|
color: "#0F6E56",
|
|
320
412
|
} }, "View Report"))))),
|
|
321
|
-
|
|
322
|
-
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: {
|
|
323
415
|
padding: "10px 0",
|
|
324
416
|
fontSize: 14,
|
|
325
417
|
fontWeight: reportTab === id ? 600 : 400,
|
|
@@ -369,20 +461,14 @@ function TaxAxisDashboard({ profile, llmResult, parsedDocuments, onDownloadClien
|
|
|
369
461
|
const clo = (_d = (_c = computed.get(s.rank)) === null || _c === void 0 ? void 0 : _c.lo) !== null && _d !== void 0 ? _d : s.lo;
|
|
370
462
|
const w = (chi / maxSavings) * 100;
|
|
371
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) },
|
|
372
|
-
react_1.default.createElement("span", { className:
|
|
373
|
-
fontSize: chartExpanded ? 13 : 12,
|
|
374
|
-
width: chartExpanded ? 180 : 140,
|
|
375
|
-
} }, 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),
|
|
376
465
|
react_1.default.createElement("div", { className: "flex-1 bg-tax-axis-surface-2 rounded-sm overflow-hidden", style: { height: chartExpanded ? 10 : 6 } },
|
|
377
466
|
react_1.default.createElement("div", { className: "h-full rounded-sm", style: {
|
|
378
467
|
width: `${w}%`,
|
|
379
468
|
background: "linear-gradient(90deg, #248384, #A1E5E6)",
|
|
380
469
|
transition: "width 0.8s cubic-bezier(.16,1,.3,1)",
|
|
381
470
|
} })),
|
|
382
|
-
react_1.default.createElement("span", { className:
|
|
383
|
-
fontSize: chartExpanded ? 13 : 12,
|
|
384
|
-
width: chartExpanded ? 100 : 80,
|
|
385
|
-
} },
|
|
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]"}` },
|
|
386
472
|
fmtK(clo),
|
|
387
473
|
"\u2013",
|
|
388
474
|
fmtK(chi))));
|
|
@@ -400,7 +486,7 @@ function TaxAxisDashboard({ profile, llmResult, parsedDocuments, onDownloadClien
|
|
|
400
486
|
dashEligible.length,
|
|
401
487
|
" Strategies"),
|
|
402
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")),
|
|
403
|
-
react_1.default.createElement("div", { className: "grid grid-cols-2 gap-2.5 mb-4" },
|
|
489
|
+
react_1.default.createElement("div", { className: "grid grid-cols-1 sm:grid-cols-2 gap-2.5 mb-4" },
|
|
404
490
|
calculable.map((s, i) => {
|
|
405
491
|
var _a, _b;
|
|
406
492
|
const c = computed.get(s.rank);
|
|
@@ -469,29 +555,46 @@ function TaxAxisDashboard({ profile, llmResult, parsedDocuments, onDownloadClien
|
|
|
469
555
|
react_1.default.createElement("div", { className: "flex items-center gap-2.5" },
|
|
470
556
|
react_1.default.createElement("span", { className: "text-[11px] font-tax-axis-mono text-tax-axis-text-2" }, a.savings),
|
|
471
557
|
react_1.default.createElement(TaxAxisBadge_1.TaxAxisBadge, { color: a.priority === "MEDIUM" ? "orange" : "neutral", size: "xs" }, a.priority))))))),
|
|
472
|
-
engagementRecs.length > 0 && (react_1.default.createElement("div", { className: "
|
|
473
|
-
react_1.default.createElement("div", { className: "
|
|
474
|
-
|
|
475
|
-
|
|
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
|
+
})))),
|
|
476
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" } },
|
|
477
574
|
react_1.default.createElement("div", { className: "text-[11px] font-bold text-white uppercase tracking-widest font-tax-axis-mono mb-2" }, "State Nexus"),
|
|
478
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" } },
|
|
479
576
|
react_1.default.createElement("span", { className: "font-semibold text-tax-axis-teal-light mr-2" }, f.state),
|
|
480
577
|
f.flag_text))))),
|
|
481
|
-
riskDisclosures.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.15)"
|
|
482
|
-
react_1.default.createElement("div", { className: "
|
|
483
|
-
|
|
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))))))),
|
|
484
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)" } },
|
|
485
|
-
react_1.default.createElement("div", { className: "px-5 py-3.5",
|
|
486
|
-
react_1.default.createElement("span", { className: "text-[13px]
|
|
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" },
|
|
487
587
|
excludedStrategies.length,
|
|
488
|
-
"
|
|
489
|
-
|
|
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" } },
|
|
490
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),
|
|
491
593
|
react_1.default.createElement("div", { className: "flex-1" },
|
|
492
594
|
react_1.default.createElement("div", { className: "text-[11px] text-tax-axis-text-2 font-tax-axis-body" }, ex.reason),
|
|
493
|
-
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)))))))),
|
|
494
|
-
react_1.default.createElement(
|
|
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" },
|
|
597
|
+
react_1.default.createElement(TaxAxisButton_1.TaxAxisButton, { onClick: onDownloadPreparer, className: "w-full" }, "Download Full Preparer Report")))) : (
|
|
495
598
|
/* ═══ CLIENT SUMMARY — Timeline View ═══ */
|
|
496
599
|
react_1.default.createElement("div", null,
|
|
497
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" },
|
|
@@ -557,8 +660,10 @@ function TaxAxisDashboard({ profile, llmResult, parsedDocuments, onDownloadClien
|
|
|
557
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)))));
|
|
558
661
|
})));
|
|
559
662
|
}),
|
|
560
|
-
react_1.default.createElement(
|
|
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")),
|
|
561
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)))),
|
|
562
|
-
react_1.default.createElement(
|
|
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 })))),
|
|
563
668
|
enrichedSelected && (react_1.default.createElement(StrategyDetailPanel_1.StrategyDetailPanel, { s: enrichedSelected, profile: profile, computed: computed, onClose: () => setSelected(null) }))));
|
|
564
669
|
}
|