@paro.io/expert-shared-components 1.14.57 → 1.14.60

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/lib/README.md +2 -0
  2. package/lib/components/DocumentCenter/MultiFileUploadSection.js +121 -220
  3. package/lib/components/TaxAxis/TaxAxisApi.d.ts +2 -0
  4. package/lib/components/TaxAxis/TaxAxisShell.d.ts +1 -1
  5. package/lib/components/TaxAxis/TaxAxisShell.js +104 -5
  6. package/lib/components/TaxAxis/types.d.ts +5 -0
  7. package/lib/components/shared/UploadClient.d.ts +1 -2
  8. package/lib/components/shared/UploadClient.js +2 -6
  9. package/lib/index.d.ts +13 -2
  10. package/lib/index.js +27 -3
  11. package/lib/package.json +68 -0
  12. package/lib/tax-axis/components/clientReport/ExecutiveSummary.d.ts +1 -4
  13. package/lib/tax-axis/components/clientReport/ExecutiveSummary.js +6 -10
  14. package/lib/tax-axis/components/clientReport/Methodology.js +2 -2
  15. package/lib/tax-axis/components/clientReport/RecommendedStrategies.d.ts +1 -6
  16. package/lib/tax-axis/components/clientReport/RecommendedStrategies.js +24 -26
  17. package/lib/tax-axis/components/clientReport/StrategyCard.d.ts +1 -1
  18. package/lib/tax-axis/components/clientReport/StrategyCard.js +23 -39
  19. package/lib/tax-axis/components/clientReport/TaxAxisClientReport.d.ts +2 -8
  20. package/lib/tax-axis/components/clientReport/TaxAxisClientReport.js +7 -9
  21. package/lib/tax-axis/components/dashboard/DashboardActions.js +4 -5
  22. package/lib/tax-axis/components/dashboard/DashboardSummary.d.ts +1 -6
  23. package/lib/tax-axis/components/dashboard/DashboardSummary.js +4 -14
  24. package/lib/tax-axis/components/dashboard/StrategyDetailPanel.d.ts +1 -1
  25. package/lib/tax-axis/components/dashboard/StrategyDetailPanel.js +91 -120
  26. package/lib/tax-axis/components/dashboard/TaxAxisDashboard.d.ts +2 -59
  27. package/lib/tax-axis/components/dashboard/TaxAxisDashboard.js +36 -412
  28. package/lib/tax-axis/components/documents/DocumentCard.d.ts +3 -7
  29. package/lib/tax-axis/components/documents/DocumentCard.js +12 -65
  30. package/lib/tax-axis/components/documents/DocumentTier.d.ts +2 -5
  31. package/lib/tax-axis/components/documents/DocumentTier.js +2 -2
  32. package/lib/tax-axis/components/documents/TaxAxisDocuments.d.ts +1 -25
  33. package/lib/tax-axis/components/documents/TaxAxisDocuments.js +52 -267
  34. package/lib/tax-axis/components/documents/qbo/QboAvailableReportsModal.d.ts +13 -0
  35. package/lib/tax-axis/components/documents/qbo/QboAvailableReportsModal.js +180 -0
  36. package/lib/tax-axis/components/documents/qbo/QboClientSelectorModal.d.ts +10 -0
  37. package/lib/tax-axis/components/documents/qbo/QboClientSelectorModal.js +155 -0
  38. package/lib/tax-axis/components/documents/qbo/QboConnectBanner.d.ts +9 -0
  39. package/lib/tax-axis/components/documents/qbo/QboConnectBanner.js +55 -0
  40. package/lib/tax-axis/components/documents/qbo/QboDocumentMappingModal.d.ts +10 -0
  41. package/lib/tax-axis/components/documents/qbo/QboDocumentMappingModal.js +202 -0
  42. package/lib/tax-axis/components/documents/qbo/QboImportingModal.d.ts +8 -0
  43. package/lib/tax-axis/components/documents/qbo/QboImportingModal.js +75 -0
  44. package/lib/tax-axis/components/documents/qbo/QboPermissionsModal.d.ts +8 -0
  45. package/lib/tax-axis/components/documents/qbo/QboPermissionsModal.js +126 -0
  46. package/lib/tax-axis/components/documents/qbo/index.d.ts +8 -0
  47. package/lib/tax-axis/components/documents/qbo/index.js +17 -0
  48. package/lib/tax-axis/components/documents/qbo/qboConstants.d.ts +24 -0
  49. package/lib/tax-axis/components/documents/qbo/qboConstants.js +71 -0
  50. package/lib/tax-axis/components/documents/qbo/types.d.ts +43 -0
  51. package/lib/tax-axis/components/documents/qbo/types.js +3 -0
  52. package/lib/tax-axis/components/documents/qbo/useQboFlow.d.ts +19 -0
  53. package/lib/tax-axis/components/documents/qbo/useQboFlow.js +207 -0
  54. package/lib/tax-axis/components/extractionReview/TaxAxisExtractionReview.js +17 -17
  55. package/lib/tax-axis/components/intake/ClientParametersSection.js +29 -13
  56. package/lib/tax-axis/components/intake/IntakeCtaCards.d.ts +2 -1
  57. package/lib/tax-axis/components/intake/IntakeCtaCards.js +13 -6
  58. package/lib/tax-axis/components/intake/TaxAxisIntake.js +44 -5
  59. package/lib/tax-axis/components/intake/intakeSchema.d.ts +3 -0
  60. package/lib/tax-axis/components/intake/intakeSchema.js +4 -2
  61. package/lib/tax-axis/components/preparerWorkpaper/TaxAxisPreparerWorkpaper.d.ts +2 -26
  62. package/lib/tax-axis/components/preparerWorkpaper/TaxAxisPreparerWorkpaper.js +4 -15
  63. package/lib/tax-axis/components/processing/TaxAxisProcessing.d.ts +1 -3
  64. package/lib/tax-axis/components/processing/TaxAxisProcessing.js +31 -102
  65. package/lib/tax-axis/components/prospectReport/ProspectPrintView.js +2 -0
  66. package/lib/tax-axis/components/prospectReport/ProspectStrategyCard.d.ts +8 -1
  67. package/lib/tax-axis/components/prospectReport/ProspectStrategyCard.js +5 -5
  68. package/lib/tax-axis/components/prospectReport/TaxAxisProspectReport.d.ts +27 -1
  69. package/lib/tax-axis/components/prospectReport/TaxAxisProspectReport.js +43 -25
  70. package/lib/tax-axis/index.d.ts +0 -4
  71. package/lib/tax-axis/index.js +1 -6
  72. package/lib/tax-axis/lib/adapters/useEngineOutput.d.ts +13 -138
  73. package/lib/tax-axis/lib/adapters/useEngineOutput.js +7 -156
  74. package/lib/tax-axis/lib/data/documents.d.ts +2 -3
  75. package/lib/tax-axis/lib/data/documents.js +25 -225
  76. package/lib/tax-axis/lib/data/strategies.js +9 -9
  77. package/lib/tax-axis/lib/documentFieldCatalog.d.ts +12 -7
  78. package/lib/tax-axis/lib/documentFieldCatalog.js +8 -805
  79. package/lib/tax-axis/lib/types/index.d.ts +1 -13
  80. package/package.json +1 -1
