@powerhousedao/contributor-billing 1.0.0-dev.13 → 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.
@@ -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,4CAktC7B"}
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 - parallel with concurrency limit
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 CONCURRENCY_LIMIT = 5;
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
- // Process accounts in batches of 5 for parallel execution
253
- for (let i = 0; i < snapshotAccounts.length; i += CONCURRENCY_LIMIT) {
254
- const batch = snapshotAccounts.slice(i, i + CONCURRENCY_LIMIT);
255
- await Promise.all(batch.map(async (account) => {
256
- const accountEntry = accountEntryMap.get(account.accountId);
257
- setSyncingAccounts((prev) => new Set(prev).add(account.id));
258
- try {
259
- const result = await syncAccount(account, accountEntry, accountsDocumentId || undefined, startDate, endDate, dispatch, snapshotAccounts, document?.header?.id);
260
- if (result.documentId && accountEntry) {
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
- finally {
268
- setSyncingAccounts((prev) => {
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" })] }))] })] })] }), _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: [
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;AAeH,OAAO,KAAK,EACV,eAAe,EAGhB,MAAM,uDAAuD,CAAC;AAC/D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uDAAuD,CAAC;AAwE1F,wBAAgB,sBAAsB;mCAKjB,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,KAC1B,OAAO,CAAC;QACT,OAAO,EAAE,OAAO,CAAC;QACjB,OAAO,EAAE,MAAM,CAAC;QAChB,iBAAiB,CAAC,EAAE,MAAM,CAAC;QAC3B,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB,CAAC;EA2qBH"}
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 syncAccount = async (snapshotAccount, accountEntry, accountsDocumentId, startDate, endDate, dispatch, allSnapshotAccounts = [], snapshotDocumentId) => {
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
- const txDoc = documents.find((doc) => doc.header.id === accountTransactionsDocId &&
123
- doc.header.documentType === "powerhouse/account-transactions");
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
- const accountTxDocId = internalAccount.accountTransactionsId;
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
- // Find the AccountTransactions document
333
- const txDoc = documents?.find((doc) => doc.header.id === accountTxDocId &&
334
- doc.header.documentType === "powerhouse/account-transactions");
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) {
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.13",
4
+ "version": "1.0.0-dev.14",
5
5
  "license": "AGPL-3.0-only",
6
6
  "repository": {
7
7
  "type": "git",