@paro.io/expert-shared-components 1.14.57 → 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.
Files changed (38) hide show
  1. package/lib/components/TaxAxis/TaxAxisApi.d.ts +1 -0
  2. package/lib/components/TaxAxis/TaxAxisShell.d.ts +1 -1
  3. package/lib/components/TaxAxis/TaxAxisShell.js +52 -2
  4. package/lib/components/TaxAxis/types.d.ts +5 -0
  5. package/lib/tax-axis/components/dashboard/DashboardActions.js +4 -4
  6. package/lib/tax-axis/components/dashboard/DashboardSummary.js +5 -6
  7. package/lib/tax-axis/components/dashboard/StrategyDetailPanel.js +2 -4
  8. package/lib/tax-axis/components/dashboard/TaxAxisDashboard.js +57 -49
  9. package/lib/tax-axis/components/documents/DocumentCard.d.ts +1 -0
  10. package/lib/tax-axis/components/documents/DocumentCard.js +19 -3
  11. package/lib/tax-axis/components/documents/TaxAxisDocuments.d.ts +12 -1
  12. package/lib/tax-axis/components/documents/TaxAxisDocuments.js +110 -48
  13. package/lib/tax-axis/components/documents/qbo/QboAvailableReportsModal.d.ts +13 -0
  14. package/lib/tax-axis/components/documents/qbo/QboAvailableReportsModal.js +180 -0
  15. package/lib/tax-axis/components/documents/qbo/QboClientSelectorModal.d.ts +10 -0
  16. package/lib/tax-axis/components/documents/qbo/QboClientSelectorModal.js +155 -0
  17. package/lib/tax-axis/components/documents/qbo/QboConnectBanner.d.ts +9 -0
  18. package/lib/tax-axis/components/documents/qbo/QboConnectBanner.js +55 -0
  19. package/lib/tax-axis/components/documents/qbo/QboDocumentMappingModal.d.ts +10 -0
  20. package/lib/tax-axis/components/documents/qbo/QboDocumentMappingModal.js +202 -0
  21. package/lib/tax-axis/components/documents/qbo/QboImportingModal.d.ts +8 -0
  22. package/lib/tax-axis/components/documents/qbo/QboImportingModal.js +75 -0
  23. package/lib/tax-axis/components/documents/qbo/QboPermissionsModal.d.ts +8 -0
  24. package/lib/tax-axis/components/documents/qbo/QboPermissionsModal.js +126 -0
  25. package/lib/tax-axis/components/documents/qbo/index.d.ts +8 -0
  26. package/lib/tax-axis/components/documents/qbo/index.js +17 -0
  27. package/lib/tax-axis/components/documents/qbo/qboConstants.d.ts +24 -0
  28. package/lib/tax-axis/components/documents/qbo/qboConstants.js +71 -0
  29. package/lib/tax-axis/components/documents/qbo/types.d.ts +43 -0
  30. package/lib/tax-axis/components/documents/qbo/types.js +3 -0
  31. package/lib/tax-axis/components/documents/qbo/useQboFlow.d.ts +19 -0
  32. package/lib/tax-axis/components/documents/qbo/useQboFlow.js +207 -0
  33. package/lib/tax-axis/components/intake/ClientParametersSection.js +1 -1
  34. package/lib/tax-axis/components/intake/CpaIntakeQuestionsSection.js +3 -3
  35. package/lib/tax-axis/components/intake/IntakeCtaCards.js +1 -1
  36. package/lib/tax-axis/components/intake/RefineAnalysisSection.js +7 -7
  37. package/lib/tax-axis/components/intake/TaxAxisIntake.js +2 -2
  38. 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' },
@@ -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
  };
@@ -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: String(scoreUp), u: "/100", l: "Avg. Confidence", warn: false, ok: false },
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 ? "Done" : String(reviewUnreviewed),
85
+ v: dataConfirmed ? "Verified" : String(reviewUnreviewed),
87
86
  u: "",
88
- l: dataConfirmed ? "Data Confirmed" : "Need Review",
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,
@@ -32,7 +32,6 @@ const useEngineOutput_1 = require("../../lib/adapters/useEngineOutput");
32
32
  const TaxAxisButton_1 = require("../shared/TaxAxisButton");
33
33
  const TaxAxisBadge_1 = require("../shared/TaxAxisBadge");
