@powerhousedao/contributor-billing 0.1.51 → 0.1.52

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 (76) hide show
  1. package/dist/document-models/expense-report/src/reducers/wallet.d.ts.map +1 -1
  2. package/dist/document-models/expense-report/src/reducers/wallet.js +4 -4
  3. package/dist/editors/account-transactions-editor/alchemyIntegration.d.ts +1 -0
  4. package/dist/editors/account-transactions-editor/alchemyIntegration.d.ts.map +1 -1
  5. package/dist/editors/account-transactions-editor/alchemyIntegration.js +1 -0
  6. package/dist/editors/account-transactions-editor/editor.d.ts.map +1 -1
  7. package/dist/editors/account-transactions-editor/editor.js +67 -10
  8. package/dist/editors/accounts-editor/components/AccountCard.d.ts.map +1 -1
  9. package/dist/editors/accounts-editor/components/AccountCard.js +1 -1
  10. package/dist/editors/accounts-editor/components/AccountForm.d.ts.map +1 -1
  11. package/dist/editors/accounts-editor/components/AccountForm.js +55 -16
  12. package/dist/editors/accounts-editor/components/AccountsList.js +1 -1
  13. package/dist/editors/accounts-editor/editor.d.ts.map +1 -1
  14. package/dist/editors/accounts-editor/editor.js +86 -44
  15. package/dist/editors/contributor-billing/components/BillingOverview.d.ts +2 -1
  16. package/dist/editors/contributor-billing/components/BillingOverview.d.ts.map +1 -1
  17. package/dist/editors/contributor-billing/components/BillingOverview.js +2 -2
  18. package/dist/editors/contributor-billing/components/DashboardHome.d.ts.map +1 -1
  19. package/dist/editors/contributor-billing/components/DashboardHome.js +78 -8
  20. package/dist/editors/contributor-billing/components/DocumentDropZone.d.ts +13 -0
  21. package/dist/editors/contributor-billing/components/DocumentDropZone.d.ts.map +1 -0
  22. package/dist/editors/contributor-billing/components/DocumentDropZone.js +101 -0
  23. package/dist/editors/contributor-billing/components/DriveContents.d.ts +2 -1
  24. package/dist/editors/contributor-billing/components/DriveContents.d.ts.map +1 -1
  25. package/dist/editors/contributor-billing/components/DriveContents.js +7 -7
  26. package/dist/editors/contributor-billing/components/DriveExplorer.d.ts.map +1 -1
  27. package/dist/editors/contributor-billing/components/DriveExplorer.js +25 -3
  28. package/dist/editors/contributor-billing/components/FolderTree.d.ts.map +1 -1
  29. package/dist/editors/contributor-billing/components/FolderTree.js +37 -34
  30. package/dist/editors/contributor-billing/components/MonthReportCard.d.ts +2 -1
  31. package/dist/editors/contributor-billing/components/MonthReportCard.d.ts.map +1 -1
  32. package/dist/editors/contributor-billing/components/MonthReportCard.js +12 -2
  33. package/dist/editors/contributor-billing/components/MonthlyReportsOverview.d.ts +2 -1
  34. package/dist/editors/contributor-billing/components/MonthlyReportsOverview.d.ts.map +1 -1
  35. package/dist/editors/contributor-billing/components/MonthlyReportsOverview.js +69 -8
  36. package/dist/editors/contributor-billing/components/ReportingView.d.ts.map +1 -1
  37. package/dist/editors/contributor-billing/components/ReportingView.js +38 -9
  38. package/dist/editors/contributor-billing/components/SubscriptionsOverview.d.ts.map +1 -1
  39. package/dist/editors/contributor-billing/components/SubscriptionsOverview.js +1 -1
  40. package/dist/editors/contributor-billing/config.d.ts.map +1 -1
  41. package/dist/editors/contributor-billing/config.js +2 -1
  42. package/dist/editors/contributor-billing/hooks/useDocumentAutoPlacement.d.ts +18 -0
  43. package/dist/editors/contributor-billing/hooks/useDocumentAutoPlacement.d.ts.map +1 -0
  44. package/dist/editors/contributor-billing/hooks/useDocumentAutoPlacement.js +149 -0
  45. package/dist/editors/contributor-billing/hooks/useMonthlyReports.d.ts.map +1 -1
  46. package/dist/editors/contributor-billing/hooks/useMonthlyReports.js +30 -4
  47. package/dist/editors/expense-report/components/SetOwner.d.ts.map +1 -1
  48. package/dist/editors/expense-report/components/SetOwner.js +43 -2
  49. package/dist/editors/expense-report/components/WalletsTable.d.ts.map +1 -1
  50. package/dist/editors/expense-report/components/WalletsTable.js +22 -3
  51. package/dist/editors/expense-report/editor.d.ts.map +1 -1
  52. package/dist/editors/expense-report/editor.js +20 -2
  53. package/dist/editors/expense-report/hooks/useSyncWallet.d.ts.map +1 -1
  54. package/dist/editors/expense-report/hooks/useSyncWallet.js +41 -24
  55. package/dist/editors/operational-hub-profile-editor/components/ProfileOverview.d.ts +10 -0
  56. package/dist/editors/operational-hub-profile-editor/components/ProfileOverview.d.ts.map +1 -0
  57. package/dist/editors/operational-hub-profile-editor/components/ProfileOverview.js +114 -0
  58. package/dist/editors/operational-hub-profile-editor/components/SubteamsPicker.d.ts.map +1 -1
  59. package/dist/editors/operational-hub-profile-editor/components/SubteamsPicker.js +44 -4
  60. package/dist/editors/operational-hub-profile-editor/editor.d.ts.map +1 -1
  61. package/dist/editors/operational-hub-profile-editor/editor.js +7 -2
  62. package/dist/editors/snapshot-report-editor/components/SetOwner.d.ts.map +1 -1
  63. package/dist/editors/snapshot-report-editor/components/SetOwner.js +43 -2
  64. package/dist/editors/snapshot-report-editor/editor.d.ts.map +1 -1
  65. package/dist/editors/snapshot-report-editor/editor.js +9 -2
  66. package/dist/editors/snapshot-report-editor/hooks/useSyncSnapshotAccount.d.ts.map +1 -1
  67. package/dist/editors/snapshot-report-editor/hooks/useSyncSnapshotAccount.js +120 -27
  68. package/dist/editors/snapshot-report-editor/utils/balanceCalculations.d.ts +5 -1
  69. package/dist/editors/snapshot-report-editor/utils/balanceCalculations.d.ts.map +1 -1
  70. package/dist/editors/snapshot-report-editor/utils/balanceCalculations.js +47 -1
  71. package/dist/style.css +138 -0
  72. package/dist/subgraphs/resources-services/resolvers.d.ts.map +1 -1
  73. package/dist/subgraphs/resources-services/resolvers.js +28 -13
  74. package/dist/subgraphs/resources-services/schema.d.ts.map +1 -1
  75. package/dist/subgraphs/resources-services/schema.js +3 -1
  76. package/package.json +1 -1
@@ -1,8 +1,8 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { useState } from "react";
3
3
  import { Button } from "@powerhousedao/document-engineering";
4
- import { ChevronDown, ChevronUp, HelpCircle, X } from "lucide-react";
5
- import { DocumentToolbar } from "@powerhousedao/design-system/connect";
4
+ import { ChevronDown, ChevronUp, HelpCircle, Plus, RefreshCw, X, } from "lucide-react";
5
+ import { DocumentToolbar, toast, ToastContainer, } from "@powerhousedao/design-system/connect";
6
6
  import { setSelectedNode, useParentFolderForSelectedNode, useSelectedDrive, } from "@powerhousedao/reactor-browser";
7
7
  import { generateId } from "document-model/core";
8
8
  import { useSelectedAccountsDocument } from "../hooks/useAccountsDocument.js";
