@powerhousedao/contributor-billing 0.1.3 → 0.1.5
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/gen/actions.d.ts +4 -0
- package/dist/document-models/expense-report/gen/actions.d.ts.map +1 -0
- package/dist/document-models/expense-report/gen/actions.js +1 -0
- package/dist/document-models/expense-report/gen/creators.d.ts +2 -0
- package/dist/document-models/expense-report/gen/creators.d.ts.map +1 -0
- package/dist/document-models/expense-report/gen/creators.js +1 -0
- package/dist/document-models/expense-report/gen/document-model.d.ts +3 -0
- package/dist/document-models/expense-report/gen/document-model.d.ts.map +1 -0
- package/dist/document-models/expense-report/gen/document-model.js +202 -0
- package/dist/document-models/expense-report/gen/expense-report/actions.d.ts +8 -0
- package/dist/document-models/expense-report/gen/expense-report/actions.d.ts.map +1 -0
- package/dist/document-models/expense-report/gen/expense-report/actions.js +1 -0
- package/dist/document-models/expense-report/gen/expense-report/creators.d.ts +4 -0
- package/dist/document-models/expense-report/gen/expense-report/creators.d.ts.map +1 -0
- package/dist/document-models/expense-report/gen/expense-report/creators.js +3 -0
- package/dist/document-models/expense-report/gen/expense-report/error.d.ts +2 -0
- package/dist/document-models/expense-report/gen/expense-report/error.d.ts.map +1 -0
- package/dist/document-models/expense-report/gen/expense-report/error.js +1 -0
- package/dist/document-models/expense-report/gen/expense-report/object.d.ts +7 -0
- package/dist/document-models/expense-report/gen/expense-report/object.d.ts.map +1 -0
- package/dist/document-models/expense-report/gen/expense-report/object.js +7 -0
- package/dist/document-models/expense-report/gen/expense-report/operations.d.ts +7 -0
- package/dist/document-models/expense-report/gen/expense-report/operations.d.ts.map +1 -0
- package/dist/document-models/expense-report/gen/expense-report/operations.js +1 -0
- package/dist/document-models/expense-report/gen/index.d.ts +8 -0
- package/dist/document-models/expense-report/gen/index.d.ts.map +1 -0
- package/dist/document-models/expense-report/gen/index.js +6 -0
- package/dist/document-models/expense-report/gen/object.d.ts +15 -0
- package/dist/document-models/expense-report/gen/object.d.ts.map +1 -0
- package/dist/document-models/expense-report/gen/object.js +25 -0
- package/dist/document-models/expense-report/gen/ph-factories.d.ts +27 -0
- package/dist/document-models/expense-report/gen/ph-factories.d.ts.map +1 -0
- package/dist/document-models/expense-report/gen/ph-factories.js +189 -0
- package/dist/document-models/expense-report/gen/reducer.d.ts +5 -0
- package/dist/document-models/expense-report/gen/reducer.d.ts.map +1 -0
- package/dist/document-models/expense-report/gen/reducer.js +76 -0
- package/dist/document-models/expense-report/gen/schema/index.d.ts +3 -0
- package/dist/document-models/expense-report/gen/schema/index.d.ts.map +1 -0
- package/dist/document-models/expense-report/gen/schema/index.js +2 -0
- package/dist/document-models/expense-report/gen/schema/types.d.ts +254 -0
- package/dist/document-models/expense-report/gen/schema/types.d.ts.map +1 -0
- package/dist/document-models/expense-report/gen/schema/types.js +1 -0
- package/dist/document-models/expense-report/gen/schema/zod.d.ts +32 -0
- package/dist/document-models/expense-report/gen/schema/zod.d.ts.map +1 -0
- package/dist/document-models/expense-report/gen/schema/zod.js +216 -0
- package/dist/document-models/expense-report/gen/types.d.ts +10 -0
- package/dist/document-models/expense-report/gen/types.d.ts.map +1 -0
- package/dist/document-models/expense-report/gen/types.js +1 -0
- package/dist/document-models/expense-report/gen/utils.d.ts +22 -0
- package/dist/document-models/expense-report/gen/utils.d.ts.map +1 -0
- package/dist/document-models/expense-report/gen/utils.js +181 -0
- package/dist/document-models/expense-report/gen/wallet/actions.d.ts +64 -0
- package/dist/document-models/expense-report/gen/wallet/actions.d.ts.map +1 -0
- package/dist/document-models/expense-report/gen/wallet/actions.js +1 -0
- package/dist/document-models/expense-report/gen/wallet/creators.d.ts +18 -0
- package/dist/document-models/expense-report/gen/wallet/creators.d.ts.map +1 -0
- package/dist/document-models/expense-report/gen/wallet/creators.js +17 -0
- package/dist/document-models/expense-report/gen/wallet/error.d.ts +2 -0
- package/dist/document-models/expense-report/gen/wallet/error.d.ts.map +1 -0
- package/dist/document-models/expense-report/gen/wallet/error.js +1 -0
- package/dist/document-models/expense-report/gen/wallet/object.d.ts +21 -0
- package/dist/document-models/expense-report/gen/wallet/object.d.ts.map +1 -0
- package/dist/document-models/expense-report/gen/wallet/object.js +49 -0
- package/dist/document-models/expense-report/gen/wallet/operations.d.ts +21 -0
- package/dist/document-models/expense-report/gen/wallet/operations.d.ts.map +1 -0
- package/dist/document-models/expense-report/gen/wallet/operations.js +1 -0
- package/dist/document-models/expense-report/index.d.ts +39 -0
- package/dist/document-models/expense-report/index.d.ts.map +1 -0
- package/dist/document-models/expense-report/index.js +21 -0
- package/dist/document-models/expense-report/src/reducers/wallet.d.ts +3 -0
- package/dist/document-models/expense-report/src/reducers/wallet.d.ts.map +1 -0
- package/dist/document-models/expense-report/src/reducers/wallet.js +180 -0
- package/dist/document-models/expense-report/src/tests/document-model.test.d.ts +6 -0
- package/dist/document-models/expense-report/src/tests/document-model.test.d.ts.map +1 -0
- package/dist/document-models/expense-report/src/tests/document-model.test.js +18 -0
- package/dist/document-models/expense-report/src/tests/expense-report.test.d.ts +6 -0
- package/dist/document-models/expense-report/src/tests/expense-report.test.d.ts.map +1 -0
- package/dist/document-models/expense-report/src/tests/expense-report.test.js +24 -0
- package/dist/document-models/expense-report/src/tests/wallet.test.d.ts +6 -0
- package/dist/document-models/expense-report/src/tests/wallet.test.d.ts.map +1 -0
- package/dist/document-models/expense-report/src/tests/wallet.test.js +24 -0
- package/dist/document-models/expense-report/src/utils.d.ts +2 -0
- package/dist/document-models/expense-report/src/utils.d.ts.map +1 -0
- package/dist/document-models/expense-report/src/utils.js +1 -0
- package/dist/document-models/index.d.ts +1 -0
- package/dist/document-models/index.d.ts.map +1 -1
- package/dist/document-models/index.js +1 -0
- package/dist/document-models/integrations/gen/ph-factories.d.ts.map +1 -1
- package/dist/document-models/integrations/gen/ph-factories.js +2 -14
- package/dist/document-models/integrations/gen/utils.d.ts.map +1 -1
- package/dist/document-models/integrations/gen/utils.js +2 -14
- package/dist/document-models/invoice/gen/ph-factories.d.ts.map +1 -1
- package/dist/document-models/invoice/gen/ph-factories.js +2 -5
- package/dist/document-models/invoice/gen/schema/types.d.ts +1 -1
- package/dist/document-models/invoice/gen/schema/types.d.ts.map +1 -1
- package/dist/document-models/invoice/gen/utils.d.ts.map +1 -1
- package/dist/document-models/invoice/gen/utils.js +1 -4
- package/dist/editors/billing-statement/components/lineItemsTable.d.ts.map +1 -1
- package/dist/editors/billing-statement/components/lineItemsTable.js +71 -13
- package/dist/editors/billing-statement/editor.js +1 -1
- package/dist/editors/contributor-billing/components/DriveExplorer.d.ts.map +1 -1
- package/dist/editors/contributor-billing/components/DriveExplorer.js +8 -4
- package/dist/editors/contributor-billing/components/InvoiceTable/HeaderControls.d.ts +4 -1
- package/dist/editors/contributor-billing/components/InvoiceTable/HeaderControls.d.ts.map +1 -1
- package/dist/editors/contributor-billing/components/InvoiceTable/HeaderControls.js +2 -2
- package/dist/editors/contributor-billing/components/InvoiceTable/InvoiceTable.d.ts.map +1 -1
- package/dist/editors/contributor-billing/components/InvoiceTable/InvoiceTable.js +24 -1
- package/dist/editors/expense-report/components/AddBillingStatementModal.d.ts +11 -0
- package/dist/editors/expense-report/components/AddBillingStatementModal.d.ts.map +1 -0
- package/dist/editors/expense-report/components/AddBillingStatementModal.js +195 -0
- package/dist/editors/expense-report/components/AggregatedExpensesTable.d.ts +11 -0
- package/dist/editors/expense-report/components/AggregatedExpensesTable.d.ts.map +1 -0
- package/dist/editors/expense-report/components/AggregatedExpensesTable.js +268 -0
- package/dist/editors/expense-report/components/ExpenseReportPDF.d.ts +10 -0
- package/dist/editors/expense-report/components/ExpenseReportPDF.d.ts.map +1 -0
- package/dist/editors/expense-report/components/ExpenseReportPDF.js +287 -0
- package/dist/editors/expense-report/components/WalletsTable.d.ts +10 -0
- package/dist/editors/expense-report/components/WalletsTable.d.ts.map +1 -0
- package/dist/editors/expense-report/components/WalletsTable.js +164 -0
- package/dist/editors/expense-report/editor.d.ts +2 -0
- package/dist/editors/expense-report/editor.d.ts.map +1 -0
- package/dist/editors/expense-report/editor.js +74 -0
- package/dist/editors/expense-report/hooks/useSyncWallet.d.ts +5 -0
- package/dist/editors/expense-report/hooks/useSyncWallet.d.ts.map +1 -0
- package/dist/editors/expense-report/hooks/useSyncWallet.js +75 -0
- package/dist/editors/expense-report/hooks/useWalletSync.d.ts +9 -0
- package/dist/editors/expense-report/hooks/useWalletSync.d.ts.map +1 -0
- package/dist/editors/expense-report/hooks/useWalletSync.js +77 -0
- package/dist/editors/expense-report/index.d.ts +3 -0
- package/dist/editors/expense-report/index.d.ts.map +1 -0
- package/dist/editors/expense-report/index.js +11 -0
- package/dist/editors/hooks/useExpenseReportDocument.d.ts +4 -0
- package/dist/editors/hooks/useExpenseReportDocument.d.ts.map +1 -0
- package/dist/editors/hooks/useExpenseReportDocument.js +8 -0
- package/dist/editors/index.d.ts +1 -0
- package/dist/editors/index.d.ts.map +1 -1
- package/dist/editors/index.js +1 -0
- package/dist/editors/invoice/components/statusModalComponents.d.ts.map +1 -1
- package/dist/editors/invoice/components/statusModalComponents.js +4 -4
- package/dist/editors/invoice/editor.js +1 -1
- package/dist/editors/invoice/ingestPDF.d.ts.map +1 -1
- package/dist/editors/invoice/ingestPDF.js +3 -3
- package/dist/editors/invoice/invoiceToGnosis.js +1 -1
- package/dist/editors/invoice/requestFinance.js +1 -1
- package/dist/editors/invoice/uploadPdfChunked.js +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/powerhouse.manifest.json +13 -2
- package/dist/style.css +539 -37
- package/dist/subgraphs/expense-report/index.d.ts +11 -0
- package/dist/subgraphs/expense-report/index.d.ts.map +1 -0
- package/dist/subgraphs/expense-report/index.js +11 -0
- package/dist/subgraphs/expense-report/resolvers.d.ts +3 -0
- package/dist/subgraphs/expense-report/resolvers.d.ts.map +1 -0
- package/dist/subgraphs/expense-report/resolvers.js +252 -0
- package/dist/subgraphs/expense-report/schema.d.ts +3 -0
- package/dist/subgraphs/expense-report/schema.d.ts.map +1 -0
- package/dist/subgraphs/expense-report/schema.js +228 -0
- package/dist/subgraphs/index.d.ts +1 -0
- package/dist/subgraphs/index.d.ts.map +1 -1
- package/dist/subgraphs/index.js +1 -0
- package/package.json +13 -13
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState } from "react";
|
|
3
|
+
import { Button, TextInput } from "@powerhousedao/document-engineering";
|
|
4
|
+
import { Plus, Trash2, Pencil, Check, X, Copy, CheckCheck, RefreshCw } from "lucide-react";
|
|
5
|
+
import { actions } from "../../../document-models/expense-report/index.js";
|
|
6
|
+
import { useWalletSync } from "../hooks/useWalletSync.js";
|
|
7
|
+
import { useSyncWallet } from "../hooks/useSyncWallet.js";
|
|
8
|
+
export function WalletsTable({ wallets, groups, onAddBillingStatement, dispatch, }) {
|
|
9
|
+
const [newWalletAddress, setNewWalletAddress] = useState("");
|
|
10
|
+
const [newWalletName, setNewWalletName] = useState("");
|
|
11
|
+
const [walletError, setWalletError] = useState("");
|
|
12
|
+
const [hoveredWallet, setHoveredWallet] = useState(null);
|
|
13
|
+
const [editingWallet, setEditingWallet] = useState(null);
|
|
14
|
+
const [editingName, setEditingName] = useState("");
|
|
15
|
+
const [copiedWallet, setCopiedWallet] = useState(null);
|
|
16
|
+
const [syncingWallet, setSyncingWallet] = useState(null);
|
|
17
|
+
// Check sync status
|
|
18
|
+
const { needsSync, outdatedWallets, tagChangedWallets } = useWalletSync(wallets);
|
|
19
|
+
const { syncWallet } = useSyncWallet();
|
|
20
|
+
const handleAddWallet = () => {
|
|
21
|
+
const trimmedAddress = newWalletAddress.trim();
|
|
22
|
+
if (trimmedAddress) {
|
|
23
|
+
// Check if wallet already exists
|
|
24
|
+
const walletExists = wallets.some(w => w.wallet === trimmedAddress);
|
|
25
|
+
if (walletExists) {
|
|
26
|
+
setWalletError("This wallet already exists");
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
dispatch(actions.addWallet({
|
|
30
|
+
wallet: trimmedAddress,
|
|
31
|
+
name: newWalletName.trim() || undefined,
|
|
32
|
+
}));
|
|
33
|
+
setNewWalletAddress("");
|
|
34
|
+
setNewWalletName("");
|
|
35
|
+
setWalletError("");
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
const handleStartEditName = (wallet) => {
|
|
39
|
+
setEditingWallet(wallet.wallet || null);
|
|
40
|
+
setEditingName(wallet.name || "");
|
|
41
|
+
};
|
|
42
|
+
const handleSaveEditName = (walletAddress) => {
|
|
43
|
+
const wallet = wallets.find(w => w.wallet === walletAddress);
|
|
44
|
+
const trimmedName = editingName.trim();
|
|
45
|
+
// Only update if the name has changed
|
|
46
|
+
if (trimmedName && wallet && trimmedName !== (wallet.name || "")) {
|
|
47
|
+
dispatch(actions.updateWallet({
|
|
48
|
+
address: walletAddress,
|
|
49
|
+
name: trimmedName,
|
|
50
|
+
}));
|
|
51
|
+
}
|
|
52
|
+
setEditingWallet(null);
|
|
53
|
+
setEditingName("");
|
|
54
|
+
};
|
|
55
|
+
const handleCancelEditName = () => {
|
|
56
|
+
setEditingWallet(null);
|
|
57
|
+
setEditingName("");
|
|
58
|
+
};
|
|
59
|
+
const handleCopyAddress = (address) => {
|
|
60
|
+
navigator.clipboard.writeText(address);
|
|
61
|
+
setCopiedWallet(address);
|
|
62
|
+
setTimeout(() => setCopiedWallet(null), 2000);
|
|
63
|
+
};
|
|
64
|
+
const formatAddress = (address) => {
|
|
65
|
+
if (!address || address.length < 11)
|
|
66
|
+
return address;
|
|
67
|
+
return `${address.substring(0, 6)}...${address.substring(address.length - 5)}`;
|
|
68
|
+
};
|
|
69
|
+
const handleSyncWallet = async (wallet) => {
|
|
70
|
+
if (!wallet.wallet || !wallet.billingStatements || wallet.billingStatements.length === 0) {
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
setSyncingWallet(wallet.wallet);
|
|
74
|
+
try {
|
|
75
|
+
// Remove all existing line items first
|
|
76
|
+
const lineItemsToRemove = [...(wallet.lineItems || [])];
|
|
77
|
+
lineItemsToRemove.forEach((item) => {
|
|
78
|
+
if (item?.id) {
|
|
79
|
+
dispatch(actions.removeLineItem({
|
|
80
|
+
wallet: wallet.wallet,
|
|
81
|
+
lineItemId: item.id,
|
|
82
|
+
}));
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
// Re-extract line items from billing statements
|
|
86
|
+
const billingStatementIds = wallet.billingStatements.filter((id) => id !== null && id !== undefined);
|
|
87
|
+
syncWallet(wallet.wallet, billingStatementIds, groups, dispatch);
|
|
88
|
+
// Small delay to show sync animation
|
|
89
|
+
setTimeout(() => {
|
|
90
|
+
setSyncingWallet(null);
|
|
91
|
+
}, 500);
|
|
92
|
+
}
|
|
93
|
+
catch (error) {
|
|
94
|
+
console.error("Error syncing wallet:", error);
|
|
95
|
+
setSyncingWallet(null);
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
const handleRemoveWallet = (walletAddress) => {
|
|
99
|
+
dispatch(actions.removeWallet({
|
|
100
|
+
wallet: walletAddress,
|
|
101
|
+
}));
|
|
102
|
+
};
|
|
103
|
+
// Calculate totals for a wallet
|
|
104
|
+
const calculateWalletTotals = (wallet) => {
|
|
105
|
+
const lineItems = wallet.lineItems || [];
|
|
106
|
+
return {
|
|
107
|
+
budget: lineItems.reduce((sum, item) => sum + (item?.budget || 0), 0),
|
|
108
|
+
forecast: lineItems.reduce((sum, item) => sum + (item?.forecast || 0), 0),
|
|
109
|
+
actuals: lineItems.reduce((sum, item) => sum + (item?.actuals || 0), 0),
|
|
110
|
+
difference: lineItems.reduce((sum, item) => {
|
|
111
|
+
const budget = item?.budget || 0;
|
|
112
|
+
const actuals = item?.actuals || 0;
|
|
113
|
+
return sum + (actuals - budget);
|
|
114
|
+
}, 0),
|
|
115
|
+
payments: lineItems.reduce((sum, item) => sum + (item?.payments || 0), 0),
|
|
116
|
+
};
|
|
117
|
+
};
|
|
118
|
+
const formatCurrency = (value) => {
|
|
119
|
+
return new Intl.NumberFormat("en-US", {
|
|
120
|
+
style: "currency",
|
|
121
|
+
currency: "USD",
|
|
122
|
+
minimumFractionDigits: 2,
|
|
123
|
+
}).format(value);
|
|
124
|
+
};
|
|
125
|
+
return (_jsxs("div", { className: "space-y-4", children: [wallets.length > 0 ? (_jsx("div", { className: "overflow-x-auto", children: _jsxs("table", { className: "min-w-full divide-y divide-gray-200 dark:divide-gray-700", children: [_jsx("thead", { className: "bg-gray-50 dark:bg-gray-800", children: _jsxs("tr", { children: [_jsx("th", { className: "px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider", children: "Wallet" }), _jsx("th", { className: "px-6 py-3 text-right text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider", children: "Monthly Budget" }), _jsx("th", { className: "px-6 py-3 text-right text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider", children: "Forecast" }), _jsx("th", { className: "px-6 py-3 text-right text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider", children: "Actuals" }), _jsx("th", { className: "px-6 py-3 text-right text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider", children: "Difference" }), _jsx("th", { className: "px-6 py-3 text-right text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider", children: "Payments" }), _jsx("th", { className: "px-6 py-3 text-right text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider", children: "Actions" })] }) }), _jsx("tbody", { className: "bg-white dark:bg-gray-900 divide-y divide-gray-200 dark:divide-gray-700", children: wallets.map((wallet) => {
|
|
126
|
+
const totals = calculateWalletTotals(wallet);
|
|
127
|
+
const isHovered = hoveredWallet === wallet.wallet;
|
|
128
|
+
return (_jsxs("tr", { onMouseEnter: () => setHoveredWallet(wallet.wallet || null), onMouseLeave: () => setHoveredWallet(null), className: "hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors", children: [_jsx("td", { className: "px-6 py-4 whitespace-nowrap", children: editingWallet === wallet.wallet ? (_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(TextInput, { value: editingName, onChange: (e) => setEditingName(e.target.value), placeholder: "Enter wallet name", className: "flex-1", onKeyDown: (e) => {
|
|
129
|
+
if (e.key === "Enter") {
|
|
130
|
+
handleSaveEditName(wallet.wallet || "");
|
|
131
|
+
}
|
|
132
|
+
else if (e.key === "Escape") {
|
|
133
|
+
handleCancelEditName();
|
|
134
|
+
}
|
|
135
|
+
}, autoFocus: true }), _jsx("button", { onClick: () => handleSaveEditName(wallet.wallet || ""), className: "inline-flex items-center justify-center w-7 h-7 text-green-600 dark:text-green-400 hover:bg-green-50 dark:hover:bg-green-900/20 rounded-md transition-colors", title: "Save", children: _jsx(Check, { size: 14 }) }), _jsx("button", { onClick: handleCancelEditName, className: "inline-flex items-center justify-center w-7 h-7 text-gray-600 dark:text-gray-400 hover:bg-gray-50 dark:hover:bg-gray-900/20 rounded-md transition-colors", title: "Cancel", children: _jsx(X, { size: 14 }) })] })) : (_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("span", { className: "text-sm font-medium text-gray-900 dark:text-white", children: wallet.name || "Unnamed Wallet" }), _jsx("button", { onClick: () => handleStartEditName(wallet), className: "inline-flex items-center justify-center w-6 h-6 text-gray-600 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-md transition-colors", title: "Edit name", children: _jsx(Pencil, { size: 12 }) }), _jsxs("button", { onClick: () => handleCopyAddress(wallet.wallet || ""), className: "inline-flex items-center gap-1 px-2 py-1 text-xs text-gray-500 dark:text-gray-400 font-mono hover:bg-gray-100 dark:hover:bg-gray-700 rounded transition-colors", title: `Copy address: ${wallet.wallet}`, children: [formatAddress(wallet.wallet || ""), copiedWallet === wallet.wallet ? (_jsx(CheckCheck, { size: 12, className: "text-green-500" })) : (_jsx(Copy, { size: 12 }))] })] })) }), _jsx("td", { className: "px-6 py-4 whitespace-nowrap text-right text-sm text-gray-900 dark:text-white", children: formatCurrency(totals.budget) }), _jsx("td", { className: "px-6 py-4 whitespace-nowrap text-right text-sm text-gray-900 dark:text-white", children: formatCurrency(totals.forecast) }), _jsx("td", { className: "px-6 py-4 whitespace-nowrap text-right text-sm text-gray-900 dark:text-white", children: formatCurrency(totals.actuals) }), _jsx("td", { className: `px-6 py-4 whitespace-nowrap text-right text-sm font-medium ${totals.difference > 0
|
|
136
|
+
? "text-red-600 dark:text-red-400"
|
|
137
|
+
: totals.difference < 0
|
|
138
|
+
? "text-green-600 dark:text-green-400"
|
|
139
|
+
: "text-gray-900 dark:text-white"}`, children: formatCurrency(totals.difference) }), _jsx("td", { className: "px-6 py-4 whitespace-nowrap text-right text-sm text-gray-900 dark:text-white", children: formatCurrency(totals.payments) }), _jsx("td", { className: "px-6 py-4 whitespace-nowrap text-right text-sm", children: _jsxs("div", { className: "flex items-center justify-end gap-2", children: [_jsxs("button", { onClick: () => onAddBillingStatement(wallet.wallet || ""), className: "inline-flex items-center gap-1 px-3 py-1 text-sm font-medium text-blue-600 dark:text-blue-400 hover:text-blue-800 dark:hover:text-blue-300 bg-blue-50 dark:bg-blue-900/20 hover:bg-blue-100 dark:hover:bg-blue-900/30 rounded-md transition-colors", title: "Add billing statement", children: [_jsx(Plus, { size: 16 }), _jsx("span", { children: "Add Bills" })] }), wallet.billingStatements && wallet.billingStatements.length > 0 && (_jsxs("button", { onClick: () => handleSyncWallet(wallet), disabled: syncingWallet === wallet.wallet, className: `inline-flex items-center gap-1 px-3 py-1 text-sm font-medium rounded-md transition-colors ${tagChangedWallets.includes(wallet.wallet || "")
|
|
140
|
+
? "text-red-600 dark:text-red-400 bg-red-50 dark:bg-red-900/20 hover:bg-red-100 dark:hover:bg-red-900/30 animate-pulse"
|
|
141
|
+
: outdatedWallets.includes(wallet.wallet || "")
|
|
142
|
+
? "text-amber-600 dark:text-amber-400 bg-amber-50 dark:bg-amber-900/20 hover:bg-amber-100 dark:hover:bg-amber-900/30 animate-pulse"
|
|
143
|
+
: "text-gray-600 dark:text-gray-400 bg-gray-50 dark:bg-gray-800 hover:bg-gray-100 dark:hover:bg-gray-700"} disabled:opacity-50 disabled:cursor-not-allowed`, title: tagChangedWallets.includes(wallet.wallet || "")
|
|
144
|
+
? "ALERT: Tags have changed in billing statements - sync required!"
|
|
145
|
+
: outdatedWallets.includes(wallet.wallet || "")
|
|
146
|
+
? "Sync needed - billing statements have been updated"
|
|
147
|
+
: "Sync with latest billing statements", children: [_jsx(RefreshCw, { size: 16, className: syncingWallet === wallet.wallet ? "animate-spin" : "" }), _jsx("span", { children: tagChangedWallets.includes(wallet.wallet || "")
|
|
148
|
+
? "Tags Changed!"
|
|
149
|
+
: outdatedWallets.includes(wallet.wallet || "")
|
|
150
|
+
? "Sync"
|
|
151
|
+
: "Synced" })] })), _jsx("button", { onClick: () => handleRemoveWallet(wallet.wallet || ""), className: "inline-flex items-center justify-center w-8 h-8 text-red-600 dark:text-red-400 hover:bg-red-50 dark:hover:bg-red-900/20 rounded-md transition-colors", title: "Remove wallet", children: _jsx(Trash2, { size: 16 }) })] }) })] }, wallet.wallet));
|
|
152
|
+
}) })] }) })) : (_jsx("div", { className: "text-center py-12 text-gray-500 dark:text-gray-400", children: _jsx("p", { className: "text-sm", children: "No wallets added yet. Add a wallet to get started." }) })), _jsxs("div", { className: "flex items-end gap-3 pt-4 border-t border-gray-200 dark:border-gray-700", children: [_jsxs("div", { className: "flex-1", children: [_jsx("label", { className: "block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1", children: "Wallet Name" }), _jsx(TextInput, { value: newWalletName, onChange: (e) => setNewWalletName(e.target.value), placeholder: "Enter wallet name (optional)", onKeyDown: (e) => {
|
|
153
|
+
if (e.key === "Enter") {
|
|
154
|
+
handleAddWallet();
|
|
155
|
+
}
|
|
156
|
+
} })] }), _jsxs("div", { className: "flex-1 relative", children: [_jsx("label", { className: "block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1", children: "Wallet Address" }), _jsx(TextInput, { value: newWalletAddress, onChange: (e) => {
|
|
157
|
+
setNewWalletAddress(e.target.value);
|
|
158
|
+
setWalletError(""); // Clear error when typing
|
|
159
|
+
}, placeholder: "Enter wallet address (e.g., 0x1234...)", onKeyDown: (e) => {
|
|
160
|
+
if (e.key === "Enter") {
|
|
161
|
+
handleAddWallet();
|
|
162
|
+
}
|
|
163
|
+
} }), walletError && (_jsx("div", { className: "absolute left-0 right-0 top-full mt-1 px-3 py-2 bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 rounded-md shadow-lg z-10", children: _jsx("p", { className: "text-sm text-red-600 dark:text-red-400", children: walletError }) }))] }), _jsx(Button, { onClick: handleAddWallet, disabled: !newWalletAddress.trim(), children: "Add Wallet" })] })] }));
|
|
164
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"editor.d.ts","sourceRoot":"","sources":["../../../editors/expense-report/editor.tsx"],"names":[],"mappings":"AAWA,wBAAgB,MAAM,4CAmMrB"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState, useMemo } from "react";
|
|
3
|
+
import { useSelectedExpenseReportDocument } from "../hooks/useExpenseReportDocument.js";
|
|
4
|
+
import { actions } from "../../document-models/expense-report/index.js";
|
|
5
|
+
import { DatePicker, Icon, Button } from "@powerhousedao/document-engineering";
|
|
6
|
+
import { WalletsTable } from "./components/WalletsTable.js";
|
|
7
|
+
import { AggregatedExpensesTable } from "./components/AggregatedExpensesTable.js";
|
|
8
|
+
import { AddBillingStatementModal } from "./components/AddBillingStatementModal.js";
|
|
9
|
+
import { ExpenseReportPDF } from "./components/ExpenseReportPDF.js";
|
|
10
|
+
import { pdf } from "@react-pdf/renderer";
|
|
11
|
+
export function Editor() {
|
|
12
|
+
const [document, dispatch] = useSelectedExpenseReportDocument();
|
|
13
|
+
const [selectedWallet, setSelectedWallet] = useState(null);
|
|
14
|
+
const [isModalOpen, setIsModalOpen] = useState(false);
|
|
15
|
+
const [periodStart, setPeriodStart] = useState(document.state.global.periodStart || "");
|
|
16
|
+
const [periodEnd, setPeriodEnd] = useState(document.state.global.periodEnd || "");
|
|
17
|
+
const { wallets, groups } = document.state.global;
|
|
18
|
+
// Handle period date changes
|
|
19
|
+
const handlePeriodStartChange = (e) => {
|
|
20
|
+
const value = e.target.value;
|
|
21
|
+
setPeriodStart(value);
|
|
22
|
+
if (value) {
|
|
23
|
+
dispatch(actions.setPeriodStart({ periodStart: value }));
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
const handlePeriodEndChange = (e) => {
|
|
27
|
+
const value = e.target.value;
|
|
28
|
+
setPeriodEnd(value);
|
|
29
|
+
if (value) {
|
|
30
|
+
dispatch(actions.setPeriodEnd({ periodEnd: value }));
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
// Handle wallet selection for adding billing statements
|
|
34
|
+
const handleAddBillingStatement = (walletAddress) => {
|
|
35
|
+
setSelectedWallet(walletAddress);
|
|
36
|
+
setIsModalOpen(true);
|
|
37
|
+
};
|
|
38
|
+
// Handle closing modal
|
|
39
|
+
const handleCloseModal = () => {
|
|
40
|
+
setIsModalOpen(false);
|
|
41
|
+
setSelectedWallet(null);
|
|
42
|
+
};
|
|
43
|
+
// Handle PDF export
|
|
44
|
+
const handleExportPDF = async () => {
|
|
45
|
+
try {
|
|
46
|
+
const blob = await pdf(_jsx(ExpenseReportPDF, { periodStart: periodStart, periodEnd: periodEnd, wallets: wallets, groups: groups })).toBlob();
|
|
47
|
+
// Create download link
|
|
48
|
+
const url = URL.createObjectURL(blob);
|
|
49
|
+
const link = window.document.createElement("a");
|
|
50
|
+
link.href = url;
|
|
51
|
+
// Generate filename with period
|
|
52
|
+
const filename = periodStart
|
|
53
|
+
? `expense-report-${new Date(periodStart).toISOString().split('T')[0]}.pdf`
|
|
54
|
+
: "expense-report.pdf";
|
|
55
|
+
link.download = filename;
|
|
56
|
+
link.click();
|
|
57
|
+
// Cleanup
|
|
58
|
+
URL.revokeObjectURL(url);
|
|
59
|
+
}
|
|
60
|
+
catch (error) {
|
|
61
|
+
console.error("Error generating PDF:", error);
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
// Format period title for the breakdown section
|
|
65
|
+
const breakdownTitle = useMemo(() => {
|
|
66
|
+
if (!periodStart)
|
|
67
|
+
return "Breakdown";
|
|
68
|
+
const date = new Date(periodStart);
|
|
69
|
+
const month = date.toLocaleDateString("en-US", { month: "short" });
|
|
70
|
+
const year = date.getFullYear();
|
|
71
|
+
return `${month} ${year} Breakdown`;
|
|
72
|
+
}, [periodStart]);
|
|
73
|
+
return (_jsxs("div", { className: "ph-default-styles flex flex-col h-full w-full bg-gray-50 dark:bg-gray-900", children: [_jsx("div", { className: "flex-1 overflow-auto px-8 py-6", children: _jsxs("div", { className: "max-w-7xl mx-auto space-y-8", children: [_jsx("section", { className: "bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700", children: _jsx("div", { className: "px-6 py-6", children: _jsxs("div", { className: "relative", children: [_jsxs("div", { className: "text-center", children: [_jsx("h1", { className: "text-3xl font-bold text-gray-900 dark:text-white mb-4", children: "Expense Report" }), _jsx("div", { className: "flex items-center justify-center gap-4 text-sm text-gray-600 dark:text-gray-400", children: _jsxs("div", { className: "flex items-center gap-2", children: [_jsx("span", { className: "font-medium", children: "Period:" }), _jsx(DatePicker, { name: "periodStart", value: periodStart, onChange: handlePeriodStartChange }), _jsx("span", { children: "to" }), _jsx(DatePicker, { name: "periodEnd", value: periodEnd, onChange: handlePeriodEndChange })] }) })] }), _jsxs(Button, { variant: "ghost", onClick: handleExportPDF, className: "absolute top-0 right-0 flex items-center gap-2", children: [_jsx(Icon, { name: "ExportPdf", size: 18 }), "Export to PDF"] })] }) }) }), _jsxs("section", { className: "bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700", children: [_jsx("div", { className: "px-6 py-4 border-b border-gray-200 dark:border-gray-700", children: _jsx("h2", { className: "text-xl font-semibold text-gray-900 dark:text-white", children: "Wallets" }) }), _jsx("div", { className: "p-6", children: _jsx(WalletsTable, { wallets: wallets, groups: groups, onAddBillingStatement: handleAddBillingStatement, dispatch: dispatch }) })] }), wallets.length > 0 && (_jsxs("section", { className: "bg-white dark:bg-gray-800 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700", children: [_jsx("div", { className: "px-6 py-4 border-b border-gray-200 dark:border-gray-700", children: _jsx("h2", { className: "text-xl font-semibold text-gray-900 dark:text-white", children: breakdownTitle }) }), _jsx("div", { className: "p-6", children: _jsx(AggregatedExpensesTable, { wallets: wallets, groups: groups, periodStart: periodStart, periodEnd: periodEnd, dispatch: dispatch }) })] }))] }) }), isModalOpen && selectedWallet && (_jsx(AddBillingStatementModal, { isOpen: isModalOpen, onClose: handleCloseModal, walletAddress: selectedWallet, dispatch: dispatch, groups: groups }))] }));
|
|
74
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { LineItemGroup } from "../../../document-models/expense-report/gen/types.js";
|
|
2
|
+
export declare function useSyncWallet(): {
|
|
3
|
+
syncWallet: (walletAddress: string, billingStatementIds: string[], groups: LineItemGroup[], dispatch: any) => void;
|
|
4
|
+
};
|
|
5
|
+
//# sourceMappingURL=useSyncWallet.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useSyncWallet.d.ts","sourceRoot":"","sources":["../../../../editors/expense-report/hooks/useSyncWallet.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sDAAsD,CAAC;AAkB1F,wBAAgB,aAAa;gCAIV,MAAM,uBACA,MAAM,EAAE,UACrB,aAAa,EAAE,YACb,GAAG;EA0FhB"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { useSelectedDriveDocuments } from "@powerhousedao/reactor-browser";
|
|
2
|
+
import { actions } from "../../../document-models/expense-report/index.js";
|
|
3
|
+
import { generateId } from "document-model";
|
|
4
|
+
export function useSyncWallet() {
|
|
5
|
+
const documents = useSelectedDriveDocuments();
|
|
6
|
+
const syncWallet = (walletAddress, billingStatementIds, groups, dispatch) => {
|
|
7
|
+
if (!documents)
|
|
8
|
+
return;
|
|
9
|
+
// Get billing statement documents
|
|
10
|
+
const billingStatements = new Map();
|
|
11
|
+
documents
|
|
12
|
+
.filter((doc) => doc.header.documentType === "powerhouse/billing-statement")
|
|
13
|
+
.forEach((doc) => {
|
|
14
|
+
billingStatements.set(doc.header.id, doc);
|
|
15
|
+
});
|
|
16
|
+
// Helper function to map tag to group
|
|
17
|
+
const mapTagToGroup = (billingLineItem) => {
|
|
18
|
+
// Find expense-account tag
|
|
19
|
+
const expenseAccountTag = billingLineItem.lineItemTag?.find((tag) => tag.dimension === "expense-account");
|
|
20
|
+
if (!expenseAccountTag || !expenseAccountTag.label)
|
|
21
|
+
return null;
|
|
22
|
+
// Find matching group by label
|
|
23
|
+
const group = groups.find((g) => g.label === expenseAccountTag.label);
|
|
24
|
+
return group ? group.id : null;
|
|
25
|
+
};
|
|
26
|
+
// Aggregate line items by category
|
|
27
|
+
const categoryAggregation = new Map();
|
|
28
|
+
// Extract and aggregate line items from all billing statements
|
|
29
|
+
billingStatementIds.forEach((statementId) => {
|
|
30
|
+
const statement = billingStatements.get(statementId);
|
|
31
|
+
if (!statement?.state?.global?.lineItems)
|
|
32
|
+
return;
|
|
33
|
+
const lineItems = statement.state.global.lineItems || [];
|
|
34
|
+
lineItems.forEach((billingLineItem) => {
|
|
35
|
+
const groupId = mapTagToGroup(billingLineItem);
|
|
36
|
+
const categoryKey = groupId || "uncategorized";
|
|
37
|
+
const existing = categoryAggregation.get(categoryKey);
|
|
38
|
+
if (existing) {
|
|
39
|
+
// Aggregate values for the same category
|
|
40
|
+
existing.actuals += billingLineItem.totalPriceCash || 0;
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
// Create new category entry
|
|
44
|
+
const group = groups.find((g) => g.id === groupId);
|
|
45
|
+
categoryAggregation.set(categoryKey, {
|
|
46
|
+
groupId: groupId,
|
|
47
|
+
groupLabel: group?.label || "Uncategorised",
|
|
48
|
+
budget: 0,
|
|
49
|
+
actuals: billingLineItem.totalPriceCash || 0,
|
|
50
|
+
forecast: 0,
|
|
51
|
+
payments: 0,
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
// Now add aggregated line items to wallet
|
|
57
|
+
categoryAggregation.forEach((aggregatedItem) => {
|
|
58
|
+
const expenseLineItem = {
|
|
59
|
+
id: generateId(),
|
|
60
|
+
label: aggregatedItem.groupLabel,
|
|
61
|
+
group: aggregatedItem.groupId,
|
|
62
|
+
budget: aggregatedItem.budget,
|
|
63
|
+
actuals: aggregatedItem.actuals,
|
|
64
|
+
forecast: aggregatedItem.forecast,
|
|
65
|
+
payments: aggregatedItem.payments,
|
|
66
|
+
comments: null,
|
|
67
|
+
};
|
|
68
|
+
dispatch(actions.addLineItem({
|
|
69
|
+
wallet: walletAddress,
|
|
70
|
+
lineItem: expenseLineItem,
|
|
71
|
+
}));
|
|
72
|
+
});
|
|
73
|
+
};
|
|
74
|
+
return { syncWallet };
|
|
75
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Wallet } from "../../../document-models/expense-report/gen/types.js";
|
|
2
|
+
interface SyncStatus {
|
|
3
|
+
needsSync: boolean;
|
|
4
|
+
outdatedWallets: string[];
|
|
5
|
+
tagChangedWallets: string[];
|
|
6
|
+
}
|
|
7
|
+
export declare function useWalletSync(wallets: Wallet[]): SyncStatus;
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=useWalletSync.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useWalletSync.d.ts","sourceRoot":"","sources":["../../../../editors/expense-report/hooks/useWalletSync.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,sDAAsD,CAAC;AAEnF,UAAU,UAAU;IAClB,SAAS,EAAE,OAAO,CAAC;IACnB,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,iBAAiB,EAAE,MAAM,EAAE,CAAC;CAC7B;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,UAAU,CAoG3D"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { useMemo } from "react";
|
|
2
|
+
import { useSelectedDriveDocuments } from "@powerhousedao/reactor-browser";
|
|
3
|
+
export function useWalletSync(wallets) {
|
|
4
|
+
const documents = useSelectedDriveDocuments();
|
|
5
|
+
const syncStatus = useMemo(() => {
|
|
6
|
+
if (!documents || wallets.length === 0) {
|
|
7
|
+
return { needsSync: false, outdatedWallets: [], tagChangedWallets: [] };
|
|
8
|
+
}
|
|
9
|
+
// Create a map of billing statement documents
|
|
10
|
+
const billingStatements = new Map();
|
|
11
|
+
documents
|
|
12
|
+
.filter((doc) => doc.header.documentType === "powerhouse/billing-statement")
|
|
13
|
+
.forEach((doc) => {
|
|
14
|
+
billingStatements.set(doc.header.id, doc);
|
|
15
|
+
});
|
|
16
|
+
const outdatedWallets = [];
|
|
17
|
+
const tagChangedWallets = [];
|
|
18
|
+
// Check each wallet
|
|
19
|
+
wallets.forEach((wallet) => {
|
|
20
|
+
if (!wallet.billingStatements || wallet.billingStatements.length === 0) {
|
|
21
|
+
return; // No billing statements to sync
|
|
22
|
+
}
|
|
23
|
+
// Get current aggregated totals by category from wallet line items
|
|
24
|
+
const currentCategoryTotals = new Map();
|
|
25
|
+
wallet.lineItems?.forEach((item) => {
|
|
26
|
+
if (item?.group) {
|
|
27
|
+
const currentTotal = currentCategoryTotals.get(item.group) || 0;
|
|
28
|
+
currentCategoryTotals.set(item.group, currentTotal + (item.actuals || 0));
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
// Calculate expected aggregated totals by category from billing statements
|
|
32
|
+
const expectedCategoryTotals = new Map();
|
|
33
|
+
const expectedCategoryLabels = new Set();
|
|
34
|
+
wallet.billingStatements.forEach((statementId) => {
|
|
35
|
+
if (!statementId)
|
|
36
|
+
return;
|
|
37
|
+
const statement = billingStatements.get(statementId);
|
|
38
|
+
if (statement?.state?.global?.lineItems) {
|
|
39
|
+
statement.state.global.lineItems.forEach((item) => {
|
|
40
|
+
// Find expense-account tag
|
|
41
|
+
const expenseAccountTag = item.lineItemTag?.find((tag) => tag.dimension === "expense-account");
|
|
42
|
+
if (expenseAccountTag?.label) {
|
|
43
|
+
expectedCategoryLabels.add(expenseAccountTag.label);
|
|
44
|
+
const currentTotal = expectedCategoryTotals.get(expenseAccountTag.label) || 0;
|
|
45
|
+
expectedCategoryTotals.set(expenseAccountTag.label, currentTotal + (item.totalPriceCash || 0));
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
// Check if categories have changed
|
|
51
|
+
const currentCategories = new Set(currentCategoryTotals.keys());
|
|
52
|
+
const hasTagChanges = currentCategories.size !== expectedCategoryLabels.size;
|
|
53
|
+
// Check if totals per category have changed
|
|
54
|
+
let hasTotalMismatch = false;
|
|
55
|
+
// We need to check if the aggregated totals match
|
|
56
|
+
// Since wallet stores group IDs but billing statements have labels,
|
|
57
|
+
// we need to sum up all line items regardless of category structure
|
|
58
|
+
const currentTotalActuals = Array.from(currentCategoryTotals.values()).reduce((sum, total) => sum + total, 0);
|
|
59
|
+
const expectedTotalActuals = Array.from(expectedCategoryTotals.values()).reduce((sum, total) => sum + total, 0);
|
|
60
|
+
hasTotalMismatch = Math.abs(currentTotalActuals - expectedTotalActuals) > 0.01;
|
|
61
|
+
if (hasTagChanges || hasTotalMismatch) {
|
|
62
|
+
if (wallet.wallet) {
|
|
63
|
+
outdatedWallets.push(wallet.wallet);
|
|
64
|
+
if (hasTagChanges) {
|
|
65
|
+
tagChangedWallets.push(wallet.wallet);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
return {
|
|
71
|
+
needsSync: outdatedWallets.length > 0,
|
|
72
|
+
outdatedWallets,
|
|
73
|
+
tagChangedWallets,
|
|
74
|
+
};
|
|
75
|
+
}, [documents, wallets]);
|
|
76
|
+
return syncStatus;
|
|
77
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../editors/expense-report/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAGnD,eAAO,MAAM,MAAM,EAAE,YASpB,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Editor } from "./editor.js";
|
|
2
|
+
export const module = {
|
|
3
|
+
Component: Editor,
|
|
4
|
+
documentTypes: ["powerhouse/expense-report"],
|
|
5
|
+
config: {
|
|
6
|
+
id: "powerhouse-expense-report-editor",
|
|
7
|
+
disableExternalControls: true,
|
|
8
|
+
documentToolbarEnabled: true,
|
|
9
|
+
showSwitchboardLink: true,
|
|
10
|
+
},
|
|
11
|
+
};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { ExpenseReportDocument } from "../../document-models/expense-report/index.js";
|
|
2
|
+
export declare function useExpenseReportDocument(documentId: string | null | undefined): never[] | [ExpenseReportDocument, import("@powerhousedao/reactor-browser").DocumentDispatch<import("../../document-models/expense-report/gen/actions.js").ExpenseReportWalletAction>];
|
|
3
|
+
export declare function useSelectedExpenseReportDocument(): never[] | [ExpenseReportDocument, import("@powerhousedao/reactor-browser").DocumentDispatch<import("../../document-models/expense-report/gen/actions.js").ExpenseReportWalletAction>];
|
|
4
|
+
//# sourceMappingURL=useExpenseReportDocument.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useExpenseReportDocument.d.ts","sourceRoot":"","sources":["../../../editors/hooks/useExpenseReportDocument.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAEV,qBAAqB,EACtB,MAAM,+CAA+C,CAAC;AAEvD,wBAAgB,wBAAwB,CACtC,UAAU,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,yLAMtC;AAED,wBAAgB,gCAAgC,0LAG/C"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { useDocumentOfType, useSelectedDocumentId, } from "@powerhousedao/reactor-browser";
|
|
2
|
+
export function useExpenseReportDocument(documentId) {
|
|
3
|
+
return useDocumentOfType(documentId, "powerhouse/expense-report");
|
|
4
|
+
}
|
|
5
|
+
export function useSelectedExpenseReportDocument() {
|
|
6
|
+
const selectedDocumentId = useSelectedDocumentId();
|
|
7
|
+
return useExpenseReportDocument(selectedDocumentId);
|
|
8
|
+
}
|
package/dist/editors/index.d.ts
CHANGED
|
@@ -2,4 +2,5 @@ export { module as Invoice } from "./invoice/index.js";
|
|
|
2
2
|
export { module as ContributorBilling } from "./contributor-billing/index.js";
|
|
3
3
|
export { module as BillingStatement } from "./billing-statement/index.js";
|
|
4
4
|
export { module as Integrations } from "./integrations/index.js";
|
|
5
|
+
export { module as ExpenseReport } from "./expense-report/index.js";
|
|
5
6
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../editors/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,OAAO,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAE,MAAM,IAAI,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AAC9E,OAAO,EAAE,MAAM,IAAI,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAC1E,OAAO,EAAE,MAAM,IAAI,YAAY,EAAE,MAAM,yBAAyB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../editors/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,OAAO,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAE,MAAM,IAAI,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AAC9E,OAAO,EAAE,MAAM,IAAI,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAC1E,OAAO,EAAE,MAAM,IAAI,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACjE,OAAO,EAAE,MAAM,IAAI,aAAa,EAAE,MAAM,2BAA2B,CAAC"}
|
package/dist/editors/index.js
CHANGED
|
@@ -2,3 +2,4 @@ export { module as Invoice } from "./invoice/index.js";
|
|
|
2
2
|
export { module as ContributorBilling } from "./contributor-billing/index.js";
|
|
3
3
|
export { module as BillingStatement } from "./billing-statement/index.js";
|
|
4
4
|
export { module as Integrations } from "./integrations/index.js";
|
|
5
|
+
export { module as ExpenseReport } from "./expense-report/index.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"statusModalComponents.d.ts","sourceRoot":"","sources":["../../../../editors/invoice/components/statusModalComponents.tsx"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,eAAe,EAEpB,KAAK,OAAO,EAEb,MAAM,2CAA2C,CAAC;AAYnD,UAAU,6BAA6B;IACrC,cAAc,EAAE,MAAM,CAAC;IACvB,iBAAiB,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC;IAChE,KAAK,EAAE,eAAe,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC;IAC1C,QAAQ,EAAE,CAAC,MAAM,EAAE,GAAG,KAAK,IAAI,CAAC;IAChC,UAAU,EAAE,CAAC,UAAU,EAAE,OAAO,KAAK,IAAI,CAAC;CAC3C;AACD,wBAAgB,wBAAwB,CAAC,EACvC,cAAc,EACd,iBAAiB,EACjB,KAAK,EACL,QAAQ,EACR,UAAU,GACX,EAAE,6BAA6B,2CAqD/B;AAED,UAAU,8BAA8B;IACtC,KAAK,EAAE,eAAe,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC;IAC1C,QAAQ,EAAE,CAAC,MAAM,EAAE,GAAG,KAAK,IAAI,CAAC;IAChC,UAAU,EAAE,CAAC,UAAU,EAAE,OAAO,KAAK,IAAI,CAAC;IAC1C,eAAe,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1C,cAAc,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IACzC,WAAW,EAAE,OAAO,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;CACtB;AACD,wBAAgB,yBAAyB,CAAC,EACxC,KAAK,EACL,QAAQ,EACR,UAAU,EACV,eAAe,EACf,cAAc,EACd,WAAW,EACX,YAAY,GACb,EAAE,8BAA8B,
|
|
1
|
+
{"version":3,"file":"statusModalComponents.d.ts","sourceRoot":"","sources":["../../../../editors/invoice/components/statusModalComponents.tsx"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,eAAe,EAEpB,KAAK,OAAO,EAEb,MAAM,2CAA2C,CAAC;AAYnD,UAAU,6BAA6B;IACrC,cAAc,EAAE,MAAM,CAAC;IACvB,iBAAiB,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC;IAChE,KAAK,EAAE,eAAe,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC;IAC1C,QAAQ,EAAE,CAAC,MAAM,EAAE,GAAG,KAAK,IAAI,CAAC;IAChC,UAAU,EAAE,CAAC,UAAU,EAAE,OAAO,KAAK,IAAI,CAAC;CAC3C;AACD,wBAAgB,wBAAwB,CAAC,EACvC,cAAc,EACd,iBAAiB,EACjB,KAAK,EACL,QAAQ,EACR,UAAU,GACX,EAAE,6BAA6B,2CAqD/B;AAED,UAAU,8BAA8B;IACtC,KAAK,EAAE,eAAe,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC;IAC1C,QAAQ,EAAE,CAAC,MAAM,EAAE,GAAG,KAAK,IAAI,CAAC;IAChC,UAAU,EAAE,CAAC,UAAU,EAAE,OAAO,KAAK,IAAI,CAAC;IAC1C,eAAe,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1C,cAAc,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IACzC,WAAW,EAAE,OAAO,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;CACtB;AACD,wBAAgB,yBAAyB,CAAC,EACxC,KAAK,EACL,QAAQ,EACR,UAAU,EACV,eAAe,EACf,cAAc,EACd,WAAW,EACX,YAAY,GACb,EAAE,8BAA8B,2CAyBhC;AAED,wBAAgB,0BAA0B,CAAC,EACzC,YAAY,GACb,EAAE;IACD,YAAY,EAAE,MAAM,CAAC;CACtB,2CAIA;AAED,UAAU,gCAAgC;IACxC,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;CAC7C;AAED,wBAAgB,2BAA2B,CAAC,EAC1C,UAAU,EACV,aAAa,GACd,EAAE,gCAAgC,2CAgBlC;AAED,UAAU,6BAA6B;IACrC,aAAa,EAAE,MAAM,CAAC;IACtB,gBAAgB,EAAE,CAAC,aAAa,EAAE,MAAM,KAAK,IAAI,CAAC;CACnD;AAED,wBAAgB,wBAAwB,CAAC,EACvC,aAAa,EACb,gBAAgB,GACjB,EAAE,6BAA6B,2CA4B/B;AAED,UAAU,kCAAkC;IAC1C,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9C,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;CACrC;AAED,wBAAgB,6BAA6B,CAAC,EAC5C,WAAW,EACX,cAAc,EACd,MAAM,EACN,SAAS,GACV,EAAE,kCAAkC,2CA2BpC;AAED,UAAU,mCAAmC;IAC3C,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,IAAI,CAAC;CACjD;AAED,wBAAgB,8BAA8B,CAAC,EAC7C,YAAY,EACZ,eAAe,GAChB,EAAE,mCAAmC,2CAgBrC;AAED,UAAU,+BAA+B;IACvC,aAAa,EAAE,MAAM,CAAC;IACtB,gBAAgB,EAAE,CAAC,aAAa,EAAE,MAAM,KAAK,IAAI,CAAC;IAClD,QAAQ,EAAE,OAAO,EAAE,CAAC;CACrB;AAED,wBAAgB,0BAA0B,CAAC,EACzC,aAAa,EACb,gBAAgB,EAChB,QAAQ,GACT,EAAE,+BAA+B,2CAuCjC"}
|
|
@@ -27,7 +27,7 @@ export function IssueInvoiceModalContent({ invoiceNoInput, setInvoiceNoInput, st
|
|
|
27
27
|
}, value: state.dateIssued })] })] }));
|
|
28
28
|
}
|
|
29
29
|
export function RejectInvoiceModalContent({ state, dispatch, setWarning, setRejectReason, setFinalReason, finalReason, rejectReason, }) {
|
|
30
|
-
return (_jsxs("div", { className: "w-full", children: [_jsxs("div", { children: [_jsx("label", { className: "block mb-1 text-sm", children: "Reason:" }), _jsx(Textarea, { placeholder: "Add reason", value: rejectReason, onChange: (e) => {
|
|
30
|
+
return (_jsxs("div", { className: "w-full", children: [_jsxs("div", { children: [_jsx("label", { className: "block mb-1 text-sm", children: "Reason:" }), _jsx(Textarea, { autoExpand: true, placeholder: "Add reason", value: rejectReason, onChange: (e) => {
|
|
31
31
|
setRejectReason(e.target.value);
|
|
32
32
|
} })] }), _jsx("div", { className: "mt-4 flex justify-center gap-2", children: _jsx(Checkbox, { label: "Final", value: finalReason, onChange: () => {
|
|
33
33
|
setFinalReason(!finalReason);
|
|
@@ -37,7 +37,7 @@ export function FinalRejectionModalContent({ rejectReason, }) {
|
|
|
37
37
|
return (_jsxs("div", { children: ["Invoice is rejected with reason: ", rejectReason, " and is final."] }));
|
|
38
38
|
}
|
|
39
39
|
export function SchedulePaymentModalContent({ paymentRef, setPaymentRef, }) {
|
|
40
|
-
return (_jsx("div", { className: "w-full", children: _jsxs("div", { children: [_jsx("label", { className: "block mb-1 text-sm", children: "Payment Reference:" }), _jsx(Textarea, { placeholder: "Add payment reference", value: paymentRef, onChange: (e) => {
|
|
40
|
+
return (_jsx("div", { className: "w-full", children: _jsxs("div", { children: [_jsx("label", { className: "block mb-1 text-sm", children: "Payment Reference:" }), _jsx(Textarea, { autoExpand: true, placeholder: "Add payment reference", value: paymentRef, onChange: (e) => {
|
|
41
41
|
setPaymentRef(e.target.value);
|
|
42
42
|
} })] }) }));
|
|
43
43
|
}
|
|
@@ -62,12 +62,12 @@ export function ClosePaymentModalContent({ closureReason, setClosureReason, }) {
|
|
|
62
62
|
export function RegisterPaymentTxModalContent({ paymentDate, setPaymentDate, txnRef, setTxnRef, }) {
|
|
63
63
|
return (_jsxs("div", { className: "w-full", children: [_jsxs("div", { className: "mt-4", children: [_jsx("label", { className: "block mb-1 text-sm", children: "Payment Date:" }), _jsx(DatePicker, { name: "paymentDate", className: String.raw `w-full p-0`, onChange: (e) => {
|
|
64
64
|
setPaymentDate(e.target.value);
|
|
65
|
-
}, value: paymentDate })] }), _jsxs("div", { className: "mt-4", children: [_jsx("label", { className: "block mb-1 text-sm", children: "Transaction Reference:" }), _jsx(Textarea, { placeholder: "Add transaction reference", value: txnRef, onChange: (e) => {
|
|
65
|
+
}, value: paymentDate })] }), _jsxs("div", { className: "mt-4", children: [_jsx("label", { className: "block mb-1 text-sm", children: "Transaction Reference:" }), _jsx(Textarea, { autoExpand: true, placeholder: "Add transaction reference", value: txnRef, onChange: (e) => {
|
|
66
66
|
setTxnRef(e.target.value);
|
|
67
67
|
} })] })] }));
|
|
68
68
|
}
|
|
69
69
|
export function ReportPaymentIssueModalContent({ paymentIssue, setPaymentIssue, }) {
|
|
70
|
-
return (_jsx("div", { className: "w-full", children: _jsxs("div", { children: [_jsx("label", { className: "block mb-1 text-sm", children: "Payment Issue:" }), _jsx(Textarea, { placeholder: "Add payment issue", value: paymentIssue, onChange: (e) => {
|
|
70
|
+
return (_jsx("div", { className: "w-full", children: _jsxs("div", { children: [_jsx("label", { className: "block mb-1 text-sm", children: "Payment Issue:" }), _jsx(Textarea, { autoExpand: true, placeholder: "Add payment issue", value: paymentIssue, onChange: (e) => {
|
|
71
71
|
setPaymentIssue(e.target.value);
|
|
72
72
|
} })] }) }));
|
|
73
73
|
}
|
|
@@ -416,7 +416,7 @@ export default function Editor(props) {
|
|
|
416
416
|
})), onAddItem: (item) => dispatch(actions.addLineItem(item)), onDeleteItem: (input) => dispatch(actions.deleteLineItem(input)), onUpdateCurrency: (input) => {
|
|
417
417
|
setFiatMode(input.currency !== "USDS");
|
|
418
418
|
dispatch(actions.editInvoice(input));
|
|
419
|
-
}, onUpdateItem: (item) => dispatch(actions.editLineItem(item)), onEditingItemChange: setEditingItemValues, dispatch: dispatch, paymentAccounts: state.invoiceTags || [] }) }), _jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4", children: [_jsx("div", { className: "col-span-1", children: _jsx("div", { className: "", children: _jsx(Textarea, { label: "Notes", placeholder: "Add notes", autoExpand:
|
|
419
|
+
}, onUpdateItem: (item) => dispatch(actions.editLineItem(item)), onEditingItemChange: setEditingItemValues, dispatch: dispatch, paymentAccounts: state.invoiceTags || [] }) }), _jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4", children: [_jsx("div", { className: "col-span-1", children: _jsx("div", { className: "", children: _jsx(Textarea, { label: "Notes", placeholder: "Add notes", autoExpand: true, rows: 4, multiline: true, value: notes, onBlur: (e) => {
|
|
420
420
|
const newValue = e.target.value;
|
|
421
421
|
if (newValue !== state.notes) {
|
|
422
422
|
dispatch(actions.editInvoice({ notes: newValue }));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ingestPDF.d.ts","sourceRoot":"","sources":["../../../editors/invoice/ingestPDF.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAW,MAAM,wCAAwC,CAAC;
|
|
1
|
+
{"version":3,"file":"ingestPDF.d.ts","sourceRoot":"","sources":["../../../editors/invoice/ingestPDF.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAW,MAAM,wCAAwC,CAAC;AAYhF,wBAAsB,WAAW,CAAC,EAChC,IAAI,EACJ,QAAQ,GACT,EAAE;IACD,IAAI,EAAE,IAAI,CAAC;IACX,QAAQ,EAAE,CAAC,MAAM,EAAE,aAAa,KAAK,IAAI,CAAC;CAC3C,iBAUA;AAED,UAAU,gBAAgB;IACxB,QAAQ,EAAE,CAAC,MAAM,EAAE,aAAa,KAAK,IAAI,CAAC;IAC1C,kBAAkB,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;CAC7C;AAED,MAAM,CAAC,OAAO,UAAU,WAAW,CAAC,EAClC,QAAQ,EACR,kBAAkB,GACnB,EAAE,gBAAgB,2CAoRlB"}
|
|
@@ -4,9 +4,9 @@ import { actions } from "../../document-models/invoice/index.js";
|
|
|
4
4
|
import { toast } from "@powerhousedao/design-system";
|
|
5
5
|
import { uploadPdfChunked } from "./uploadPdfChunked.js";
|
|
6
6
|
import { getCountryCodeFromName } from "./utils/utils.js";
|
|
7
|
-
let GRAPHQL_URL =
|
|
8
|
-
if (!window.document.baseURI.includes(
|
|
9
|
-
GRAPHQL_URL =
|
|
7
|
+
let GRAPHQL_URL = 'http://localhost:4001/graphql/invoice';
|
|
8
|
+
if (!window.document.baseURI.includes('localhost')) {
|
|
9
|
+
GRAPHQL_URL = 'https://switchboard-dev.powerhouse.xyz/graphql/invoice';
|
|
10
10
|
}
|
|
11
11
|
export async function loadPDFFile({ file, dispatch, }) {
|
|
12
12
|
if (!file)
|
|
@@ -4,7 +4,7 @@ import { actions } from "../../document-models/invoice/index.js";
|
|
|
4
4
|
import { generateId } from "document-model";
|
|
5
5
|
let GRAPHQL_URL = "http://localhost:4001/graphql/invoice";
|
|
6
6
|
if (!window.document.baseURI.includes("localhost")) {
|
|
7
|
-
GRAPHQL_URL = "https://
|
|
7
|
+
GRAPHQL_URL = "https://switchboard-dev.powerhouse.xyz/graphql/invoice";
|
|
8
8
|
}
|
|
9
9
|
const InvoiceToGnosis = ({ docState, dispatch, }) => {
|
|
10
10
|
const [isLoading, setIsLoading] = useState(false);
|
|
@@ -4,7 +4,7 @@ import { actions } from "../../document-models/invoice/index.js";
|
|
|
4
4
|
import { generateId } from "document-model";
|
|
5
5
|
let GRAPHQL_URL = "http://localhost:4001/graphql/invoice";
|
|
6
6
|
if (!window.document.baseURI.includes("localhost")) {
|
|
7
|
-
GRAPHQL_URL = "https://
|
|
7
|
+
GRAPHQL_URL = "https://switchboard-dev.powerhouse.xyz/graphql/invoice";
|
|
8
8
|
}
|
|
9
9
|
const RequestFinance = ({ docState, dispatch, }) => {
|
|
10
10
|
const [isLoading, setIsLoading] = useState(false);
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
let GRAPHQL_URL = 'http://localhost:4001/graphql/invoice';
|
|
9
9
|
if (!window.document.baseURI.includes('localhost')) {
|
|
10
|
-
GRAPHQL_URL =
|
|
10
|
+
GRAPHQL_URL = 'https://switchboard-dev.powerhouse.xyz/graphql/invoice';
|
|
11
11
|
}
|
|
12
12
|
export async function uploadPdfChunked(pdfData, endpoint = GRAPHQL_URL, chunkSize = 500 * 1024, // 500KB chunks
|
|
13
13
|
onProgress) {
|