@@ -128,6 +128,30 @@ function buildSessionInput(profile) {
128
128
  states: profile.states || [],
129
129
  };
130
130
  }
131
+ function buildProspectInput(profile) {
132
+ var _a;
133
+ const fedRateStr = (profile.federalRate || '24%').replace('%', '');
134
+ const stateRateStr = (profile.stateRate || '0').replace('%', '');
135
+ return {
136
+ businessName: profile.bizName || 'Client',
137
+ entityType: profile.entity || 'S-Corporation',
138
+ primaryState: ((_a = profile.states) === null || _a === void 0 ? void 0 : _a[0]) || 'IL',
139
+ states: profile.states || [],
140
+ industry: profile.industry || 'Professional Services',
141
+ annualRevenue: toInt(profile.revenue),
142
+ netIncome: toInt(profile.netIncome) || null,
143
+ ownerCompensation: toInt(profile.ownerComp) || null,
144
+ employees: toInt(profile.employees) || null,
145
+ federalRate: parseFloat(fedRateStr) / 100 || 0.24,
146
+ stateRate: parseFloat(stateRateStr) / 100 || 0,
147
+ taxYear: Number(profile.year) || new Date().getFullYear(),
148
+ analysisPeriod: profile.period || 'Full Year',
149
+ riskTolerance: profile.riskTolerance || null,
150
+ equipmentPurchased: toInt(profile.equipmentPurchased) || null,
151
+ realEstateValue: toInt(profile.realEstateValue) || null,
152
+ capitalGains: toInt(profile.capitalGains) || null,
153
+ };
154
+ }
131
155
  function ShellContainer({ children, fullWidth = false, }) {
132
156
  if (fullWidth) {
133
157
  return react_1.default.createElement(react_1.default.Fragment, null, children);
@@ -135,7 +159,7 @@ function ShellContainer({ children, fullWidth = false, }) {
135
159
  return (react_1.default.createElement("div", { className: 'min-h-screen bg-tax-axis-navy text-white font-tax-axis-body' },
136
160
  react_1.default.createElement("div", { className: 'max-w-[960px] mx-auto px-5 py-7' }, children)));
137
161
  }
138
- const TaxAxisShell = ({ taxAxisApi, userContext = 'expert', initialSessionId, initialProfile, onSessionChange, documentUploadUrl, uploadBucketName, sessionDefaults, }) => {
162
+ const TaxAxisShell = ({ taxAxisApi, userContext = 'expert', initialSessionId, initialProfile, onSessionChange, documentUploadUrl, uploadBucketName, sessionDefaults, qboAuthorizeUrl, expertId, qboConnected, qboCompanyName, }) => {
139
163
  const [step, setStep] = (0, react_1.useState)('SESSION_SETUP');
140
164
  const [profile, setProfile] = (0, react_1.useState)(initialProfile ? Object.assign({}, initialProfile) : null);
141
165
  const [sessionId, setSessionId] = (0, react_1.useState)(initialSessionId || null);
@@ -146,7 +170,15 @@ const TaxAxisShell = ({ taxAxisApi, userContext = 'expert', initialSessionId, in
146
170
  const [error, setError] = (0, react_1.useState)(null);
147
171
  const [busyMessage, setBusyMessage] = (0, react_1.useState)('Syncing Tax Axis session...');
148
172
  const [reportReady, setReportReady] = (0, react_1.useState)(false);
173
+ const [backendResults, setBackendResults] = (0, react_1.useState)(null);
174
+ const [generating, setGenerating] = (0, react_1.useState)(false);
149
175
  const isPollingRef = react_1.default.useRef(false);
176
+ // QBO state driven by EPS props — not localStorage
177
+ const [qboConnectedState, setQboConnectedState] = (0, react_1.useState)(!!qboConnected);
178
+ const [qboCompanyNameState, setQboCompanyNameState] = (0, react_1.useState)(qboCompanyName !== null && qboCompanyName !== void 0 ? qboCompanyName : null);
179
+ // Sync if parent re-fetches EPS data
180
+ react_1.default.useEffect(() => { setQboConnectedState(!!qboConnected); }, [qboConnected]);
181
+ react_1.default.useEffect(() => { setQboCompanyNameState(qboCompanyName !== null && qboCompanyName !== void 0 ? qboCompanyName : null); }, [qboCompanyName]);
150
182
  // Derive live strategies from engineOutput so CLIENT_REPORT and PREPARER_WORKPAPER
151
183
  // render real engine data instead of the static STRATEGIES catalog.
152
184
  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]);
@@ -230,13 +262,29 @@ const TaxAxisShell = ({ taxAxisApi, userContext = 'expert', initialSessionId, in
230
262
  setIsProspectFlow(false);
231
263
  setError(null);
232
264
  setReportReady(false);
265
+ setBackendResults(null);
233
266
  updateSessionId(null);
234
267
  }, [updateSessionId]);
235
- const handleProspect = (0, react_1.useCallback)((nextProfile) => {
268
+ const handleProspect = (0, react_1.useCallback)((nextProfile) => __awaiter(void 0, void 0, void 0, function* () {
236
269
  setProfile(nextProfile);
237
270
  setIsProspectFlow(true);
271
+ setBackendResults(null);
272
+ if (taxAxisApi.generateProspectReport) {
273
+ setGenerating(true);
274
+ try {
275
+ const input = buildProspectInput(nextProfile);
276
+ const result = yield taxAxisApi.generateProspectReport(input);
277
+ if (result) {
278
+ setBackendResults(result);
279
+ }
280
+ }
281
+ catch (_err) {
282
+ // LLM call failed — fall through to template mode
283
+ }
284
+ setGenerating(false);
285
+ }
238
286
  setStep('PROSPECT_REPORT');
239
- }, []);
287
+ }), [taxAxisApi]);
240
288
  const handleFullAnalysis = (0, react_1.useCallback)((nextProfile) => __awaiter(void 0, void 0, void 0, function* () {
241
289
  setProfile(nextProfile);
242
290
  setIsProspectFlow(false);
@@ -300,6 +348,17 @@ const TaxAxisShell = ({ taxAxisApi, userContext = 'expert', initialSessionId, in
300
348
  const handleDeleteDocument = (0, react_1.useCallback)((documentId) => __awaiter(void 0, void 0, void 0, function* () {
301
349
  yield taxAxisApi.deleteDocument(documentId);
302
350
  }), [taxAxisApi]);
351
+ const handleImportQboReport = (0, react_1.useCallback)((sid, _realmId, reportType, _accountingMethod, year) => __awaiter(void 0, void 0, void 0, function* () {
352
+ var _a;
353
+ if (!taxAxisApi.importQboReport) {
354
+ throw new Error('QBO import is not available.');
355
+ }
356
+ if (!expertId) {
357
+ throw new Error('Expert ID is required for QBO import.');
358
+ }
359
+ 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();
360
+ return taxAxisApi.importQboReport(sid, expertId, taxYear, reportType);
361
+ }), [taxAxisApi, expertId, profile]);
303
362
  const pollForResult = (0, react_1.useCallback)((sid) => __awaiter(void 0, void 0, void 0, function* () {
304
363
  const POLL_INTERVAL_MS = 4000;
305
364
  const MAX_ATTEMPTS = 4500; // 300 minutes max
@@ -406,9 +465,31 @@ const TaxAxisShell = ({ taxAxisApi, userContext = 'expert', initialSessionId, in
406
465
  switch (step) {
407
466
  case 'PROSPECT_REPORT':
408
467
  return (react_1.default.createElement(ShellContainer, null,
409
- react_1.default.createElement(TaxAxisProspectReport_1.TaxAxisProspectReport, { profile: profile, userContext: userContext, onUpgrade: () => setStep('DOCUMENT_UPLOAD'), onPresent: () => setStep('PRESENTATION'), onReset: handleReset })));
468
+ react_1.default.createElement(TaxAxisProspectReport_1.TaxAxisProspectReport, { profile: profile, userContext: userContext, backendResults: backendResults, onUpgrade: () => setStep('DOCUMENT_UPLOAD'), onPresent: () => setStep('PRESENTATION'), onReset: handleReset })));
410
469
  case 'DOCUMENT_UPLOAD':
411
470
  return (react_1.default.createElement(ShellContainer, null,
471
+ react_1.default.createElement("div", { className: "flex items-center justify-between rounded-lg px-4 py-3 mb-5", style: {
472
+ background: '#1A1F3A',
473
+ border: '1px solid #2E3160',
474
+ } },
475
+ react_1.default.createElement("div", { className: "flex items-center gap-3 min-w-0" },
476
+ 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'),
477
+ profile.entity && (react_1.default.createElement("span", { className: "text-[10px] font-semibold font-tax-axis-mono flex-shrink-0", style: {
478
+ padding: '2px 8px',
479
+ borderRadius: 4,
480
+ background: 'rgba(36,131,132,0.10)',
481
+ border: '1px solid rgba(36,131,132,0.25)',
482
+ color: '#A1E5E6',
483
+ letterSpacing: '0.03em',
484
+ } }, profile.entity)),
485
+ 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" },
486
+ "TY ",
487
+ profile.year))),
488
+ 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: {
489
+ background: 'rgba(99,102,241,0.12)',
490
+ border: '1px solid rgba(99,102,241,0.30)',
491
+ color: '#a5b4fc',
492
+ } }, "Edit")),
412
493
  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
494
  const ensuredSessionId = sessionId || (profile ? yield createSessionIfNeeded(profile) : null);
414
495
  if (!ensuredSessionId) {
@@ -430,7 +511,13 @@ const TaxAxisShell = ({ taxAxisApi, userContext = 'expert', initialSessionId, in
430
511
  });
431
512
  }), jobId: sessionId || undefined, onSaveReviewedField: (documentId, reviewedData) => __awaiter(void 0, void 0, void 0, function* () {
432
513
  yield taxAxisApi.saveReviewedData(documentId, reviewedData);
433
- }), onContinue: handleAnalyzeDocuments, onBack: () => isProspectFlow ? setStep('PROSPECT_REPORT') : setStep('SESSION_SETUP') })));
514
+ }), 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) => {
515
+ setQboConnectedState(true);
516
+ setQboCompanyNameState(companyName);
517
+ }, onQboDisconnected: () => {
518
+ setQboConnectedState(false);
519
+ setQboCompanyNameState(null);
520
+ } })));
434
521
  case 'PROCESSING':
