@paro.io/expert-shared-components 1.14.52 → 1.14.53

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 (31) hide show
  1. package/lib/components/DocumentCenter/MultiFileUploadSection.js +220 -121
  2. package/lib/components/TaxAxis/TaxAxisApi.d.ts +1 -0
  3. package/lib/components/TaxAxis/TaxAxisShell.js +36 -9
  4. package/lib/index.d.ts +1 -14
  5. package/lib/index.js +1 -27
  6. package/lib/tax-axis/components/clientReport/TaxAxisClientReport.d.ts +6 -2
  7. package/lib/tax-axis/components/clientReport/TaxAxisClientReport.js +5 -3
  8. package/lib/tax-axis/components/dashboard/TaxAxisDashboard.d.ts +2 -1
  9. package/lib/tax-axis/components/dashboard/TaxAxisDashboard.js +163 -34
  10. package/lib/tax-axis/components/documents/DocumentCard.d.ts +3 -1
  11. package/lib/tax-axis/components/documents/DocumentCard.js +17 -5
  12. package/lib/tax-axis/components/documents/DocumentReviewModal.d.ts +13 -0
  13. package/lib/tax-axis/components/documents/DocumentReviewModal.js +248 -0
  14. package/lib/tax-axis/components/documents/DocumentTier.d.ts +3 -1
  15. package/lib/tax-axis/components/documents/DocumentTier.js +2 -2
  16. package/lib/tax-axis/components/documents/TaxAxisDocuments.d.ts +5 -1
  17. package/lib/tax-axis/components/documents/TaxAxisDocuments.js +86 -5
  18. package/lib/tax-axis/components/extractionReview/TaxAxisExtractionReview.js +17 -17
  19. package/lib/tax-axis/components/intake/ClientParametersSection.js +1 -1
  20. package/lib/tax-axis/components/intake/intakeSchema.js +1 -1
  21. package/lib/tax-axis/components/preparerWorkpaper/TaxAxisPreparerWorkpaper.d.ts +6 -2
  22. package/lib/tax-axis/components/preparerWorkpaper/TaxAxisPreparerWorkpaper.js +5 -3
  23. package/lib/tax-axis/index.d.ts +4 -0
  24. package/lib/tax-axis/index.js +6 -1
  25. package/lib/tax-axis/lib/adapters/useEngineOutput.d.ts +144 -0
  26. package/lib/tax-axis/lib/adapters/useEngineOutput.js +155 -0
  27. package/lib/tax-axis/lib/data/documents.d.ts +1 -0
  28. package/lib/tax-axis/lib/data/documents.js +5 -0
  29. package/lib/tax-axis/lib/documentFieldCatalog.d.ts +13 -0
  30. package/lib/tax-axis/lib/documentFieldCatalog.js +808 -0
  31. package/package.json +1 -1
@@ -1,9 +1,13 @@
1
1
  import React from "react";
2
- import type { ClientProfile } from "../../lib/types";
2
+ import type { ClientProfile, Strategy, ComputedMap } from "../../lib/types";
3
3
  import type { TaxAxisScreenProps } from "../../lib/types";
4
4
  export interface TaxAxisClientReportProps extends TaxAxisScreenProps {
5
5
  profile: ClientProfile;
6
6
  onBack: () => void;
7
7
  onNavigatePreparer?: () => void;
8
+ /** When provided, bypasses local filterEligibleStrategies + computeAllStrategies. */
9
+ liveStrategies?: Strategy[];
10
+ /** When provided, bypasses local computeAllStrategies. Must accompany liveStrategies. */
11
+ liveComputedMap?: ComputedMap;
8
12
  }
9
- export declare function TaxAxisClientReport({ profile, onBack, onNavigatePreparer }: TaxAxisClientReportProps): React.JSX.Element;
13
+ export declare function TaxAxisClientReport({ profile, onBack, onNavigatePreparer, liveStrategies, liveComputedMap }: TaxAxisClientReportProps): React.JSX.Element;
@@ -34,11 +34,13 @@ const ExecutiveSummary_1 = require("./ExecutiveSummary");
34
34
  const RecommendedStrategies_1 = require("./RecommendedStrategies");
35
35
  const ImplementationRoadmap_1 = require("./ImplementationRoadmap");
36
36
  const Methodology_1 = require("./Methodology");