@@ -24,6 +24,8 @@ export default function Editor() {
24
24
  const [creatingTransactionsFor, setCreatingTransactionsFor] = useState(null);
25
25
  const [isSyncingAll, setIsSyncingAll] = useState(false);
26
26
  const [syncProgress, setSyncProgress] = useState(null);
27
+ const [deleteConfirm, setDeleteConfirm] = useState({ isOpen: false, accountId: null, accountName: "" });
28
+ const [syncConfirm, setSyncConfirm] = useState(false);
27
29
  const [showHelp, setShowHelp] = useState(() => {
28
30
  if (typeof window !== "undefined") {
29
31
  return localStorage.getItem(HELP_DISMISSED_KEY) !== "true";
@@ -69,9 +71,19 @@ export default function Editor() {
69
71
  setEditingAccount(null);
70
72
  }
71
73
  function handleDeleteAccount(id) {
72
- if (window.confirm("Are you sure you want to delete this account?")) {
73
- dispatch(deleteAccount({ id }));
74
+ const account = accounts.find((a) => a.id === id);
75
+ setDeleteConfirm({
76
+ isOpen: true,
77
+ accountId: id,
78
+ accountName: account?.name || "this account",
79
+ });
80
+ }
81
+ function confirmDelete() {
82
+ if (deleteConfirm.accountId) {
83
+ dispatch(deleteAccount({ id: deleteConfirm.accountId }));
84
+ toast("Account deleted successfully", { type: "success" });
74
85
  }
86
+ setDeleteConfirm({ isOpen: false, accountId: null, accountName: "" });
75
87
  }
76
88
  function handleUpdateKycStatus(id, KycAmlStatus) {
77
89
  dispatch(updateKycStatus({ id, KycAmlStatus }));
@@ -99,67 +111,91 @@ export default function Editor() {
99
111
  accountTransactionsId: result.documentId,
100
112
  }));
101
113
  }
102
- alert(`Success! Created document and fetched ${result.transactionsAdded} transactions`);
114
+ toast(`Created document and fetched ${result.transactionsAdded} transactions`, { type: "success" });
103
115
  }
104
116
  else {
105
- alert(`Error: ${result.message}`);
117
+ toast(`Error: ${result.message}`, { type: "error" });
106
118
  }
107
119
  }
108
120
  catch (error) {
109
- alert(`Error: ${error instanceof Error ? error.message : "Unknown error occurred"}`);
121
+ toast(`Error: ${error instanceof Error ? error.message : "Unknown error occurred"}`, { type: "error" });
110
122
  }
111
123
  finally {
112
124
  setCreatingTransactionsFor(null);
113
125
  }
114
126
  }