34
34
  const DashboardSummary_1 = require("./DashboardSummary");
35
- const DashboardTopBar_1 = require("./DashboardTopBar");
36
35
  const DashboardActions_1 = require("./DashboardActions");
37
36
  const StrategyTile_1 = require("./StrategyTile");
38
37
  const StrategyDetailPanel_1 = require("./StrategyDetailPanel");
@@ -244,7 +243,7 @@ const BUCKETS = [
244
243
  { key: "90d", label: "Within 90 Days", desc: "Structural changes — new accounts or plan setup" },
245
244
  ];
246
245
  function TaxAxisDashboard({ profile, llmResult, parsedDocuments, onDownloadClient, onDownloadPreparer, onPresent, onSend, onReset, onReviewData, onUploadMore, userContext: _userContext = "expert", }) {
247
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v;
246
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u;
248
247
  const hasLlm = !!((_a = llmResult === null || llmResult === void 0 ? void 0 : llmResult.strategies) === null || _a === void 0 ? void 0 : _a.length);
249
248
  // All live fields from rawOutput — nothing hardcoded
250
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;
@@ -340,29 +339,25 @@ function TaxAxisDashboard({ profile, llmResult, parsedDocuments, onDownloadClien
340
339
  return map;
341
340
  }, [uncalculated]);
342
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);
343
344
  return (react_1.default.createElement("div", null,
344
- hasLlm && (llmResult === null || llmResult === void 0 ? void 0 : llmResult.meta) && (react_1.default.createElement("div", { className: "rounded-lg mb-3 px-4 py-2.5 flex items-center justify-between text-[11px] font-tax-axis-mono", style: {
345
- background: "rgba(36,131,132,0.06)",
346
- border: "1px solid rgba(36,131,132,0.15)",
347
- color: "#9498B8",
348
- } },
349
- react_1.default.createElement("span", null,
350
- "Source: ",
351
- react_1.default.createElement("strong", { className: "text-tax-axis-teal-light" }, llmResult.meta.provider),
352
- " · ",
353
- llmResult.meta.parsedDocumentCount,
354
- " documents parsed",
355
- " · ",
356
- ((_v = llmResult.meta.detectedDocumentTypes) === null || _v === void 0 ? void 0 : _v.length) || 0,
357
- " document types detected"),
358
- react_1.default.createElement("span", { className: "text-tax-axis-text-4" }, (() => {
359
- var _a, _b;
360
- const tokens = (_b = (_a = llmResult.meta.totalTokens) !== null && _a !== void 0 ? _a : llmResult.meta.tokenCount) !== null && _b !== void 0 ? _b : 0;
361
- return tokens > 0 ? `${tokens} tokens` : "";
362
- })()))),
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
+ `),
363
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 }),
364
- react_1.default.createElement(DashboardTopBar_1.DashboardTopBar, { topTab: topTab, setTopTab: setTopTab, dataConfirmed: dataConfirmed, reviewUnreviewed: reviewStatus.unreviewed }),
365
- topTab === "extraction" && (react_1.default.createElement("div", null,
360
+ false && (react_1.default.createElement("div", null,
366
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" } },
367
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" },
368
363
  react_1.default.createElement("svg", { width: "12", height: "12", viewBox: "0 0 12 12", fill: "none" },
@@ -415,8 +410,8 @@ function TaxAxisDashboard({ profile, llmResult, parsedDocuments, onDownloadClien
415
410
  border: "1px solid rgba(15,110,86,0.25)",
416
411
  color: "#0F6E56",
417
412
  } }, "View Report"))))),
418
- topTab === "report" && dataConfirmed && (react_1.default.createElement("div", null,
419
- 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: {
420
415
  padding: "10px 0",
421
416
  fontSize: 14,
422
417
  fontWeight: reportTab === id ? 600 : 400,
@@ -466,20 +461,14 @@ function TaxAxisDashboard({ profile, llmResult, parsedDocuments, onDownloadClien
466
461
  const clo = (_d = (_c = computed.get(s.rank)) === null || _c === void 0 ? void 0 : _c.lo) !== null && _d !== void 0 ? _d : s.lo;
467
462
  const w = (chi / maxSavings) * 100;
468
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) },
469
- react_1.default.createElement("span", { className: "text-tax-axis-text font-tax-axis-body flex-shrink-0 overflow-hidden text-ellipsis whitespace-nowrap", style: {
470
- fontSize: chartExpanded ? 13 : 12,
471
- width: chartExpanded ? 180 : 140,
472
- } }, 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),
473
465
  react_1.default.createElement("div", { className: "flex-1 bg-tax-axis-surface-2 rounded-sm overflow-hidden", style: { height: chartExpanded ? 10 : 6 } },
474
466
  react_1.default.createElement("div", { className: "h-full rounded-sm", style: {
475
467
  width: `${w}%`,
476
468
  background: "linear-gradient(90deg, #248384, #A1E5E6)",
477
469
  transition: "width 0.8s cubic-bezier(.16,1,.3,1)",
478
470
  } })),
479
- react_1.default.createElement("span", { className: "font-semibold text-tax-axis-teal-light font-tax-axis-mono flex-shrink-0 text-right", style: {
480
- fontSize: chartExpanded ? 13 : 12,
481
- width: chartExpanded ? 100 : 80,
482
- } },
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]"}` },
483
472
  fmtK(clo),
484
473
  "\u2013",
485
474
  fmtK(chi))));