37
- function TaxAxisClientReport({ profile, onBack, onNavigatePreparer }) {
37
+ function TaxAxisClientReport({ profile, onBack, onNavigatePreparer, liveStrategies, liveComputedMap }) {
38
38
  var _a, _b, _c;
39
39
  const [view, setView] = (0, react_1.useState)("client");
40
- const eligible = (0, react_1.useMemo)(() => (0, compute_1.filterEligibleStrategies)(profile), [profile]);
41
- const computed = (0, react_1.useMemo)(() => (0, compute_1.computeAllStrategies)(profile), [profile]);
40
+ const staticEligible = (0, react_1.useMemo)(() => (0, compute_1.filterEligibleStrategies)(profile), [profile]);
41
+ const staticComputed = (0, react_1.useMemo)(() => (0, compute_1.computeAllStrategies)(profile), [profile]);
42
+ const eligible = liveStrategies !== null && liveStrategies !== void 0 ? liveStrategies : staticEligible;
43
+ const computed = liveComputedMap !== null && liveComputedMap !== void 0 ? liveComputedMap : staticComputed;
42
44
  const totalLo = Math.round(eligible.reduce((a, s) => { var _a, _b; return a + ((_b = (_a = computed.get(s.rank)) === null || _a === void 0 ? void 0 : _a.lo) !== null && _b !== void 0 ? _b : s.lo); }, 0) / 1000);
43
45
  const totalHi = Math.round(eligible.reduce((a, s) => { var _a, _b; return a + ((_b = (_a = computed.get(s.rank)) === null || _a === void 0 ? void 0 : _a.hi) !== null && _b !== void 0 ? _b : s.hi); }, 0) / 1000);
44
46
  const top3 = [...eligible].sort((a, b) => b.score - a.score).slice(0, 3);
@@ -63,5 +63,6 @@ export interface TaxAxisDashboardProps extends TaxAxisScreenProps {
63
63
  onSend: () => void;
64
64
  onReset: () => void;
65
65
  onReviewData?: () => void;
66
+ onUploadMore?: () => void;
66
67
  }
67
- export declare function TaxAxisDashboard({ profile, llmResult, onDownloadClient, onDownloadPreparer, onPresent, onSend, onReset, onReviewData, userContext: _userContext, }: TaxAxisDashboardProps): React.JSX.Element;
68
+ export declare function TaxAxisDashboard({ profile, llmResult, onDownloadClient, onDownloadPreparer, onPresent, onSend, onReset, onReviewData, onUploadMore, userContext: _userContext, }: TaxAxisDashboardProps): React.JSX.Element;
@@ -61,29 +61,74 @@ function humanizeStrategyType(raw) {
61
61
  .replace(/_/g, " ")
62
62
  .replace(/\b\w/g, (c) => c.toUpperCase());
63
63
  }
64
+ // Build a lookup from strategy_id → strategy_name using engineOutput.strategy_analysis
65
+ function buildEngineNameLookup(llm) {
66
+ var _a;
67
+ const map = new Map();
68
+ const analysis = (_a = llm.engineOutput) === null || _a === void 0 ? void 0 : _a.strategy_analysis;
69
+ if (Array.isArray(analysis)) {
70
+ for (const a of analysis) {
71
+ if (a.strategy_id && a.strategy_name)
72
+ map.set(a.strategy_id, a.strategy_name);
73
+ }
74
+ }
75
+ return map;
76
+ }
77
+ // Build a lookup from strategy_id → roadmap bucket using engineOutput.implementation_roadmap
78
+ function buildRoadmapBucketLookup(llm) {
79
+ var _a, _b;
80
+ const map = new Map();
81
+ const roadmap = (_a = llm.engineOutput) === null || _a === void 0 ? void 0 : _a.implementation_roadmap;
82
+ if (!roadmap)
83
+ return map;
84
+ const bucketKeys = [
85
+ { key: "quick_wins", bucket: "now" },
86
+ { key: "immediate", bucket: "now" },
87
+ { key: "thirty_day", bucket: "30d" },
88
+ { key: "ninety_day", bucket: "90d" },
89
+ { key: "annual", bucket: "filing" },
90
+ ];
91
+ for (const { key, bucket } of bucketKeys) {
92
+ for (const item of (_b = roadmap[key]) !== null && _b !== void 0 ? _b : []) {
93
+ if (item.strategy_id)
94
+ map.set(item.strategy_id, bucket);
95
+ }
96
+ }
97
+ return map;
98
+ }
64
99
  function mapLlmToStrategies(llm) {
100
+ const nameLookup = buildEngineNameLookup(llm);
101
+ const bucketLookup = buildRoadmapBucketLookup(llm);
65
102
  return llm.strategies
66
103
  .filter((s) => s.applicable)
67
- .map((s, idx) => ({
68
- rank: idx + 1,
69
- code: s.strategyType,
70
- name: humanizeStrategyType(s.strategyType),
71
- cat: "income",
72
- priority: (s.priority || "MEDIUM").toUpperCase(),
73
- score: s.priority === "HIGH" ? 85 : s.priority === "MEDIUM" ? 70 : 55,
74
- entities: [],
75
- lo: s.estimatedSavings.min,
76
- hi: s.estimatedSavings.max,
77
- timeline: s.priority === "HIGH" ? "Act now" : "Within 90 days",
78
- timelineBucket: s.priority === "HIGH" ? "now" : "90d",
79
- clientBrief: s.summary,
80
- action: s.implementationSteps.join(". "),
81
- forms: s.requiredForms.join(", "),
82
- abstract: s.summary,
83
- sources: [],
84
- trace: [],
85
- cost: undefined,
86
- }));
104
+ .map((s, idx) => {
105
+ var _a, _b, _c, _d, _e;
106
+ const id = (_a = s.strategyId) !== null && _a !== void 0 ? _a : s.strategyType;
107
+ // Prefer the real strategy_name from engineOutput, fall back to humanized strategyType
108
+ const name = (_b = nameLookup.get(id)) !== null && _b !== void 0 ? _b : humanizeStrategyType(s.strategyType);
109
+ const timelineBucket = (_c = bucketLookup.get(id)) !== null && _c !== void 0 ? _c : (s.priority === "HIGH" ? "now" : "90d");
110
+ const weightedScore = (_d = s.weightedScore) !== null && _d !== void 0 ? _d : (s.priority === "HIGH" ? 85 : s.priority === "MEDIUM" ? 70 : 55);
111
+ return {
112
+ rank: idx + 1,
113
+ code: id,
114
+ name,
115
+ cat: "income",
116
+ priority: (s.priority || "MEDIUM").toUpperCase(),
117
+ score: Math.round(weightedScore),
118
+ entities: [],
119
+ lo: s.estimatedSavings.min,
120
+ hi: s.estimatedSavings.max,
121
+ timeline: timelineBucket === "now" ? "Act now" : timelineBucket === "30d" ? "Within 30 days" : "Within 90 days",
122
+ timelineBucket,
123
+ clientBrief: s.summary,
124
+ action: (_e = s.implementationSteps[0]) !== null && _e !== void 0 ? _e : s.summary,
125
+ forms: s.requiredForms.join(", "),
126
+ abstract: s.summary,
127
+ sources: [],
128
+ trace: [],
129
+ cost: undefined,
130
+ };
131
+ });
87
132
  }
88
133
  function buildLlmComputed(strategies) {
89
134
  const map = new Map();
@@ -100,7 +145,7 @@ const BUCKETS = [
100
145
  { key: "30d", label: "Within 30 Days", desc: "Documentation or payroll changes" },
101
146
  { key: "90d", label: "Within 90 Days", desc: "Structural changes — new accounts or plan setup" },
102
147
  ];
103
- function TaxAxisDashboard({ profile, llmResult, onDownloadClient, onDownloadPreparer, onPresent, onSend, onReset, onReviewData, userContext: _userContext = "expert", }) {
148
+ function TaxAxisDashboard({ profile, llmResult, onDownloadClient, onDownloadPreparer, onPresent, onSend, onReset, onReviewData, onUploadMore, userContext: _userContext = "expert", }) {
104
149
  var _a, _b;
105
150
  const hasLlm = !!((_a = llmResult === null || llmResult === void 0 ? void 0 : llmResult.strategies) === null || _a === void 0 ? void 0 : _a.length);
106
151
  // ─── Derived data ──────────────────────────────────────────────
@@ -110,11 +155,13 @@ function TaxAxisDashboard({ profile, llmResult, onDownloadClient, onDownloadPrep
110
155
  const dashEligible = (0, react_1.useMemo)(() => (hasLlm ? llmStrategies : (0, compute_1.filterEligibleStrategies)(profile)), [hasLlm, llmStrategies, profile]);
111
156
  const maxSavings = Math.max(...dashEligible.map((s) => { var _a, _b; return (_b = (_a = computed.get(s.rank)) === null || _a === void 0 ? void 0 : _a.hi) !== null && _b !== void 0 ? _b : s.hi; }), 1);
112
157
  // ─── State ─────────────────────────────────────────────────────
113
- const [topTab, setTopTab] = (0, react_1.useState)("extraction");
158
+ // When LLM result is present, land directly on the Intelligence Report tab
159
+ const [topTab, setTopTab] = (0, react_1.useState)(hasLlm ? "report" : "extraction");
114
160
  const [reportTab, setReportTab] = (0, react_1.useState)("report");
115
161
  const [chartExpanded, setChartExpanded] = (0, react_1.useState)(false);
116
162
  const [selected, setSelected] = (0, react_1.useState)(null);
117
- const [dataConfirmed, setDataConfirmed] = (0, react_1.useState)(false);
163
+ // When LLM result is present, data is implicitly confirmed — skip the gate
164
+ const [dataConfirmed, setDataConfirmed] = (0, react_1.useState)(hasLlm);
118
165
  const [reviewStatus, setReviewStatus] = (0, react_1.useState)({
119
166
  unreviewed: data_1.EXTRACTED_DATA.reduce((a, d) => a + d.flagCount, 0),
120
167
  edits: 0,
@@ -139,8 +186,23 @@ function TaxAxisDashboard({ profile, llmResult, onDownloadClient, onDownloadPrep
139
186
  const c = computed.get(selected.rank);
140
187
  return Object.assign(Object.assign({}, selected), { lo: (_a = c === null || c === void 0 ? void 0 : c.lo) !== null && _a !== void 0 ? _a : selected.lo, hi: (_b = c === null || c === void 0 ? void 0 : c.hi) !== null && _b !== void 0 ? _b : selected.hi, sources: (_c = c === null || c === void 0 ? void 0 : c.sources) !== null && _c !== void 0 ? _c : selected.sources, trace: (_d = c === null || c === void 0 ? void 0 : c.trace) !== null && _d !== void 0 ? _d : selected.trace });
141
188
  }, [selected, computed]);
142
- // Sorted strategies for impact distribution
143
- const sortedByImpact = (0, react_1.useMemo)(() => [...dashEligible].sort((a, b) => { var _a, _b, _c, _d; return ((_b = (_a = computed.get(b.rank)) === null || _a === void 0 ? void 0 : _a.hi) !== null && _b !== void 0 ? _b : b.hi) - ((_d = (_c = computed.get(a.rank)) === null || _c === void 0 ? void 0 : _c.hi) !== null && _d !== void 0 ? _d : a.hi); }), [dashEligible, computed]);
189
+ // Split eligible strategies into calculable (hi > 0) vs uncalculated ($0K)
190
+ const calculable = (0, react_1.useMemo)(() => dashEligible.filter((s) => { var _a, _b; return ((_b = (_a = computed.get(s.rank)) === null || _a === void 0 ? void 0 : _a.hi) !== null && _b !== void 0 ? _b : s.hi) > 0; }), [dashEligible, computed]);
191
+ const uncalculated = (0, react_1.useMemo)(() => dashEligible.filter((s) => { var _a, _b; return ((_b = (_a = computed.get(s.rank)) === null || _a === void 0 ? void 0 : _a.hi) !== null && _b !== void 0 ? _b : s.hi) === 0; }), [dashEligible, computed]);
192
+ // Sorted calculable strategies for impact distribution
193
+ const sortedByImpact = (0, react_1.useMemo)(() => [...calculable].sort((a, b) => { var _a, _b, _c, _d; return ((_b = (_a = computed.get(b.rank)) === null || _a === void 0 ? void 0 : _a.hi) !== null && _b !== void 0 ? _b : b.hi) - ((_d = (_c = computed.get(a.rank)) === null || _c === void 0 ? void 0 : _c.hi) !== null && _d !== void 0 ? _d : a.hi); }), [calculable, computed]);
194
+ // Reverse-map: strategy name → document names needed (from DOC_SPECS_BASE)
195
+ const strategyDocNeeds = (0, react_1.useMemo)(() => {
196
+ const map = new Map();
197
+ uncalculated.forEach((s) => {
198
+ const docs = data_1.DOC_SPECS_BASE
199
+ .filter((d) => d.strategies.some((st) => s.name.includes(st) || st.includes(s.code)))
200
+ .map((d) => d.name);
201
+ map.set(s.name, docs.length > 0 ? docs : ["Upload additional documents"]);
202
+ });
203
+ return map;
204
+ }, [uncalculated]);
205
+ const [uncalcExpanded, setUncalcExpanded] = (0, react_1.useState)(false);
144
206
  return (react_1.default.createElement("div", null,
145
207
  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: {
146
208
  background: "rgba(36,131,132,0.06)",
@@ -220,6 +282,23 @@ function TaxAxisDashboard({ profile, llmResult, onDownloadClient, onDownloadPrep
220
282
  marginBottom: "-1px",
221
283
  } }, lbl)))),
222
284
  reportTab === "report" ? (react_1.default.createElement("div", null,
285
+ reviewStatus.unreviewed > 0 && (react_1.default.createElement("div", { className: "rounded-[14px] mb-4 flex items-center gap-3", style: {
286
+ background: "rgba(251,154,29,0.06)",
287
+ border: "1px solid rgba(251,154,29,0.20)",
288
+ borderLeft: "4px solid #FB9A1D",
289
+ padding: "14px 20px",
290
+ } },
291
+ react_1.default.createElement("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", className: "flex-shrink-0" },
292
+ react_1.default.createElement("path", { d: "M8 1.5l6.5 12H1.5L8 1.5z", stroke: "#FB9A1D", strokeWidth: "1.3", fill: "none" }),
293
+ react_1.default.createElement("path", { d: "M8 6.5v3M8 11h.005", stroke: "#FB9A1D", strokeWidth: "1.3", strokeLinecap: "round" })),
294
+ react_1.default.createElement("div", { className: "flex-1" },
295
+ react_1.default.createElement("span", { className: "text-[13px] font-semibold text-white font-tax-axis-body" },
296
+ reviewStatus.unreviewed,
297
+ " extracted value",
298
+ reviewStatus.unreviewed > 1 ? "s" : "",
299
+ " flagged for review"),
300
+ react_1.default.createElement("span", { className: "text-[12px] text-tax-axis-text-2 font-tax-axis-body ml-2" }, "\u2014 strategy savings may shift after corrections")),
301
+ onReviewData && (react_1.default.createElement(TaxAxisButton_1.TaxAxisButton, { variant: "secondary", onClick: onReviewData, className: "flex-shrink-0" }, "Review Extracted Values")))),
223
302
  react_1.default.createElement("div", { className: "rounded-[14px] mb-4", style: {
224
303
  background: "#0E1132",
225
304
  border: "1px solid rgba(36,131,132,0.12)",
@@ -235,7 +314,7 @@ function TaxAxisDashboard({ profile, llmResult, onDownloadClient, onDownloadPrep
235
314
  color: "#9498B8",
236
315
  } }, chartExpanded ? "Collapse \u2191" : "Expand \u2193")),
237
316
  sortedByImpact
238
- .slice(0, chartExpanded ? dashEligible.length : 12)
317
+ .slice(0, chartExpanded ? calculable.length : 12)
239
318
  .map((s, i) => {
240
319
  var _a, _b, _c, _d;
241
320
  const chi = (_b = (_a = computed.get(s.rank)) === null || _a === void 0 ? void 0 : _a.hi) !== null && _b !== void 0 ? _b : s.hi;
@@ -260,24 +339,74 @@ function TaxAxisDashboard({ profile, llmResult, onDownloadClient, onDownloadPrep
260
339
  "\u2013",
261
340
  fmtK(chi))));
262
341
  }),
263
- !chartExpanded && dashEligible.length > 12 && (react_1.default.createElement("div", { onClick: () => setChartExpanded(true), className: "text-[11px] text-tax-axis-teal-light font-tax-axis-mono mt-1 cursor-pointer hover:underline" },
342
+ !chartExpanded && calculable.length > 12 && (react_1.default.createElement("div", { onClick: () => setChartExpanded(true), className: "text-[11px] text-tax-axis-teal-light font-tax-axis-mono mt-1 cursor-pointer hover:underline" },
264
343
  "+ ",
265
- dashEligible.length - 12,
344
+ calculable.length - 12,
266
345
  " more strategies \u2014 click to view all")),
267
346
  chartExpanded && (react_1.default.createElement("div", { onClick: () => setChartExpanded(false), className: "text-[11px] text-tax-axis-text-3 font-tax-axis-mono mt-1 cursor-pointer hover:text-tax-axis-teal" },
268
347
  "Showing all ",
269
- dashEligible.length,
348
+ calculable.length,
270
349
  " strategies \u2014 click to collapse"))),
271
350
  react_1.default.createElement("div", { className: "text-[13px] font-bold text-white uppercase tracking-widest mb-2.5 font-tax-axis-head flex justify-between items-center" },
272
351
  react_1.default.createElement("span", null,
273
352
  dashEligible.length,
274
353
  " Strategies"),
275
354
  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")),
276
- react_1.default.createElement("div", { className: "grid grid-cols-2 gap-2.5 mb-4" }, dashEligible.map((s, i) => {
277
- var _a, _b;
278
- const c = computed.get(s.rank);
279
- return (react_1.default.createElement(StrategyTile_1.StrategyTile, { key: s.rank, s: Object.assign(Object.assign({}, s), { lo: (_a = c === null || c === void 0 ? void 0 : c.lo) !== null && _a !== void 0 ? _a : s.lo, hi: (_b = c === null || c === void 0 ? void 0 : c.hi) !== null && _b !== void 0 ? _b : s.hi }), delay: 0.2 + i * 0.06, onClick: () => setSelected(s), maxSavings: maxSavings }));
280
- })),
355
+ react_1.default.createElement("div", { className: "grid grid-cols-2 gap-2.5 mb-4" },
356
+ calculable.map((s, i) => {
357
+ var _a, _b;
358
+ const c = computed.get(s.rank);
359
+ return (react_1.default.createElement(StrategyTile_1.StrategyTile, { key: s.rank, s: Object.assign(Object.assign({}, s), { lo: (_a = c === null || c === void 0 ? void 0 : c.lo) !== null && _a !== void 0 ? _a : s.lo, hi: (_b = c === null || c === void 0 ? void 0 : c.hi) !== null && _b !== void 0 ? _b : s.hi }), delay: 0.2 + i * 0.06, onClick: () => setSelected(s), maxSavings: maxSavings }));
360
+ }),
361
+ hasLlm && uncalculated.map((s, i) => (react_1.default.createElement("div", { key: s.rank, onClick: () => setSelected(s), className: "rounded-[14px] p-4 cursor-pointer", style: {
362
+ background: "#0E1132",
363
+ border: "1px solid rgba(36,131,132,0.12)",
364
+ boxShadow: "0 2px 8px rgba(6,8,33,0.3)",
365
+ animationDelay: `${0.2 + (calculable.length + i) * 0.06}s`,
366
+ } },
367
+ react_1.default.createElement("div", { className: "flex items-start justify-between gap-2 mb-2" },
368
+ react_1.default.createElement("div", { className: "flex items-center gap-2 flex-wrap" },
369
+ react_1.default.createElement("span", { className: "text-[10px] font-semibold font-tax-axis-mono px-2 py-0.5 rounded", style: { background: "rgba(36,131,132,0.12)", color: "#A1E5E6", border: "1px solid rgba(36,131,132,0.2)" } }, s.code),
370
+ react_1.default.createElement("span", { className: "text-[10px] font-semibold font-tax-axis-mono px-2 py-0.5 rounded", style: { background: "rgba(148,152,184,0.1)", color: "#9498B8", border: "1px solid rgba(148,152,184,0.15)" } }, "Qualitative")),
371
+ react_1.default.createElement("div", { className: "w-8 h-8 rounded-full flex items-center justify-center text-[12px] font-bold font-tax-axis-mono flex-shrink-0", style: {
372
+ background: "conic-gradient(#248384 0%, #248384 55%, #1A1D3A 55%)",
373
+ color: "#A1E5E6",
374
+ } }, s.score)),
375
+ react_1.default.createElement("div", { className: "text-[14px] font-semibold text-white font-tax-axis-head mb-1 leading-tight" }, s.name),
376
+ react_1.default.createElement("div", { className: "text-[12px] text-tax-axis-teal-light font-tax-axis-mono mb-2" }, s.timeline),
377
+ react_1.default.createElement("div", { className: "h-0.5 w-full rounded-sm mb-2", style: { background: "rgba(36,131,132,0.2)" } }),
378
+ react_1.default.createElement("p", { className: "text-[11px] text-tax-axis-text-2 font-tax-axis-body leading-relaxed line-clamp-2" }, s.abstract || s.clientBrief))))),
379
+ uncalculated.length > 0 && !hasLlm && (react_1.default.createElement("div", { className: "rounded-[14px] overflow-hidden mb-4", style: {
380
+ background: "#0E1132",
381
+ border: "1px solid rgba(251,154,29,0.15)",
382
+ boxShadow: "0 2px 8px rgba(6,8,33,0.3)",
383
+ } },
384
+ react_1.default.createElement("div", { onClick: () => setUncalcExpanded((p) => !p), className: "px-5 py-3.5 flex items-center gap-3 cursor-pointer" },
385
+ react_1.default.createElement("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", className: "flex-shrink-0" },
386
+ react_1.default.createElement("circle", { cx: "7", cy: "7", r: "5.5", stroke: "#FB9A1D", strokeWidth: "1.2" }),
387
+ react_1.default.createElement("path", { d: "M7 4.5v3M7 9.5h.005", stroke: "#FB9A1D", strokeWidth: "1.2", strokeLinecap: "round" })),
388
+ react_1.default.createElement("span", { className: "text-[13px] font-semibold text-white font-tax-axis-body flex-1" }, hasLlm
389
+ ? `${uncalculated.length} qualitative strateg${uncalculated.length > 1 ? "ies" : "y"} — CPA review recommended`
390
+ : `${uncalculated.length} strateg${uncalculated.length > 1 ? "ies" : "y"} need more data to calculate savings`),
391
+ react_1.default.createElement("svg", { width: "12", height: "12", viewBox: "0 0 12 12", fill: "none", style: {
392
+ transform: uncalcExpanded ? "rotate(180deg)" : "none",
393
+ transition: "transform .2s",
394
+ } },
395
+ react_1.default.createElement("path", { d: "M3 4.5l3 3 3-3", stroke: "#9498B8", strokeWidth: "1.5", strokeLinecap: "round" }))),
396
+ uncalcExpanded && (react_1.default.createElement("div", { style: { borderTop: "1px solid rgba(251,154,29,0.12)", padding: "12px 20px" } },
397
+ uncalculated.map((s, i) => (react_1.default.createElement("div", { key: s.rank, className: "py-2.5 cursor-pointer", style: {
398
+ borderBottom: i < uncalculated.length - 1
399
+ ? "1px solid rgba(36,131,132,0.08)"
400
+ : "none",
401
+ }, onClick: () => setSelected(s) },
402
+ react_1.default.createElement("div", { className: "flex items-center gap-2.5 mb-1" },
403
+ react_1.default.createElement("span", { className: "text-[11px] font-tax-axis-mono px-2 py-0.5 rounded", style: { color: "#FB9A1D", background: "rgba(251,154,29,0.08)", border: "1px solid rgba(251,154,29,0.15)" } }, s.code),
404
+ react_1.default.createElement("span", { className: "text-[13px] text-white font-tax-axis-body font-semibold" }, s.name)),
405
+ react_1.default.createElement("div", { className: "text-[11px] text-tax-axis-text-2 font-tax-axis-body pl-0.5" }, hasLlm
406
+ ? (s.abstract || s.clientBrief || "See CPA for details")
407
+ : `Needs: ${(strategyDocNeeds.get(s.name) || ["Upload additional documents"]).join(", ")}`)))),
408
+ !hasLlm && onUploadMore && (react_1.default.createElement("div", { className: "pt-3 mt-1", style: { borderTop: "1px solid rgba(251,154,29,0.12)" } },
409
+ react_1.default.createElement(TaxAxisButton_1.TaxAxisButton, { variant: "secondary", onClick: onUploadMore }, "Upload Documents"))))))),
281
410
  !hasLlm && (react_1.default.createElement("div", { className: "rounded-[14px] overflow-hidden mb-4", style: {
282
411
  background: "#0E1132",
283
412
  border: "1px solid rgba(36,131,132,0.12)",
@@ -12,9 +12,11 @@ interface DocumentCardProps {
12
12
  tierBadgeColor: "red" | "orange" | "neutral";
13
13
  tierBadgeText: string;
14
14
  helpOverride?: string;
15
+ fieldCount?: number;
15
16
  onUpload: (file: File) => void;
16
17
  onClear: () => void;
17
18
  onRemove?: () => void;
19
+ onReview?: () => void;
18
20
  }
19
- export declare function DocumentCard({ doc, tierBorderColor, tierBadgeColor, tierBadgeText, helpOverride, onUpload, onClear, onRemove, }: DocumentCardProps): React.JSX.Element;
21
+ export declare function DocumentCard({ doc, tierBorderColor, tierBadgeColor, tierBadgeText, helpOverride, fieldCount, onUpload, onClear, onRemove, onReview, }: DocumentCardProps): React.JSX.Element;
20
22
  export {};
@@ -33,7 +33,7 @@ const STATUS_STYLES = {
33
33
  cardBorder: "rgba(15,110,86,0.25)",
34
34
  },
35
35
  };
36
- function DocumentCard({ doc, tierBorderColor, tierBadgeColor, tierBadgeText, helpOverride, onUpload, onClear, onRemove, }) {
36
+ function DocumentCard({ doc, tierBorderColor, tierBadgeColor, tierBadgeText, helpOverride, fieldCount, onUpload, onClear, onRemove, onReview, }) {
37
37
  var _a, _b, _c;
38
38
  const ss = STATUS_STYLES[doc.status];
39
39
  const leftBorder = doc.status === "valid" ? "rgba(15,110,86,0.6)" : tierBorderColor;
@@ -64,12 +64,24 @@ function DocumentCard({ doc, tierBorderColor, tierBadgeColor, tierBadgeText, hel
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
66
  doc.status === "failed" && (react_1.default.createElement(TaxAxisBadge_1.TaxAxisBadge, { color: "red", size: "xs" }, "FAILED"))),
67
- react_1.default.createElement("div", { className: "text-[11px] text-tax-axis-text-3 font-tax-axis-body mt-0.5" }, doc.status === "failed" && doc.parseError
68
- ? doc.parseError
69
- : (_a = doc.fileName) !== null && _a !== void 0 ? _a : (helpOverride !== null && helpOverride !== void 0 ? helpOverride : doc.help))),
67
+ 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
+ ? `${doc.fileName}${fieldCount ? ` \u00b7 ${fieldCount} fields extracted` : ""}`
69
+ : doc.status === "failed" && doc.parseError
70
+ ? doc.parseError
71
+ : ((_a = doc.fileName) !== null && _a !== void 0 ? _a : (helpOverride !== null && helpOverride !== void 0 ? helpOverride : doc.help)))),
70
72
  react_1.default.createElement("div", { className: "flex items-center gap-2 flex-shrink-0" },
71
73
  doc.status === "valid" && (react_1.default.createElement(react_1.default.Fragment, null,
72
- react_1.default.createElement("span", { className: "text-[10px] font-semibold font-tax-axis-mono", style: { color: "#0F6E56" } }, "Parsed"),
74
+ react_1.default.createElement("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none" },
75
+ react_1.default.createElement("path", { d: "M2.5 7l3.5 3.5 5.5-6", stroke: "#0F6E56", strokeWidth: "2", strokeLinecap: "round" })),
76
+ onReview && (react_1.default.createElement("button", { onClick: onReview, className: "rounded-md px-3 py-1 text-[11px] font-semibold font-tax-axis-mono cursor-pointer flex items-center gap-1.5", style: {
77
+ background: "rgba(99,102,241,0.12)",
78
+ border: "1px solid rgba(99,102,241,0.30)",
79
+ color: "#a5b4fc",
80
+ } },
81
+ react_1.default.createElement("svg", { width: "12", height: "12", viewBox: "0 0 12 12", fill: "none" },
82
+ react_1.default.createElement("rect", { x: "2", y: "1.5", width: "8", height: "9", rx: "1.5", stroke: "#a5b4fc", strokeWidth: "1.2" }),
83
+ react_1.default.createElement("path", { d: "M4 4.5h4M4 6.5h4M4 8.5h2", stroke: "#a5b4fc", strokeWidth: "0.9", strokeLinecap: "round" })),
84
+ "Review")),
73
85
  react_1.default.createElement("button", { onClick: onClear, className: "bg-transparent border-none p-1 text-tax-axis-text-4 text-sm cursor-pointer" }, "\u00D7"))),
74
86
  (doc.status === "parsing" || doc.status === "validating") && (react_1.default.createElement("span", { className: "text-[10px] font-semibold font-tax-axis-mono", style: { color: doc.status === "parsing" ? "#248384" : "#FB9A1D" } }, doc.status === "parsing" ? "Parsing…" : "Uploading…")),
75
87
  doc.status === "failed" && (react_1.default.createElement(react_1.default.Fragment, null,
@@ -0,0 +1,13 @@
1
+ import React from "react";
2
+ export declare const EXTRACTED_FIELDS_QUERY = "\n query ExtractedDocumentFields($jobId: ID!, $documentId: ID!) {\n extractedDocumentFields(jobId: $jobId, documentId: $documentId) {\n documentId\n documentName\n fileName\n sections {\n head\n fields {\n key\n label\n value\n sourceRef\n confidence\n }\n }\n }\n }\n";
3
+ export declare const SAVE_FIELD_EDIT_MUTATION = "\n mutation SaveExtractedFieldEdit($jobId: ID!, $documentId: ID!, $fieldKey: String!, $value: String!) {\n saveExtractedFieldEdit(jobId: $jobId, documentId: $documentId, fieldKey: $fieldKey, value: $value) {\n success\n fieldKey\n savedValue\n }\n }\n";
4
+ export interface DocumentReviewModalProps {
5
+ documentId: string;
6
+ documentName: string;
7
+ fileName: string;
8
+ jobId: string;
9
+ parsedData?: Record<string, unknown> | null;
10
+ onSaveReviewedData?: (fields: Record<string, string>) => Promise<void>;
11
+ onClose: () => void;
12
+ }
13
+ export declare function DocumentReviewModal({ documentId, documentName, fileName, jobId: _jobId, parsedData, onSaveReviewedData, onClose, }: DocumentReviewModalProps): React.JSX.Element;