115
- async function handleSyncAllTransactions() {
116
- // Filter accounts that have transaction documents
117
- const accountsWithTransactions = accounts.filter((account) => account.accountTransactionsId &&
118
- account.accountTransactionsId.trim() !== "");
119
- if (accountsWithTransactions.length === 0) {
120
- alert("No accounts have transaction documents to sync. Create transaction documents first.");
121
- return;
122
- }
123
- if (!window.confirm(`This will sync transactions for ${accountsWithTransactions.length} account(s). Continue?`)) {
127
+ function initiateSync() {
128
+ if (accounts.length === 0) {
129
+ toast("No accounts to sync transactions for", { type: "warning" });
124
130
  return;
125
131
  }
132
+ setSyncConfirm(true);
133
+ }
134
+ async function handleSyncAllTransactions() {
135
+ setSyncConfirm(false);
126
136
  setIsSyncingAll(true);
127
137
  const results = [];
128
138
  try {
129
- for (let i = 0; i < accountsWithTransactions.length; i++) {
130
- const account = accountsWithTransactions[i];
139
+ const driveId = selectedDrive?.header?.id;
140
+ const accountsDocumentId = document.header.id;
141
+ for (let i = 0; i < accounts.length; i++) {
142
+ const account = accounts[i];
131
143
  setSyncProgress({
132
144
  current: i + 1,
133
- total: accountsWithTransactions.length,
145
+ total: accounts.length,
134
146
  account: account.name,
135
147
  });
136
- const result = await accountTransactionsService.syncTransactionsForDocument(account.accountTransactionsId, account.account);
137
- results.push({
138
- account: account.name,
139
- success: result.success,
140
- transactionsAdded: result.transactionsAdded || 0,
141
- message: result.message,
142
- });
148
+ try {
149
+ // If account already has a transaction document, sync it
150
+ if (account.accountTransactionsId) {
151
+ const result = await accountTransactionsService.syncTransactionsForDocument(account.accountTransactionsId, account.account);
152
+ results.push({
153
+ account: account.name,
154
+ success: result.success,
155
+ transactionsAdded: result.transactionsAdded || 0,
156
+ message: result.message,
157
+ });
158
+ }
159
+ else {
160
+ // Otherwise, create a new transaction document and fetch transactions
161
+ const result = await accountTransactionsService.createAccountTransactionsDocument(account, accountsDocumentId, driveId);
162
+ if (result.success && result.documentId) {
163
+ // Update the account with the new transaction document ID
164
+ dispatch(updateAccount({
165
+ id: account.id,
166
+ accountTransactionsId: result.documentId,
167
+ }));
168
+ }
169
+ results.push({
170
+ account: account.name,
171
+ success: result.success,
172
+ transactionsAdded: result.transactionsAdded || 0,
173
+ message: result.message,
174
+ });
175
+ }
176
+ }
177
+ catch (error) {
178
+ results.push({
179
+ account: account.name,
180
+ success: false,
181
+ transactionsAdded: 0,
182
+ message: error instanceof Error ? error.message : "Unknown error occurred",
183
+ });
184
+ }
143
185
  }
144
186
  // Show summary
145
187
  const totalAdded = results.reduce((sum, r) => sum + r.transactionsAdded, 0);
146
188
  const successCount = results.filter((r) => r.success).length;
147
189
  const failedCount = results.length - successCount;
148
- let message = `Sync complete!\n\n`;
149
- message += `Successfully synced: ${successCount}/${results.length} accounts\n`;
150
- message += `Total new transactions: ${totalAdded}\n`;
151
- if (failedCount > 0) {
152
- message += `\nFailed accounts:\n`;
153
- results
154
- .filter((r) => !r.success)
155
- .forEach((r) => {
156
- message += `- ${r.account}: ${r.message}\n`;
157
- });
190
+ if (failedCount === 0) {
191
+ toast(`Synced ${successCount} account${successCount !== 1 ? "s" : ""}, ${totalAdded} new transactions`, { type: "success" });
192
+ }
193
+ else {
194
+ toast(`Synced ${successCount}/${results.length} accounts. ${failedCount} failed.`, { type: "warning" });
158
195
  }
159
- alert(message);
160
196
  }
161
197
  catch (error) {
162
- alert(`Error during bulk sync: ${error instanceof Error ? error.message : "Unknown error occurred"}`);
198
+ toast(`Error during sync: ${error instanceof Error ? error.message : "Unknown error occurred"}`, { type: "error" });
163
199
  }
164
200
  finally {
165
201
  setIsSyncingAll(false);
@@ -167,9 +203,15 @@ export default function Editor() {
167
203
  }
168
204
  }
169
205
  const accounts = document.state.global.accounts;
170
- return (_jsxs("div", { className: "h-screen flex flex-col bg-gray-50", children: [_jsx(DocumentToolbar, { document: document, onClose: handleClose }), _jsx("div", { className: "bg-white border-b border-gray-200 px-4 py-3 flex items-center justify-between", children: _jsx("h1", { className: "text-lg font-semibold text-gray-900", children: "Accounts" }) }), _jsx("div", { className: "flex-1 overflow-auto", children: _jsx("div", { className: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8", children: _jsxs("div", { children: [viewMode === "list" && (_jsxs("div", { className: "space-y-6", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("div", { children: [_jsx("h2", { className: "text-2xl font-semibold text-gray-900", children: "Accounts" }), _jsx("p", { className: "mt-1 text-sm text-gray-600", children: "Manage your accounts and sync transactions" })] }), _jsxs("div", { className: "flex gap-3", children: [_jsx(Button, { onClick: handleSyncAllTransactions, disabled: isSyncingAll ||
171
- accounts.filter((a) => a.accountTransactionsId)
172
- .length === 0, className: "bg-green-600 hover:bg-green-700 disabled:bg-gray-400 text-white px-6 py-2.5 rounded-lg font-medium shadow-sm transition-colors", children: isSyncingAll ? (_jsxs("span", { className: "flex items-center gap-2", children: [_jsxs("svg", { className: "animate-spin h-4 w-4", xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", children: [_jsx("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }), _jsx("path", { className: "opacity-75", fill: "currentColor", d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" })] }), syncProgress
173
- ? `${syncProgress.current}/${syncProgress.total}`
174
- : "Syncing..."] })) : ("Sync All Transactions") }), _jsx(Button, { onClick: () => setViewMode("add"), className: "bg-blue-600 hover:bg-blue-700 text-white px-6 py-2.5 rounded-lg font-medium shadow-sm transition-colors", children: "Add Account" })] })] }), showHelp && (_jsx(InstructionSection, { onDismiss: handleDismissHelp })), syncProgress && (_jsx("div", { className: "bg-blue-50 border border-blue-200 rounded-lg p-4", children: _jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("div", { children: [_jsxs("p", { className: "text-sm font-medium text-blue-900", children: ["Syncing transactions: ", syncProgress.account] }), _jsxs("p", { className: "text-xs text-blue-700 mt-1", children: ["Progress: ", syncProgress.current, " of", " ", syncProgress.total, " accounts"] })] }), _jsx("div", { className: "flex items-center gap-2", children: _jsxs("svg", { className: "animate-spin h-5 w-5 text-blue-600", xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", children: [_jsx("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }), _jsx("path", { className: "opacity-75", fill: "currentColor", d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" })] }) })] }) })), accounts.length === 0 ? (_jsxs("div", { className: "bg-white rounded-xl border border-gray-200 p-12 text-center", children: [_jsx("svg", { className: "mx-auto h-12 w-12 text-gray-400", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4" }) }), _jsx("h3", { className: "mt-4 text-lg font-medium text-gray-900", children: "No accounts yet" }), _jsx("p", { className: "mt-2 text-sm text-gray-600", children: "Get started by creating your first account" }), _jsx(Button, { onClick: () => setViewMode("add"), className: "mt-6 bg-blue-600 hover:bg-blue-700 text-white px-6 py-2.5 rounded-lg font-medium shadow-sm transition-colors", children: "Add Account" })] })) : (_jsx(AccountsList, { accounts: accounts, onEdit: handleEditClick, onDelete: handleDeleteAccount, onUpdateKycStatus: handleUpdateKycStatus, onCreateTransactions: handleCreateTransactions, creatingTransactionsFor: creatingTransactionsFor || undefined }))] })), viewMode === "add" && (_jsxs("div", { className: "max-w-3xl", children: [_jsxs("div", { className: "mb-6", children: [_jsx("h2", { className: "text-2xl font-semibold text-gray-900", children: "Add New Account" }), _jsx("p", { className: "mt-1 text-sm text-gray-600", children: "Fill in the account details below" })] }), _jsx(AccountForm, { onSubmit: handleAddAccount, onCancel: handleCancelForm })] })), viewMode === "edit" && editingAccount && (_jsxs("div", { className: "max-w-3xl", children: [_jsxs("div", { className: "mb-6", children: [_jsx("h2", { className: "text-2xl font-semibold text-gray-900", children: "Edit Account" }), _jsx("p", { className: "mt-1 text-sm text-gray-600", children: "Update the account details below" })] }), _jsx(AccountForm, { account: editingAccount, onSubmit: handleUpdateAccount, onCancel: handleCancelForm })] }))] }) }) })] }));
206
+ return (_jsxs("div", { className: "h-screen flex flex-col bg-gray-50", children: [_jsx(DocumentToolbar, { document: document, onClose: handleClose }), _jsx("div", { className: "bg-white border-b border-gray-200 px-4 py-3 flex items-center justify-between", children: _jsx("h1", { className: "text-lg font-semibold text-gray-900", children: "Accounts" }) }), _jsx("div", { className: "flex-1 overflow-auto", children: _jsx("div", { className: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8", children: _jsxs("div", { children: [viewMode === "list" && (_jsxs("div", { className: "space-y-6", children: [_jsxs("div", { children: [_jsx("h2", { className: "text-2xl font-semibold text-gray-900", children: "Accounts" }), _jsx("p", { className: "mt-1 text-sm text-gray-600", children: "Manage your accounts and sync transactions" })] }), showHelp && (_jsx(InstructionSection, { onDismiss: handleDismissHelp })), _jsxs("div", { className: "flex items-center justify-end gap-3", children: [_jsxs(Button, { onClick: () => setViewMode("add"), className: "bg-blue-600 hover:bg-blue-700 text-white px-6 py-2.5 rounded-lg font-medium shadow-sm transition-colors flex items-center gap-2", children: [_jsx(Plus, { className: "w-4 h-4", "aria-hidden": "true" }), "Add Account"] }), _jsx(Button, { onClick: initiateSync, disabled: isSyncingAll || accounts.length === 0, className: "border border-gray-300 bg-white hover:bg-gray-50 disabled:bg-gray-100 disabled:text-gray-400 text-gray-700 px-4 py-2 rounded-lg font-medium transition-colors flex items-center gap-2", children: isSyncingAll ? (_jsxs(_Fragment, { children: [_jsxs("svg", { className: "animate-spin h-4 w-4", xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", "aria-hidden": "true", children: [_jsx("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }), _jsx("path", { className: "opacity-75", fill: "currentColor", d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" })] }), syncProgress
207
+ ? `Syncing ${syncProgress.current}/${syncProgress.total}…`
208
+ : "Syncing…"] })) : (_jsxs(_Fragment, { children: [_jsx(RefreshCw, { className: "w-4 h-4", "aria-hidden": "true" }), "Sync Transactions"] })) })] }), syncProgress && (_jsx("div", { className: "bg-blue-50 border border-blue-200 rounded-lg p-4", children: _jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("div", { children: [_jsxs("p", { className: "text-sm font-medium text-blue-900", children: ["Syncing transactions: ", syncProgress.account] }), _jsxs("p", { className: "text-xs text-blue-700 mt-1", children: ["Progress: ", syncProgress.current, " of", " ", syncProgress.total, " accounts"] })] }), _jsx("div", { className: "flex items-center gap-2", children: _jsxs("svg", { className: "animate-spin h-5 w-5 text-blue-600", xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", children: [_jsx("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }), _jsx("path", { className: "opacity-75", fill: "currentColor", d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" })] }) })] }) })), accounts.length === 0 ? (_jsxs("div", { className: "bg-white rounded-xl border border-gray-200 p-12 text-center", children: [_jsx("svg", { className: "mx-auto h-12 w-12 text-gray-400", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4" }) }), _jsx("h3", { className: "mt-4 text-lg font-medium text-gray-900", children: "No accounts yet" }), _jsx("p", { className: "mt-2 text-sm text-gray-600", children: "Get started by creating your first account" }), _jsx(Button, { onClick: () => setViewMode("add"), className: "mt-6 bg-blue-600 hover:bg-blue-700 text-white px-6 py-2.5 rounded-lg font-medium shadow-sm transition-colors", children: "Add Account" })] })) : (_jsx(AccountsList, { accounts: accounts, onEdit: handleEditClick, onDelete: handleDeleteAccount, onUpdateKycStatus: handleUpdateKycStatus, onCreateTransactions: handleCreateTransactions, creatingTransactionsFor: creatingTransactionsFor || undefined }))] })), viewMode === "add" && (_jsxs("div", { className: "max-w-3xl", children: [_jsxs("div", { className: "mb-6", children: [_jsx("h2", { className: "text-2xl font-semibold text-gray-900", children: "Add New Account" }), _jsx("p", { className: "mt-1 text-sm text-gray-600", children: "Fill in the account details below" })] }), _jsx(AccountForm, { onSubmit: handleAddAccount, onCancel: handleCancelForm })] })), viewMode === "edit" && editingAccount && (_jsxs("div", { className: "max-w-3xl", children: [_jsxs("div", { className: "mb-6", children: [_jsx("h2", { className: "text-2xl font-semibold text-gray-900", children: "Edit Account" }), _jsx("p", { className: "mt-1 text-sm text-gray-600", children: "Update the account details below" })] }), _jsx(AccountForm, { account: editingAccount, onSubmit: handleUpdateAccount, onCancel: handleCancelForm })] }))] }) }) }), deleteConfirm.isOpen && (_jsx("div", { className: "fixed inset-0 bg-black/50 flex items-center justify-center z-50", onClick: () => setDeleteConfirm({
209
+ isOpen: false,
210
+ accountId: null,
211
+ accountName: "",
212
+ }), children: _jsxs("div", { className: "bg-white rounded-lg shadow-xl max-w-md w-full mx-4 p-6", onClick: (e) => e.stopPropagation(), role: "dialog", "aria-modal": "true", "aria-labelledby": "delete-modal-title", children: [_jsx("h3", { id: "delete-modal-title", className: "text-lg font-semibold text-gray-900 mb-2", children: "Delete Account" }), _jsxs("p", { className: "text-gray-600 mb-6", children: ["Are you sure you want to delete \"", deleteConfirm.accountName, "\"? This action cannot be undone."] }), _jsxs("div", { className: "flex justify-end gap-3", children: [_jsx(Button, { onClick: () => setDeleteConfirm({
213
+ isOpen: false,
214
+ accountId: null,
215
+ accountName: "",
216
+ }), className: "px-4 py-2 border border-gray-300 rounded-lg font-medium text-gray-700 hover:bg-gray-50 transition-colors", children: "Cancel" }), _jsx(Button, { onClick: confirmDelete, className: "px-4 py-2 bg-red-600 hover:bg-red-700 text-white rounded-lg font-medium transition-colors", children: "Delete Account" })] })] }) })), syncConfirm && (_jsx("div", { className: "fixed inset-0 bg-black/50 flex items-center justify-center z-50", onClick: () => setSyncConfirm(false), children: _jsxs("div", { className: "bg-white rounded-lg shadow-xl max-w-md w-full mx-4 p-6", onClick: (e) => e.stopPropagation(), role: "dialog", "aria-modal": "true", "aria-labelledby": "sync-modal-title", children: [_jsx("h3", { id: "sync-modal-title", className: "text-lg font-semibold text-gray-900 mb-2", children: "Sync Transactions" }), _jsxs("p", { className: "text-gray-600 mb-6", children: ["This will sync transactions for all ", accounts.length, " account", accounts.length !== 1 ? "s" : "", ". Accounts without transaction documents will have them created automatically."] }), _jsxs("div", { className: "flex justify-end gap-3", children: [_jsx(Button, { onClick: () => setSyncConfirm(false), className: "px-4 py-2 border border-gray-300 rounded-lg font-medium text-gray-700 hover:bg-gray-50 transition-colors", children: "Cancel" }), _jsx(Button, { onClick: () => void handleSyncAllTransactions(), className: "px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-lg font-medium transition-colors", children: "Sync All" })] })] }) })), _jsx(ToastContainer, { position: "bottom-right", autoClose: 4000, hideProgressBar: false, newestOnTop: false, closeOnClick: true, rtl: false, pauseOnFocusLoss: true, draggable: true, pauseOnHover: true })] }));
175
217
  }
