@paro.io/expert-shared-components 1.14.74 → 1.14.76

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.
@@ -128,6 +128,19 @@ function buildSessionInput(profile) {
128
128
  states: profile.states || [],
129
129
  };
130
130
  }
131
+ function enrichWithAllocations(p) {
132
+ var _a;
133
+ if (!((_a = p.partners) === null || _a === void 0 ? void 0 : _a.length))
134
+ return p;
135
+ const netIncome = toInt(p.netIncome);
136
+ const ownerComp = toInt(p.ownerComp);
137
+ return Object.assign(Object.assign({}, p), { per_owner_allocations: p.partners.map(partner => ({
138
+ owner_name: partner.name,
139
+ ownership_pct: partner.ownershipPct / 100,
140
+ qbi: Math.round(netIncome * (partner.ownershipPct / 100)),
141
+ w2_wages: Math.round(ownerComp * (partner.ownershipPct / 100)),
142
+ })) });
143
+ }
131
144
  function ShellContainer({ children, fullWidth = false, }) {
132
145
  if (fullWidth) {
133
146
  return react_1.default.createElement(react_1.default.Fragment, null, children);
@@ -195,20 +208,68 @@ const TaxAxisShell = ({ taxAxisApi, userContext = 'expert', initialSessionId, in
195
208
  }
196
209
  }), [taxAxisApi]);
197
210
  // On mount: if a sessionId was injected (e.g. returning to an existing session),
