@powerhousedao/contributor-billing 1.0.0-dev.12 → 1.0.0-dev.14
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/editors/snapshot-report-editor/editor.d.ts.map +1 -1
- package/dist/editors/snapshot-report-editor/editor.js +129 -20
- package/dist/editors/snapshot-report-editor/hooks/useSyncSnapshotAccount.d.ts +2 -1
- package/dist/editors/snapshot-report-editor/hooks/useSyncSnapshotAccount.d.ts.map +1 -1
- package/dist/editors/snapshot-report-editor/hooks/useSyncSnapshotAccount.js +29 -12
- package/dist/style.css +14 -1
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"editor.d.ts","sourceRoot":"","sources":["../../../editors/snapshot-report-editor/editor.tsx"],"names":[],"mappings":"AAwEA,MAAM,CAAC,OAAO,UAAU,MAAM,
|
|
1
|
+
{"version":3,"file":"editor.d.ts","sourceRoot":"","sources":["../../../editors/snapshot-report-editor/editor.tsx"],"names":[],"mappings":"AAwEA,MAAM,CAAC,OAAO,UAAU,MAAM,4CA43C7B"}
|
|
@@ -2,7 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
2
2
|
import { generateId, setName } from "document-model";
|
|
3
3
|
import { useState, useMemo, useEffect, useCallback } from "react";
|
|
4
4
|
import { useDocumentsInSelectedDrive, useParentFolderForSelectedNode, setSelectedNode, dispatchActions, } from "@powerhousedao/reactor-browser";
|
|
5
|
-
import { DocumentToolbar } from "@powerhousedao/design-system/connect";
|
|
5
|
+
import { DocumentToolbar, toast } from "@powerhousedao/design-system/connect";
|
|
6
6
|
import { Button, Select } from "@powerhousedao/document-engineering";
|
|
7
7
|
import { ChevronDown, ChevronUp, RefreshCw } from "lucide-react";
|
|
8
8
|
import { DateRangePicker } from "./components/DateRangePicker.js";
|
|
@@ -136,6 +136,48 @@ export default function Editor() {
|
|
|
136
136
|
suggested.setUTCHours(0, 0, 0, 0);
|
|
137
137
|
return suggested;
|
|
138
138
|
}, [documentsInDrive, reportPeriodStart, document.header.id]);
|
|
139
|
+
// Compute suggested end date from next month's snapshot startDate
|
|
140
|
+
const suggestedEndDate = useMemo(() => {
|
|
141
|
+
if (!documentsInDrive || !reportPeriodStart)
|
|
142
|
+
return null;
|
|
143
|
+
const currentPeriodStart = new Date(reportPeriodStart);
|
|
144
|
+
if (isNaN(currentPeriodStart.getTime()))
|
|
145
|
+
return null;
|
|
146
|
+
// Find all other snapshot reports in the drive
|
|
147
|
+
const otherSnapshots = documentsInDrive.filter((doc) => doc.header.documentType === "powerhouse/snapshot-report" &&
|
|
148
|
+
doc.header.id !== document.header.id);
|
|
149
|
+
// Find the snapshot whose reportPeriodStart is closest after this one
|
|
150
|
+
let nextSnapshot = null;
|
|
151
|
+
let closestDistance = Infinity;
|
|
152
|
+
for (const snap of otherSnapshots) {
|
|
153
|
+
const state = snap.state;
|
|
154
|
+
const rps = state?.global?.reportPeriodStart;
|
|
155
|
+
if (!rps)
|
|
156
|
+
continue;
|
|
157
|
+
const rpDate = new Date(rps);
|
|
158
|
+
if (isNaN(rpDate.getTime()))
|
|
159
|
+
continue;
|
|
160
|
+
// Must be after current period
|
|
161
|
+
const diff = rpDate.getTime() - currentPeriodStart.getTime();
|
|
162
|
+
if (diff > 0 && diff < closestDistance) {
|
|
163
|
+
closestDistance = diff;
|
|
164
|
+
nextSnapshot = {
|
|
165
|
+
startDate: state?.global?.startDate || null,
|
|
166
|
+
reportPeriodStart: rps,
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
if (!nextSnapshot?.startDate)
|
|
171
|
+
return null;
|
|
172
|
+
const nextStart = new Date(nextSnapshot.startDate);
|
|
173
|
+
if (isNaN(nextStart.getTime()))
|
|
174
|
+
return null;
|
|
175
|
+
// Suggested end = next startDate - 1 day (end of previous day)
|
|
176
|
+
const suggested = new Date(nextStart);
|
|
177
|
+
suggested.setUTCDate(suggested.getUTCDate() - 1);
|
|
178
|
+
suggested.setUTCHours(23, 59, 59, 999);
|
|
179
|
+
return suggested;
|
|
180
|
+
}, [documentsInDrive, reportPeriodStart, document.header.id]);
|
|
139
181
|
const handleSnapshotPeriodChange = useCallback((newFromDate, newToDate) => {
|
|
140
182
|
dispatch?.(setReportConfig({
|
|
141
183
|
startDate: newFromDate,
|
|
@@ -151,6 +193,13 @@ export default function Editor() {
|
|
|
151
193
|
const toISO = endDate || "";
|
|
152
194
|
handleSnapshotPeriodChange(fromISO, toISO);
|
|
153
195
|
}, [suggestedStartDate, endDate, handleSnapshotPeriodChange]);
|
|
196
|
+
const handleApplySuggestedEndDate = useCallback(() => {
|
|
197
|
+
if (!suggestedEndDate)
|
|
198
|
+
return;
|
|
199
|
+
const fromISO = startDate || "";
|
|
200
|
+
const toISO = suggestedEndDate.toISOString();
|
|
201
|
+
handleSnapshotPeriodChange(fromISO, toISO);
|
|
202
|
+
}, [suggestedEndDate, startDate, handleSnapshotPeriodChange]);
|
|
154
203
|
// Update selected period when document period changes externally
|
|
155
204
|
useEffect(() => {
|
|
156
205
|
if (savedPeriod && savedPeriod !== selectedPeriod) {
|
|
@@ -239,7 +288,7 @@ export default function Editor() {
|
|
|
239
288
|
});
|
|
240
289
|
}
|
|
241
290
|
};
|
|
242
|
-
// Handle sync all accounts
|
|
291
|
+
// Handle sync all accounts — Internal first (sequentially), then non-Internal
|
|
243
292
|
const handleSyncAll = async () => {
|
|
244
293
|
if (!startDate || !endDate) {
|
|
245
294
|
alert("Please set the Snapshot Period (start and end dates) before syncing");
|
|
@@ -247,36 +296,86 @@ export default function Editor() {
|
|
|
247
296
|
}
|
|
248
297
|
setIsSyncingAll(true);
|
|
249
298
|
const accountUpdates = [];
|
|
250
|
-
const
|
|
299
|
+
const totalAccounts = snapshotAccounts.length;
|
|
300
|
+
let syncedCount = 0;
|
|
301
|
+
let failedCount = 0;
|
|
302
|
+
toast(`Syncing ${totalAccounts} accounts...`, { type: "connect-loading" });
|
|
251
303
|
try {
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
304
|
+
const internalAccounts = snapshotAccounts.filter((a) => a.type === "Internal");
|
|
305
|
+
// Phase 1: Sync Internal accounts sequentially to avoid race conditions
|
|
306
|
+
// on concurrent dispatchActions to the same document
|
|
307
|
+
const accountTransactionsIdMap = new Map();
|
|
308
|
+
let latestSnapshotDoc;
|
|
309
|
+
for (const account of internalAccounts) {
|
|
310
|
+
const accountEntry = accountEntryMap.get(account.accountId);
|
|
311
|
+
setSyncingAccounts((prev) => new Set(prev).add(account.id));
|
|
312
|
+
try {
|
|
313
|
+
const result = await syncAccount(account, accountEntry, accountsDocumentId || undefined, startDate, endDate, dispatch, snapshotAccounts, document?.header?.id);
|
|
314
|
+
if (result.documentId) {
|
|
315
|
+
accountTransactionsIdMap.set(account.id, result.documentId);
|
|
316
|
+
if (accountEntry) {
|
|
261
317
|
accountUpdates.push({
|
|
262
318
|
id: accountEntry.id,
|
|
263
319
|
accountTransactionsId: result.documentId,
|
|
264
320
|
});
|
|
265
321
|
}
|
|
266
322
|
}
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
const newSet = new Set(prev);
|
|
270
|
-
newSet.delete(account.id);
|
|
271
|
-
return newSet;
|
|
272
|
-
});
|
|
323
|
+
if (result.updatedSnapshotDoc) {
|
|
324
|
+
latestSnapshotDoc = result.updatedSnapshotDoc;
|
|
273
325
|
}
|
|
274
|
-
|
|
326
|
+
if (result.success) {
|
|
327
|
+
syncedCount++;
|
|
328
|
+
}
|
|
329
|
+
else {
|
|
330
|
+
failedCount++;
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
finally {
|
|
334
|
+
setSyncingAccounts((prev) => {
|
|
335
|
+
const newSet = new Set(prev);
|
|
336
|
+
newSet.delete(account.id);
|
|
337
|
+
return newSet;
|
|
338
|
+
});
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
// Use fresh snapshot accounts from the latest dispatch result for Phase 2
|
|
342
|
+
const freshSnapshotAccounts = latestSnapshotDoc?.state?.global?.snapshotAccounts ?? snapshotAccounts;
|
|
343
|
+
const freshNonInternalAccounts = freshSnapshotAccounts.filter((a) => a.type !== "Internal");
|
|
344
|
+
// Phase 2: Sync non-Internal accounts sequentially
|
|
345
|
+
// These derive transactions from Internal accounts' AccountTransactions docs
|
|
346
|
+
for (const account of freshNonInternalAccounts) {
|
|
347
|
+
const accountEntry = accountEntryMap.get(account.accountId);
|
|
348
|
+
setSyncingAccounts((prev) => new Set(prev).add(account.id));
|
|
349
|
+
try {
|
|
350
|
+
const result = await syncAccount(account, accountEntry, accountsDocumentId || undefined, startDate, endDate, dispatch, freshSnapshotAccounts, document?.header?.id, accountTransactionsIdMap);
|
|
351
|
+
if (result.success) {
|
|
352
|
+
syncedCount++;
|
|
353
|
+
}
|
|
354
|
+
else {
|
|
355
|
+
failedCount++;
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
finally {
|
|
359
|
+
setSyncingAccounts((prev) => {
|
|
360
|
+
const newSet = new Set(prev);
|
|
361
|
+
newSet.delete(account.id);
|
|
362
|
+
return newSet;
|
|
363
|
+
});
|
|
364
|
+
}
|
|
275
365
|
}
|
|
276
366
|
// Single batch update to Accounts document
|
|
277
367
|
if (accountUpdates.length > 0 && accountsDocumentId) {
|
|
278
368
|
await dispatchActions(accountUpdates.map((u) => accountsActions.updateAccount(u)), accountsDocumentId);
|
|
279
369
|
}
|
|
370
|
+
if (failedCount === 0) {
|
|
371
|
+
toast(`Synced ${syncedCount} account${syncedCount !== 1 ? "s" : ""} successfully`, { type: "success" });
|
|
372
|
+
}
|
|
373
|
+
else {
|
|
374
|
+
toast(`Synced ${syncedCount}/${totalAccounts} accounts. ${failedCount} failed.`, { type: "warning" });
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
catch (error) {
|
|
378
|
+
toast(`Sync failed: ${error instanceof Error ? error.message : "Unknown error"}`, { type: "error" });
|
|
280
379
|
}
|
|
281
380
|
finally {
|
|
282
381
|
setIsSyncingAll(false);
|
|
@@ -455,7 +554,17 @@ export default function Editor() {
|
|
|
455
554
|
month: "short",
|
|
456
555
|
day: "numeric",
|
|
457
556
|
timeZone: "UTC",
|
|
458
|
-
}) }), " ", "to avoid gaps."] }), _jsx("button", { onClick: handleApplySuggestedStartDate, className: "px-2 py-1 text-xs font-medium text-indigo-700 bg-indigo-100 hover:bg-indigo-200 rounded transition-colors whitespace-nowrap", children: "Apply" })] }))
|
|
557
|
+
}) }), " ", "to avoid gaps."] }), _jsx("button", { onClick: handleApplySuggestedStartDate, className: "px-2 py-1 text-xs font-medium text-indigo-700 bg-indigo-100 hover:bg-indigo-200 rounded transition-colors whitespace-nowrap", children: "Apply" })] })), suggestedEndDate &&
|
|
558
|
+
endDate &&
|
|
559
|
+
new Date(endDate) >= suggestedEndDate && (_jsxs("div", { className: "mt-2 flex items-center gap-2 p-2 bg-amber-50 border border-amber-200 rounded-md", children: [_jsxs("span", { className: "text-xs text-amber-700 flex-1", children: ["Next snapshot period starts", " ", new Date(suggestedEndDate.getTime() + 86400000).toLocaleDateString("en-US", {
|
|
560
|
+
month: "short",
|
|
561
|
+
day: "numeric",
|
|
562
|
+
timeZone: "UTC",
|
|
563
|
+
}), ". End by", " ", _jsx("strong", { children: suggestedEndDate.toLocaleDateString("en-US", {
|
|
564
|
+
month: "short",
|
|
565
|
+
day: "numeric",
|
|
566
|
+
timeZone: "UTC",
|
|
567
|
+
}) }), " ", "to avoid overlap."] }), _jsx("button", { onClick: handleApplySuggestedEndDate, className: "px-2 py-1 text-xs font-medium text-amber-700 bg-amber-100 hover:bg-amber-200 rounded transition-colors whitespace-nowrap", children: "Apply" })] }))] })] })] }), _jsxs("div", { className: "bg-white rounded-lg shadow p-6", children: [_jsxs("div", { className: "flex justify-between items-center mb-4", children: [_jsx("h2", { className: "text-xl font-semibold", children: "Snapshot Accounts" }), _jsxs("div", { className: "flex gap-2", children: [snapshotAccounts.length > 0 && (_jsxs("button", { onClick: handleSyncAll, disabled: isSyncingAll || !startDate || !endDate, className: "px-4 py-2 bg-green-600 text-white rounded-md hover:bg-green-700 focus:outline-none focus:ring-2 focus:ring-green-500 disabled:bg-gray-400 disabled:cursor-not-allowed flex items-center gap-2", children: [_jsx(RefreshCw, { className: `w-4 h-4 ${isSyncingAll ? "animate-spin" : ""}` }), "Sync All"] })), _jsx("button", { onClick: handleOpenAccountPicker, disabled: !accountsDocumentId, className: "px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 disabled:bg-gray-400 disabled:cursor-not-allowed", children: "Add Account" })] })] }), snapshotAccounts.length === 0 ? (_jsxs("div", { className: "text-center py-12 text-gray-500", children: [_jsx("p", { children: "No accounts added yet" }), _jsx("p", { className: "text-sm mt-2", children: "Click \"Add Account\" to select accounts for this snapshot" })] })) : (_jsx("div", { className: "space-y-6", children: [
|
|
459
568
|
{
|
|
460
569
|
type: "Source",
|
|
461
570
|
label: "Source",
|
|
@@ -5,11 +5,12 @@
|
|
|
5
5
|
import type { SnapshotAccount } from "../../../document-models/snapshot-report/gen/types.js";
|
|
6
6
|
import type { AccountEntry } from "../../../document-models/accounts/gen/schema/types.js";
|
|
7
7
|
export declare function useSyncSnapshotAccount(): {
|
|
8
|
-
syncAccount: (snapshotAccount: SnapshotAccount, accountEntry: AccountEntry | undefined, accountsDocumentId: string | null | undefined, startDate: string | null | undefined, endDate: string | null | undefined, dispatch: any, allSnapshotAccounts?: SnapshotAccount[], snapshotDocumentId?: string) => Promise<{
|
|
8
|
+
syncAccount: (snapshotAccount: SnapshotAccount, accountEntry: AccountEntry | undefined, accountsDocumentId: string | null | undefined, startDate: string | null | undefined, endDate: string | null | undefined, dispatch: any, allSnapshotAccounts?: SnapshotAccount[], snapshotDocumentId?: string, accountTransactionsIdMap?: Map<string, string>) => Promise<{
|
|
9
9
|
success: boolean;
|
|
10
10
|
message: string;
|
|
11
11
|
transactionsAdded?: number;
|
|
12
12
|
documentId?: string;
|
|
13
|
+
updatedSnapshotDoc?: any;
|
|
13
14
|
}>;
|
|
14
15
|
};
|
|
15
16
|
//# sourceMappingURL=useSyncSnapshotAccount.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useSyncSnapshotAccount.d.ts","sourceRoot":"","sources":["../../../../editors/snapshot-report-editor/hooks/useSyncSnapshotAccount.ts"],"names":[],"mappings":"AAAA;;;GAGG;
|
|
1
|
+
{"version":3,"file":"useSyncSnapshotAccount.d.ts","sourceRoot":"","sources":["../../../../editors/snapshot-report-editor/hooks/useSyncSnapshotAccount.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAgBH,OAAO,KAAK,EACV,eAAe,EAGhB,MAAM,uDAAuD,CAAC;AAC/D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uDAAuD,CAAC;AAwE1F,wBAAgB,sBAAsB;mCAMjB,eAAe,gBAClB,YAAY,GAAG,SAAS,sBAClB,MAAM,GAAG,IAAI,GAAG,SAAS,aAClC,MAAM,GAAG,IAAI,GAAG,SAAS,WAC3B,MAAM,GAAG,IAAI,GAAG,SAAS,YACxB,GAAG,wBACQ,eAAe,EAAE,uBACjB,MAAM,6BACA,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,KAC7C,OAAO,CAAC;QACT,OAAO,EAAE,OAAO,CAAC;QACjB,OAAO,EAAE,MAAM,CAAC;QAChB,iBAAiB,CAAC,EAAE,MAAM,CAAC;QAC3B,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,kBAAkB,CAAC,EAAE,GAAG,CAAC;KAC1B,CAAC;EA6rBH"}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Hook for syncing snapshot accounts with account transactions documents
|
|
3
3
|
* Similar to useSyncWallet in expense-report
|
|
4
4
|
*/
|
|
5
|
-
import { useDocumentsInSelectedDrive, useSelectedDrive, dispatchActions, } from "@powerhousedao/reactor-browser";
|
|
5
|
+
import { useDocumentsInSelectedDrive, useSelectedDrive, useGetDocument, dispatchActions, } from "@powerhousedao/reactor-browser";
|
|
6
6
|
import { generateId } from "document-model/core";
|
|
7
7
|
import { accountTransactionsService } from "../../accounts-editor/services/accountTransactionsService.js";
|
|
8
8
|
import { balancesActions, transactionsActions, } from "../../../document-models/snapshot-report/index.js";
|
|
@@ -59,7 +59,8 @@ function calculateNonInternalStartingBalances(allTransactions, nonInternalAccoun
|
|
|
59
59
|
export function useSyncSnapshotAccount() {
|
|
60
60
|
const documents = useDocumentsInSelectedDrive();
|
|
61
61
|
const [selectedDrive] = useSelectedDrive();
|
|
62
|
-
const
|
|
62
|
+
const getDocument = useGetDocument();
|
|
63
|
+
const syncAccount = async (snapshotAccount, accountEntry, accountsDocumentId, startDate, endDate, dispatch, allSnapshotAccounts = [], snapshotDocumentId, accountTransactionsIdMap) => {
|
|
63
64
|
if (!documents || !startDate || !endDate) {
|
|
64
65
|
return {
|
|
65
66
|
success: false,
|
|
@@ -69,7 +70,7 @@ export function useSyncSnapshotAccount() {
|
|
|
69
70
|
try {
|
|
70
71
|
// Handle non-Internal accounts differently - derive from Internal accounts
|
|
71
72
|
if (snapshotAccount.type !== "Internal") {
|
|
72
|
-
return await syncNonInternalAccount(snapshotAccount, startDate, endDate, dispatch, allSnapshotAccounts, snapshotDocumentId);
|
|
73
|
+
return await syncNonInternalAccount(snapshotAccount, startDate, endDate, dispatch, allSnapshotAccounts, snapshotDocumentId, accountTransactionsIdMap);
|
|
73
74
|
}
|
|
74
75
|
// For Internal accounts: sync from AccountTransactions document
|
|
75
76
|
// Step 1: Ensure account transactions document exists
|
|
@@ -119,8 +120,13 @@ export function useSyncSnapshotAccount() {
|
|
|
119
120
|
message: "No account transactions document available",
|
|
120
121
|
};
|
|
121
122
|
}
|
|
122
|
-
|
|
123
|
-
|
|
123
|
+
let txDoc;
|
|
124
|
+
try {
|
|
125
|
+
txDoc = await getDocument(accountTransactionsDocId);
|
|
126
|
+
}
|
|
127
|
+
catch {
|
|
128
|
+
txDoc = undefined;
|
|
129
|
+
}
|
|
124
130
|
if (!txDoc?.state?.global?.transactions) {
|
|
125
131
|
return {
|
|
126
132
|
success: false,
|
|
@@ -280,8 +286,9 @@ export function useSyncSnapshotAccount() {
|
|
|
280
286
|
});
|
|
281
287
|
}
|
|
282
288
|
// Dispatch all actions in a single batch if we have a document ID
|
|
289
|
+
let updatedSnapshotDoc;
|
|
283
290
|
if (snapshotDocumentId && allActions.length > 0) {
|
|
284
|
-
await dispatchActions(allActions, snapshotDocumentId);
|
|
291
|
+
updatedSnapshotDoc = await dispatchActions(allActions, snapshotDocumentId);
|
|
285
292
|
}
|
|
286
293
|
else {
|
|
287
294
|
// Fallback to individual dispatches if no document ID
|
|
@@ -292,6 +299,7 @@ export function useSyncSnapshotAccount() {
|
|
|
292
299
|
message: `Synced ${periodTransactions.length} transactions and updated balances`,
|
|
293
300
|
transactionsAdded: periodTransactions.length,
|
|
294
301
|
documentId: accountTransactionsDocId,
|
|
302
|
+
updatedSnapshotDoc,
|
|
295
303
|
};
|
|
296
304
|
}
|
|
297
305
|
catch (error) {
|
|
@@ -307,7 +315,7 @@ export function useSyncSnapshotAccount() {
|
|
|
307
315
|
* Uses FULL transaction history from AccountTransactions documents (not just snapshot transactions)
|
|
308
316
|
* to correctly calculate opening balances from pre-period transactions
|
|
309
317
|
*/
|
|
310
|
-
const syncNonInternalAccount = async (snapshotAccount, startDate, endDate, dispatch, allSnapshotAccounts, snapshotDocumentId) => {
|
|
318
|
+
const syncNonInternalAccount = async (snapshotAccount, startDate, endDate, dispatch, allSnapshotAccounts, snapshotDocumentId, accountTransactionsIdMap) => {
|
|
311
319
|
try {
|
|
312
320
|
// Get Internal accounts
|
|
313
321
|
const internalAccounts = allSnapshotAccounts.filter((acc) => acc.type === "Internal");
|
|
@@ -326,12 +334,19 @@ export function useSyncSnapshotAccount() {
|
|
|
326
334
|
const internalAccountAddresses = new Set(internalAccounts.map((acc) => acc.accountAddress.toLowerCase()));
|
|
327
335
|
// Scan ALL transactions from each Internal account's AccountTransactions document
|
|
328
336
|
for (const internalAccount of internalAccounts) {
|
|
329
|
-
|
|
337
|
+
// Use override map first (from Phase 1 results), then fall back to snapshot state
|
|
338
|
+
const accountTxDocId = accountTransactionsIdMap?.get(internalAccount.id) ||
|
|
339
|
+
internalAccount.accountTransactionsId;
|
|
330
340
|
if (!accountTxDocId)
|
|
331
341
|
continue;
|
|
332
|
-
//
|
|
333
|
-
|
|
334
|
-
|
|
342
|
+
// Fetch fresh from document cache instead of stale React state
|
|
343
|
+
let txDoc;
|
|
344
|
+
try {
|
|
345
|
+
txDoc = await getDocument(accountTxDocId);
|
|
346
|
+
}
|
|
347
|
+
catch {
|
|
348
|
+
txDoc = undefined;
|
|
349
|
+
}
|
|
335
350
|
if (!txDoc?.state?.global?.transactions)
|
|
336
351
|
continue;
|
|
337
352
|
const allTxFromDoc = txDoc.state.global.transactions;
|
|
@@ -514,13 +529,14 @@ export function useSyncSnapshotAccount() {
|
|
|
514
529
|
}
|
|
515
530
|
});
|
|
516
531
|
// Dispatch all actions in a single batch if we have a document ID
|
|
532
|
+
let updatedSnapshotDoc;
|
|
517
533
|
if (snapshotDocumentId && allActions.length > 0) {
|
|
518
534
|
console.log("[syncNonInternalAccount] Dispatching actions:", {
|
|
519
535
|
accountId: snapshotAccount.id,
|
|
520
536
|
totalActions: allActions.length,
|
|
521
537
|
endingBalanceActions: allActions.filter((a) => a.type === "SET_ENDING_BALANCE").length,
|
|
522
538
|
});
|
|
523
|
-
await dispatchActions(allActions, snapshotDocumentId);
|
|
539
|
+
updatedSnapshotDoc = await dispatchActions(allActions, snapshotDocumentId);
|
|
524
540
|
}
|
|
525
541
|
else {
|
|
526
542
|
// Fallback to individual dispatches if no document ID
|
|
@@ -530,6 +546,7 @@ export function useSyncSnapshotAccount() {
|
|
|
530
546
|
success: true,
|
|
531
547
|
message: `Derived ${periodTransactions.length} transactions from Internal accounts`,
|
|
532
548
|
transactionsAdded: periodTransactions.length,
|
|
549
|
+
updatedSnapshotDoc,
|
|
533
550
|
};
|
|
534
551
|
}
|
|
535
552
|
catch (error) {
|
package/dist/style.css
CHANGED
|
@@ -2401,6 +2401,13 @@
|
|
|
2401
2401
|
}
|
|
2402
2402
|
}
|
|
2403
2403
|
}
|
|
2404
|
+
.hover\:bg-amber-200 {
|
|
2405
|
+
&:hover {
|
|
2406
|
+
@media (hover: hover) {
|
|
2407
|
+
background-color: var(--color-amber-200);
|
|
2408
|
+
}
|
|
2409
|
+
}
|
|
2410
|
+
}
|
|
2404
2411
|
.hover\:bg-blue-50 {
|
|
2405
2412
|
&:hover {
|
|
2406
2413
|
@media (hover: hover) {
|
|
@@ -6661,7 +6668,7 @@
|
|
|
6661
6668
|
}
|
|
6662
6669
|
}
|
|
6663
6670
|
}
|
|
6664
|
-
/*! tailwindcss v4.1
|
|
6671
|
+
/*! tailwindcss v4.2.1 | MIT License | https://tailwindcss.com */
|
|
6665
6672
|
@layer properties;
|
|
6666
6673
|
@layer theme, base, components, utilities;
|
|
6667
6674
|
@layer theme {
|
|
@@ -6927,6 +6934,12 @@
|
|
|
6927
6934
|
.sticky {
|
|
6928
6935
|
position: sticky;
|
|
6929
6936
|
}
|
|
6937
|
+
.start {
|
|
6938
|
+
inset-inline-start: var(--spacing);
|
|
6939
|
+
}
|
|
6940
|
+
.end {
|
|
6941
|
+
inset-inline-end: var(--spacing);
|
|
6942
|
+
}
|
|
6930
6943
|
.top-0 {
|
|
6931
6944
|
top: calc(var(--spacing) * 0);
|
|
6932
6945
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@powerhousedao/contributor-billing",
|
|
3
3
|
"description": "Document models that help contributors of open organisations get paid anonymously for their work on a monthly basis.",
|
|
4
|
-
"version": "1.0.0-dev.
|
|
4
|
+
"version": "1.0.0-dev.14",
|
|
5
5
|
"license": "AGPL-3.0-only",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -74,7 +74,7 @@
|
|
|
74
74
|
"@powerhousedao/common": "5.3.4",
|
|
75
75
|
"@powerhousedao/design-system": "5.3.4",
|
|
76
76
|
"@powerhousedao/document-engineering": "^1.40.1",
|
|
77
|
-
"@powerhousedao/service-offering": "0.0.
|
|
77
|
+
"@powerhousedao/service-offering": "0.0.12",
|
|
78
78
|
"@powerhousedao/vetra": "^5.3.4",
|
|
79
79
|
"@react-pdf/renderer": "^4.3.1",
|
|
80
80
|
"@safe-global/api-kit": "^4.0.0",
|