@@ -1,10 +1,11 @@
1
1
  import type { SelectedFolderInfo } from "./FolderTree.js";
2
2
  interface BillingOverviewProps {
3
3
  onFolderSelect?: (folderInfo: SelectedFolderInfo | null) => void;
4
+ onActiveNodeIdChange?: (nodeId: string) => void;
4
5
  }
5
6
  /**
6
7
  * Overview for the Billing folder showing payment stats and monthly reporting
7
8
  */
8
- export declare function BillingOverview({ onFolderSelect }: BillingOverviewProps): import("react/jsx-runtime").JSX.Element;
9
+ export declare function BillingOverview({ onFolderSelect, onActiveNodeIdChange, }: BillingOverviewProps): import("react/jsx-runtime").JSX.Element;
9
10
  export {};
10
11
  //# sourceMappingURL=BillingOverview.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"BillingOverview.d.ts","sourceRoot":"","sources":["../../../../editors/contributor-billing/components/BillingOverview.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAE1D,UAAU,oBAAoB;IAC5B,cAAc,CAAC,EAAE,CAAC,UAAU,EAAE,kBAAkB,GAAG,IAAI,KAAK,IAAI,CAAC;CAClE;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,EAAE,cAAc,EAAE,EAAE,oBAAoB,2CAkLvE"}
1
+ {"version":3,"file":"BillingOverview.d.ts","sourceRoot":"","sources":["../../../../editors/contributor-billing/components/BillingOverview.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAE1D,UAAU,oBAAoB;IAC5B,cAAc,CAAC,EAAE,CAAC,UAAU,EAAE,kBAAkB,GAAG,IAAI,KAAK,IAAI,CAAC;IACjE,oBAAoB,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;CACjD;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,EAC9B,cAAc,EACd,oBAAoB,GACrB,EAAE,oBAAoB,2CAmLtB"}
@@ -7,7 +7,7 @@ import { MonthlyReportsOverview } from "./MonthlyReportsOverview.js";
7
7
  /**
8
8
  * Overview for the Billing folder showing payment stats and monthly reporting
9
9
  */
10
- export function BillingOverview({ onFolderSelect }) {
10
+ export function BillingOverview({ onFolderSelect, onActiveNodeIdChange, }) {
11
11
  const { billingFolder, monthFolders, createMonthFolder, createBillingFolder, paymentsFolderIds, } = useBillingFolderStructure();
12
12
  const documentsInDrive = useDocumentsInSelectedDrive();
13
13
  const [driveDocument] = useSelectedDrive();
@@ -71,5 +71,5 @@ export function BillingOverview({ onFolderSelect }) {
71
71
  return (_jsxs("div", { children: [_jsxs("div", { className: "mb-6", children: [_jsx("h1", { className: "text-2xl font-bold text-gray-900", children: "Billing" }), _jsx("p", { className: "text-gray-600", children: "Manage monthly billing, payments, and reports" })] }), _jsxs("div", { className: "bg-white rounded-xl border border-gray-200 p-6 mb-6", children: [_jsxs("div", { className: "flex items-center gap-3 mb-4", children: [_jsx("div", { className: "p-2 bg-blue-100 rounded-lg", children: _jsx(CreditCard, { className: "w-5 h-5 text-blue-600" }) }), _jsxs("div", { children: [_jsx("h2", { className: "text-lg font-semibold text-gray-900", children: "Payment Summary" }), _jsx("p", { className: "text-sm text-gray-600", children: "Overview of all invoices across billing months" })] })] }), _jsxs("div", { className: "grid grid-cols-2 md:grid-cols-4 gap-4", children: [_jsxs("div", { className: "bg-gray-50 rounded-lg p-3", children: [_jsxs("div", { className: "flex items-center gap-2 mb-1", children: [_jsx(FileText, { className: "w-4 h-4 text-gray-500" }), _jsx("span", { className: "text-sm text-gray-600", children: "Total Invoices" })] }), _jsx("p", { className: "text-xl font-bold text-gray-900", children: paymentStats.totalInvoices })] }), _jsxs("div", { className: "bg-gray-50 rounded-lg p-3", children: [_jsxs("div", { className: "flex items-center gap-2 mb-1", children: [_jsx(CreditCard, { className: "w-4 h-4 text-gray-500" }), _jsx("span", { className: "text-sm text-gray-600", children: "Total Amount" })] }), _jsxs("p", { className: "text-xl font-bold text-gray-900", children: ["$", paymentStats.totalAmount.toLocaleString("en-US", {
72
72
  minimumFractionDigits: 2,
73
73
  maximumFractionDigits: 2,
74
- })] })] }), _jsxs("div", { className: "bg-amber-50 rounded-lg p-3", children: [_jsx("span", { className: "text-sm text-amber-600", children: "Pending" }), _jsx("p", { className: "text-xl font-bold text-amber-700", children: paymentStats.pendingCount })] }), _jsxs("div", { className: "bg-green-50 rounded-lg p-3", children: [_jsx("span", { className: "text-sm text-green-600", children: "Paid" }), _jsx("p", { className: "text-xl font-bold text-green-700", children: paymentStats.paidCount })] })] })] }), _jsx(MonthlyReportsOverview, { onFolderSelect: onFolderSelect, monthFolders: monthFolders, onCreateMonth: createMonthFolder })] }));
74
+ })] })] }), _jsxs("div", { className: "bg-amber-50 rounded-lg p-3", children: [_jsx("span", { className: "text-sm text-amber-600", children: "Pending" }), _jsx("p", { className: "text-xl font-bold text-amber-700", children: paymentStats.pendingCount })] }), _jsxs("div", { className: "bg-green-50 rounded-lg p-3", children: [_jsx("span", { className: "text-sm text-green-600", children: "Paid" }), _jsx("p", { className: "text-xl font-bold text-green-700", children: paymentStats.paidCount })] })] })] }), _jsx(MonthlyReportsOverview, { onFolderSelect: onFolderSelect, monthFolders: monthFolders, onCreateMonth: createMonthFolder, onActiveNodeIdChange: onActiveNodeIdChange })] }));
75
75
  }
