@powerhousedao/contributor-billing 0.1.4 → 0.1.6

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.
@@ -0,0 +1,287 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Document, Page, Text, View, StyleSheet } from "@react-pdf/renderer";
3
+ // Tailwind-inspired styles for PDF
4
+ const styles = StyleSheet.create({
5
+ page: {
6
+ padding: 32,
7
+ fontSize: 8,
8
+ fontFamily: "Helvetica",
9
+ backgroundColor: "#ffffff",
10
+ },
11
+ header: {
12
+ marginBottom: 20,
13
+ borderBottom: "1pt solid #e5e7eb",
14
+ paddingBottom: 12,
15
+ },
16
+ title: {
17
+ fontSize: 18,
18
+ fontWeight: "bold",
19
+ marginBottom: 6,
20
+ color: "#111827",
21
+ textAlign: "center",
22
+ },
23
+ period: {
24
+ fontSize: 9,
25
+ color: "#6b7280",
26
+ textAlign: "center",
27
+ marginTop: 2,
28
+ },
29
+ sectionTitle: {
30
+ fontSize: 12,
31
+ fontWeight: "bold",
32
+ marginTop: 16,
33
+ marginBottom: 8,
34
+ color: "#111827",
35
+ },
36
+ walletInfo: {
37
+ fontSize: 8,
38
+ color: "#6b7280",
39
+ marginBottom: 8,
40
+ },
41
+ table: {
42
+ marginBottom: 16,
43
+ },
44
+ tableHeader: {
45
+ flexDirection: "row",
46
+ borderBottom: "1pt solid #e5e7eb",
47
+ paddingBottom: 6,
48
+ marginBottom: 6,
49
+ backgroundColor: "#f9fafb",
50
+ paddingTop: 6,
51
+ paddingHorizontal: 6,
52
+ },
53
+ tableRow: {
54
+ flexDirection: "row",
55
+ paddingVertical: 4,
56
+ paddingHorizontal: 6,
57
+ borderBottom: "0.5pt solid #f3f4f6",
58
+ minHeight: 20,
59
+ },
60
+ tableRowAlt: {
61
+ flexDirection: "row",
62
+ paddingVertical: 4,
63
+ paddingHorizontal: 6,
64
+ backgroundColor: "#f9fafb",
65
+ borderBottom: "0.5pt solid #f3f4f6",
66
+ minHeight: 20,
67
+ },
68
+ subtotalRow: {
69
+ flexDirection: "row",
70
+ paddingVertical: 6,
71
+ paddingHorizontal: 6,
72
+ borderTop: "1pt solid #d1d5db",
73
+ marginTop: 3,
74
+ fontWeight: "bold",
75
+ backgroundColor: "#fafafa",
76
+ },
77
+ totalRow: {
78
+ flexDirection: "row",
79
+ paddingVertical: 6,
80
+ paddingHorizontal: 6,
81
+ borderTop: "2pt solid #111827",
82
+ marginTop: 3,
83
+ fontWeight: "bold",
84
+ backgroundColor: "#f3f4f6",
85
+ },
86
+ headerCell: {
87
+ fontSize: 7,
88
+ fontWeight: "bold",
89
+ color: "#374151",
90
+ textTransform: "uppercase",
91
+ letterSpacing: 0.3,
92
+ },
93
+ cell: {
94
+ fontSize: 8,
95
+ color: "#111827",
96
+ },
97
+ cellRight: {
98
+ fontSize: 8,
99
+ color: "#111827",
100
+ textAlign: "right",
101
+ },
102
+ cellBold: {
103
+ fontSize: 8,
104
+ color: "#111827",
105
+ fontWeight: "bold",
106
+ },
107
+ // Breakdown table columns - adjusted to match AggregatedExpensesTable
108
+ categoryCol: { width: "20%" },
109
+ budgetCol: { width: "11%", textAlign: "right" },
110
+ forecastCol: { width: "11%", textAlign: "right" },
111
+ actualsCol: { width: "11%", textAlign: "right" },
112
+ differenceCol: { width: "11%", textAlign: "right" },
113
+ commentsCol: { width: "25%", paddingLeft: 4 },
114
+ paymentsCol: { width: "11%", textAlign: "right" },
115
+ commentsText: {
116
+ fontSize: 7,
117
+ color: "#6b7280",
118
+ lineHeight: 1.4,
119
+ },
120
+ // Color styles for difference column
121
+ differenceNegative: {
122
+ color: "#dc2626", // red-600 for negative values
123
+ },
124
+ differenceNormal: {
125
+ color: "#111827", // gray-900 for positive or zero
126
+ },
127
+ pageNumber: {
128
+ position: "absolute",
129
+ bottom: 20,
130
+ left: 0,
131
+ right: 0,
132
+ textAlign: "center",
133
+ fontSize: 7,
134
+ color: "#6b7280",
135
+ },
136
+ });
137
+ // Format number as currency
138
+ const formatNumber = (value) => {
139
+ if (value === null || value === undefined)
140
+ return "0.00";
141
+ return value.toLocaleString("en-US", {
142
+ minimumFractionDigits: 2,
143
+ maximumFractionDigits: 2,
144
+ });
145
+ };
146
+ // Format date
147
+ const formatDate = (dateString) => {
148
+ if (!dateString)
149
+ return "";
150
+ const date = new Date(dateString);
151
+ return date.toLocaleDateString("en-US", {
152
+ month: "short",
153
+ day: "numeric",
154
+ year: "numeric",
155
+ });
156
+ };
157
+ export function ExpenseReportPDF({ periodStart, periodEnd, wallets, groups, }) {
158
+ // Create a map of groups with their parent info
159
+ const groupsMap = new Map();
160
+ groups.forEach((group) => {
161
+ groupsMap.set(group.id, { group });
162
+ });
163
+ groups.forEach((group) => {
164
+ if (group.parentId) {
165
+ const entry = groupsMap.get(group.id);
166
+ const parentEntry = groupsMap.get(group.parentId);
167
+ if (entry && parentEntry) {
168
+ entry.parent = parentEntry.group;
169
+ }
170
+ }
171
+ });
172
+ // Get line items for a wallet with group information
173
+ const getWalletLineItems = (wallet) => {
174
+ const lineItems = wallet.lineItems || [];
175
+ return lineItems
176
+ .filter((item) => item !== null && item !== undefined)
177
+ .map((item) => {
178
+ const groupInfo = item.group ? groupsMap.get(item.group) : undefined;
179
+ return {
180
+ ...item,
181
+ groupLabel: groupInfo?.group.label || item.label || undefined,
182
+ parentGroupId: groupInfo?.parent?.id || null,
183
+ parentGroupLabel: groupInfo?.parent?.label || undefined,
184
+ };
185
+ });
186
+ };
187
+ // Group line items by parent category
188
+ const groupLineItemsByParent = (lineItems) => {
189
+ const grouped = new Map();
190
+ lineItems.forEach((item) => {
191
+ const key = item.parentGroupId || "uncategorized";
192
+ if (!grouped.has(key)) {
193
+ grouped.set(key, []);
194
+ }
195
+ grouped.get(key).push(item);
196
+ });
197
+ // Convert to array and sort by hierarchy: Headcount, Non-Headcount, others, then uncategorized
198
+ const entries = Array.from(grouped.entries());
199
+ // Find Headcount and Non-Headcount group IDs
200
+ const headcountGroup = groups.find((g) => g.label === "Headcount Expenses");
201
+ const nonHeadcountGroup = groups.find((g) => g.label === "Non-Headcount Expenses");
202
+ entries.sort(([keyA], [keyB]) => {
203
+ // Uncategorized always goes last
204
+ if (keyA === "uncategorized")
205
+ return 1;
206
+ if (keyB === "uncategorized")
207
+ return -1;
208
+ // Headcount Expenses always first
209
+ if (keyA === headcountGroup?.id)
210
+ return -1;
211
+ if (keyB === headcountGroup?.id)
212
+ return 1;
213
+ // Non-Headcount Expenses always second
214
+ if (keyA === nonHeadcountGroup?.id)
215
+ return -1;
216
+ if (keyB === nonHeadcountGroup?.id)
217
+ return 1;
218
+ // For other groups, maintain their original order
219
+ return 0;
220
+ });
221
+ return entries.map(([key, items]) => ({
222
+ parentLabel: key === "uncategorized"
223
+ ? "Uncategorised"
224
+ : items[0]?.parentGroupLabel || "Unknown",
225
+ items,
226
+ }));
227
+ };
228
+ return (_jsx(Document, { children: _jsxs(Page, { size: "A4", style: styles.page, children: [_jsxs(View, { style: styles.header, children: [_jsx(Text, { style: styles.title, children: "Expense Report" }), periodStart && (_jsxs(Text, { style: styles.period, children: ["Period: ", formatDate(periodStart), " to ", formatDate(periodEnd)] }))] }), wallets.map((wallet, walletIndex) => {
229
+ const lineItems = getWalletLineItems(wallet);
230
+ const groupedItems = groupLineItemsByParent(lineItems);
231
+ // Calculate grand totals
232
+ const grandTotals = lineItems.reduce((acc, item) => ({
233
+ budget: acc.budget + (item.budget || 0),
234
+ forecast: acc.forecast + (item.forecast || 0),
235
+ actuals: acc.actuals + (item.actuals || 0),
236
+ payments: acc.payments + (item.payments || 0),
237
+ }), { budget: 0, forecast: 0, actuals: 0, payments: 0 });
238
+ return (_jsxs(View, { break: walletIndex > 0, children: [_jsxs(View, { wrap: false, children: [_jsxs(Text, { style: styles.sectionTitle, children: [periodStart &&
239
+ new Date(periodStart).toLocaleDateString("en-US", {
240
+ month: "short",
241
+ year: "numeric",
242
+ }), " ", "Breakdown"] }), _jsxs(Text, { style: styles.walletInfo, children: [wallet.name && `${wallet.name} • `, wallet.wallet || "Unknown Wallet"] })] }), _jsxs(View, { style: styles.table, children: [groupedItems.map((group, groupIndex) => {
243
+ const subtotals = group.items.reduce((acc, item) => ({
244
+ budget: acc.budget + (item.budget || 0),
245
+ forecast: acc.forecast + (item.forecast || 0),
246
+ actuals: acc.actuals + (item.actuals || 0),
247
+ payments: acc.payments + (item.payments || 0),
248
+ }), { budget: 0, forecast: 0, actuals: 0, payments: 0 });
249
+ const subtotalDifference = subtotals.forecast - subtotals.actuals;
250
+ return (_jsxs(View, { children: [groupIndex === 0 && (_jsxs(View, { style: styles.tableHeader, wrap: false, children: [_jsx(Text, { style: [styles.headerCell, styles.categoryCol], children: "Category" }), _jsx(Text, { style: [styles.headerCell, styles.budgetCol], children: "Budget" }), _jsx(Text, { style: [styles.headerCell, styles.forecastCol], children: "Forecast" }), _jsx(Text, { style: [styles.headerCell, styles.actualsCol], children: "Actuals" }), _jsx(Text, { style: [styles.headerCell, styles.differenceCol], children: "Difference" }), _jsx(Text, { style: [styles.headerCell, styles.commentsCol], children: "Comments" }), _jsx(Text, { style: [styles.headerCell, styles.paymentsCol], children: "Payments" })] })), _jsx(View, { style: {
251
+ paddingVertical: 6,
252
+ paddingHorizontal: 6,
253
+ backgroundColor: "#f9fafb",
254
+ borderBottom: "1pt solid #e5e7eb",
255
+ marginTop: groupIndex > 0 ? 8 : 0,
256
+ }, wrap: false, children: _jsx(Text, { style: {
257
+ fontSize: 9,
258
+ fontWeight: "bold",
259
+ color: "#111827",
260
+ }, children: group.parentLabel }) }), group.items.map((item, itemIndex) => {
261
+ const difference = (item.forecast || 0) - (item.actuals || 0);
262
+ const differenceStyle = difference < 0
263
+ ? styles.differenceNegative
264
+ : styles.differenceNormal;
265
+ return (_jsxs(View, { style: itemIndex % 2 === 0
266
+ ? styles.tableRow
267
+ : styles.tableRowAlt, children: [_jsx(Text, { style: [styles.cell, styles.categoryCol], children: item.groupLabel || item.label || "Uncategorised" }), _jsx(Text, { style: [styles.cellRight, styles.budgetCol], children: formatNumber(item.budget) }), _jsx(Text, { style: [styles.cellRight, styles.forecastCol], children: formatNumber(item.forecast) }), _jsx(Text, { style: [styles.cellRight, styles.actualsCol], children: formatNumber(item.actuals) }), _jsx(Text, { style: [
268
+ styles.cellRight,
269
+ styles.differenceCol,
270
+ differenceStyle,
271
+ ], children: formatNumber(difference) }), _jsx(View, { style: styles.commentsCol, children: item.comments && (_jsx(Text, { style: styles.commentsText, children: item.comments })) }), _jsx(Text, { style: [styles.cellRight, styles.paymentsCol], children: formatNumber(item.payments) })] }, item.id));
272
+ }), _jsxs(View, { style: styles.subtotalRow, children: [_jsx(Text, { style: [styles.cellBold, styles.categoryCol], children: "Subtotal" }), _jsx(Text, { style: [styles.cellRight, styles.budgetCol], children: formatNumber(subtotals.budget) }), _jsx(Text, { style: [styles.cellRight, styles.forecastCol], children: formatNumber(subtotals.forecast) }), _jsx(Text, { style: [styles.cellRight, styles.actualsCol], children: formatNumber(subtotals.actuals) }), _jsx(Text, { style: [
273
+ styles.cellRight,
274
+ styles.differenceCol,
275
+ subtotalDifference < 0
276
+ ? styles.differenceNegative
277
+ : styles.differenceNormal,
278
+ ], children: formatNumber(subtotalDifference) }), _jsx(View, { style: styles.commentsCol }), _jsx(Text, { style: [styles.cellRight, styles.paymentsCol], children: formatNumber(subtotals.payments) })] })] }, group.parentLabel));
279
+ }), _jsxs(View, { style: styles.totalRow, children: [_jsx(Text, { style: [styles.cellBold, styles.categoryCol], children: "Total" }), _jsx(Text, { style: [styles.cellRight, styles.budgetCol], children: formatNumber(grandTotals.budget) }), _jsx(Text, { style: [styles.cellRight, styles.forecastCol], children: formatNumber(grandTotals.forecast) }), _jsx(Text, { style: [styles.cellRight, styles.actualsCol], children: formatNumber(grandTotals.actuals) }), _jsx(Text, { style: [
280
+ styles.cellRight,
281
+ styles.differenceCol,
282
+ grandTotals.forecast - grandTotals.actuals < 0
283
+ ? styles.differenceNegative
284
+ : styles.differenceNormal,
285
+ ], children: formatNumber(grandTotals.forecast - grandTotals.actuals) }), _jsx(View, { style: styles.commentsCol }), _jsx(Text, { style: [styles.cellRight, styles.paymentsCol], children: formatNumber(grandTotals.payments) })] })] })] }, wallet.wallet || walletIndex));
286
+ }), _jsx(Text, { style: styles.pageNumber, render: ({ pageNumber, totalPages }) => `Page ${pageNumber} of ${totalPages}`, fixed: true })] }) }));
287
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"WalletsTable.d.ts","sourceRoot":"","sources":["../../../../editors/expense-report/components/WalletsTable.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,sDAAsD,CAAC;AAKlG,UAAU,iBAAiB;IACzB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,MAAM,EAAE,aAAa,EAAE,CAAC;IACxB,qBAAqB,EAAE,CAAC,aAAa,EAAE,MAAM,KAAK,IAAI,CAAC;IACvD,QAAQ,EAAE,GAAG,CAAC;CACf;AAED,wBAAgB,YAAY,CAAC,EAC3B,OAAO,EACP,MAAM,EACN,qBAAqB,EACrB,QAAQ,GACT,EAAE,iBAAiB,2CA+XnB"}
1
+ {"version":3,"file":"WalletsTable.d.ts","sourceRoot":"","sources":["../../../../editors/expense-report/components/WalletsTable.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,sDAAsD,CAAC;AAKlG,UAAU,iBAAiB;IACzB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,MAAM,EAAE,aAAa,EAAE,CAAC;IACxB,qBAAqB,EAAE,CAAC,aAAa,EAAE,MAAM,KAAK,IAAI,CAAC;IACvD,QAAQ,EAAE,GAAG,CAAC;CACf;AAED,wBAAgB,YAAY,CAAC,EAC3B,OAAO,EACP,MAAM,EACN,qBAAqB,EACrB,QAAQ,GACT,EAAE,iBAAiB,2CAwanB"}
@@ -122,7 +122,19 @@ export function WalletsTable({ wallets, groups, onAddBillingStatement, dispatch,
122
122
  minimumFractionDigits: 2,
123
123
  }).format(value);
124
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) => {
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: _jsxs("div", { className: "flex items-center justify-end gap-2", children: [needsSync && (_jsx("button", { onClick: () => {
126
+ // Sync all outdated wallets
127
+ [...tagChangedWallets, ...outdatedWallets].forEach((walletAddress) => {
128
+ const wallet = wallets.find(w => w.wallet === walletAddress);
129
+ if (wallet) {
130
+ handleSyncWallet(wallet);
131
+ }
132
+ });
133
+ }, disabled: syncingWallet !== null, className: `inline-flex items-center justify-center w-8 h-8 rounded-md transition-colors ${tagChangedWallets.length > 0
134
+ ? "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"
135
+ : "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"} disabled:opacity-50 disabled:cursor-not-allowed`, title: tagChangedWallets.length > 0
136
+ ? "ALERT: Tags have changed in billing statements - sync all wallets!"
137
+ : "Sync all wallets with latest billing statements", children: _jsx(RefreshCw, { size: 16, className: syncingWallet !== null ? "animate-spin" : "" }) })), _jsx("span", { 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
138
  const totals = calculateWalletTotals(wallet);
127
139
  const isHovered = hoveredWallet === wallet.wallet;
128
140
  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) => {
@@ -132,23 +144,23 @@ export function WalletsTable({ wallets, groups, onAddBillingStatement, dispatch,
132
144
  else if (e.key === "Escape") {
133
145
  handleCancelEditName();
134
146
  }
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 || "")
147
+ }, 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", children: totals.actuals === 0 && (!wallet.billingStatements || wallet.billingStatements.length === 0) ? (
148
+ // When actuals is 0 and no billing statements, only show the Add Bills button
149
+ _jsx("div", { className: "flex items-center justify-end", 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 for this wallet", children: [_jsx(Plus, { size: 16 }), _jsx("span", { children: "Add Bills" })] }) })) : (
150
+ // When actuals is not 0 or has billing statements, show compact buttons + value horizontally
151
+ _jsxs("div", { className: "flex items-center justify-end gap-2", children: [_jsx("button", { onClick: () => onAddBillingStatement(wallet.wallet || ""), className: "inline-flex items-center justify-center w-8 h-8 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 for this wallet", children: _jsx(Plus, { size: 16 }) }), wallet.billingStatements && wallet.billingStatements.length > 0 && (_jsx("button", { onClick: () => handleSyncWallet(wallet), disabled: syncingWallet === wallet.wallet, className: `inline-flex items-center justify-center w-8 h-8 rounded-md transition-colors ${tagChangedWallets.includes(wallet.wallet || "")
140
152
  ? "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
153
  : outdatedWallets.includes(wallet.wallet || "")
142
154
  ? "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
155
  : "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!"
156
+ ? "ALERT: Tags have changed - sync required!"
145
157
  : 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));
158
+ ? "Sync needed - billing statements updated"
159
+ : "Sync with latest billing statements", children: _jsx(RefreshCw, { size: 16, className: syncingWallet === wallet.wallet ? "animate-spin" : "" }) })), _jsx("span", { className: "text-sm font-medium 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
160
+ ? "text-red-600 dark:text-red-400"
161
+ : totals.difference < 0
162
+ ? "text-green-600 dark:text-green-400"
163
+ : "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: _jsx("div", { className: "flex items-center justify-end gap-2", children: _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
164
  }) })] }) })) : (_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
165
  if (e.key === "Enter") {
154
166
  handleAddWallet();
@@ -1 +1 @@
1
- {"version":3,"file":"editor.d.ts","sourceRoot":"","sources":["../../../editors/expense-report/editor.tsx"],"names":[],"mappings":"AAUA,wBAAgB,MAAM,4CAiLrB"}
1
+ {"version":3,"file":"editor.d.ts","sourceRoot":"","sources":["../../../editors/expense-report/editor.tsx"],"names":[],"mappings":"AAWA,wBAAgB,MAAM,4CAmMrB"}
@@ -1,13 +1,13 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useState, useMemo, useEffect } from "react";
2
+ import { useState, useMemo } from "react";
3
3
  import { useSelectedExpenseReportDocument } from "../hooks/useExpenseReportDocument.js";
4
4
  import { actions } from "../../document-models/expense-report/index.js";
5
- import { DatePicker } from "@powerhousedao/document-engineering";
5
+ import { DatePicker, Icon, Button } from "@powerhousedao/document-engineering";
6
6
  import { WalletsTable } from "./components/WalletsTable.js";
7
7
  import { AggregatedExpensesTable } from "./components/AggregatedExpensesTable.js";
8
8
  import { AddBillingStatementModal } from "./components/AddBillingStatementModal.js";
9
- import { useWalletSync } from "./hooks/useWalletSync.js";
10
- import { useSyncWallet } from "./hooks/useSyncWallet.js";
9
+ import { ExpenseReportPDF } from "./components/ExpenseReportPDF.js";
10
+ import { pdf } from "@react-pdf/renderer";
11
11
  export function Editor() {
12
12
  const [document, dispatch] = useSelectedExpenseReportDocument();
13
13
  const [selectedWallet, setSelectedWallet] = useState(null);
@@ -15,41 +15,6 @@ export function Editor() {
15
15
  const [periodStart, setPeriodStart] = useState(document.state.global.periodStart || "");
16
16
  const [periodEnd, setPeriodEnd] = useState(document.state.global.periodEnd || "");
17
17
  const { wallets, groups } = document.state.global;
18
- // Check sync status
19
- const { needsSync, outdatedWallets, tagChangedWallets } = useWalletSync(wallets);
20
- const { syncWallet } = useSyncWallet();
21
- // Auto-sync on component mount
22
- useEffect(() => {
23
- if (needsSync && outdatedWallets.length > 0) {
24
- if (tagChangedWallets.length > 0) {
25
- console.warn("⚠️ Tag changes detected in wallets:", tagChangedWallets);
26
- console.log("Auto-syncing wallets with tag changes:", outdatedWallets);
27
- }
28
- else {
29
- console.log("Auto-syncing wallets:", outdatedWallets);
30
- }
31
- // Sync each outdated wallet
32
- outdatedWallets.forEach((walletAddress) => {
33
- const wallet = wallets.find((w) => w.wallet === walletAddress);
34
- if (!wallet || !wallet.billingStatements || wallet.billingStatements.length === 0) {
35
- return;
36
- }
37
- // Remove all existing line items first
38
- const lineItemsToRemove = [...(wallet.lineItems || [])];
39
- lineItemsToRemove.forEach((item) => {
40
- if (item?.id) {
41
- dispatch(actions.removeLineItem({
42
- wallet: wallet.wallet,
43
- lineItemId: item.id,
44
- }));
45
- }
46
- });
47
- // Re-extract line items from billing statements
48
- const billingStatementIds = wallet.billingStatements.filter((id) => id !== null && id !== undefined);
49
- syncWallet(wallet.wallet, billingStatementIds, groups, dispatch);
50
- });
51
- }
52
- }, [needsSync, outdatedWallets, wallets, groups, dispatch, syncWallet]);
53
18
  // Handle period date changes
54
19
  const handlePeriodStartChange = (e) => {
55
20
  const value = e.target.value;
@@ -75,6 +40,27 @@ export function Editor() {
75
40
  setIsModalOpen(false);
76
41
  setSelectedWallet(null);
77
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
+ };
78
64
  // Format period title for the breakdown section
79
65
  const breakdownTitle = useMemo(() => {
80
66
  if (!periodStart)
@@ -84,5 +70,5 @@ export function Editor() {
84
70
  const year = date.getFullYear();
85
71
  return `${month} ${year} Breakdown`;
86
72
  }, [periodStart]);
87
- 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: "bg-white dark:bg-gray-800 border-b border-gray-200 dark:border-gray-700 px-8 py-6", children: _jsx("div", { className: "max-w-7xl mx-auto", children: _jsxs("div", { className: "text-center mb-6", children: [_jsx("h1", { className: "text-3xl font-bold text-gray-900 dark:text-white mb-2", 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 })] }) })] }) }) }), _jsx("div", { className: "flex-1 overflow-auto px-8 py-6", children: _jsxs("div", { className: "max-w-7xl mx-auto space-y-8", children: [_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 }))] }));
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 }))] }));
88
74
  }
@@ -1 +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;EA8DhB"}
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"}
@@ -23,10 +23,9 @@ export function useSyncWallet() {
23
23
  const group = groups.find((g) => g.label === expenseAccountTag.label);
24
24
  return group ? group.id : null;
25
25
  };
26
- // Clear existing line items for this wallet first
27
- // Note: We'll need to add a new action for this, or remove items one by one
28
- // For now, let's re-add all line items from billing statements
29
- // Extract and add line items from all billing statements
26
+ // Aggregate line items by category
27
+ const categoryAggregation = new Map();
28
+ // Extract and aggregate line items from all billing statements
30
29
  billingStatementIds.forEach((statementId) => {
31
30
  const statement = billingStatements.get(statementId);
32
31
  if (!statement?.state?.global?.lineItems)
@@ -34,22 +33,43 @@ export function useSyncWallet() {
34
33
  const lineItems = statement.state.global.lineItems || [];
35
34
  lineItems.forEach((billingLineItem) => {
36
35
  const groupId = mapTagToGroup(billingLineItem);
37
- const expenseLineItem = {
38
- id: generateId(),
39
- label: billingLineItem.description,
40
- group: groupId,
41
- budget: 0,
42
- actuals: billingLineItem.totalPriceCash || 0,
43
- forecast: 0,
44
- payments: 0,
45
- comments: null,
46
- };
47
- dispatch(actions.addLineItem({
48
- wallet: walletAddress,
49
- lineItem: expenseLineItem,
50
- }));
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
+ }
51
54
  });
52
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
+ });
53
73
  };
54
74
  return { syncWallet };
55
75
  }
@@ -1 +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,CA2F3D"}
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"}