@@ -497,7 +486,7 @@ function TaxAxisDashboard({ profile, llmResult, parsedDocuments, onDownloadClien
497
486
  dashEligible.length,
498
487
  " Strategies"),
499
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")),
500
- 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" },
501
490
  calculable.map((s, i) => {
502
491
  var _a, _b;
503
492
  const c = computed.get(s.rank);
@@ -566,29 +555,46 @@ function TaxAxisDashboard({ profile, llmResult, parsedDocuments, onDownloadClien
566
555
  react_1.default.createElement("div", { className: "flex items-center gap-2.5" },
567
556
  react_1.default.createElement("span", { className: "text-[11px] font-tax-axis-mono text-tax-axis-text-2" }, a.savings),
568
557
  react_1.default.createElement(TaxAxisBadge_1.TaxAxisBadge, { color: a.priority === "MEDIUM" ? "orange" : "neutral", size: "xs" }, a.priority))))))),
569
- engagementRecs.length > 0 && (react_1.default.createElement("div", { className: "rounded-[14px] mb-4 overflow-hidden", style: { background: "#0E1132", border: "1px solid rgba(36,131,132,0.12)" } },
570
- react_1.default.createElement("div", { className: "px-5 py-3.5", style: { borderBottom: "1px solid rgba(36,131,132,0.12)" } },
571
- react_1.default.createElement("span", { className: "text-[13px] font-bold text-white uppercase tracking-widest font-tax-axis-head" }, "CPA Engagement Notes")),
572
- engagementRecs.map((rec, i) => (react_1.default.createElement("div", { key: i, className: "px-5 py-3.5 text-[12px] text-tax-axis-text leading-[1.7] font-tax-axis-body", style: { borderTop: i > 0 ? "1px solid rgba(36,131,132,0.08)" : "none" } }, rec))))),
558
+ engagementRecs.length > 0 && (react_1.default.createElement("div", { className: "mb-4" },
559
+ react_1.default.createElement("div", { className: "text-[13px] font-bold text-white uppercase tracking-widest font-tax-axis-head mb-3" }, "CPA Engagement Notes"),
560
+ react_1.default.createElement("div", { className: "flex flex-col gap-3" }, engagementRecs.map((rec, i) => {
561
+ const colonIdx = rec.indexOf(":");
562
+ const hasLabel = colonIdx > 0 && colonIdx < 60;
563
+ const label = hasLabel ? rec.slice(0, colonIdx).trim() : null;
564
+ const body = hasLabel ? rec.slice(colonIdx + 1).trim() : rec;
565
+ return (react_1.default.createElement("div", { key: i, className: "rounded-[10px] p-4", style: {
566
+ background: "#0E1132",
567
+ border: "1px solid rgba(36,131,132,0.12)",
568
+ borderLeft: "3px solid rgba(36,131,132,0.4)",
569
+ } },
570
+ label && (react_1.default.createElement("div", { className: "text-xs font-semibold tracking-wide text-tax-axis-teal-light font-tax-axis-mono mb-1.5 uppercase" }, label)),
571
+ react_1.default.createElement("div", { className: "text-[12px] text-tax-axis-text leading-[1.7] font-tax-axis-body" }, body)));
572
+ })))),
573
573
  nexusFlags.length > 0 && (react_1.default.createElement("div", { className: "rounded-[14px] mb-4", style: { background: "#0E1132", border: "1px solid rgba(36,131,132,0.12)", padding: "16px 20px" } },
574
574
  react_1.default.createElement("div", { className: "text-[11px] font-bold text-white uppercase tracking-widest font-tax-axis-mono mb-2" }, "State Nexus"),
575
575
  nexusFlags.map((f, i) => (react_1.default.createElement("div", { key: i, className: "text-[12px] text-tax-axis-text-2 font-tax-axis-body py-1.5", style: { borderTop: i > 0 ? "1px solid rgba(36,131,132,0.08)" : "none" } },
576
576
  react_1.default.createElement("span", { className: "font-semibold text-tax-axis-teal-light mr-2" }, f.state),
577
577
  f.flag_text))))),