435
522
  return (react_1.default.createElement(ShellContainer, null,
436
523
  react_1.default.createElement(TaxAxisProcessing_1.TaxAxisProcessing, { profile: profile, userContext: userContext, reportReady: reportReady, onComplete: () => setStep('DASHBOARD') })));
@@ -468,7 +555,14 @@ const TaxAxisShell = ({ taxAxisApi, userContext = 'expert', initialSessionId, in
468
555
  llmResult,
469
556
  adapted,
470
557
  reportReady,
558
+ backendResults,
559
+ generating,
471
560
  parsedDocuments,
561
+ qboConnectedState,
562
+ qboCompanyNameState,
563
+ qboAuthorizeUrl,
564
+ expertId,
565
+ handleImportQboReport,
472
566
  ]);
473
567
  return (react_1.default.createElement(react_1.default.Fragment, null,
474
568
  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' },
@@ -480,6 +574,11 @@ const TaxAxisShell = ({ taxAxisApi, userContext = 'expert', initialSessionId, in
480
574
  react_1.default.createElement("div", { className: 'flex items-center gap-2' },
481
575
  react_1.default.createElement("div", { className: 'w-3 h-3 rounded-full animate-spin flex-shrink-0', style: { border: '2px solid transparent', borderTopColor: '#248384' } }),
482
576
  busyMessage)))),
577
+ generating && (react_1.default.createElement("div", { className: 'fixed inset-0 z-[180] bg-black/25' },
578
+ react_1.default.createElement("div", { className: 'absolute left-1/2 top-1/3 -translate-x-1/2 rounded-xl bg-tax-axis-surface px-8 py-6 text-center shadow-lg border border-tax-axis-border', style: { maxWidth: 360 } },
579
+ react_1.default.createElement("div", { className: 'w-6 h-6 rounded-full animate-spin mx-auto mb-3', style: { border: '2.5px solid transparent', borderTopColor: '#248384' } }),
580
+ react_1.default.createElement("div", { className: 'text-sm font-semibold text-white mb-1 font-tax-axis-body' }, "Generating Prospect Report"),
581
+ react_1.default.createElement("div", { className: 'text-xs text-tax-axis-text-3 font-tax-axis-body' }, "Analyzing strategies and generating insights...")))),
483
582
  currentView));