198
- // reload the last GENERATION llmRun so the report screens get live data.
211
+ // fetch the session stage and resume at the correct step.
199
212
  (0, react_1.useEffect)(() => {
200
- if (!initialSessionId || !taxAxisApi.getLlmRun)
213
+ if (!initialSessionId)
201
214
  return;
202
- taxAxisApi.getLlmRun(initialSessionId, 'GENERATION')
203
- .then((run) => {
204
- if (run === null || run === void 0 ? void 0 : run.outputPayload) {
205
- setLlmResult(run.outputPayload);
215
+ taxAxisApi.getSession(initialSessionId)
216
+ .then((session) => __awaiter(void 0, void 0, void 0, function* () {
217
+ var _a;
218
+ if (!session)
219
+ return;
220
+ // Restore profile from session fields so DOCUMENT_UPLOAD header renders correctly
221
+ setSessionId(initialSessionId);
222
+ setProfile((prev) => {
223
+ var _a, _b, _c, _d, _e, _f, _g, _h;
224
+ return prev !== null && prev !== void 0 ? prev : {
225
+ bizName: (_a = session.businessName) !== null && _a !== void 0 ? _a : '',
226
+ entity: (_b = session.entityType) !== null && _b !== void 0 ? _b : '',
227
+ industry: (_c = session.industry) !== null && _c !== void 0 ? _c : '',
228
+ year: String((_d = session.taxYear) !== null && _d !== void 0 ? _d : new Date().getFullYear()),
229
+ revenue: String((_e = session.annualRevenue) !== null && _e !== void 0 ? _e : ''),
230
+ ownerComp: String((_f = session.w2Compensation) !== null && _f !== void 0 ? _f : ''),
231
+ employees: String((_g = session.employeeCount) !== null && _g !== void 0 ? _g : ''),
232
+ states: (_h = session.states) !== null && _h !== void 0 ? _h : [],
233
+ };
234
+ });
235
+ const stage = (_a = session.stage) !== null && _a !== void 0 ? _a : '';
236
+ if (stage === 'REPORT_READY' || stage === 'COMPLETED') {
237
+ // Load LLM run data and jump to dashboard
238
+ if (taxAxisApi.getLlmRun) {
239
+ try {
240
+ const run = yield taxAxisApi.getLlmRun(initialSessionId, 'GENERATION');
241
+ if (run === null || run === void 0 ? void 0 : run.outputPayload) {
242
+ setLlmResult(run.outputPayload);
243
+ }
244
+ }
245
+ catch ( /* non-blocking */_b) { /* non-blocking */ }
246
+ }
247
+ yield fetchAndSetParsedDocuments(initialSessionId);
206
248
  setStep('DASHBOARD');
207
- fetchAndSetParsedDocuments(initialSessionId);
249
+ if (onSessionChange)
250
+ onSessionChange(initialSessionId);
251
+ return;
208
252
  }
209
- })
210
- .catch(() => { });
211
- // fetchAndSetParsedDocuments intentionally excluded: only runs on mount for initial session restore
253
+ if (stage === 'LLM_RUNNING' || stage === 'EVAL_RUNNING') {
254
+ // Jump straight to processing screen and start polling
255
+ setStep('PROCESSING');
256
+ pollForResult(initialSessionId);
257
+ if (onSessionChange)
258
+ onSessionChange(initialSessionId);
259
+ return;
260
+ }
261
+ // INITIALIZED, DOCUMENTS_UPLOADED, PARSING, PARSED, EXTRACTION_REVIEW, FAILED, EVAL_FAILED
262
+ // Resume at document upload so the user can review/add documents or retry
263
+ setStep('DOCUMENT_UPLOAD');
264
+ if (onSessionChange)
265
+ onSessionChange(initialSessionId);
266
+ }))
267
+ .catch(() => {
268
+ // On error fall back to SESSION_SETUP — clear skeleton so page isn't stuck
269
+ if (onSessionChange)
270
+ onSessionChange(null);
271
+ });
272
+ // fetchAndSetParsedDocuments and pollForResult intentionally excluded: only runs on mount
212
273
  // eslint-disable-next-line react-hooks/exhaustive-deps
213
274
  }, [initialSessionId]);
214
275
  const updateSessionId = (0, react_1.useCallback)((nextSessionId) => {
@@ -245,7 +306,8 @@ const TaxAxisShell = ({ taxAxisApi, userContext = 'expert', initialSessionId, in
245
306
  updateSessionId(null);
246
307
  }, [updateSessionId]);
247
308
  const handleProspect = (nextProfile) => __awaiter(void 0, void 0, void 0, function* () {
248
- setProfile(nextProfile);
309
+ const enriched = enrichWithAllocations(nextProfile);
310
+ setProfile(enriched);
249
311
  setIsProspectFlow(true);
250
312
  setProspectData(null);
251
313
  setProspectLoading(true);
@@ -253,7 +315,7 @@ const TaxAxisShell = ({ taxAxisApi, userContext = 'expert', initialSessionId, in
253
315
  try {
254
316
  if (taxAxisApi.generateProspectReport) {
255
317
  const result = yield taxAxisApi.generateProspectReport({
256
- clientProfile: nextProfile,
318
+ clientProfile: enriched,
257
319
  });
258
320
  setProspectData({
259
321
  computePayload: result.computePayload,
@@ -269,7 +331,8 @@ const TaxAxisShell = ({ taxAxisApi, userContext = 'expert', initialSessionId, in
269
331
  }
270
332
  });
271
333
  const handleFullAnalysis = (0, react_1.useCallback)((nextProfile) => __awaiter(void 0, void 0, void 0, function* () {
272
- setProfile(nextProfile);
334
+ const enriched = enrichWithAllocations(nextProfile);
335
+ setProfile(enriched);
273
336
  setIsProspectFlow(false);
274
337
  setError(null);
275
338
  setBusyMessage('Creating Tax Axis session...');
@@ -52,7 +52,7 @@ function ExecutiveSummary({ profile, eligible, computed, totalLo, totalHi, leadC
52
52
  " Savings estimates reflect your current revenue of ",
53
53
  rev >= 1000000 ? "$" + (rev / 1000000).toFixed(1) + "M" : "$" + Math.round(rev / 1000) + "K",
54
54
  ", an effective tax rate of ",
55
- effectiveTaxRate != null ? Math.round((effectiveTaxRate <= 1 ? effectiveTaxRate * 100 : effectiveTaxRate) * 10) / 10 : ((profile.entity === "C-Corporation" ? 21 : parseFloat(profile.federalRate || "24")) + parseFloat(profile.stateRate || "4.95")),
55
+ effectiveTaxRate != null ? Math.round((effectiveTaxRate <= 1 ? effectiveTaxRate * 100 : effectiveTaxRate) * 10) / 10 : ((profile.entity === "C-Corporation" ? 21 : parseFloat(profile.federalRate || "24")) + parseFloat(profile.stateRate || "0")),
56
56
  "%, and ",
57
57
  dataYearsLabel,
58
58
  " of financial data."),
@@ -60,7 +60,7 @@ function ExecutiveSummary({ profile, eligible, computed, totalLo, totalHi, leadC
60
60
  // C-Corps have a flat 21% federal rate
61
61
  const isCCorp = profile.entity === "C-Corporation";
62
62
  const fedRate = isCCorp ? 21 : parseFloat(profile.federalRate || "24");
63
- const stateRate = parseFloat(profile.stateRate || "4.95");
63
+ const stateRate = parseFloat(profile.stateRate || "0");
64
64
  // If engine provided effective_tax_rate (as a decimal 0-1), convert to percentage
65
65
  const currentRate = effectiveTaxRate != null
66
66
  ? (effectiveTaxRate <= 1 ? effectiveTaxRate * 100 : effectiveTaxRate)
@@ -80,13 +80,6 @@ function ClientParametersSection({ userContext = "expert", }) {
80
80
  setValue("period", "YTD");
81
81
  }
82
82
  }, [isCurrentOrFuture, setValue]);
83
- // Auto-select 21% federal rate for C-Corporations (flat TCJA rate)
84
- const selectedEntity = watch("entity");
85
- react_1.default.useEffect(() => {
86
- if (selectedEntity === "C-Corporation") {
87
- setValue("federalRate", "21%");
88
- }
89
- }, [selectedEntity, setValue]);
90
83
  const [expanded, setExpanded] = (0, react_1.useState)(true);
91
84
  return (react_1.default.createElement(TaxAxisCard_1.TaxAxisCard, null,
92
85
  react_1.default.createElement("div", { onClick: () => setExpanded((prev) => !prev), className: "flex items-center justify-between cursor-pointer", style: { marginBottom: expanded ? 14 : 0 } },
@@ -42,7 +42,7 @@ const SSTB_OPTIONS = ["Yes", "No", "Unsure"];
42
42
  const REAL_ESTATE_OPTIONS = ["No", "Yes — Commercial", "Yes — Residential", "Yes — Both"];
43
43
  const ITEMIZES_OPTIONS = ["Yes", "No", "Unsure"];
44
44
  const SINGLE_OWNER_OPTIONS = ["Yes", "No"];
45
- const FEDERAL_RATE_OPTIONS = ["10%", "12%", "21%", "22%", "24%", "32%", "35%", "37%"];
45
+ const FEDERAL_RATE_OPTIONS = ["10%", "12%", "22%", "24%", "32%", "35%", "37%"];
46
46
  const TAX_DATA_YEARS_OPTIONS = ["1 year", "2 years", "3 years", "4 years", "5 years"];
47
47
  // Risk Tolerance: mock stores first char ("1"-"5") as value.
48
48
  // NOTE: intakeDefaultValues sets riskTolerance to "M" (spec) but the mock
@@ -60,6 +60,22 @@ function RefineAnalysisSection({ userContext: _userContext, }) {
60
60
  const [expanded, setExpanded] = (0, react_1.useState)(false);
61
61
  const { control, watch, formState: { errors }, } = (0, react_hook_form_1.useFormContext)();
62
62
  const ownsRealEstate = watch("ownsRealEstate");
63
+ const entity = watch("entity");
64
+ const singleOwner = watch("singleOwner");
65
+ const showRoster = (entity === "Partnership" || entity === "LLC") && singleOwner === "No";
66
+ const { fields, append, remove } = (0, react_hook_form_1.useFieldArray)({ control, name: "partners" });
67
+ const watchedPartners = watch("partners") || [];
68
+ const totalPct = watchedPartners.reduce((sum, p) => sum + (Number(p === null || p === void 0 ? void 0 : p.ownershipPct) || 0), 0);
69
+ const pctValid = Math.abs(totalPct - 100) < 0.01;
70
+ (0, react_1.useEffect)(() => {
71
+ if (showRoster && fields.length === 0) {
72
+ append([
73
+ { name: "", ownershipPct: 0, partnerType: "general" },
74
+ { name: "", ownershipPct: 0, partnerType: "general" },
75
+ ]);
76
+ }
77
+ // eslint-disable-next-line react-hooks/exhaustive-deps
78
+ }, [showRoster]);
63
79
  return (react_1.default.createElement(TaxAxisCard_1.TaxAxisCard, null,
64
80
  react_1.default.createElement("div", { onClick: () => setExpanded(prev => !prev), className: "flex items-center justify-between cursor-pointer", style: { marginBottom: expanded ? 10 : 0 } },
65
81
  react_1.default.createElement("span", { className: "text-[11px] font-semibold uppercase tracking-wider text-tax-axis-text-3" }, "Refine Analysis"),
@@ -102,6 +118,34 @@ function RefineAnalysisSection({ userContext: _userContext, }) {
102
118
  react_1.default.createElement(react_hook_form_1.Controller, { name: "singleOwner", control: control, render: ({ field }) => (react_1.default.createElement("div", { className: "relative" },
103
119
  react_1.default.createElement("select", Object.assign({}, field, { className: selectCls }), SINGLE_OWNER_OPTIONS.map(o => (react_1.default.createElement("option", { key: o, value: o, className: "bg-tax-axis-surface-2" }, o)))),
104
120
  react_1.default.createElement(Chevron, null))) }))),
121
+ showRoster && (react_1.default.createElement("div", { className: "mt-3 mb-2.5" },
122
+ react_1.default.createElement("div", { className: subHeaderCls, style: { marginTop: 0 } }, "Partner / Member Roster"),
123
+ react_1.default.createElement("div", { className: "space-y-2" }, fields.map((field, idx) => (react_1.default.createElement("div", { key: field.id, className: "flex items-end gap-2" },
124
+ react_1.default.createElement("div", { className: "flex-1 min-w-0" },
125
+ idx === 0 && react_1.default.createElement("label", { className: labelCls }, "Name"),
126
+ react_1.default.createElement(react_hook_form_1.Controller, { name: `partners.${idx}.name`, control: control, render: ({ field: f }) => (react_1.default.createElement("input", Object.assign({}, f, { placeholder: "Partner name", className: inputCls }))) })),
127
+ react_1.default.createElement("div", { className: "w-[90px] shrink-0" },
128
+ idx === 0 && react_1.default.createElement("label", { className: labelCls }, "Ownership %"),
129
+ react_1.default.createElement(react_hook_form_1.Controller, { name: `partners.${idx}.ownershipPct`, control: control, render: ({ field: f }) => (react_1.default.createElement("div", { className: "relative" },
130
+ react_1.default.createElement("input", Object.assign({}, f, { type: "number", min: 0, max: 100, placeholder: "0", className: `${inputCls} pr-6`, onChange: (e) => f.onChange(Number(e.target.value) || 0) })),
131
+ react_1.default.createElement("span", { className: "absolute right-2.5 top-1/2 -translate-y-1/2 text-tax-axis-text-3 text-[13px]" }, "%"))) })),
132
+ react_1.default.createElement("div", { className: "w-[130px] shrink-0" },
133
+ idx === 0 && react_1.default.createElement("label", { className: labelCls }, "Type"),
134
+ react_1.default.createElement(react_hook_form_1.Controller, { name: `partners.${idx}.partnerType`, control: control, render: ({ field: f }) => (react_1.default.createElement("div", { className: "relative" },
135
+ react_1.default.createElement("select", Object.assign({}, f, { className: selectCls }),
136
+ react_1.default.createElement("option", { value: "general", className: "bg-tax-axis-surface-2" }, "General"),
137
+ react_1.default.createElement("option", { value: "limited", className: "bg-tax-axis-surface-2" }, "Limited")),
138
+ react_1.default.createElement(Chevron, null))) })),
139
+ fields.length > 1 && (react_1.default.createElement("button", { type: "button", onClick: () => remove(idx), className: "w-7 h-[38px] shrink-0 flex items-center justify-center text-tax-axis-text-4 hover:text-tax-axis-red transition-colors", title: "Remove partner" },
140
+ react_1.default.createElement("svg", { width: "12", height: "12", viewBox: "0 0 12 12", fill: "none" },
141
+ react_1.default.createElement("path", { d: "M2 2l8 8M10 2l-8 8", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" })))))))),
142
+ react_1.default.createElement("div", { className: "flex items-center justify-between mt-2 px-1" },
143
+ react_1.default.createElement("button", { type: "button", onClick: () => append({ name: "", ownershipPct: 0, partnerType: "general" }), className: "text-[11px] text-tax-axis-teal-light hover:text-white transition-colors font-tax-axis-body" }, "+ Add Partner"),
144
+ react_1.default.createElement("div", { className: `text-[11px] font-tax-axis-body ${pctValid ? "text-green-400" : "text-tax-axis-red"}` },
145
+ "Total: ",
146
+ totalPct,
147
+ "%",
148
+ !pctValid && " — must equal 100%")))),
105
149
  react_1.default.createElement("div", { className: subHeaderCls }, "Financial Data"),
106
150
  react_1.default.createElement("div", { className: "grid grid-cols-1 sm:grid-cols-2 gap-3 mb-2.5" },
107
151
  react_1.default.createElement("div", null,
@@ -110,8 +110,8 @@ function StrategyRadar({ profile }) {
110
110
  // so [profile] as a dep would never re-fire the memo on field changes
111
111
  const profileKey = JSON.stringify(profile);
112
112
  const computed = (0, react_1.useMemo)(() => (0, compute_1.computeAllStrategies)(safeProfile), [profileKey]);
113
- const fedRate = entity === "C-Corporation" ? 0.21 : parseFloat((profile.federalRate || "24").replace("%", "")) / 100 || 0.24;
114
- const stateRate = parseFloat(profile.stateRate || "4.95") / 100;
113
+ const fedRate = parseFloat((profile.federalRate || "24").replace("%", "")) / 100 || 0.24;
114
+ const stateRate = parseFloat(profile.stateRate || "0") / 100;
115
115
  const netIncome = parseInt((profile.netIncome || "0").replace(/,/g, "")) || Math.round(rev * 0.3);
116
116
  let loSum = eligibleStrategies.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);
117
117
  let hiSum = eligibleStrategies.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);
@@ -17,6 +17,23 @@ export declare const intakeSchema: Yup.ObjectSchema<import("yup/lib/object").Ass
17
17
  ownsRealEstate: Yup.StringSchema<string, import("yup/lib/types").AnyObject, string>;
18
18
  itemizesDeductions: Yup.StringSchema<string, import("yup/lib/types").AnyObject, string>;
19
19
  singleOwner: Yup.StringSchema<string, import("yup/lib/types").AnyObject, string>;
20
+ partners: import("yup/lib/array").RequiredArraySchema<Yup.ObjectSchema<import("yup/lib/object").Assign<import("yup/lib/object").ObjectShape, {
21
+ name: Yup.StringSchema<string, import("yup/lib/types").AnyObject, string>;
22
+ ownershipPct: Yup.NumberSchema<number, import("yup/lib/types").AnyObject, number>;
23
+ partnerType: Yup.StringSchema<string, import("yup/lib/types").AnyObject, string>;
24
+ }>, import("yup/lib/object").AnyObject, import("yup/lib/object").TypeOfShape<import("yup/lib/object").Assign<import("yup/lib/object").ObjectShape, {
25
+ name: Yup.StringSchema<string, import("yup/lib/types").AnyObject, string>;
26
+ ownershipPct: Yup.NumberSchema<number, import("yup/lib/types").AnyObject, number>;
27
+ partnerType: Yup.StringSchema<string, import("yup/lib/types").AnyObject, string>;
28
+ }>>, import("yup/lib/object").AssertsShape<import("yup/lib/object").Assign<import("yup/lib/object").ObjectShape, {
29
+ name: Yup.StringSchema<string, import("yup/lib/types").AnyObject, string>;
30
+ ownershipPct: Yup.NumberSchema<number, import("yup/lib/types").AnyObject, number>;
31
+ partnerType: Yup.StringSchema<string, import("yup/lib/types").AnyObject, string>;
32
+ }>>>, import("yup/lib/types").AnyObject, import("yup/lib/object").TypeOfShape<import("yup/lib/object").Assign<import("yup/lib/object").ObjectShape, {
33
+ name: Yup.StringSchema<string, import("yup/lib/types").AnyObject, string>;
34
+ ownershipPct: Yup.NumberSchema<number, import("yup/lib/types").AnyObject, number>;
35
+ partnerType: Yup.StringSchema<string, import("yup/lib/types").AnyObject, string>;
36
+ }>>[] | undefined>;
20
37
  equipmentPurchased: Yup.StringSchema<string, import("yup/lib/types").AnyObject, string>;
21
38
  realEstateValue: Yup.StringSchema<string, import("yup/lib/types").AnyObject, string>;
22
39
  capitalGains: Yup.StringSchema<string, import("yup/lib/types").AnyObject, string>;
@@ -49,6 +66,23 @@ export declare const intakeSchema: Yup.ObjectSchema<import("yup/lib/object").Ass
49
66
  ownsRealEstate: Yup.StringSchema<string, import("yup/lib/types").AnyObject, string>;
50
67
  itemizesDeductions: Yup.StringSchema<string, import("yup/lib/types").AnyObject, string>;
51
68
  singleOwner: Yup.StringSchema<string, import("yup/lib/types").AnyObject, string>;
69
+ partners: import("yup/lib/array").RequiredArraySchema<Yup.ObjectSchema<import("yup/lib/object").Assign<import("yup/lib/object").ObjectShape, {
70
+ name: Yup.StringSchema<string, import("yup/lib/types").AnyObject, string>;
71
+ ownershipPct: Yup.NumberSchema<number, import("yup/lib/types").AnyObject, number>;
72
+ partnerType: Yup.StringSchema<string, import("yup/lib/types").AnyObject, string>;
73
+ }>, import("yup/lib/object").AnyObject, import("yup/lib/object").TypeOfShape<import("yup/lib/object").Assign<import("yup/lib/object").ObjectShape, {
74
+ name: Yup.StringSchema<string, import("yup/lib/types").AnyObject, string>;
75
+ ownershipPct: Yup.NumberSchema<number, import("yup/lib/types").AnyObject, number>;
76
+ partnerType: Yup.StringSchema<string, import("yup/lib/types").AnyObject, string>;
77
+ }>>, import("yup/lib/object").AssertsShape<import("yup/lib/object").Assign<import("yup/lib/object").ObjectShape, {
78
+ name: Yup.StringSchema<string, import("yup/lib/types").AnyObject, string>;
79
+ ownershipPct: Yup.NumberSchema<number, import("yup/lib/types").AnyObject, number>;
80
+ partnerType: Yup.StringSchema<string, import("yup/lib/types").AnyObject, string>;
81
+ }>>>, import("yup/lib/types").AnyObject, import("yup/lib/object").TypeOfShape<import("yup/lib/object").Assign<import("yup/lib/object").ObjectShape, {
82
+ name: Yup.StringSchema<string, import("yup/lib/types").AnyObject, string>;
83
+ ownershipPct: Yup.NumberSchema<number, import("yup/lib/types").AnyObject, number>;
84
+ partnerType: Yup.StringSchema<string, import("yup/lib/types").AnyObject, string>;
85
+ }>>[] | undefined>;
52
86
  equipmentPurchased: Yup.StringSchema<string, import("yup/lib/types").AnyObject, string>;
53
87
  realEstateValue: Yup.StringSchema<string, import("yup/lib/types").AnyObject, string>;
54
88
  capitalGains: Yup.StringSchema<string, import("yup/lib/types").AnyObject, string>;
@@ -81,6 +115,23 @@ export declare const intakeSchema: Yup.ObjectSchema<import("yup/lib/object").Ass
81
115
  ownsRealEstate: Yup.StringSchema<string, import("yup/lib/types").AnyObject, string>;
82
116
  itemizesDeductions: Yup.StringSchema<string, import("yup/lib/types").AnyObject, string>;
83
117
  singleOwner: Yup.StringSchema<string, import("yup/lib/types").AnyObject, string>;
118
+ partners: import("yup/lib/array").RequiredArraySchema<Yup.ObjectSchema<import("yup/lib/object").Assign<import("yup/lib/object").ObjectShape, {
119
+ name: Yup.StringSchema<string, import("yup/lib/types").AnyObject, string>;
120
+ ownershipPct: Yup.NumberSchema<number, import("yup/lib/types").AnyObject, number>;
121
+ partnerType: Yup.StringSchema<string, import("yup/lib/types").AnyObject, string>;
122
+ }>, import("yup/lib/object").AnyObject, import("yup/lib/object").TypeOfShape<import("yup/lib/object").Assign<import("yup/lib/object").ObjectShape, {
123
+ name: Yup.StringSchema<string, import("yup/lib/types").AnyObject, string>;
124
+ ownershipPct: Yup.NumberSchema<number, import("yup/lib/types").AnyObject, number>;
125
+ partnerType: Yup.StringSchema<string, import("yup/lib/types").AnyObject, string>;
126
+ }>>, import("yup/lib/object").AssertsShape<import("yup/lib/object").Assign<import("yup/lib/object").ObjectShape, {
127
+ name: Yup.StringSchema<string, import("yup/lib/types").AnyObject, string>;
128
+ ownershipPct: Yup.NumberSchema<number, import("yup/lib/types").AnyObject, number>;
129
+ partnerType: Yup.StringSchema<string, import("yup/lib/types").AnyObject, string>;
130
+ }>>>, import("yup/lib/types").AnyObject, import("yup/lib/object").TypeOfShape<import("yup/lib/object").Assign<import("yup/lib/object").ObjectShape, {
131
+ name: Yup.StringSchema<string, import("yup/lib/types").AnyObject, string>;
132
+ ownershipPct: Yup.NumberSchema<number, import("yup/lib/types").AnyObject, number>;
133
+ partnerType: Yup.StringSchema<string, import("yup/lib/types").AnyObject, string>;
134
+ }>>[] | undefined>;
84
135
  equipmentPurchased: Yup.StringSchema<string, import("yup/lib/types").AnyObject, string>;
85
136
  realEstateValue: Yup.StringSchema<string, import("yup/lib/types").AnyObject, string>;
86
137
  capitalGains: Yup.StringSchema<string, import("yup/lib/types").AnyObject, string>;
@@ -42,6 +42,11 @@ exports.intakeSchema = Yup.object().shape({
42
42
  ownsRealEstate: Yup.string().ensure(),
43
43
  itemizesDeductions: Yup.string().ensure(),
44
44
  singleOwner: Yup.string().ensure(),
45
+ partners: Yup.array().of(Yup.object().shape({
46
+ name: Yup.string().ensure(),
47
+ ownershipPct: Yup.number().min(0).max(100).default(0),
48
+ partnerType: Yup.string().oneOf(["general", "limited"]).default("general"),
49
+ })).ensure(),
45
50
  equipmentPurchased: Yup.string().ensure(),
46
51
  realEstateValue: Yup.string().ensure(),
47
52
  capitalGains: Yup.string().ensure(),
@@ -58,36 +63,79 @@ exports.intakeSchema = Yup.object().shape({
58
63
  familyEmployed: Yup.string().ensure(),
59
64
  period: Yup.string().ensure(),
60
65
  });
61
- exports.intakeDefaultValues = {
62
- bizName: "Ironclad Systems, Inc.",
63
- cpaName: "Amar",
66
+ /* ── Blackridge Construction Partners, LP — Test Fixture ──
67
+ * Swap _BLACKRIDGE_FIXTURE for _EMPTY_DEFAULTS below to revert.
68
+ */
69
+ const _EMPTY_DEFAULTS = {
70
+ bizName: "",
71
+ cpaName: "",
64
72
  entity: "C-Corporation",
65
- industry: "Technology",
66
- revenue: "2150000",
67
- netIncome: "410000",
68
- ownerComp: "405000",
69
- employees: "11",
70
- year: "2023",
71
- states: ["GA"],
73
+ industry: "Professional Services",
74
+ revenue: "",
75
+ netIncome: "",
76
+ ownerComp: "",
77
+ employees: "",
78
+ year: "2026",
79
+ states: [],
72
80
  filingStatus: "MFJ",
73
- age: "45",
81
+ age: "",
74
82
  sstb: "No",
75
83
  ownsRealEstate: "No",
76
84
  itemizesDeductions: "No",
77
- singleOwner: "No",
78
- equipmentPurchased: "87000",
85
+ singleOwner: "Yes",
86
+ partners: [],
87
+ equipmentPurchased: "0",
79
88
  realEstateValue: "0",
80
89
  capitalGains: "0",
81
- federalRate: "22%",
82
- stateRate: "5.39",
90
+ federalRate: "24%",
91
+ stateRate: "",
83
92
  taxDataYears: "1 year",
84
93
  riskTolerance: "3",
85
94
  overtimePremium: "0",
86
95
  tipIncomePct: "0",
87
96
  retirementContributions: "0",
88
- hdhpEnrolled: "Yes",
97
+ hdhpEnrolled: "No",
89
98
  hsaContributions: "0",
90
99
  wotcHires: "No",
91
100
  familyEmployed: "No",
92
101
  period: "YTD",
93
102
  };
103
+ const _BLACKRIDGE_FIXTURE = {
104
+ bizName: "Blackridge Construction Partners, LP",
105
+ cpaName: "Amar",
106
+ entity: "Partnership",
107
+ industry: "Construction",
108
+ revenue: "4800000",
109
+ netIncome: "720000",
110
+ ownerComp: "412000",
111
+ employees: "28",
112
+ year: "2023",
113
+ states: ["TX", "CA"],
114
+ filingStatus: "MFJ",
115
+ age: "52",
116
+ sstb: "No",
117
+ ownsRealEstate: "Yes — Commercial",
118
+ itemizesDeductions: "No",
119
+ singleOwner: "No",
120
+ partners: [
121
+ { name: "Marcus D. Blackridge", ownershipPct: 50, partnerType: "general" },
122
+ { name: "David L. Chen", ownershipPct: 30, partnerType: "general" },
123
+ { name: "Sarah A. Okonkwo", ownershipPct: 20, partnerType: "general" },
124
+ ],
125
+ equipmentPurchased: "193000",
126
+ realEstateValue: "560000",
127
+ capitalGains: "0",
128
+ federalRate: "32%",
129
+ stateRate: "0",
130
+ taxDataYears: "3 years",
131
+ riskTolerance: "3",
132
+ overtimePremium: "34000",
133
+ tipIncomePct: "0",
134
+ retirementContributions: "42000",
135
+ hdhpEnrolled: "Yes",
136
+ hsaContributions: "0",
137
+ wotcHires: "Yes",
138
+ familyEmployed: "No",
139
+ period: "Full Year",
140
+ };
141
+ exports.intakeDefaultValues = _BLACKRIDGE_FIXTURE;
@@ -30,7 +30,7 @@ function EngagementHeader({ profile, palette }) {
30
30
  ["Filing", filingDisplay],
31
31
  ["SSTB", profile.sstb || "No"],
32
32
  ["Fed Rate", fedRateDisplay],
33
- ["State Rate", (profile.stateRate || "4.95") + "%"],
33
+ ["State Rate", (profile.stateRate || "0") + "%"],
34
34
  ["Revenue", "$" + (rev || 0).toLocaleString()],
35
35
  ["Net Income", "$" + (0, compute_1.parseNum)(profile.netIncome).toLocaleString()],
36
36
  ["Owner Comp", "$" + (0, compute_1.parseNum)(profile.ownerComp).toLocaleString()],
@@ -2,9 +2,6 @@ import React from "react";
2
2
  interface SampleAnalysisPreviewProps {
3
3
  sectionNum: string;
4
4
  eligibleCount: number;
5
- fedRatePct?: number;
6
- stateRatePct?: number;
7
- stateCode?: string;
8
5
  }
9
- export declare function SampleAnalysisPreview({ sectionNum, eligibleCount, fedRatePct, stateRatePct, stateCode }: SampleAnalysisPreviewProps): React.JSX.Element;
6
+ export declare function SampleAnalysisPreview({ sectionNum, eligibleCount }: SampleAnalysisPreviewProps): React.JSX.Element;
10
7
  export {};
@@ -26,9 +26,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
26
26
  exports.SampleAnalysisPreview = SampleAnalysisPreview;
27
27
  const react_1 = __importStar(require("react"));
28
28
  const theme_1 = require("./theme");
29
- function SampleAnalysisPreview({ sectionNum, eligibleCount, fedRatePct = 24, stateRatePct = 4.95, stateCode = "IL" }) {
30
- const fedRateDecimal = (fedRatePct / 100).toFixed(2);
31
- const stateRateDecimal = (stateRatePct / 100).toFixed(4);
29
+ function SampleAnalysisPreview({ sectionNum, eligibleCount }) {
32
30
  return (react_1.default.createElement("div", { style: { marginBottom: 24 } },
33
31
  react_1.default.createElement("div", { style: { display: "flex", alignItems: "baseline", gap: 10, marginBottom: 6 } },
34
32
  react_1.default.createElement("span", { style: { fontSize: 11, fontWeight: 700, color: theme_1.T.accent, fontFamily: theme_1.T.body } }, sectionNum),
@@ -64,12 +62,12 @@ function SampleAnalysisPreview({ sectionNum, eligibleCount, fedRatePct = 24, sta
64
62
  react_1.default.createElement("span", { style: { color: theme_1.T.orange, fontWeight: 700 } }, "\u00B7 illustrative")),
65
63
  react_1.default.createElement("div", { style: { display: "grid", gridTemplateColumns: "1fr auto", gap: "6px 16px", fontSize: 11, fontFamily: theme_1.T.mono, marginBottom: 6 } }, [
66
64
  ["state_income_attributable_to_owner", "$1,750,000"],
67
- ["state_rate", `${stateRateDecimal} (${stateCode})`],
65
+ ["state_rate", "0.0495 (IL)"],
68
66
  ["filing_status", "mfj"],
69
67
  ["MAGI_PROXY: net_income", "$1,750,000"],
70
68
  ["EFFECTIVE_SALT_CAP", "$0 (fully phased out by MFJ income)"],
71
- ["federal_marginal_rate", fedRateDecimal],
72
- ["state_credit_rate", `1.00 (${stateCode} full credit)`],
69
+ ["federal_marginal_rate", "0.24"],
70
+ ["state_credit_rate", "1.00 (IL full credit)"],
73
71
  ["pte_tax_paid", "$86,625"],
74
72
  ].map(([k, v]) => (react_1.default.createElement(react_1.Fragment, { key: k },
75
73
  react_1.default.createElement("span", { style: { color: theme_1.T.text3 } }, k),
@@ -81,8 +79,8 @@ function SampleAnalysisPreview({ sectionNum, eligibleCount, fedRatePct = 24, sta
81
79
  { doc: "Form 1120-S", line: "Line 12 \u00B7 Taxes and licenses", field: "pte_tax_paid" },
82
80
  { doc: "Schedule K-1", line: "Box 16, Code A \u00B7 State tax credit info", field: "state_credit_pass_through" },
83
81
  { doc: "Form 1040 Sch A", line: "Line 5a \u00B7 State and local income tax", field: "salt_paid" },
84
- { doc: `State Return (${stateCode}-1120-ST)`, line: "PTE election line items", field: "pte_election_status" },
85
- { doc: "Parser-injected", line: `state_pte_lookup[${stateCode}]`, field: "state_credit_rate, pte_deadline" },
82
+ { doc: "State Return (IL-1120-ST)", line: "PTE election line items", field: "pte_election_status" },
83
+ { doc: "Parser-injected", line: "state_pte_lookup[IL]", field: "state_credit_rate, pte_deadline" },
86
84
  ].map((s, idx) => (react_1.default.createElement("div", { key: idx, style: { display: "grid", gridTemplateColumns: "1.1fr 1.4fr 1fr", gap: 12, fontSize: 11, fontFamily: theme_1.T.body, padding: "7px 12px", background: theme_1.T.surface2, border: `1px solid ${theme_1.T.border}`, borderRadius: 6 } },
87
85
  react_1.default.createElement("span", { style: { color: theme_1.T.text, fontWeight: 600 } }, s.doc),
88
86
  react_1.default.createElement("span", { style: { color: theme_1.T.text2, fontFamily: theme_1.T.mono, fontSize: 10 } }, s.line),
@@ -104,20 +102,13 @@ function SampleAnalysisPreview({ sectionNum, eligibleCount, fedRatePct = 24, sta
104
102
  react_1.default.createElement("div", { style: { fontSize: 11, color: theme_1.T.text2, fontFamily: theme_1.T.mono, lineHeight: 1.6 } },
105
103
  "State PTE election form",
106
104
  react_1.default.createElement("br", null),
107
- "(",
108
- stateCode,
109
- ": Schedule B, Form ",
110
- stateCode,
111
- "-1120-ST)",
105
+ "(IL: Schedule B, Form IL-1120-ST)",
112
106
  react_1.default.createElement("br", null),
113
107
  "Updated Schedule K-1 (Box 13)"))),
114
108
  react_1.default.createElement("div", { style: { marginTop: 14, paddingTop: 14, borderTop: `1px solid ${theme_1.T.border}`, display: "flex", justifyContent: "space-between", alignItems: "center", gap: 14 } },
115
109
  react_1.default.createElement("div", null,
116
110
  react_1.default.createElement("div", { style: { fontSize: 9, fontWeight: 700, color: theme_1.T.orange, textTransform: "uppercase", letterSpacing: "0.12em", fontFamily: theme_1.T.body, marginBottom: 3 } }, "deadline_flag"),
117
- react_1.default.createElement("div", { style: { fontSize: 11, color: theme_1.T.text2, fontFamily: theme_1.T.body } },
118
- "Per state_pte_lookup \u2014 ",
119
- stateCode,
120
- ": file with original return")),
111
+ react_1.default.createElement("div", { style: { fontSize: 11, color: theme_1.T.text2, fontFamily: theme_1.T.body } }, "Per state_pte_lookup \u2014 IL: file with original return")),
121
112
  react_1.default.createElement("span", { style: { fontSize: 9, fontWeight: 700, padding: "4px 9px", background: theme_1.T.surface2, border: `1px solid ${theme_1.T.border}`, borderRadius: 4, color: theme_1.T.text3, fontFamily: theme_1.T.mono, letterSpacing: 0.6, textTransform: "uppercase" } }, "algorithm_version V9.0")))),
122
113
  react_1.default.createElement("div", { style: { marginTop: 14, padding: "14px 18px", background: `linear-gradient(135deg,${theme_1.T.accentBg} 0%,rgba(36,131,132,0.04) 100%)`, border: `1px solid ${theme_1.T.accent}`, borderRadius: 10, display: "flex", alignItems: "center", gap: 14 } },
123
114
  react_1.default.createElement("div", { style: { flex: 1, fontSize: 13, color: theme_1.T.text, fontFamily: theme_1.T.body, lineHeight: 1.55 } },
@@ -36,7 +36,7 @@ const ProspectDocuments_1 = require("./ProspectDocuments");
36
36
  const ProspectNextSteps_1 = require("./ProspectNextSteps");
37
37
  const ProspectPrintView_1 = require("./ProspectPrintView");
38
38
  function TaxAxisProspectReport({ profile, backendComputePayload, outputPayload, onUpgrade, onPresent, onReset, }) {
39
- var _a, _b, _c, _d, _e, _f, _g, _h;
39
+ var _a, _b, _c, _d, _e, _f, _g;
40
40
  const bizName = profile.bizName || "Client";
41
41
  const [confirmReset, setConfirmReset] = (0, react_1.useState)(false);
42
42
  const [printMode, setPrintMode] = (0, react_1.useState)(false);
@@ -47,26 +47,29 @@ function TaxAxisProspectReport({ profile, backendComputePayload, outputPayload,
47
47
  const top3 = (0, react_1.useMemo)(() => [...eligible].sort((a, b) => b.score - a.score).slice(0, 3), [eligible]);
48
48
  const remaining = eligible.length - top3.length;
49
49
  const remainingNames = eligible.filter(s => !top3.includes(s)).slice(0, 4).map(s => s.name);
50
- // ═══ RAW SAVINGS RANGE — backend-authoritative when available ═══
50
+ // ═══ SAVINGS RANGE — backend-authoritative when available ═══
51
51
  const computed = (0, react_1.useMemo)(() => (0, compute_1.computeAllStrategies)(profile), [profile]);
52
- const rawLo = backendComputePayload
52
+ let displayLo = backendComputePayload
53
53
  ? Math.round(backendComputePayload.savingsLo / 1000)
54
54
  : 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);
55
- const rawHi = backendComputePayload
55
+ let displayHi = backendComputePayload
56
56
  ? Math.round(backendComputePayload.savingsHi / 1000)
57
57
  : 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);
58
58
  // ═══ GAP BLOCK — backend-authoritative when available ═══
59
- const fedRatePct = (_a = backendComputePayload === null || backendComputePayload === void 0 ? void 0 : backendComputePayload.gapBlock.fedRatePct) !== null && _a !== void 0 ? _a : (profile.entity === "C-Corporation" ? 21 : (parseFloat((profile.federalRate || "24").replace("%", "")) || 24));
60
- const stateRatePct = (_b = backendComputePayload === null || backendComputePayload === void 0 ? void 0 : backendComputePayload.gapBlock.stateRatePct) !== null && _b !== void 0 ? _b : (parseFloat(profile.stateRate || "4.95") || 4.95);
59
+ const fedRatePct = (_a = backendComputePayload === null || backendComputePayload === void 0 ? void 0 : backendComputePayload.gapBlock.fedRatePct) !== null && _a !== void 0 ? _a : (parseFloat((profile.federalRate || "24").replace("%", "")) || 24);
60
+ const stateRatePct = (_b = backendComputePayload === null || backendComputePayload === void 0 ? void 0 : backendComputePayload.gapBlock.stateRatePct) !== null && _b !== void 0 ? _b : (parseFloat(profile.stateRate || "0"));
61
61
  const currentTax = (_c = backendComputePayload === null || backendComputePayload === void 0 ? void 0 : backendComputePayload.gapBlock.currentTax) !== null && _c !== void 0 ? _c : Math.round(((0, compute_1.parseNum)(profile.netIncome) || Math.round((0, compute_1.parseNum)(profile.revenue) * 0.20))
62
62
  * (fedRatePct + stateRatePct) / 100);
63
- // ═══ SAVINGS CAP headline savings cannot exceed total tax liability ═══
64
- const currentTaxK = Math.round(currentTax / 1000);
65
- let displayHi = Math.min(rawHi, currentTaxK);
66
- let displayLo = Math.min(rawLo, Math.round(currentTax * 0.6 / 1000));
67
- // If cap squashed lo close to hi, re-spread to maintain a meaningful range
68
- if (displayHi > 0 && displayLo >= displayHi * 0.9) {
69
- displayLo = Math.round(displayHi / 3);
63
+ // Cap savings range: hi currentTax, lo 60% of hi, K-rounding safety
64
+ if (!backendComputePayload) {
65
+ const currentTaxK = Math.round(currentTax / 1000);
66
+ if (displayHi > currentTaxK)
67
+ displayHi = currentTaxK;
68
+ const loFloor = Math.round(displayHi * 0.60);
69
+ if (displayLo > loFloor)
70
+ displayLo = loFloor;
71
+ if (displayLo >= displayHi && displayHi > 1)
72
+ displayLo = displayHi - 1;
70
73
  }
71
74
  const realizedSavings = (_d = backendComputePayload === null || backendComputePayload === void 0 ? void 0 : backendComputePayload.gapBlock.realizedSavings) !== null && _d !== void 0 ? _d : Math.min(Math.round((displayLo + displayHi) / 2 * 1000 * 0.325), Math.round(currentTax * 0.6));
72
75
  const optimizedTax = (_e = backendComputePayload === null || backendComputePayload === void 0 ? void 0 : backendComputePayload.gapBlock.optimizedTax) !== null && _e !== void 0 ? _e : (currentTax - realizedSavings);
@@ -176,7 +179,7 @@ function TaxAxisProspectReport({ profile, backendComputePayload, outputPayload,
176
179
  react_1.default.createElement("div", { style: { fontSize: 13, color: theme_1.T.text2, fontFamily: theme_1.T.body, lineHeight: 1.7, marginBottom: 10 } }, (outputPayload === null || outputPayload === void 0 ? void 0 : outputPayload.additionalStrategiesBlurb)
177
180
  || `Including: ${remainingNames.join(", ")}${remaining > 4 ? " and more" : ""}`),
178
181
  react_1.default.createElement("div", { style: { fontSize: 12, color: theme_1.T.text3, fontFamily: theme_1.T.body, lineHeight: 1.6, borderLeft: `3px solid ${theme_1.T.accent}`, paddingLeft: 12 } }, "Full analysis with documents unlocks specific savings estimates for every eligible strategy.")))),
179
- react_1.default.createElement(SampleAnalysisPreview_1.SampleAnalysisPreview, { sectionNum: sectionNums.sample, eligibleCount: eligible.length, fedRatePct: fedRatePct, stateRatePct: stateRatePct, stateCode: ((_h = profile.states) === null || _h === void 0 ? void 0 : _h[0]) || "IL" }),
182
+ react_1.default.createElement(SampleAnalysisPreview_1.SampleAnalysisPreview, { sectionNum: sectionNums.sample, eligibleCount: eligible.length }),
180
183
  react_1.default.createElement(ProspectDocuments_1.ProspectDocuments, { sectionNum: sectionNums.documents, requiredDocs: requiredDocs, recommendedDocs: recommendedDocs, conditionalDocs: conditionalDocs }),
181
184
  react_1.default.createElement(ProspectNextSteps_1.ProspectNextSteps, { sectionNum: sectionNums.nextSteps, bizName: bizName, onUpgrade: onUpgrade, onPresent: onPresent, onPrint: handlePrint, onReset: onReset, confirmReset: confirmReset, onConfirmResetChange: setConfirmReset })));
182
185
  }