578
- 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)", padding: "16px 20px" } },
579
- react_1.default.createElement("div", { className: "text-[11px] font-bold text-white uppercase tracking-widest font-tax-axis-mono mb-2.5" }, "Risk Disclosures"),
580
- 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))))),
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))))))),
581
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)" } },
582
- react_1.default.createElement("div", { className: "px-5 py-3.5", style: { borderBottom: "1px solid rgba(148,152,184,0.1)" } },
583
- react_1.default.createElement("span", { className: "text-[13px] font-bold text-white uppercase tracking-widest font-tax-axis-head" },
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" },
584
587
  excludedStrategies.length,
585
- " Strategies Not Applicable")),
586
- 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" } },
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" } },
587
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),
588
593
  react_1.default.createElement("div", { className: "flex-1" },
589
594
  react_1.default.createElement("div", { className: "text-[11px] text-tax-axis-text-2 font-tax-axis-body" }, ex.reason),
590
- 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)))))))),
591
- react_1.default.createElement(TaxAxisButton_1.TaxAxisButton, { onClick: onDownloadPreparer, className: "w-full" }, "Download Full Preparer Report"))) : (
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")))) : (
592
598
  /* ═══ CLIENT SUMMARY — Timeline View ═══ */
593
599
  react_1.default.createElement("div", null,
594
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" },
@@ -654,8 +660,10 @@ function TaxAxisDashboard({ profile, llmResult, parsedDocuments, onDownloadClien
654
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)))));
655
661
  })));
656
662
  }),
657
- react_1.default.createElement(TaxAxisButton_1.TaxAxisButton, { onClick: onDownloadClient, className: "w-full mt-1.5" }, "Download Client Summary"),
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")),
658
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)))),
659
- react_1.default.createElement(DashboardActions_1.DashboardActions, { profile: profile, dashEligible: dashEligible, computed: computed, onDownloadPreparer: onDownloadPreparer, onPresent: onPresent, onSend: onSend, onReset: onReset }))),
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 })))),
660
668
  enrichedSelected && (react_1.default.createElement(StrategyDetailPanel_1.StrategyDetailPanel, { s: enrichedSelected, profile: profile, computed: computed, onClose: () => setSelected(null) }))));
661
669
  }
@@ -5,6 +5,7 @@ export interface DocState extends DocSpec {
5
5
  status: DocStatus;
6
6
  fileName: string | null;
7
7
  parseError?: string | null;
8
+ qboSource?: boolean;
8
9
  }