484
583
  };
485
584
  exports.TaxAxisShell = TaxAxisShell;
@@ -13,4 +13,9 @@ export type TaxAxisShellProps = {
13
13
  freelancerId: number;
14
14
  clientId?: number | null;
15
15
  };
16
+ qboAuthorizeUrl?: string;
17
+ qboGetClientsUrl?: string;
18
+ expertId?: string;
19
+ qboConnected?: boolean;
20
+ qboCompanyName?: string | null;
16
21
  };
@@ -8,10 +8,9 @@ export default class UploadClient {
8
8
  bucketName: string;
9
9
  escalationId?: string;
10
10
  taskId?: string;
11
- keyPrefix?: string;
12
11
  };
13
12
  constructor(props: any);
14
- generateS3Key(projectId: number, escalationId: string, fileName: string, taskId: string, keyPrefix?: string): string;
13
+ generateS3Key(projectId: number, escalationId: string, fileName: string, taskId: string): string;
15
14
  triggerMultipartUpload(): Promise<string | undefined>;
16
15
  uploadMultiPartFile(): Promise<string | undefined>;
17
16
  completeUpload(partsArray: any): Promise<string | undefined>;
@@ -20,14 +20,10 @@ class UploadClient {
20
20
  bucketName: props.bucketName,
21
21
  escalationId: props.escalationId,
22
22
  taskId: props.taskId,
23
- keyPrefix: props.keyPrefix,
24
23
  };
25
24
  }
