@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.
- package/dist/document-models/expense-report/src/reducers/wallet.d.ts.map +1 -1
- package/dist/document-models/expense-report/src/reducers/wallet.js +4 -4
- package/dist/editors/account-transactions-editor/alchemyIntegration.d.ts +1 -0
- package/dist/editors/account-transactions-editor/alchemyIntegration.d.ts.map +1 -1
- package/dist/editors/account-transactions-editor/alchemyIntegration.js +1 -0
- package/dist/editors/account-transactions-editor/editor.d.ts.map +1 -1
- package/dist/editors/account-transactions-editor/editor.js +67 -10
- package/dist/editors/accounts-editor/components/AccountCard.d.ts.map +1 -1
- package/dist/editors/accounts-editor/components/AccountCard.js +1 -1
- package/dist/editors/accounts-editor/components/AccountForm.d.ts.map +1 -1
- package/dist/editors/accounts-editor/components/AccountForm.js +55 -16
- package/dist/editors/accounts-editor/components/AccountsList.js +1 -1
- package/dist/editors/accounts-editor/editor.d.ts.map +1 -1
- package/dist/editors/accounts-editor/editor.js +86 -44
- package/dist/editors/contributor-billing/components/BillingOverview.d.ts +2 -1
- package/dist/editors/contributor-billing/components/BillingOverview.d.ts.map +1 -1
- package/dist/editors/contributor-billing/components/BillingOverview.js +2 -2
- package/dist/editors/contributor-billing/components/DashboardHome.d.ts.map +1 -1
- package/dist/editors/contributor-billing/components/DashboardHome.js +78 -8
- package/dist/editors/contributor-billing/components/DocumentDropZone.d.ts +13 -0
- package/dist/editors/contributor-billing/components/DocumentDropZone.d.ts.map +1 -0
- package/dist/editors/contributor-billing/components/DocumentDropZone.js +101 -0
- package/dist/editors/contributor-billing/components/DriveContents.d.ts +2 -1
- package/dist/editors/contributor-billing/components/DriveContents.d.ts.map +1 -1
- package/dist/editors/contributor-billing/components/DriveContents.js +7 -7
- package/dist/editors/contributor-billing/components/DriveExplorer.d.ts.map +1 -1
- package/dist/editors/contributor-billing/components/DriveExplorer.js +25 -3
- package/dist/editors/contributor-billing/components/FolderTree.d.ts.map +1 -1
- package/dist/editors/contributor-billing/components/FolderTree.js +37 -34
- package/dist/editors/contributor-billing/components/MonthReportCard.d.ts +2 -1
- package/dist/editors/contributor-billing/components/MonthReportCard.d.ts.map +1 -1
- package/dist/editors/contributor-billing/components/MonthReportCard.js +12 -2
- package/dist/editors/contributor-billing/components/MonthlyReportsOverview.d.ts +2 -1
- package/dist/editors/contributor-billing/components/MonthlyReportsOverview.d.ts.map +1 -1
- package/dist/editors/contributor-billing/components/MonthlyReportsOverview.js +69 -8
- package/dist/editors/contributor-billing/components/ReportingView.d.ts.map +1 -1
- package/dist/editors/contributor-billing/components/ReportingView.js +38 -9
- package/dist/editors/contributor-billing/components/SubscriptionsOverview.d.ts.map +1 -1
- package/dist/editors/contributor-billing/components/SubscriptionsOverview.js +1 -1
- package/dist/editors/contributor-billing/config.d.ts.map +1 -1
- package/dist/editors/contributor-billing/config.js +2 -1
- package/dist/editors/contributor-billing/hooks/useDocumentAutoPlacement.d.ts +18 -0
- package/dist/editors/contributor-billing/hooks/useDocumentAutoPlacement.d.ts.map +1 -0
- package/dist/editors/contributor-billing/hooks/useDocumentAutoPlacement.js +149 -0
- package/dist/editors/contributor-billing/hooks/useMonthlyReports.d.ts.map +1 -1
- package/dist/editors/contributor-billing/hooks/useMonthlyReports.js +30 -4
- package/dist/editors/expense-report/components/SetOwner.d.ts.map +1 -1
- package/dist/editors/expense-report/components/SetOwner.js +43 -2
- package/dist/editors/expense-report/components/WalletsTable.d.ts.map +1 -1
- package/dist/editors/expense-report/components/WalletsTable.js +22 -3
- package/dist/editors/expense-report/editor.d.ts.map +1 -1
- package/dist/editors/expense-report/editor.js +20 -2
- package/dist/editors/expense-report/hooks/useSyncWallet.d.ts.map +1 -1
- package/dist/editors/expense-report/hooks/useSyncWallet.js +41 -24
- package/dist/editors/operational-hub-profile-editor/components/ProfileOverview.d.ts +10 -0
- package/dist/editors/operational-hub-profile-editor/components/ProfileOverview.d.ts.map +1 -0
- package/dist/editors/operational-hub-profile-editor/components/ProfileOverview.js +114 -0
- package/dist/editors/operational-hub-profile-editor/components/SubteamsPicker.d.ts.map +1 -1
- package/dist/editors/operational-hub-profile-editor/components/SubteamsPicker.js +44 -4
- package/dist/editors/operational-hub-profile-editor/editor.d.ts.map +1 -1
- package/dist/editors/operational-hub-profile-editor/editor.js +7 -2
- package/dist/editors/snapshot-report-editor/components/SetOwner.d.ts.map +1 -1
- package/dist/editors/snapshot-report-editor/components/SetOwner.js +43 -2
- package/dist/editors/snapshot-report-editor/editor.d.ts.map +1 -1
- package/dist/editors/snapshot-report-editor/editor.js +9 -2
- package/dist/editors/snapshot-report-editor/hooks/useSyncSnapshotAccount.d.ts.map +1 -1
- package/dist/editors/snapshot-report-editor/hooks/useSyncSnapshotAccount.js +120 -27
- package/dist/editors/snapshot-report-editor/utils/balanceCalculations.d.ts +5 -1
- package/dist/editors/snapshot-report-editor/utils/balanceCalculations.d.ts.map +1 -1
- package/dist/editors/snapshot-report-editor/utils/balanceCalculations.js +47 -1
- package/dist/style.css +138 -0
- package/dist/subgraphs/resources-services/resolvers.d.ts.map +1 -1
- package/dist/subgraphs/resources-services/resolvers.js +28 -13
- package/dist/subgraphs/resources-services/schema.d.ts.map +1 -1
- package/dist/subgraphs/resources-services/schema.js +3 -1
- 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
|
-
|
|
73
|
-
|
|
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
|
-
|
|
114
|
+
toast(`Created document and fetched ${result.transactionsAdded} transactions`, { type: "success" });
|
|
103
115
|
}
|
|
104
116
|
else {
|
|
105
|
-
|
|
117
|
+
toast(`Error: ${result.message}`, { type: "error" });
|
|
106
118
|
}
|
|
107
119
|
}
|
|
108
120
|
catch (error) {
|
|
109
|
-
|
|
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
|
-
|
|
116
|
-
|
|
117
|
-
|
|
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
|
-
|
|
130
|
-
|
|
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:
|
|
145
|
+
total: accounts.length,
|
|
134
146
|
account: account.name,
|
|
135
147
|
});
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
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
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
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
|
-
|
|
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", {
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
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;
|
|
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":"
|
|
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: [
|
|
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:
|
|
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;
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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;
|
|
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"}
|