9
10
  interface DocumentCardProps {
10
11
  doc: DocState;
@@ -45,7 +45,7 @@ function DocumentCard({ doc, tierBorderColor, tierBadgeColor, tierBadgeText, hel
45
45
  borderRadius: "0 10px 10px 0",
46
46
  boxShadow: "0 2px 12px rgba(6,8,33,0.5)",
47
47
  } },
48
- react_1.default.createElement("div", { className: "px-4 py-3 flex gap-3 items-center" },
48
+ react_1.default.createElement("div", { className: "px-4 py-3 flex flex-col sm:flex-row gap-3 items-start sm:items-center" },
49
49
  react_1.default.createElement("div", { className: "w-9 h-9 rounded-lg flex items-center justify-center flex-shrink-0", style: {
50
50
  background: ss.iconBg,
51
51
  border: `1px solid ${ss.iconBorder}`,
@@ -63,13 +63,29 @@ function DocumentCard({ doc, tierBorderColor, tierBadgeColor, tierBadgeText, hel
63
63
  react_1.default.createElement("div", { className: "flex items-center gap-1.5" },
64
64
  react_1.default.createElement("span", { className: "text-[13px] font-medium text-white font-tax-axis-body" }, doc.name),
65
65
  doc.status === "empty" && (react_1.default.createElement(TaxAxisBadge_1.TaxAxisBadge, { color: tierBadgeColor, size: "xs" }, tierBadgeText)),
66
- doc.status === "failed" && (react_1.default.createElement(TaxAxisBadge_1.TaxAxisBadge, { color: "red", size: "xs" }, "FAILED"))),
66
+ doc.status === "failed" && (react_1.default.createElement(TaxAxisBadge_1.TaxAxisBadge, { color: "red", size: "xs" }, "FAILED")),
67
+ doc.status === "valid" && doc.qboSource && (react_1.default.createElement(react_1.default.Fragment, null,
68
+ react_1.default.createElement("span", { style: {
69
+ fontSize: 9,
70
+ fontWeight: 700,
71
+ letterSpacing: "0.05em",
72
+ padding: "1px 6px",
73
+ borderRadius: 3,
74
+ background: "rgba(44,160,28,0.1)",
75
+ border: "1px solid rgba(44,160,28,0.2)",
76
+ color: "#2CA01C",
77
+ } }, "QUICKBOOKS"),
78
+ react_1.default.createElement("span", { style: {
79
+ fontSize: 9,
80
+ fontWeight: 600,
81
+ color: "#2CA01C",
82
+ } }, "Synced")))),
67
83
  react_1.default.createElement("div", { className: "text-[11px] text-tax-axis-text-3 font-tax-axis-body mt-0.5" }, doc.status === "valid" && doc.fileName
68
84
  ? `${doc.fileName}${fieldCount ? ` \u00b7 ${fieldCount} fields extracted` : ""}`
69
85
  : doc.status === "failed" && doc.parseError
70
86
  ? doc.parseError
71
87
  : ((_a = doc.fileName) !== null && _a !== void 0 ? _a : (helpOverride !== null && helpOverride !== void 0 ? helpOverride : doc.help)))),
72
- react_1.default.createElement("div", { className: "flex items-center gap-2 flex-shrink-0" },
88
+ react_1.default.createElement("div", { className: "flex items-center gap-2 flex-shrink-0 w-full sm:w-auto" },
73
89
  doc.status === "valid" && (react_1.default.createElement(react_1.default.Fragment, null,
74
90
  react_1.default.createElement("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none" },
75
91
  react_1.default.createElement("path", { d: "M2.5 7l3.5 3.5 5.5-6", stroke: "#0F6E56", strokeWidth: "2", strokeLinecap: "round" })),
@@ -28,5 +28,16 @@ export interface TaxAxisDocumentsProps extends TaxAxisScreenProps {
28
28
  parsedFieldCounts?: Record<string, number>;
29
29
  jobId?: string;
30
30
  onSaveReviewedField?: (documentId: string, reviewedData: Record<string, unknown>) => Promise<void>;
31
+ qboConnected?: boolean;
32
+ qboCompanyName?: string | null;
33
+ qboAuthorizeUrl?: string;
34
+ onImportQboReport?: (sessionId: string, realmId: string, reportType: string, accountingMethod: string) => Promise<any>;
35
+ onQboConnected?: (companyName: string) => void;
36
+ onQboDisconnected?: () => void;
37
+ onQboImport?: (mappedDocs: {
38
+ slot: string;
39
+ fileName: string;
40
+ }[]) => void;
41
+ qboClientConfirmed?: boolean;
31
42
  }
32
- export declare function TaxAxisDocuments({ profile, entityType, onContinue, onBack, onUploadDocument, onDeleteDocument, fetchUploadedDocuments, parsedFieldCounts, jobId, onSaveReviewedField, userContext: _userContext, }: TaxAxisDocumentsProps): React.JSX.Element;
43
+ export declare function TaxAxisDocuments({ profile, entityType, onContinue, onBack, onUploadDocument, onDeleteDocument, fetchUploadedDocuments, parsedFieldCounts, jobId, onSaveReviewedField, userContext: _userContext, qboConnected, qboCompanyName, qboAuthorizeUrl, onImportQboReport, onQboConnected, onQboDisconnected, onQboImport, qboClientConfirmed, }: TaxAxisDocumentsProps): React.JSX.Element;