@@ -1 +1 @@
1
- {"version":3,"file":"DashboardHome.d.ts","sourceRoot":"","sources":["../../../../editors/contributor-billing/components/DashboardHome.tsx"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAI1D,UAAU,kBAAkB;IAC1B,cAAc,CAAC,EAAE,CAAC,UAAU,EAAE,kBAAkB,GAAG,IAAI,KAAK,IAAI,CAAC;CAClE;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,EAAE,cAAc,EAAE,EAAE,kBAAkB,2CAyQnE"}
1
+ {"version":3,"file":"DashboardHome.d.ts","sourceRoot":"","sources":["../../../../editors/contributor-billing/components/DashboardHome.tsx"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAK1D,UAAU,kBAAkB;IAC1B,cAAc,CAAC,EAAE,CAAC,UAAU,EAAE,kBAAkB,GAAG,IAAI,KAAK,IAAI,CAAC;CAClE;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,EAAE,cAAc,EAAE,EAAE,kBAAkB,2CA8WnE"}
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Wallet, CheckCircle2, ArrowRight, Building2, User, } from "lucide-react";
3
3
  import { useCallback, useMemo, useState } from "react";
4
- import { addDocument, useDocumentsInSelectedDrive, useSelectedDrive, setSelectedNode, } from "@powerhousedao/reactor-browser";
4
+ import { addDocument, useDocumentsInSelectedDrive, useSelectedDrive, setSelectedNode, isFileNodeKind, } from "@powerhousedao/reactor-browser";
5
5
  import { useBillingFolderStructure } from "../hooks/useBillingFolderStructure.js";
6
6
  import { CreateHubProfileModal } from "./CreateHubProfileModal.js";
7
7
  /**
@@ -11,7 +11,7 @@ import { CreateHubProfileModal } from "./CreateHubProfileModal.js";
11
11
  export function DashboardHome({ onFolderSelect }) {
12
12
  const documentsInDrive = useDocumentsInSelectedDrive();
13
13
  const [selectedDrive] = useSelectedDrive();
14
- const { billingFolder, monthFolders } = useBillingFolderStructure();
14
+ const { billingFolder, monthFolders, paymentsFolderIds } = useBillingFolderStructure();
15
15
  // Check if accounts document exists
16
16
  const accountsDocument = useMemo(() => {
17
17
  if (!documentsInDrive)
@@ -25,6 +25,78 @@ export function DashboardHome({ onFolderSelect }) {
25
25
  return documentsInDrive.find((doc) => doc.header.documentType === "powerhouse/operational-hub-profile");
26
26
  }, [documentsInDrive]);
27
27
  const hubName = operationalHubProfileDocument?.state?.global?.name || "Operational Hub";
28
+ // Computed stats for action cards
29
+ const profileStats = useMemo(() => {
30
+ const profile = operationalHubProfileDocument?.state?.global;
31
+ if (!profile)
32
+ return null;
33
+ const hasTeam = !!profile.operatorTeam;
34
+ const subteamCount = profile.subteams?.length ?? 0;
35
+ const parts = [];
36
+ parts.push(hasTeam ? "Operator team set" : "No operator team");
37
+ if (subteamCount > 0) {
38
+ parts.push(`${subteamCount} subteam${subteamCount > 1 ? "s" : ""}`);
39
+ }
40
+ return parts.join(" · ");
41
+ }, [operationalHubProfileDocument]);
42
+ const accountStats = useMemo(() => {
43
+ const accounts = accountsDocument?.state?.global?.accounts;
44
+ if (!accounts || accounts.length === 0)
45
+ return null;
46
+ const counts = {};
47
+ for (const acct of accounts) {
48
+ const t = acct.type.toLowerCase();
49
+ counts[t] = (counts[t] ?? 0) + 1;
50
+ }
51
+ const entries = Object.entries(counts);
52
+ if (entries.length <= 3) {
53
+ return entries.map(([type, count]) => `${count} ${type}`).join(", ");
54
+ }
55
+ return `${accounts.length} accounts`;
56
+ }, [accountsDocument]);
57
+ const billingStats = useMemo(() => {
58
+ if (!selectedDrive || !documentsInDrive)
59
+ return null;
60
+ const monthCount = monthFolders.size;
61
+ if (monthCount === 0)
62
+ return null;
63
+ const nodes = selectedDrive.state.global.nodes;
64
+ const invoiceIds = new Set(nodes
65
+ .filter((n) => isFileNodeKind(n) &&
66
+ paymentsFolderIds.has(n.parentFolder || "") &&
67
+ n.documentType === "powerhouse/invoice")
68
+ .map((n) => n.id));
69
+ const invoices = documentsInDrive.filter((doc) => doc.header.documentType === "powerhouse/invoice" &&
70
+ invoiceIds.has(doc.header.id));
71
+ if (invoices.length === 0) {
72
+ return `${monthCount} month${monthCount > 1 ? "s" : ""} configured`;
73
+ }
74
+ let pendingCount = 0;
75
+ let paidCount = 0;
76
+ for (const invoice of invoices) {
77
+ const status = (invoice.state.global?.status ?? "").toUpperCase();
78
+ if (status === "PAYMENTSENT" ||
79
+ status === "PAYMENTRECEIVED" ||
80
+ status === "PAYMENTCLOSED") {
81
+ paidCount++;
82
+ }
83
+ else if (status !== "REJECTED" && status !== "CANCELLED") {
84
+ pendingCount++;
85
+ }
86
+ }
87
+ const parts = [
88
+ `${monthCount} month${monthCount > 1 ? "s" : ""}`,
89
+ `${invoices.length} invoice${invoices.length > 1 ? "s" : ""}`,
90
+ ];
91
+ const statusParts = [];
92
+ if (pendingCount > 0)
93
+ statusParts.push(`${pendingCount} pending`);
94
+ if (paidCount > 0)
95
+ statusParts.push(`${paidCount} paid`);
96
+ if (statusParts.length > 0)
97
+ parts.push(statusParts.join(", "));
98
+ return parts.join(" · ");
99
+ }, [selectedDrive, documentsInDrive, monthFolders.size, paymentsFolderIds]);
28
100
  // State for custom create hub profile modal
29
101
  const [showCreateHubModal, setShowCreateHubModal] = useState(false);
30
102
  const handleOpenAccounts = useCallback(async () => {
@@ -87,13 +159,11 @@ export function DashboardHome({ onFolderSelect }) {
87
159
  handleOpenBilling,
88
160
  ]);
89
161
  const setupComplete = setupSteps.every((step) => step.done);
90
- return (_jsxs("div", { className: "max-w-4xl mx-auto", children: [_jsxs("div", { className: "mb-8", children: [_jsx("h1", { className: "text-2xl font-bold text-gray-900", children: hubName }), _jsx("p", { className: "text-gray-600 mt-1", children: "Manage accounts, billing, and financial reporting" })] }), !setupComplete && (_jsxs("div", { className: "bg-gradient-to-r from-blue-50 to-indigo-50 rounded-xl border border-blue-100 p-6 mb-6", children: [_jsxs("div", { className: "flex items-center gap-3 mb-5", children: [_jsx("div", { className: "p-2 bg-blue-100 rounded-lg", children: _jsx(CheckCircle2, { className: "w-5 h-5 text-blue-600" }) }), _jsxs("div", { children: [_jsx("h2", { className: "text-lg font-semibold text-gray-900", children: "Getting Started" }), _jsx("p", { className: "text-sm text-gray-600", children: "Complete these steps to set up your operational hub" })] })] }), _jsx("div", { className: "space-y-3", children: setupSteps.map((step, index) => (_jsxs("button", { onClick: step.onClick, disabled: step.done, className: `w-full flex items-start gap-3 p-3 rounded-lg text-left transition-colors ${step.done
162
+ return (_jsxs("div", { className: "max-w-4xl mx-auto", children: [_jsxs("div", { className: "mb-8", children: [_jsxs("h1", { className: "text-2xl font-bold text-gray-900 flex items-center gap-2", children: [_jsx("span", { className: "flex items-center justify-center w-6 h-6 rounded bg-purple-800 flex-shrink-0", children: _jsx("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: "text-white", children: _jsx("path", { d: "M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z" }) }) }), hubName] }), _jsx("p", { className: "text-gray-600 mt-1", children: "Manage accounts, billing, and financial reporting" })] }), !setupComplete && (_jsxs("div", { className: "bg-gradient-to-r from-blue-50 to-indigo-50 rounded-xl border border-blue-100 p-6 mb-6", children: [_jsxs("div", { className: "flex items-center gap-3 mb-5", children: [_jsx("div", { className: "p-2 bg-blue-100 rounded-lg", children: _jsx(CheckCircle2, { className: "w-5 h-5 text-blue-600" }) }), _jsxs("div", { children: [_jsx("h2", { className: "text-lg font-semibold text-gray-900", children: "Getting Started" }), _jsx("p", { className: "text-sm text-gray-600", children: "Complete these steps to set up your operational hub" })] })] }), _jsx("div", { className: "space-y-3", children: setupSteps.map((step, index) => (_jsxs("button", { onClick: step.onClick, disabled: step.done, className: `w-full flex items-start gap-3 p-3 rounded-lg text-left transition-colors ${step.done
91
163
  ? "bg-white/50 cursor-default"
92
164
  : "bg-white hover:bg-blue-50 cursor-pointer"}`, children: [_jsx("div", { className: "mt-0.5", children: step.done ? (_jsx(CheckCircle2, { className: "w-5 h-5 text-green-500" })) : (_jsx("div", { className: "w-5 h-5 rounded-full border-2 border-blue-400 flex items-center justify-center text-xs font-semibold text-blue-600", children: index + 1 })) }), _jsxs("div", { className: "flex-1", children: [_jsx("span", { className: `font-medium ${step.done ? "text-gray-400 line-through" : "text-gray-900"}`, children: step.label }), _jsx("p", { className: `text-sm mt-0.5 ${step.done ? "text-gray-400" : "text-gray-600"}`, children: step.description })] }), !step.done && (_jsx(ArrowRight, { className: "w-4 h-4 text-blue-500 mt-1" }))] }, index))) })] })), _jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4", children: [_jsxs("button", { onClick: handleOpenProfile, className: "bg-white rounded-xl border border-gray-200 p-5 text-left hover:shadow-md hover:border-blue-200 transition-all group", children: [_jsxs("div", { className: "flex items-start justify-between", children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsx("div", { className: "p-3 rounded-lg bg-purple-100", children: _jsx(User, { className: "w-5 h-5 text-purple-600" }) }), _jsxs("div", { children: [_jsx("h3", { className: "font-semibold text-gray-900", children: "Profile" }), _jsx("p", { className: "text-sm text-gray-500", children: operationalHubProfileDocument
93
- ? "View and update your hub profile"
165
+ ? profileStats || "View and update your hub profile"
94
166
  : "Set up your hub profile" })] })] }), _jsx(ArrowRight, { className: "w-5 h-5 text-gray-400 group-hover:text-blue-500 transition-colors" })] }), !operationalHubProfileDocument && (_jsx("div", { className: "mt-3 pt-3 border-t border-gray-100", children: _jsx("span", { className: "text-xs font-medium text-amber-600 bg-amber-50 px-2 py-1 rounded", children: "Action Required" }) }))] }), _jsxs("button", { onClick: () => void handleOpenAccounts(), className: "bg-white rounded-xl border border-gray-200 p-5 text-left hover:shadow-md hover:border-blue-200 transition-all group", children: [_jsxs("div", { className: "flex items-start justify-between", children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsx("div", { className: `p-3 rounded-lg ${accountsDocument ? "bg-green-100" : "bg-amber-100"}`, children: _jsx(Wallet, { className: `w-5 h-5 ${accountsDocument ? "text-green-600" : "text-amber-600"}` }) }), _jsxs("div", { children: [_jsx("h3", { className: "font-semibold text-gray-900", children: "Accounts" }), _jsx("p", { className: "text-sm text-gray-500", children: accountsDocument
95
- ? "View and manage accounts"
96
- : "Set up your accounts first" })] })] }), _jsx(ArrowRight, { className: "w-5 h-5 text-gray-400 group-hover:text-blue-500 transition-colors" })] }), !accountsDocument && (_jsx("div", { className: "mt-3 pt-3 border-t border-gray-100", children: _jsx("span", { className: "text-xs font-medium text-amber-600 bg-amber-50 px-2 py-1 rounded", children: "Action Required" }) }))] }), _jsx("button", { onClick: handleOpenBilling, className: "bg-white rounded-xl border border-gray-200 p-5 text-left hover:shadow-md hover:border-blue-200 transition-all group", children: _jsxs("div", { className: "flex items-start justify-between", children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsx("div", { className: "p-3 bg-blue-100 rounded-lg", children: _jsx(Building2, { className: "w-5 h-5 text-blue-600" }) }), _jsxs("div", { children: [_jsx("h3", { className: "font-semibold text-gray-900", children: "Billing" }), _jsx("p", { className: "text-sm text-gray-500", children: monthFolders.size > 0
97
- ? `${monthFolders.size} month${monthFolders.size > 1 ? "s" : ""} configured`
98
- : "Manage monthly billing cycles" })] })] }), _jsx(ArrowRight, { className: "w-5 h-5 text-gray-400 group-hover:text-blue-500 transition-colors" })] }) })] }), _jsx(CreateHubProfileModal, { isOpen: showCreateHubModal, onClose: () => setShowCreateHubModal(false) })] }));
167
+ ? accountStats || "View and manage accounts"
168
+ : "Set up your accounts first" })] })] }), _jsx(ArrowRight, { className: "w-5 h-5 text-gray-400 group-hover:text-blue-500 transition-colors" })] }), !accountsDocument && (_jsx("div", { className: "mt-3 pt-3 border-t border-gray-100", children: _jsx("span", { className: "text-xs font-medium text-amber-600 bg-amber-50 px-2 py-1 rounded", children: "Action Required" }) }))] }), _jsx("button", { onClick: handleOpenBilling, className: "bg-white rounded-xl border border-gray-200 p-5 text-left hover:shadow-md hover:border-blue-200 transition-all group", children: _jsxs("div", { className: "flex items-start justify-between", children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsx("div", { className: "p-3 bg-blue-100 rounded-lg", children: _jsx(Building2, { className: "w-5 h-5 text-blue-600" }) }), _jsxs("div", { children: [_jsx("h3", { className: "font-semibold text-gray-900", children: "Billing" }), _jsx("p", { className: "text-sm text-gray-500", children: billingStats || "Manage monthly billing cycles" })] })] }), _jsx(ArrowRight, { className: "w-5 h-5 text-gray-400 group-hover:text-blue-500 transition-colors" })] }) })] }), _jsx(CreateHubProfileModal, { isOpen: showCreateHubModal, onClose: () => setShowCreateHubModal(false) })] }));
99
169
  }
@@ -0,0 +1,13 @@
1
+ interface DocumentDropZoneProps {
2
+ children: React.ReactNode;
3
+ className?: string;
4
+ }
5
+ /**
6
+ * Drop zone component that handles document uploads for the Contributor Billing drive.
7
+ * Supports:
8
+ * - Expense Reports: Auto-placed in Reporting folders based on period
9
+ * - Accounts: Kept at root level
10
+ */
11
+ export declare function DocumentDropZone({ children, className, }: DocumentDropZoneProps): import("react/jsx-runtime").JSX.Element;
12
+ export {};
13
+ //# sourceMappingURL=DocumentDropZone.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DocumentDropZone.d.ts","sourceRoot":"","sources":["../../../../editors/contributor-billing/components/DocumentDropZone.tsx"],"names":[],"mappings":"AAUA,UAAU,qBAAqB;IAC7B,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,EAC/B,QAAQ,EACR,SAAc,GACf,EAAE,qBAAqB,2CA8IvB"}
@@ -0,0 +1,101 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useCallback, useRef, useState } from "react";
3
+ import { useOnDropFile, useSelectedDrive, useDocumentsInSelectedDrive, } from "@powerhousedao/reactor-browser";
4
+ import { toast } from "@powerhousedao/design-system/connect";
5
+ import { useDocumentAutoPlacement } from "../hooks/useDocumentAutoPlacement.js";
6
+ /**
7
+ * Drop zone component that handles document uploads for the Contributor Billing drive.
8
+ * Supports:
9
+ * - Expense Reports: Auto-placed in Reporting folders based on period
10
+ * - Accounts: Kept at root level
11
+ */
12
+ export function DocumentDropZone({ children, className = "", }) {
13
+ const onDropFile = useOnDropFile();
14
+ const [selectedDrive] = useSelectedDrive();
15
+ const documentsInDrive = useDocumentsInSelectedDrive();
16
+ const [isDragging, setIsDragging] = useState(false);
17
+ const dragCounterRef = useRef(0);
18
+ // Activate auto-placement hook
19
+ useDocumentAutoPlacement();
20
+ const driveId = selectedDrive?.header.id;
21
+ const handleDragEnter = useCallback((e) => {
22
+ e.preventDefault();
23
+ e.stopPropagation();
24
+ dragCounterRef.current++;
25
+ if (e.dataTransfer.items && e.dataTransfer.items.length > 0) {
26
+ setIsDragging(true);
27
+ }
28
+ }, []);
29
+ const handleDragLeave = useCallback((e) => {
30
+ e.preventDefault();
31
+ e.stopPropagation();
32
+ dragCounterRef.current--;
33
+ if (dragCounterRef.current === 0) {
34
+ setIsDragging(false);
35
+ }
36
+ }, []);
37
+ const handleDragOver = useCallback((e) => {
38
+ e.preventDefault();
39
+ e.stopPropagation();
40
+ e.dataTransfer.dropEffect = "copy";
41
+ }, []);
42
+ const handleDrop = useCallback(async (e) => {
43
+ e.preventDefault();
44
+ e.stopPropagation();
45
+ setIsDragging(false);
46
+ dragCounterRef.current = 0;
47
+ const files = Array.from(e.dataTransfer.files);
48
+ if (files.length === 0 || !onDropFile || !driveId)
49
+ return;
50
+ // Filter to only accept .phd files (Powerhouse document archives)
51
+ const phdFiles = files.filter((file) => file.name.endsWith(".phd"));
52
+ const rejectedFiles = files.filter((file) => !file.name.endsWith(".phd"));
53
+ // Show error for rejected files
54
+ if (rejectedFiles.length > 0) {
55
+ const rejectedNames = rejectedFiles.map((f) => f.name).join(", ");
56
+ toast(`Only .phd files (Powerhouse documents) can be dropped here. Rejected: ${rejectedNames}`, { type: "error" });
57
+ }
58
+ if (phdFiles.length === 0)
59
+ return;
60
+ // Process all files
61
+ const filePromises = phdFiles.map(async (file) => {
62
+ try {
63
+ const fileNode = await onDropFile(file, (progress) => {
64
+ if (progress.stage === "complete") {
65
+ toast(`Successfully uploaded ${file.name}`, {
66
+ type: "success",
67
+ });
68
+ }
69
+ else if (progress.stage === "failed") {
70
+ toast(`Failed to upload ${file.name}`, {
71
+ type: "error",
72
+ });
73
+ }
74
+ });
75
+ if (fileNode) {
76
+ // Auto-placement hook will handle moving the document to the correct location
77
+ // Give it a moment to detect the new document
78
+ setTimeout(() => {
79
+ // Check if document was loaded and what type it is
80
+ const doc = documentsInDrive?.find((d) => d.header.id === fileNode.id);
81
+ if (doc) {
82
+ const docType = doc.header.documentType;
83
+ if (docType === "powerhouse/expense-report") {
84
+ toast(`Expense report uploaded. It will be placed in the appropriate Reporting folder based on its period.`, { type: "info" });
85
+ }
86
+ else if (docType === "powerhouse/accounts") {
87
+ toast(`Accounts document uploaded. It will remain at the root level.`, { type: "info" });
88
+ }
89
+ }
90
+ }, 1000);
91
+ }
92
+ }
93
+ catch (error) {
94
+ console.error("Error dropping file:", error);
95
+ toast(`Error uploading ${file.name}`, { type: "error" });
96
+ }
97
+ });
98
+ await Promise.allSettled(filePromises);
99
+ }, [onDropFile, driveId, documentsInDrive]);
100
+ return (_jsxs("div", { className: `relative ${className}`, onDragEnter: handleDragEnter, onDragLeave: handleDragLeave, onDragOver: handleDragOver, onDrop: handleDrop, children: [children, isDragging && (_jsx("div", { className: "absolute inset-0 z-50 flex items-center justify-center bg-blue-500/10 border-2 border-dashed border-blue-500 rounded-lg pointer-events-none", children: _jsx("div", { className: "bg-white rounded-lg shadow-lg p-6 border border-blue-200", children: _jsxs("div", { className: "text-center", children: [_jsx("div", { className: "text-4xl mb-2", children: "\uD83D\uDCC4" }), _jsx("p", { className: "text-lg font-semibold text-gray-900", children: "Drop documents here" }), _jsx("p", { className: "text-sm text-gray-600 mt-1", children: "Expense Reports and Accounts documents will be automatically organized" })] }) }) }))] }));
101
+ }
@@ -2,8 +2,9 @@ import type { SelectedFolderInfo } from "./FolderTree.js";
2
2
  interface DriveContentsProps {
3
3
  selectedFolder: SelectedFolderInfo | null;
4
4
  onFolderSelect?: (folderInfo: SelectedFolderInfo | null) => void;
5
+ onActiveNodeIdChange?: (nodeId: string) => void;
5
6
  }
6
7
  /** Shows the content based on the selected folder */
7
- export declare function DriveContents({ selectedFolder, onFolderSelect, }: DriveContentsProps): import("react/jsx-runtime").JSX.Element;
8
+ export declare function DriveContents({ selectedFolder, onFolderSelect, onActiveNodeIdChange, }: DriveContentsProps): import("react/jsx-runtime").JSX.Element;
8
9
  export {};
9
10
  //# sourceMappingURL=DriveContents.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"DriveContents.d.ts","sourceRoot":"","sources":["../../../../editors/contributor-billing/components/DriveContents.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAE1D,UAAU,kBAAkB;IAC1B,cAAc,EAAE,kBAAkB,GAAG,IAAI,CAAC;IAC1C,cAAc,CAAC,EAAE,CAAC,UAAU,EAAE,kBAAkB,GAAG,IAAI,KAAK,IAAI,CAAC;CAClE;AAED,qDAAqD;AACrD,wBAAgB,aAAa,CAAC,EAC5B,cAAc,EACd,cAAc,GACf,EAAE,kBAAkB,2CAsFpB"}
1
+ {"version":3,"file":"DriveContents.d.ts","sourceRoot":"","sources":["../../../../editors/contributor-billing/components/DriveContents.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAE1D,UAAU,kBAAkB;IAC1B,cAAc,EAAE,kBAAkB,GAAG,IAAI,CAAC;IAC1C,cAAc,CAAC,EAAE,CAAC,UAAU,EAAE,kBAAkB,GAAG,IAAI,KAAK,IAAI,CAAC;IACjE,oBAAoB,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;CACjD;AAED,qDAAqD;AACrD,wBAAgB,aAAa,CAAC,EAC5B,cAAc,EACd,cAAc,EACd,oBAAoB,GACrB,EAAE,kBAAkB,2CAyFpB"}
@@ -7,27 +7,27 @@ import { BillingOverview } from "./BillingOverview.js";
7
7
  import { DashboardHome } from "./DashboardHome.js";
8
8
  import { SubscriptionsOverview } from "./SubscriptionsOverview.js";
9
9
  /** Shows the content based on the selected folder */
10
- export function DriveContents({ selectedFolder, onFolderSelect, }) {
10
+ export function DriveContents({ selectedFolder, onFolderSelect, onActiveNodeIdChange, }) {
11
11
  // Default view (no folder selected or root) - show the dashboard home
12
12
  if (!selectedFolder) {
13
- return (_jsx("div", { className: "container mx-auto flex-1 overflow-y-auto p-4", children: _jsx(Suspense, { children: _jsx(DashboardHome, { onFolderSelect: onFolderSelect }) }) }));
13
+ return (_jsx("div", { className: "container mx-auto flex-1 p-4", children: _jsx(Suspense, { children: _jsx(DashboardHome, { onFolderSelect: onFolderSelect }) }) }));
14
14
  }
15
15
  // Payments folder - show invoice table
16
16
  if (selectedFolder.folderType === "payments") {
17
- return (_jsxs("div", { className: "container mx-auto flex-1 overflow-y-auto p-4", children: [_jsxs("div", { className: "mb-4", children: [_jsxs("h1", { className: "text-2xl font-bold text-gray-900", children: ["Payments - ", selectedFolder.monthName] }), _jsxs("p", { className: "text-gray-600", children: ["Manage invoices and billing statements for", " ", selectedFolder.monthName] })] }), _jsx(Suspense, { children: _jsx(HeaderStats, { folderId: selectedFolder.folderId }) }), _jsx(Suspense, { children: _jsx(InvoiceTableContainer, { folderId: selectedFolder.folderId, monthName: selectedFolder.monthName, reportingFolderId: selectedFolder.reportingFolderId }) })] }, selectedFolder.folderId));
17
+ return (_jsxs("div", { className: "container mx-auto flex-1 p-4", children: [_jsxs("div", { className: "mb-4", children: [_jsxs("h1", { className: "text-2xl font-bold text-gray-900", children: ["Payments - ", selectedFolder.monthName] }), _jsxs("p", { className: "text-gray-600", children: ["Manage invoices and billing statements for", " ", selectedFolder.monthName] })] }), _jsx(Suspense, { children: _jsx(HeaderStats, { folderId: selectedFolder.folderId }) }), _jsx(Suspense, { children: _jsx(InvoiceTableContainer, { folderId: selectedFolder.folderId, monthName: selectedFolder.monthName, reportingFolderId: selectedFolder.reportingFolderId }) })] }, selectedFolder.folderId));
18
18
  }
19
19
  // Reporting folder - show expense and snapshot reports
20
20
  if (selectedFolder.folderType === "reporting") {
21
- return (_jsx("div", { className: "container mx-auto flex-1 overflow-y-auto p-4", children: _jsx(Suspense, { children: _jsx(ReportingView, { folderId: selectedFolder.folderId, monthName: selectedFolder.monthName }) }) }));
21
+ return (_jsx("div", { className: "container mx-auto flex-1 p-4", children: _jsx(Suspense, { children: _jsx(ReportingView, { folderId: selectedFolder.folderId, monthName: selectedFolder.monthName }) }) }));
22
22
  }
23
23
  // Billing folder - show all months overview
24
24
  if (selectedFolder.folderType === "billing") {
25
- return (_jsx("div", { className: "container mx-auto flex-1 overflow-y-auto p-4", children: _jsx(Suspense, { children: _jsx(BillingOverview, { onFolderSelect: onFolderSelect }) }) }));
25
+ return (_jsx("div", { className: "container mx-auto flex-1 p-4", children: _jsx(Suspense, { children: _jsx(BillingOverview, { onFolderSelect: onFolderSelect, onActiveNodeIdChange: onActiveNodeIdChange }) }) }));
26
26
  }
27
27
  // Subscriptions folder - show subscriptions overview
28
28
  if (selectedFolder.folderType === "subscriptions") {
29
- return (_jsx("div", { className: "container mx-auto flex-1 overflow-y-auto p-4", children: _jsx(Suspense, { children: _jsx(SubscriptionsOverview, {}) }) }));
29
+ return (_jsx("div", { className: "container mx-auto flex-1 p-4", children: _jsx(Suspense, { children: _jsx(SubscriptionsOverview, {}) }) }));
30
30
  }
31
31
  // Fallback - show dashboard home
32
- return (_jsx("div", { className: "container mx-auto flex-1 overflow-y-auto p-4", children: _jsx(Suspense, { children: _jsx(DashboardHome, { onFolderSelect: onFolderSelect }) }) }));
32
+ return (_jsx("div", { className: "container mx-auto flex-1 p-4", children: _jsx(Suspense, { children: _jsx(DashboardHome, { onFolderSelect: onFolderSelect }) }) }));
33
33
  }
@@ -1 +1 @@
1
- {"version":3,"file":"DriveExplorer.d.ts","sourceRoot":"","sources":["../../../../editors/contributor-billing/components/DriveExplorer.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAOlD;;;GAGG;AACH,wBAAgB,aAAa,CAAC,EAAE,QAAQ,EAAE,EAAE,WAAW,2CA+DtD"}
1
+ {"version":3,"file":"DriveExplorer.d.ts","sourceRoot":"","sources":["../../../../editors/contributor-billing/components/DriveExplorer.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAQlD;;;GAGG;AACH,wBAAgB,aAAa,CAAC,EAAE,QAAQ,EAAE,EAAE,WAAW,2CAwFtD"}