@paro.io/expert-shared-components 1.14.56 → 1.14.59

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) 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/clientReport/Methodology.js +2 -2
  6. package/lib/tax-axis/components/dashboard/DashboardActions.js +4 -4
  7. package/lib/tax-axis/components/dashboard/DashboardSummary.js +5 -6
  8. package/lib/tax-axis/components/dashboard/StrategyDetailPanel.js +2 -4
  9. package/lib/tax-axis/components/dashboard/TaxAxisDashboard.js +162 -57
  10. package/lib/tax-axis/components/documents/DocumentCard.d.ts +1 -0
  11. package/lib/tax-axis/components/documents/DocumentCard.js +19 -3
  12. package/lib/tax-axis/components/documents/TaxAxisDocuments.d.ts +12 -1
  13. package/lib/tax-axis/components/documents/TaxAxisDocuments.js +110 -48
  14. package/lib/tax-axis/components/documents/qbo/QboAvailableReportsModal.d.ts +13 -0
  15. package/lib/tax-axis/components/documents/qbo/QboAvailableReportsModal.js +180 -0
  16. package/lib/tax-axis/components/documents/qbo/QboClientSelectorModal.d.ts +10 -0
  17. package/lib/tax-axis/components/documents/qbo/QboClientSelectorModal.js +155 -0
  18. package/lib/tax-axis/components/documents/qbo/QboConnectBanner.d.ts +9 -0
  19. package/lib/tax-axis/components/documents/qbo/QboConnectBanner.js +55 -0
  20. package/lib/tax-axis/components/documents/qbo/QboDocumentMappingModal.d.ts +10 -0
  21. package/lib/tax-axis/components/documents/qbo/QboDocumentMappingModal.js +202 -0
  22. package/lib/tax-axis/components/documents/qbo/QboImportingModal.d.ts +8 -0
  23. package/lib/tax-axis/components/documents/qbo/QboImportingModal.js +75 -0
  24. package/lib/tax-axis/components/documents/qbo/QboPermissionsModal.d.ts +8 -0
  25. package/lib/tax-axis/components/documents/qbo/QboPermissionsModal.js +126 -0
  26. package/lib/tax-axis/components/documents/qbo/index.d.ts +8 -0
  27. package/lib/tax-axis/components/documents/qbo/index.js +17 -0
  28. package/lib/tax-axis/components/documents/qbo/qboConstants.d.ts +24 -0
  29. package/lib/tax-axis/components/documents/qbo/qboConstants.js +71 -0
  30. package/lib/tax-axis/components/documents/qbo/types.d.ts +43 -0
  31. package/lib/tax-axis/components/documents/qbo/types.js +3 -0
  32. package/lib/tax-axis/components/documents/qbo/useQboFlow.d.ts +19 -0
  33. package/lib/tax-axis/components/documents/qbo/useQboFlow.js +207 -0
  34. package/lib/tax-axis/components/intake/ClientParametersSection.js +1 -1
  35. package/lib/tax-axis/components/intake/CpaIntakeQuestionsSection.js +3 -3
  36. package/lib/tax-axis/components/intake/IntakeCtaCards.js +1 -1
  37. package/lib/tax-axis/components/intake/RefineAnalysisSection.js +7 -7
  38. package/lib/tax-axis/components/intake/TaxAxisIntake.js +2 -2
  39. package/lib/tax-axis/components/processing/TaxAxisProcessing.js +30 -5
  40. package/package.json +1 -1
@@ -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;
@@ -38,6 +38,13 @@ const documents_1 = require("../../lib/data/documents");
38
38
  const TaxAxisButton_1 = require("../shared/TaxAxisButton");
39
39
  const DocumentTier_1 = require("./DocumentTier");
40
40
  const DocumentReviewModal_1 = require("./DocumentReviewModal");