26
- generateS3Key(projectId, escalationId, fileName, taskId, keyPrefix) {
25
+ generateS3Key(projectId, escalationId, fileName, taskId) {
27
26
  const sanitizedFileName = fileName.replace(/[^a-zA-Z0-9.-]/g, '_');
28
- if (!!keyPrefix) {
29
- return `${keyPrefix.replace(/\/+$/, '')}/${sanitizedFileName}`;
30
- }
31
27
  if (!!taskId) {
32
28
  return `project-task-${taskId}/${sanitizedFileName}`;
33
29
  }
@@ -41,7 +37,7 @@ class UploadClient {
41
37
  return __awaiter(this, void 0, void 0, function* () {
42
38
  var _a, _b;
43
39
  try {
44
- const fileName = this.generateS3Key(this.state.projectId, (_a = this.state.escalationId) !== null && _a !== void 0 ? _a : '', this.state.fileName, (_b = this.state.taskId) !== null && _b !== void 0 ? _b : '', this.state.keyPrefix);
40
+ const fileName = this.generateS3Key(this.state.projectId, (_a = this.state.escalationId) !== null && _a !== void 0 ? _a : '', this.state.fileName, (_b = this.state.taskId) !== null && _b !== void 0 ? _b : '');
45
41
  this.state = Object.assign(Object.assign({}, this.state), { fileName: fileName });
46
42
  const params = {
47
43
  fileName: this.state.fileName,
package/lib/index.d.ts CHANGED
@@ -16,5 +16,16 @@ export { DiscussionSection } from './components/Invoices/DiscussionSection';
16
16
  export { fileDownloader } from './components/FileDownloader';
17
17
  export { Escalations } from './components/Escalations';
18
18
  export { ProjectIntelligence } from "./components/ProjectIntelligence";
19
- export { TaxAxisShell } from './components/TaxAxis';
20
- export type { TaxAxisApi, TaxAxisSessionInput, TaxAxisUploadInput } from './components/TaxAxis';
19
+ export { SectionHeader } from './tax-axis';
20
+ export { TaxAxisBadge } from './tax-axis';
21
+ export { TaxAxisButton } from './tax-axis';
22
+ export { TaxAxisCard } from './tax-axis';
23
+ export { TaxAxisIntake } from './tax-axis';
24
+ export { TaxAxisDocuments } from './tax-axis';
25
+ export { TaxAxisProcessing } from './tax-axis';
26
+ export { TaxAxisDashboard } from './tax-axis';
27
+ export { TaxAxisClientReport } from './tax-axis';
28
+ export { TaxAxisPreparerWorkpaper } from './tax-axis';
29
+ export { TaxAxisExtractionReview } from './tax-axis';
30
+ export { TaxAxisProspectReport } from './tax-axis';
31
+ export { TaxAxisPresentationMode } from './tax-axis';
package/lib/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.TaxAxisShell = exports.ProjectIntelligence = exports.Escalations = exports.fileDownloader = exports.DiscussionSection = exports.fileUploader = exports.InvoiceCard = exports.ActiveProjectCard = exports.sharedUtils = exports.ServiceLinesTemplate = exports.HeaderNavBar = exports.DocumentCenter = exports.ProfileCompletedPercentage = exports.ExpertProfileHeader = exports.OrganizationChart = exports.FirmEmployeeSection = exports.ClientReferenceSection = exports.Reviews = exports.ReviewsTab = void 0;
3
+ exports.TaxAxisPresentationMode = exports.TaxAxisProspectReport = exports.TaxAxisExtractionReview = exports.TaxAxisPreparerWorkpaper = exports.TaxAxisClientReport = exports.TaxAxisDashboard = exports.TaxAxisProcessing = exports.TaxAxisDocuments = exports.TaxAxisIntake = exports.TaxAxisCard = exports.TaxAxisButton = exports.TaxAxisBadge = exports.SectionHeader = exports.ProjectIntelligence = exports.Escalations = exports.fileDownloader = exports.DiscussionSection = exports.fileUploader = exports.InvoiceCard = exports.ActiveProjectCard = exports.sharedUtils = exports.ServiceLinesTemplate = exports.HeaderNavBar = exports.DocumentCenter = exports.ProfileCompletedPercentage = exports.ExpertProfileHeader = exports.OrganizationChart = exports.FirmEmployeeSection = exports.ClientReferenceSection = exports.Reviews = exports.ReviewsTab = void 0;
4
4
  var ReviewsTab_1 = require("./components/ReviewsTab");
5
5
  Object.defineProperty(exports, "ReviewsTab", { enumerable: true, get: function () { return ReviewsTab_1.ReviewsTab; } });
6
6
  var Reviews_1 = require("./components/Reviews");
@@ -37,5 +37,29 @@ var Escalations_1 = require("./components/Escalations");
37
37
  Object.defineProperty(exports, "Escalations", { enumerable: true, get: function () { return Escalations_1.Escalations; } });
38
38
  var ProjectIntelligence_1 = require("./components/ProjectIntelligence");
39
39
  Object.defineProperty(exports, "ProjectIntelligence", { enumerable: true, get: function () { return ProjectIntelligence_1.ProjectIntelligence; } });
40
- var TaxAxis_1 = require("./components/TaxAxis");
41
- Object.defineProperty(exports, "TaxAxisShell", { enumerable: true, get: function () { return TaxAxis_1.TaxAxisShell; } });
40
+ var tax_axis_1 = require("./tax-axis");
41
+ Object.defineProperty(exports, "SectionHeader", { enumerable: true, get: function () { return tax_axis_1.SectionHeader; } });
42
+ var tax_axis_2 = require("./tax-axis");
43
+ Object.defineProperty(exports, "TaxAxisBadge", { enumerable: true, get: function () { return tax_axis_2.TaxAxisBadge; } });
44
+ var tax_axis_3 = require("./tax-axis");
45
+ Object.defineProperty(exports, "TaxAxisButton", { enumerable: true, get: function () { return tax_axis_3.TaxAxisButton; } });
46
+ var tax_axis_4 = require("./tax-axis");
47
+ Object.defineProperty(exports, "TaxAxisCard", { enumerable: true, get: function () { return tax_axis_4.TaxAxisCard; } });
48
+ var tax_axis_5 = require("./tax-axis");
49
+ Object.defineProperty(exports, "TaxAxisIntake", { enumerable: true, get: function () { return tax_axis_5.TaxAxisIntake; } });
50
+ var tax_axis_6 = require("./tax-axis");
51
+ Object.defineProperty(exports, "TaxAxisDocuments", { enumerable: true, get: function () { return tax_axis_6.TaxAxisDocuments; } });
52
+ var tax_axis_7 = require("./tax-axis");
53
+ Object.defineProperty(exports, "TaxAxisProcessing", { enumerable: true, get: function () { return tax_axis_7.TaxAxisProcessing; } });
54
+ var tax_axis_8 = require("./tax-axis");
55
+ Object.defineProperty(exports, "TaxAxisDashboard", { enumerable: true, get: function () { return tax_axis_8.TaxAxisDashboard; } });
56
+ var tax_axis_9 = require("./tax-axis");
57
+ Object.defineProperty(exports, "TaxAxisClientReport", { enumerable: true, get: function () { return tax_axis_9.TaxAxisClientReport; } });
58
+ var tax_axis_10 = require("./tax-axis");
59
+ Object.defineProperty(exports, "TaxAxisPreparerWorkpaper", { enumerable: true, get: function () { return tax_axis_10.TaxAxisPreparerWorkpaper; } });
60
+ var tax_axis_11 = require("./tax-axis");
61
+ Object.defineProperty(exports, "TaxAxisExtractionReview", { enumerable: true, get: function () { return tax_axis_11.TaxAxisExtractionReview; } });
62
+ var tax_axis_12 = require("./tax-axis");
63
+ Object.defineProperty(exports, "TaxAxisProspectReport", { enumerable: true, get: function () { return tax_axis_12.TaxAxisProspectReport; } });
64
+ var tax_axis_13 = require("./tax-axis");
65
+ Object.defineProperty(exports, "TaxAxisPresentationMode", { enumerable: true, get: function () { return tax_axis_13.TaxAxisPresentationMode; } });
@@ -0,0 +1,68 @@
1
+ {
2
+ "name": "@paro.io/expert-shared-components",
3
+ "version": "1.14.48",
4
+ "description": "",
5
+ "main": "lib/index.js",
6
+ "scripts": {
7
+ "build": "tsc",
8
+ "build:watch": "tsc --watch",
9
+ "prepare": "yarn build",
10
+ "test": "yarn test:build",
11
+ "test:build": "yarn build",
12
+ "clean": "yarn -rf lib",
13
+ "predeploy": "tsc && cp package.json README.md ./lib",
14
+ "link-local": "yarn link && cd node_modules/react && yarn link && cd ../react-dom && yarn link",
15
+ "unlink-local": "yarn unlink && cd node_modules/react && yarn unlink && cd ../react-dom && yarn unlink"
16
+ },
17
+ "repository": "https://github.com/paroadmin/expert-shared-components.git",
18
+ "keywords": [
19
+ "react",
20
+ "components",
21
+ "shared"
22
+ ],
23
+ "author": "apande@paro.io",
24
+ "license": "MIT",
25
+ "dependencies": {
26
+ "@date-io/dayjs": "1.x",
27
+ "@fortawesome/fontawesome-svg-core": "^6.6.0",
28
+ "@fortawesome/free-solid-svg-icons": "^6.6.0",
29
+ "@fortawesome/react-fontawesome": "^0.2.2",
30
+ "@hookform/resolvers": "3.3.4",
31
+ "@material-ui/core": "^4.11.0",
32
+ "@material-ui/icons": "^4.11.3",
33
+ "@material-ui/lab": "^4.0.0-alpha.61",
34
+ "@material-ui/pickers": "^3.3.11",
35
+ "@paro.io/base-icons": "^1.0.4",
36
+ "@paro.io/base-ui": "^1.8.3",
37
+ "@types/react-input-mask": "^3.0.5",
38
+ "dayjs": "^1.10.7",
39
+ "lodash": "^4.17.21",
40
+ "react": "^18.2.0",
41
+ "react-copy-to-clipboard": "^5.0.4",
42
+ "react-datepicker": "^4.6.0",
43
+ "react-dom": "^17.0.2",
44
+ "react-hook-form": "7.51.1",
45
+ "react-hot-toast": "^2.4.1",
46
+ "react-input-mask": "^3.0.0-alpha.2",
47
+ "styled-components": "^5.3.3",
48
+ "uuid": "8.3.2",
49
+ "yup": "^0.32.11"
50
+ },
51
+ "devDependencies": {
52
+ "@types/lodash": "^4.14.170",
53
+ "@types/react": "18.3.12",
54
+ "@types/react-copy-to-clipboard": "^5.0.2",
55
+ "@types/react-datepicker": "^4.19.6",
56
+ "@types/react-dom": "^18.2.22",
57
+ "@types/styled-components": "^5.1.22",
58
+ "@types/uuid": "^10.0.0",
59
+ "@types/yup": "^0.29.13",
60
+ "typescript": "^5.3.3"
61
+ },
62
+ "files": [
63
+ "lib/**/*"
64
+ ],
65
+ "directories": {
66
+ "lib": "lib"
67
+ }
68
+ }
@@ -10,9 +10,6 @@ interface ExecutiveSummaryProps {
10
10
  nowCount: number;
11
11
  top3: Strategy[];
12
12
  palette: Palette;
13
- effectiveTaxRate?: number;
14
- confidenceTier?: string;
15
- dataYears?: number;
16
13
  }
17
- export declare function ExecutiveSummary({ profile, eligible, computed, totalLo, totalHi, nowCount, top3, palette, effectiveTaxRate, confidenceTier, dataYears }: ExecutiveSummaryProps): React.JSX.Element;
14
+ export declare function ExecutiveSummary({ profile, eligible, computed, totalLo, totalHi, nowCount, top3, palette }: ExecutiveSummaryProps): React.JSX.Element;
18
15
  export {};
@@ -8,17 +8,16 @@ const react_1 = __importDefault(require("react"));
8
8
  const compute_1 = require("../../lib/compute");
9
9
  const SectionOpener_1 = require("./SectionOpener");
10
10
  const ETRChart_1 = require("./ETRChart");
11
- function ExecutiveSummary({ profile, eligible, computed, totalLo, totalHi, nowCount, top3, palette, effectiveTaxRate, confidenceTier, dataYears }) {
11
+ function ExecutiveSummary({ profile, eligible, computed, totalLo, totalHi, nowCount, top3, palette }) {
12
12
  const bizName = profile.bizName || "Client";
13
13
  const rev = parseInt((profile.revenue || "0").replace(/,/g, "")) || 500000;
14
- const dataYearsLabel = dataYears ? `${dataYears} year${dataYears > 1 ? "s" : ""}` : (profile.taxDataYears || "1 year");
15
14
  return (react_1.default.createElement(react_1.default.Fragment, null,
16
15
  react_1.default.createElement(SectionOpener_1.SectionOpener, { number: "01", eyebrow: "EXECUTIVE SUMMARY", headline: "Where " + bizName + "'s tax dollars are going \u2014 and where they don't have to.", bullets: [
17
16
  eligible.length + " strategies apply to your current profile, with combined estimated savings of $" + totalLo + "K\u2013$" + totalHi + "K annually.",
18
17
  nowCount > 0
19
18
  ? nowCount + " can be initiated this week without any structural changes to your business."
20
19
  : "Implementation timeline spans the current tax year with no structural changes required.",
21
- "Analysis is based on " + dataYearsLabel + " of financial data and current law as of April 2026, including OBBBA provisions.",
20
+ "Analysis is based on " + (profile.taxDataYears || "1 year") + " of financial data and current law as of April 2026, including OBBBA provisions.",
22
21
  ], palette: palette }),
23
22
  react_1.default.createElement("div", { style: { marginBottom: 28 } },
24
23
  react_1.default.createElement("div", { style: { background: palette.gray50, border: "1px solid " + palette.gray200, borderRadius: 10, padding: "24px 28px", marginBottom: 20 } },
@@ -47,18 +46,15 @@ function ExecutiveSummary({ profile, eligible, computed, totalLo, totalHi, nowCo
47
46
  nowCount > 0 ? "Of these and the broader eligible set, " + nowCount + " can be initiated this week with no structural changes to your business." : "",
48
47
  " Savings estimates reflect your current revenue of ",
49
48
  "$" + Math.round(rev / 1000) + "K",
50
- ", an effective tax rate of ",
51
- effectiveTaxRate != null ? Math.round((effectiveTaxRate <= 1 ? effectiveTaxRate * 100 : effectiveTaxRate) * 10) / 10 : (parseFloat(profile.federalRate || "24") + parseFloat(profile.stateRate || "4.95")),
49
+ ", a combined federal/state marginal rate of ",
50
+ parseFloat(profile.federalRate || "24") + parseFloat(profile.stateRate || "4.95"),
52
51
  "%, and ",
53
- dataYearsLabel,
52
+ profile.taxDataYears || "1 year",
54
53
  " of financial data."),
55
54
  (() => {
56
55
  const fedRate = parseFloat(profile.federalRate || "24");
57
56
  const stateRate = parseFloat(profile.stateRate || "4.95");
58
- // If engine provided effective_tax_rate (as a decimal 0-1), convert to percentage
59
- const currentRate = effectiveTaxRate != null
60
- ? (effectiveTaxRate <= 1 ? effectiveTaxRate * 100 : effectiveTaxRate)
61
- : (fedRate + stateRate);
57
+ const currentRate = fedRate + stateRate;
62
58
  const net = (0, compute_1.parseNum)(profile.netIncome) || (rev * 0.20);
63
59
  const aggregateMidSavings = eligible.reduce((a, s) => {
64
60
  var _a, _b;
@@ -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 through a two-stage AI and deterministic pipeline \u2014 every recommendation traces to a specific IRC section, revenue ruling, or OBBBA provision.",
13
+ "25 federal strategies evaluated against your profile via deterministic, rule-based computation at temperature zero \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 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.")),
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. The computation is entirely deterministic and rule-based, operating at temperature zero \u2014 no generative model is involved at any stage. Each strategy passes through a three-phase pipeline: an eligibility filter removes strategies that do not apply to the entity type, industry, or fact pattern, then the computation engine calculates savings ranges against IRC-cited rules using the client's actual financial data. 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."),
@@ -1,10 +1,6 @@
1
1
  import React from "react";
2
2
  import type { ClientProfile, Strategy, ComputedMap } from "../../lib/types";
3
3
  import type { Palette } from "./palette";
4
- interface InteractionWarning {
5
- strategy_pair: [string, string];
6
- warning_text: string;
7
- }
8
4
  interface RecommendedStrategiesProps {
9
5
  profile: ClientProfile;
10
6
  eligible: Strategy[];
@@ -12,7 +8,6 @@ interface RecommendedStrategiesProps {
12
8
  top3: Strategy[];
13
9
  hasOBBBA: boolean;
14
10
  palette: Palette;
15
- interactionWarnings?: InteractionWarning[];
16
11
  }
17
- export declare function RecommendedStrategies({ profile, eligible, computed, top3, hasOBBBA, palette, interactionWarnings }: RecommendedStrategiesProps): React.JSX.Element;
12
+ export declare function RecommendedStrategies({ profile, eligible, computed, top3, hasOBBBA, palette }: RecommendedStrategiesProps): React.JSX.Element;
18
13
  export {};
@@ -5,49 +5,47 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.RecommendedStrategies = RecommendedStrategies;
7
7
  const react_1 = __importDefault(require("react"));
8
+ const data_1 = require("../../lib/data");
8
9
  const SectionOpener_1 = require("./SectionOpener");
9
10
  const SavingsStackChart_1 = require("./SavingsStackChart");
10
11
  const StrategyCard_1 = require("./StrategyCard");
11
- function RecommendedStrategies({ profile, eligible, computed, top3, hasOBBBA, palette, interactionWarnings = [] }) {
12
- // Build a map from strategy code → strategy index in top3 (for interaction display)
13
- const top3Codes = new Set(top3.map(s => s.code));
14
- // Interaction warnings that involve at least one top-3 strategy
15
- const activeWarnings = interactionWarnings.filter((w) => w.strategy_pair.some((id) => top3Codes.has(id)));
16
- // For each top-3 strategy, find if it participates in any active interaction
17
- const interactionMap = new Map(); // code → index of the other strategy in top3
18
- for (const w of activeWarnings) {
19
- const [a, b] = w.strategy_pair;
20
- const idxA = top3.findIndex(s => s.code === a);
21
- const idxB = top3.findIndex(s => s.code === b);
22
- if (idxA >= 0 && idxB >= 0) {
23
- interactionMap.set(a, idxB + 1);
24
- interactionMap.set(b, idxA + 1);
25
- }
26
- }
12
+ function RecommendedStrategies({ profile, eligible, computed, top3, hasOBBBA, palette }) {
13
+ const top3Ranks = new Set(top3.map(s => s.rank));
14
+ const interactingPairs = data_1.INTERACTION_PAIRS.filter(([a, b]) => top3Ranks.has(a) && top3Ranks.has(b));
15
+ const hasInteractions = interactingPairs.length > 0;
16
+ const interactionMap = {};
17
+ interactingPairs.forEach(([a, b]) => { interactionMap[a] = b; interactionMap[b] = a; });
27
18
  const stSavings = (s) => {
28
19
  var _a, _b;
29
20
  const c = computed.get(s.rank);
30
21
  const lo = Math.round(((_a = c === null || c === void 0 ? void 0 : c.lo) !== null && _a !== void 0 ? _a : s.lo) / 100) * 100;
31
22
  const hi = Math.round(((_b = c === null || c === void 0 ? void 0 : c.hi) !== null && _b !== void 0 ? _b : s.hi) / 100) * 100;
32
- return "$" + (lo / 1000).toFixed(1) + "K–$" + (hi / 1000).toFixed(1) + "K";
23
+ return "$" + (lo / 1000).toFixed(1) + "K\u2013$" + (hi / 1000).toFixed(1) + "K";
33
24
  };
34
25
  return (react_1.default.createElement(react_1.default.Fragment, null,
35
26
  react_1.default.createElement(SectionOpener_1.SectionOpener, { number: "02", eyebrow: "RECOMMENDED STRATEGIES", headline: "Three priorities to discuss first.", bullets: [
36
- top3.length + " strategies highlighted below are ranked by combined impact score weighting dollar value, audit posture, and implementation effort.",
37
- "Each strategy is anchored to a specific IRC section and explains the math, the audit posture, and the implementation path.",
27
+ "The " + top3.length + " strategies highlighted below are ranked by combined impact score \u2014 weighting dollar value, audit posture, and implementation effort.",
28
+ "Each strategy below is anchored to a specific IRC section and explains the math, the audit posture, and the implementation path.",
38
29
  hasOBBBA
39
- ? "One or more recommendations rely on OBBBA provisions enacted July 2025 with limited IRS guidance flagged where applicable."
30
+ ? "One or more recommendations rely on OBBBA provisions enacted July 2025 with limited IRS guidance \u2014 flagged where applicable."
40
31
  : "All recommendations rely on settled IRS guidance, published rulings, or controlling case law.",
41
32
  ], palette: palette }),
42
33
  react_1.default.createElement(SavingsStackChart_1.SavingsStackChart, { eligible: eligible, computed: computed, palette: palette }),
43
34
  react_1.default.createElement("div", { style: { marginBottom: 28 } }, top3.map((s, i) => {
44
- var _a, _b;
45
35
  const rank = i + 1;
46
- const interactsIdx = (_a = interactionMap.get(s.code)) !== null && _a !== void 0 ? _a : 0;
47
- const interactsWith = interactsIdx > 0 ? (_b = top3[interactsIdx - 1]) === null || _b === void 0 ? void 0 : _b.rank : undefined;
48
- return (react_1.default.createElement(StrategyCard_1.StrategyCard, { key: s.rank, strategy: s, rank: rank, profile: profile, computed: computed, palette: palette, nextStepText: s.action || "Discuss with your CPA to implement this strategy.", interactsWith: interactsWith, interactsIdx: interactsIdx, stSavings: stSavings(s) }));
36
+ const interactsWith = interactionMap[s.rank];
37
+ const interactsIdx = interactsWith ? top3.findIndex(t => t.rank === interactsWith) + 1 : 0;
38
+ return (react_1.default.createElement(StrategyCard_1.StrategyCard, { key: s.rank, strategy: s, rank: rank, profile: profile, computed: computed, palette: palette, nextStepText: data_1.NEXT_STEPS[s.rank] || NARRATIVE_FALLBACK_NEXT(s), interactsWith: interactsWith, interactsIdx: interactsIdx, stSavings: stSavings(s) }));
49
39
  })),
50
- activeWarnings.length > 0 && (react_1.default.createElement("div", { style: { background: palette.orangePale, borderLeft: "3px solid " + palette.orange, borderRadius: "0 8px 8px 0", padding: "16px 20px", marginBottom: 24 } },
40
+ hasInteractions && (react_1.default.createElement("div", { style: { background: palette.orangePale, borderLeft: "3px solid " + palette.orange, borderRadius: "0 8px 8px 0", padding: "16px 20px", marginBottom: 24 } },
51
41
  react_1.default.createElement("div", { style: { fontSize: 13, fontWeight: 700, color: palette.gray800, fontFamily: palette.head, marginBottom: 6 } }, "Strategy Interactions"),
52
- activeWarnings.map((w, i) => (react_1.default.createElement("p", { key: i, style: { fontSize: 12, color: palette.gray700, lineHeight: 1.7, fontFamily: palette.body, marginBottom: 4 } }, w.warning_text)))))));
42
+ interactingPairs.map(([a, b], pi) => {
43
+ const idxA = top3.findIndex(t => t.rank === a) + 1;
44
+ const idxB = top3.findIndex(t => t.rank === b) + 1;
45
+ return (react_1.default.createElement("p", { key: pi, style: { fontSize: 12, color: palette.gray700, lineHeight: 1.7, fontFamily: palette.body, marginBottom: 4 } }, "Strategies #" + idxA + " and #" + idxB + " affect each other. Your preparer has accounted for this \u2014 the combined savings may be less than the sum of individual estimates."));
46
+ })))));
47
+ }
48
+ // Inline fallback for next-steps text when NARRATIVE_FALLBACK is needed
49
+ function NARRATIVE_FALLBACK_NEXT(s) {
50
+ return "Discuss with your preparer to implement " + s.name + ".";
53
51
  }
@@ -12,5 +12,5 @@ interface StrategyCardProps {
12
12
  interactsIdx: number;
13
13
  stSavings: string;
14
14
  }
15
- export declare function StrategyCard({ strategy: s, rank, profile: _profile, computed, palette, nextStepText, interactsWith, interactsIdx, stSavings, }: StrategyCardProps): React.JSX.Element;
15
+ export declare function StrategyCard({ strategy: s, rank, profile, computed, palette, nextStepText, interactsWith, interactsIdx, stSavings, }: StrategyCardProps): React.JSX.Element;
16
16
  export {};