41
+ const QboConnectBanner_1 = require("./qbo/QboConnectBanner");
42
+ const QboPermissionsModal_1 = require("./qbo/QboPermissionsModal");
43
+ const QboClientSelectorModal_1 = require("./qbo/QboClientSelectorModal");
44
+ const QboAvailableReportsModal_1 = require("./qbo/QboAvailableReportsModal");
45
+ const QboDocumentMappingModal_1 = require("./qbo/QboDocumentMappingModal");
46
+ const QboImportingModal_1 = require("./qbo/QboImportingModal");
47
+ const useQboFlow_1 = require("./qbo/useQboFlow");
41
48
  const TIER_DEFS = [
42
49
  {
43
50
  key: "required",
@@ -70,8 +77,8 @@ const TIER_DEFS = [
70
77
  ids: [],
71
78
  },
72
79
  ];
73
- function TaxAxisDocuments({ profile, entityType, onContinue, onBack, onUploadDocument, onDeleteDocument, fetchUploadedDocuments, parsedFieldCounts, jobId = "stub-job-id", onSaveReviewedField, userContext: _userContext = "expert", }) {
74
- var _a, _b, _c, _d, _e;
80
+ function TaxAxisDocuments({ profile, entityType, onContinue, onBack, onUploadDocument, onDeleteDocument, fetchUploadedDocuments, parsedFieldCounts, jobId = "stub-job-id", onSaveReviewedField, userContext: _userContext = "expert", qboConnected = false, qboCompanyName, qboAuthorizeUrl, onImportQboReport, onQboConnected, onQboDisconnected, onQboImport, qboClientConfirmed, }) {
81
+ var _a, _b, _c, _d, _e, _f, _g, _h;
75
82
  const docSpecs = (0, react_1.useMemo)(() => (0, documents_1.getDocSpecs)(entityType !== null && entityType !== void 0 ? entityType : undefined), [entityType]);
76
83
  // Build tier defs dynamically from the doc spec list so they're always in sync.
77
84
  const tierDefs = (0, react_1.useMemo)(() => {
@@ -87,6 +94,52 @@ function TaxAxisDocuments({ profile, entityType, onContinue, onBack, onUploadDoc
87
94
  const [parsedDataByDocType, setParsedDataByDocType] = (0, react_1.useState)({});
88
95
  // reviewedData keyed by documentType — populated after CPA saves corrections; takes priority over parsedData in modal
89
96
  const [reviewedDataByDocType, setReviewedDataByDocType] = (0, react_1.useState)({});
97
+ // FIX A: handler for QBO import completion — updates doc card state and refreshes parsedData
98
+ const handleQboImportComplete = (0, react_1.useCallback)((mappedDocs) => {
99
+ setDocs((prev) => prev.map((d) => {
100
+ const match = mappedDocs.find((m) => m.slot === (d.documentType || d.id));
101
+ if (!match)
102
+ return d;
103
+ return Object.assign(Object.assign({}, d), { status: "valid", qboSource: true, fileName: match.fileName, parseError: null });
104
+ }));
105
+ // Refresh parsedData so the review modal has data immediately after import
106
+ if (fetchUploadedDocuments) {
107
+ fetchUploadedDocuments().then((uploaded) => {
108
+ const parsedByType = {};
109
+ for (const doc of uploaded) {
110
+ if (doc.documentType && doc.parsedData) {
111
+ parsedByType[doc.documentType] = doc.parsedData;
112
+ }
113
+ }
114
+ if (Object.keys(parsedByType).length > 0) {
115
+ setParsedDataByDocType((prev) => (Object.assign(Object.assign({}, prev), parsedByType)));
116
+ }
117
+ }).catch(() => { });
118
+ }
119
+ if (onQboImport)
120
+ onQboImport(mappedDocs);
121
+ }, [onQboImport, fetchUploadedDocuments]);
122
+ // QBO connect flow
123
+ const qboFlow = (0, useQboFlow_1.useQboFlow)({
124
+ qboConnected,
125
+ qboCompanyName,
126
+ qboAuthorizeUrl,
127
+ onImportQboReport,
128
+ fetchUploadedDocuments,
129
+ sessionId: jobId,
130
+ profileYear: (profile === null || profile === void 0 ? void 0 : profile.year) ? Number(profile.year) : undefined,
131
+ onQboConnected,
132
+ onQboDisconnected,
133
+ onQboImportComplete: handleQboImportComplete,
134
+ });
135
+ const showQboBanner = !!qboAuthorizeUrl || qboConnected;
136
+ // FIX B: gate document list behind QBO client confirmation or manual skip
137
+ const [clientConfirmed, setClientConfirmed] = (0, react_1.useState)(!!(qboClientConfirmed || qboConnected || !showQboBanner));
138
+ // Sync when qboConnected prop updates (e.g. localStorage restore in parent)
139
+ (0, react_1.useEffect)(() => {
140
+ if (qboConnected)
141
+ setClientConfirmed(true);
142
+ }, [qboConnected]);
90
143
  // On mount, restore card state from any already-uploaded documents in this session.
91
144
  // This runs whenever the user re-enters the DOCUMENT_UPLOAD step (e.g. after an
92
145
  // eval failure) so previously uploaded files appear as valid/failed instead of empty.
@@ -314,51 +367,55 @@ function TaxAxisDocuments({ profile, entityType, onContinue, onBack, onUploadDoc
314
367
  react_1.default.createElement("div", { className: "text-center mb-5 pt-5" },
315
368
  react_1.default.createElement("h1", { className: "text-[28px] font-bold text-white font-tax-axis-head mb-1.5" }, "Source Documents"),
316
369
  react_1.default.createElement("p", { className: "text-sm text-tax-axis-text-2 font-tax-axis-body" }, "Upload documents to run the full analysis.")),
317
- react_1.default.createElement("div", { className: "py-3.5 px-[18px] mb-4 text-xs leading-relaxed font-tax-axis-body", style: {
318
- background: "#171B44",
319
- borderLeft: "3px solid #248384",
320
- borderRadius: "0 8px 8px 0",
321
- color: "#E6E8F5",
322
- } }, "The minimum to run an analysis is the current-year P&L and Balance Sheet. However, accuracy and strategy coverage improve significantly with additional documents \u2014 particularly the federal tax return, fixed asset schedule, and W-2 forms."),
323
- react_1.default.createElement("div", { className: "bg-tax-axis-surface border border-tax-axis-border rounded-[10px] px-[18px] py-3.5 mb-4" },
324
- react_1.default.createElement("div", { className: "text-[10px] font-bold text-tax-axis-text-3 uppercase tracking-widest mb-2.5 font-tax-axis-mono" }, "Analysis Coverage"),
325
- react_1.default.createElement("div", { className: "flex justify-between mb-1.5" },
326
- react_1.default.createElement("span", { className: "text-xs text-tax-axis-text-2 font-tax-axis-body" },
327
- "Documents uploaded:",
328
- " ",
329
- react_1.default.createElement("strong", { className: "text-white" },
330
- validCount,
331
- " / ",
332
- docs.length)),
333
- react_1.default.createElement("span", { className: "text-xs text-tax-axis-text-2 font-tax-axis-body" },
334
- "Strategies covered:",
335
- " ",
336
- react_1.default.createElement("strong", { className: "text-tax-axis-teal-light" },
337
- strategiesCovered,
338
- " / 25"))),
339
- react_1.default.createElement("div", { className: "h-1.5 bg-tax-axis-surface-2 rounded-sm overflow-hidden mb-1.5" },
340
- react_1.default.createElement("div", { className: "h-full rounded-sm transition-[width] duration-[400ms]", style: {
341
- width: `${coveragePct}%`,
342
- background: "linear-gradient(90deg, #248384, #A1E5E6)",
343
- } })),
344
- react_1.default.createElement("div", { className: "flex justify-between" },
345
- react_1.default.createElement("span", { className: "text-[10px] text-tax-axis-text-4 font-tax-axis-mono" },
346
- coveragePct,
347
- "% coverage"),
348
- validCount < docs.length && (react_1.default.createElement("span", { className: "text-[10px] text-tax-axis-text-4 font-tax-axis-body" }, "Upload more documents to increase strategy coverage")))),
349
- continueError && (react_1.default.createElement("div", { className: "py-3 px-4 mb-4 text-xs leading-relaxed font-tax-axis-body rounded-lg", style: {
350
- background: "rgba(197,48,48,0.08)",
351
- border: "1px solid rgba(197,48,48,0.3)",
352
- color: "#FEB2B2",
353
- } }, continueError)),
354
- tierDefs.map((tier) => (react_1.default.createElement(DocumentTier_1.DocumentTier, { key: tier.key, tier: tier, docs: docs, helpOverrides: {}, fieldCounts: parsedFieldCounts, onUpload: handleUpload, onClear: handleClear, onRemove: handleRemove, onReview: (docId) => setReviewDocId(docId) }))),
355
- react_1.default.createElement("div", { className: "flex gap-3 mt-6" },
356
- react_1.default.createElement(TaxAxisButton_1.TaxAxisButton, { variant: "secondary", onClick: onBack }, "Back"),
357
- react_1.default.createElement(TaxAxisButton_1.TaxAxisButton, { onClick: handleContinue, className: "flex-1", disabled: busyCount > 0 }, busyCount > 0
358
- ? "Processing..."
359
- : failedCount > 0
360
- ? `Continue (${failedCount} failed)`
361
- : "Continue")),
370
+ showQboBanner && (react_1.default.createElement(QboConnectBanner_1.QboConnectBanner, { connected: qboConnected, companyName: qboCompanyName, onConnect: qboConnected ? qboFlow.openImport : qboFlow.openPermissions, onDisconnect: qboFlow.handleDisconnect })),
371
+ showQboBanner && !clientConfirmed && (react_1.default.createElement("div", { className: "text-center mt-3 mb-4" },
372
+ react_1.default.createElement("button", { onClick: () => setClientConfirmed(true), className: "text-[12px] text-tax-axis-text-3 font-tax-axis-body bg-transparent border-none cursor-pointer", style: { textDecoration: "underline", textUnderlineOffset: "2px" } }, "Skip and upload manually"))),
373
+ clientConfirmed && (react_1.default.createElement(react_1.default.Fragment, null,
374
+ react_1.default.createElement("div", { className: "py-3.5 px-[18px] mb-4 text-xs leading-relaxed font-tax-axis-body", style: {
375
+ background: "#171B44",
376
+ borderLeft: "3px solid #248384",
377
+ borderRadius: "0 8px 8px 0",
378
+ color: "#E6E8F5",
379
+ } }, "The minimum to run an analysis is the current-year P&L and Balance Sheet. However, accuracy and strategy coverage improve significantly with additional documents \u2014 particularly the federal tax return, fixed asset schedule, and W-2 forms."),
380
+ react_1.default.createElement("div", { className: "bg-tax-axis-surface border border-tax-axis-border rounded-[10px] px-[18px] py-3.5 mb-4" },
381
+ react_1.default.createElement("div", { className: "text-[10px] font-bold text-tax-axis-text-3 uppercase tracking-widest mb-2.5 font-tax-axis-mono" }, "Analysis Coverage"),
382
+ react_1.default.createElement("div", { className: "flex flex-col gap-1 sm:flex-row sm:justify-between mb-1.5" },
383
+ react_1.default.createElement("span", { className: "text-xs text-tax-axis-text-2 font-tax-axis-body" },
384
+ "Documents uploaded:",
385
+ " ",
386
+ react_1.default.createElement("strong", { className: "text-white" },
387
+ validCount,
388
+ " / ",
389
+ docs.length)),
390
+ react_1.default.createElement("span", { className: "text-xs text-tax-axis-text-2 font-tax-axis-body" },
391
+ "Strategies covered:",
392
+ " ",
393
+ react_1.default.createElement("strong", { className: "text-tax-axis-teal-light" },
394
+ strategiesCovered,
395
+ " / 25"))),
396
+ react_1.default.createElement("div", { className: "h-1.5 bg-tax-axis-surface-2 rounded-sm overflow-hidden mb-1.5" },
397
+ react_1.default.createElement("div", { className: "h-full rounded-sm transition-[width] duration-[400ms]", style: {
398
+ width: `${coveragePct}%`,
399
+ background: "linear-gradient(90deg, #248384, #A1E5E6)",
400
+ } })),
401
+ react_1.default.createElement("div", { className: "flex flex-col gap-1 sm:flex-row sm:justify-between" },
402
+ react_1.default.createElement("span", { className: "text-[10px] text-tax-axis-text-4 font-tax-axis-mono" },
403
+ coveragePct,
404
+ "% coverage"),
405
+ validCount < docs.length && (react_1.default.createElement("span", { className: "text-[10px] text-tax-axis-text-4 font-tax-axis-body" }, "Upload more documents to increase strategy coverage")))),
406
+ continueError && (react_1.default.createElement("div", { className: "py-3 px-4 mb-4 text-xs leading-relaxed font-tax-axis-body rounded-lg", style: {
407
+ background: "rgba(197,48,48,0.08)",
408
+ border: "1px solid rgba(197,48,48,0.3)",
409
+ color: "#FEB2B2",
410
+ } }, continueError)),
411
+ tierDefs.map((tier) => (react_1.default.createElement(DocumentTier_1.DocumentTier, { key: tier.key, tier: tier, docs: docs, helpOverrides: {}, fieldCounts: parsedFieldCounts, onUpload: handleUpload, onClear: handleClear, onRemove: handleRemove, onReview: (docId) => setReviewDocId(docId) }))),
412
+ react_1.default.createElement("div", { className: "flex gap-3 mt-6" },
413
+ react_1.default.createElement(TaxAxisButton_1.TaxAxisButton, { variant: "secondary", onClick: onBack }, "Back"),
414
+ react_1.default.createElement(TaxAxisButton_1.TaxAxisButton, { onClick: handleContinue, className: "flex-1", disabled: busyCount > 0 }, busyCount > 0
415
+ ? "Processing..."
416
+ : failedCount > 0
417
+ ? `Continue (${failedCount} failed)`
418
+ : "Continue")))),
362
419
  reviewDoc && (react_1.default.createElement(DocumentReviewModal_1.DocumentReviewModal, { documentId: reviewDoc.id, documentName: reviewDoc.name, fileName: reviewDoc.fileName || "", jobId: jobId, parsedData: reviewParsedData, onSaveReviewedData: onSaveReviewedField
363
420
  ? (fields) => __awaiter(this, void 0, void 0, function* () {
364
421
  const docId = uploadedDocIds[docs.indexOf(reviewDoc)];
@@ -368,5 +425,10 @@ function TaxAxisDocuments({ profile, entityType, onContinue, onBack, onUploadDoc
368
425
  const docTypeKey = reviewDoc.documentType || reviewDoc.id;
369
426
  setReviewedDataByDocType((prev) => (Object.assign(Object.assign({}, prev), { [docTypeKey]: fields })));
370
427
  })
371
- : undefined, onClose: () => setReviewDocId(null) }))));
428
+ : undefined, onClose: () => setReviewDocId(null) })),
429
+ react_1.default.createElement(QboPermissionsModal_1.QboPermissionsModal, { open: qboFlow.modalStep === "permissions", onCancel: qboFlow.closeModal, onContinue: qboFlow.handlePermissionsContinue }),
430
+ react_1.default.createElement(QboClientSelectorModal_1.QboClientSelectorModal, { open: qboFlow.modalStep === "client_selector", companies: qboFlow.companies, onCancel: qboFlow.closeModal, onSelect: qboFlow.handleCompanySelected }),
431
+ react_1.default.createElement(QboAvailableReportsModal_1.QboAvailableReportsModal, { open: qboFlow.modalStep === "available_reports", companyName: ((_f = qboFlow.selectedCompany) === null || _f === void 0 ? void 0 : _f.name) || "", selectedYear: qboFlow.selectedYear, onYearChange: qboFlow.setSelectedYear, onCancel: qboFlow.closeModal, onConfirm: qboFlow.handleReportsConfirmed }),
432
+ react_1.default.createElement(QboDocumentMappingModal_1.QboDocumentMappingModal, { open: qboFlow.modalStep === "mapping", companyName: ((_g = qboFlow.selectedCompany) === null || _g === void 0 ? void 0 : _g.name) || "", selectedReports: qboFlow.selectedReports, onCancel: qboFlow.closeModal, onConfirm: qboFlow.handleMappingConfirm }),
433
+ react_1.default.createElement(QboImportingModal_1.QboImportingModal, { open: qboFlow.modalStep === "importing", currentStepIndex: qboFlow.importStepIndex, companyName: ((_h = qboFlow.selectedCompany) === null || _h === void 0 ? void 0 : _h.name) || "" })));
372
434
  }
@@ -0,0 +1,13 @@
1
+ import React from "react";
2
+ import type { QboReportOption } from "./types";
3
+ interface QboAvailableReportsModalProps {
4
+ open: boolean;
5
+ companyName: string;
6
+ reports?: QboReportOption[];
7
+ selectedYear?: number;
8
+ onYearChange?: (year: number) => void;
9
+ onCancel: () => void;
10
+ onConfirm: (selectedReportIds: string[]) => void;
11
+ }
12
+ export declare function QboAvailableReportsModal({ open, companyName, reports, selectedYear, onYearChange, onCancel, onConfirm, }: QboAvailableReportsModalProps): React.JSX.Element | null;
13
+ export {};
@@ -0,0 +1,180 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.QboAvailableReportsModal = QboAvailableReportsModal;
27
+ const react_1 = __importStar(require("react"));
28
+ const qboConstants_1 = require("./qboConstants");
29
+ const QBO_YEAR_OPTIONS = [2023, 2024, 2025, 2026];
30
+ function QboAvailableReportsModal({ open, companyName, reports = qboConstants_1.QBO_REPORT_OPTIONS, selectedYear, onYearChange, onCancel, onConfirm, }) {
31
+ const availableReports = reports.filter((r) => r.available);
32
+ const [selected, setSelected] = (0, react_1.useState)(() => new Set(availableReports.map((r) => r.id)));
33
+ const [localYear, setLocalYear] = (0, react_1.useState)(selectedYear !== null && selectedYear !== void 0 ? selectedYear : new Date().getFullYear());
34
+ const handleYearChange = (year) => {
35
+ setLocalYear(year);
36
+ if (onYearChange)
37
+ onYearChange(year);
38
+ };
39
+ if (!open)
40
+ return null;
41
+ const toggleReport = (id) => {
42
+ setSelected((prev) => {
43
+ const next = new Set(prev);
44
+ if (next.has(id))
45
+ next.delete(id);
46
+ else
47
+ next.add(id);
48
+ return next;
49
+ });
50
+ };
51
+ return (react_1.default.createElement("div", { onClick: onCancel, style: {
52
+ position: "fixed",
53
+ inset: 0,
54
+ zIndex: 9999,
55
+ background: "rgba(0,0,0,0.65)",
56
+ display: "flex",
57
+ alignItems: "center",
58
+ justifyContent: "center",
59
+ } },
60
+ react_1.default.createElement("div", { onClick: (e) => e.stopPropagation(), style: {
61
+ width: 480,
62
+ maxHeight: "85vh",
63
+ background: "#111827",
64
+ border: "1px solid #1f2937",
65
+ borderRadius: 16,
66
+ display: "flex",
67
+ flexDirection: "column",
68
+ boxShadow: "0 25px 60px rgba(0,0,0,0.5)",
69
+ } },
70
+ react_1.default.createElement("div", { style: { padding: "20px 24px 16px", borderBottom: "1px solid #1f2937" } },
71
+ react_1.default.createElement("div", { style: { display: "flex", alignItems: "center", gap: 12 } },
72
+ react_1.default.createElement("div", { style: {
73
+ width: 36,
74
+ height: 36,
75
+ borderRadius: 8,
76
+ background: "rgba(44,160,28,0.12)",
77
+ border: "1px solid rgba(44,160,28,0.25)",
78
+ display: "flex",
79
+ alignItems: "center",
80
+ justifyContent: "center",
81
+ } },
82
+ react_1.default.createElement("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none" },
83
+ react_1.default.createElement("rect", { x: "3", y: "2", width: "10", height: "12", rx: "1.5", stroke: qboConstants_1.QBO_GREEN, strokeWidth: "1.2" }),
84
+ react_1.default.createElement("path", { d: "M5.5 5.5h5M5.5 8h5M5.5 10.5h3", stroke: qboConstants_1.QBO_GREEN, strokeWidth: "0.9", strokeLinecap: "round" }))),
85
+ react_1.default.createElement("div", { style: { flex: 1 } },
86
+ react_1.default.createElement("div", { style: { fontSize: 15, fontWeight: 600, color: "#f3f4f6" } }, "Available Reports"),
87
+ react_1.default.createElement("div", { style: { fontSize: 12, color: "#9ca3af", marginTop: 2 } },
88
+ companyName,
89
+ " \u00B7 Select reports to import")),
90
+ react_1.default.createElement("button", { onClick: onCancel, style: {
91
+ background: "transparent",
92
+ border: "none",
93
+ color: "#6b7280",
94
+ fontSize: 18,
95
+ cursor: "pointer",
96
+ padding: 4,
97
+ lineHeight: 1,
98
+ } }, "\u00D7"))),
99
+ react_1.default.createElement("div", { style: { padding: "14px 24px 0", borderBottom: "1px solid #1f2937" } },
100
+ react_1.default.createElement("div", { style: { display: "flex", alignItems: "center", gap: 10, paddingBottom: 14 } },
101
+ react_1.default.createElement("span", { style: { fontSize: 12, color: "#9ca3af", flexShrink: 0 } }, "Tax Year"),
102
+ react_1.default.createElement("div", { style: { display: "flex", gap: 6 } }, QBO_YEAR_OPTIONS.map((yr) => (react_1.default.createElement("button", { key: yr, onClick: () => handleYearChange(yr), style: Object.assign(Object.assign({ padding: "4px 12px", borderRadius: 6, fontSize: 12, fontWeight: 600, cursor: "pointer", border: "none" }, (localYear === yr
103
+ ? { background: qboConstants_1.QBO_GREEN, color: "white" }
104
+ : { background: "rgba(255,255,255,0.05)", color: "#9ca3af" })), { transition: "all 150ms" }) }, yr)))))),
105
+ react_1.default.createElement("div", { style: { padding: "16px 24px", flex: 1, overflowY: "auto" } }, reports.map((report, i) => {
106
+ const isAvailable = report.available;
107
+ const isChecked = selected.has(report.id);
108
+ return (react_1.default.createElement("div", { key: report.id, style: {
109
+ display: "flex",
110
+ alignItems: "center",
111
+ gap: 12,
112
+ padding: "12px 0",
113
+ borderBottom: i < reports.length - 1 ? "1px solid #1f2937" : "none",
114
+ opacity: isAvailable ? 1 : 0.5,
115
+ } },
116
+ react_1.default.createElement("div", { onClick: () => isAvailable && toggleReport(report.id), style: {
117
+ width: 18,
118
+ height: 18,
119
+ borderRadius: 4,
120
+ border: isChecked
121
+ ? `none`
122
+ : `2px solid ${isAvailable ? "#4b5563" : "#374151"}`,
123
+ background: isChecked ? qboConstants_1.QBO_GREEN : "transparent",
124
+ display: "flex",
125
+ alignItems: "center",
126
+ justifyContent: "center",
127
+ cursor: isAvailable ? "pointer" : "not-allowed",
128
+ flexShrink: 0,
129
+ transition: "all 150ms",
130
+ } }, isChecked && (react_1.default.createElement("svg", { width: "10", height: "10", viewBox: "0 0 10 10", fill: "none" },
131
+ react_1.default.createElement("path", { d: "M2 5l2.5 2.5L8 3", stroke: "white", strokeWidth: "1.5", strokeLinecap: "round" })))),
132
+ react_1.default.createElement("div", { style: { flex: 1 } },
133
+ react_1.default.createElement("span", { style: { fontSize: 13, fontWeight: 500, color: isAvailable ? "#e5e7eb" : "#6b7280" } }, report.label)),
134
+ react_1.default.createElement("span", { style: Object.assign({ fontSize: 9, fontWeight: 700, letterSpacing: "0.05em", padding: "2px 8px", borderRadius: 4 }, (isAvailable
135
+ ? {
136
+ background: "rgba(44,160,28,0.1)",
137
+ border: "1px solid rgba(44,160,28,0.2)",
138
+ color: qboConstants_1.QBO_GREEN,
139
+ }
140
+ : {
141
+ background: "rgba(107,114,128,0.1)",
142
+ border: "1px solid rgba(107,114,128,0.2)",
143
+ color: "#6b7280",
144
+ })) }, isAvailable ? "AVAILABLE" : "NOT FOUND")));
145
+ })),
146
+ react_1.default.createElement("div", { style: {
147
+ padding: "14px 24px",
148
+ borderTop: "1px solid #1f2937",
149
+ display: "flex",
150
+ justifyContent: "space-between",
151
+ alignItems: "center",
152
+ } },
153
+ react_1.default.createElement("span", { style: { fontSize: 11, color: "#6b7280" } },
154
+ selected.size,
155
+ " report",
156
+ selected.size !== 1 ? "s" : "",
157
+ " selected"),
158
+ react_1.default.createElement("div", { style: { display: "flex", gap: 10 } },
159
+ react_1.default.createElement("button", { onClick: onCancel, style: {
160
+ background: "transparent",
161
+ border: "1px solid #374151",
162
+ borderRadius: 8,
163
+ padding: "8px 18px",
164
+ fontSize: 13,
165
+ fontWeight: 500,
166
+ color: "#9ca3af",
167
+ cursor: "pointer",
168
+ } }, "Cancel"),
169
+ react_1.default.createElement("button", { onClick: () => onConfirm(Array.from(selected)), disabled: selected.size === 0, style: {
170
+ background: selected.size > 0 ? qboConstants_1.QBO_GREEN : "#374151",
171
+ border: "none",
172
+ borderRadius: 8,
173
+ padding: "8px 20px",
174
+ fontSize: 13,
175
+ fontWeight: 600,
176
+ color: "white",
177
+ cursor: selected.size > 0 ? "pointer" : "not-allowed",
178
+ opacity: selected.size > 0 ? 1 : 0.5,
179
+ } }, "Confirm & Import"))))));
180
+ }
@@ -0,0 +1,10 @@
1
+ import React from "react";
2
+ import type { QboCompany } from "./types";
3
+ interface QboClientSelectorModalProps {
4
+ open: boolean;
5
+ companies: QboCompany[];
6
+ onCancel: () => void;
7
+ onSelect: (company: QboCompany) => void;
8
+ }
9
+ export declare function QboClientSelectorModal({ open, companies, onCancel, onSelect, }: QboClientSelectorModalProps): React.JSX.Element | null;
10
+ export {};
@@ -0,0 +1,155 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.QboClientSelectorModal = QboClientSelectorModal;
27
+ const react_1 = __importStar(require("react"));
28
+ const qboConstants_1 = require("./qboConstants");
29
+ function QboClientSelectorModal({ open, companies, onCancel, onSelect, }) {
30
+ const [selectedId, setSelectedId] = (0, react_1.useState)(companies.length > 0 ? companies[0].id : null);
31
+ if (!open)
32
+ return null;
33
+ const handleConfirm = () => {
34
+ const company = companies.find((c) => c.id === selectedId);
35
+ if (company)
36
+ onSelect(company);
37
+ };
38
+ return (react_1.default.createElement("div", { onClick: onCancel, style: {
39
+ position: "fixed",
40
+ inset: 0,
41
+ zIndex: 9999,
42
+ background: "rgba(0,0,0,0.65)",
43
+ display: "flex",
44
+ alignItems: "center",
45
+ justifyContent: "center",
46
+ } },
47
+ react_1.default.createElement("div", { onClick: (e) => e.stopPropagation(), style: {
48
+ width: 440,
49
+ maxHeight: "85vh",
50
+ background: "#111827",
51
+ border: "1px solid #1f2937",
52
+ borderRadius: 16,
53
+ display: "flex",
54
+ flexDirection: "column",
55
+ boxShadow: "0 25px 60px rgba(0,0,0,0.5)",
56
+ } },
57
+ react_1.default.createElement("div", { style: { padding: "20px 24px 16px", borderBottom: "1px solid #1f2937" } },
58
+ react_1.default.createElement("div", { style: { display: "flex", alignItems: "center", gap: 12 } },
59
+ react_1.default.createElement("div", { style: {
60
+ width: 36,
61
+ height: 36,
62
+ borderRadius: 8,
63
+ background: "rgba(44,160,28,0.12)",
64
+ border: "1px solid rgba(44,160,28,0.25)",
65
+ display: "flex",
66
+ alignItems: "center",
67
+ justifyContent: "center",
68
+ } },
69
+ react_1.default.createElement("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none" },
70
+ react_1.default.createElement("rect", { x: "2", y: "3", width: "12", height: "10", rx: "2", stroke: qboConstants_1.QBO_GREEN, strokeWidth: "1.5" }),
71
+ react_1.default.createElement("path", { d: "M5 7h6M5 9.5h4", stroke: qboConstants_1.QBO_GREEN, strokeWidth: "1", strokeLinecap: "round" }))),
72
+ react_1.default.createElement("div", { style: { flex: 1 } },
73
+ react_1.default.createElement("div", { style: { fontSize: 15, fontWeight: 600, color: "#f3f4f6" } }, "Select a Company"),
74
+ react_1.default.createElement("div", { style: { fontSize: 12, color: "#9ca3af", marginTop: 2 } }, "Select the QuickBooks account for this client")),
75
+ react_1.default.createElement("button", { onClick: onCancel, style: {
76
+ background: "transparent",
77
+ border: "none",
78
+ color: "#6b7280",
79
+ fontSize: 18,
80
+ cursor: "pointer",
81
+ padding: 4,
82
+ lineHeight: 1,
83
+ } }, "\u00D7"))),
84
+ react_1.default.createElement("div", { style: { padding: "12px 24px", flex: 1, overflowY: "auto" } }, companies.map((company) => {
85
+ const isSelected = company.id === selectedId;
86
+ return (react_1.default.createElement("label", { key: company.id, style: {
87
+ display: "flex",
88
+ alignItems: "center",
89
+ gap: 12,
90
+ padding: "10px 12px",
91
+ borderRadius: 10,
92
+ cursor: "pointer",
93
+ marginBottom: 4,
94
+ background: isSelected ? "rgba(44,160,28,0.06)" : "transparent",
95
+ border: isSelected
96
+ ? "1px solid rgba(44,160,28,0.25)"
97
+ : "1px solid transparent",
98
+ transition: "all 150ms",
99
+ } },
100
+ react_1.default.createElement("div", { style: {
101
+ width: 16,
102
+ height: 16,
103
+ borderRadius: "50%",
104
+ border: isSelected
105
+ ? `5px solid ${qboConstants_1.QBO_GREEN}`
106
+ : "2px solid #4b5563",
107
+ background: isSelected ? "white" : "transparent",
108
+ flexShrink: 0,
109
+ transition: "all 150ms",
110
+ } }),
111
+ react_1.default.createElement("input", { type: "radio", name: "qbo-company", value: company.id, checked: isSelected, onChange: () => setSelectedId(company.id), style: { display: "none" } }),
112
+ react_1.default.createElement("div", { style: {
113
+ width: 32,
114
+ height: 32,
115
+ borderRadius: 8,
116
+ background: company.color,
117
+ display: "flex",
118
+ alignItems: "center",
119
+ justifyContent: "center",
120
+ fontSize: 12,
121
+ fontWeight: 700,
122
+ color: "white",
123
+ flexShrink: 0,
124
+ } }, company.initials),
125
+ react_1.default.createElement("span", { style: { fontSize: 13, fontWeight: 500, color: "#e5e7eb" } }, company.name)));
126
+ })),
127
+ react_1.default.createElement("div", { style: {
128
+ padding: "14px 24px",
129
+ borderTop: "1px solid #1f2937",
130
+ display: "flex",
131
+ justifyContent: "flex-end",
132
+ gap: 10,
133
+ } },
134
+ react_1.default.createElement("button", { onClick: onCancel, style: {
135
+ background: "transparent",
136
+ border: "1px solid #374151",
137
+ borderRadius: 8,
138
+ padding: "8px 18px",
139
+ fontSize: 13,
140
+ fontWeight: 500,
141
+ color: "#9ca3af",
142
+ cursor: "pointer",
143
+ } }, "Cancel"),
144
+ react_1.default.createElement("button", { onClick: handleConfirm, disabled: !selectedId, style: {
145
+ background: selectedId ? qboConstants_1.QBO_GREEN : "#374151",
146
+ border: "none",
147
+ borderRadius: 8,
148
+ padding: "8px 20px",
149
+ fontSize: 13,
150
+ fontWeight: 600,
151
+ color: "white",
152
+ cursor: selectedId ? "pointer" : "not-allowed",
153
+ opacity: selectedId ? 1 : 0.5,
154
+ } }, "Continue")))));
155
+ }