Enhance Treasury page: add state management and account hierarchy visualization

- Added refreshKey state to force re-renders when accounts change
- Enhanced account hierarchy display with clickable subledger cards
- Improved transfer tab with validation messages
- Enhanced report generation with better UX
- Auto-select newly created accounts
- Update selected account after transfers
This commit is contained in:
defiQUG
2026-01-23 17:12:14 -08:00
parent 1e89413ec6
commit 8ea83d6088

View File

@@ -1,4 +1,4 @@
import React, { useState, useMemo } from 'react';
import React, { useState, useMemo, useEffect } from 'react';
import {
getAccountStore,
createTreasuryAccount,
@@ -23,15 +23,16 @@ export default function TreasuryPage() {
const [reportData, setReportData] = useState<SubledgerReport | null>(null);
const [isProcessing, setIsProcessing] = useState(false);
const [error, setError] = useState<string | null>(null);
const [refreshKey, setRefreshKey] = useState(0); // Force re-render when accounts change
// Get all accounts
// Get all accounts - refresh when refreshKey changes
const treasuryAccounts = useMemo(() => {
return accountStore.getAll().filter((acc) => acc.type === 'treasury') as TreasuryAccount[];
}, [accountStore]);
}, [refreshKey]);
const subledgerAccounts = useMemo(() => {
return accountStore.getAll().filter((acc) => acc.type === 'subledger') as SubledgerAccount[];
}, [accountStore]);
}, [refreshKey]);
// Get subledgers for selected treasury account
const subledgersForSelected = useMemo(() => {
@@ -51,6 +52,8 @@ export default function TreasuryPage() {
accountStore.add(account);
setShowCreateTreasury(false);
setError(null);
setRefreshKey((k) => k + 1); // Force re-render
setSelectedAccount(account); // Select the newly created account
} catch (err) {
setError(err instanceof Error ? err.message : 'Failed to create treasury account');
}
@@ -62,6 +65,8 @@ export default function TreasuryPage() {
accountStore.add(account);
setShowCreateSubledger(false);
setError(null);
setRefreshKey((k) => k + 1); // Force re-render
setSelectedAccount(account); // Select the newly created account
} catch (err) {
setError(err instanceof Error ? err.message : 'Failed to create subledger account');
}
@@ -73,6 +78,12 @@ export default function TreasuryPage() {
try {
executeSubledgerTransfer(fromId, toId, amount, currency, description);
setShowTransfer(false);
setRefreshKey((k) => k + 1); // Force re-render to update balances
// Update selected account if it was involved in the transfer
if (selectedAccount && (selectedAccount.id === fromId || selectedAccount.id === toId)) {
const updated = accountStore.get(selectedAccount.id);
if (updated) setSelectedAccount(updated);
}
} catch (err) {
setError(err instanceof Error ? err.message : 'Transfer failed');
} finally {
@@ -281,21 +292,53 @@ export default function TreasuryPage() {
{activeTab === 'transfers' && (
<div className="bg-white rounded-lg shadow p-6">
<h2 className="text-lg font-semibold mb-4">Inter-Subledger Transfers</h2>
<button
onClick={() => setShowTransfer(true)}
className="px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700"
>
New Transfer
</button>
{/* Transfer history would go here */}
<div className="flex justify-between items-center mb-4">
<h2 className="text-lg font-semibold">Inter-Subledger Transfers</h2>
<button
onClick={() => setShowTransfer(true)}
className="px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700"
disabled={subledgerAccounts.length < 2}
>
New Transfer
</button>
</div>
{subledgerAccounts.length < 2 ? (
<p className="text-gray-500">You need at least 2 subledger accounts to make transfers</p>
) : (
<div className="mt-4">
<p className="text-sm text-gray-600 mb-2">Recent transfers will appear here</p>
</div>
)}
</div>
)}
{activeTab === 'reports' && (
<div className="bg-white rounded-lg shadow p-6">
<h2 className="text-lg font-semibold mb-4">Subledger Reports</h2>
{reportData && (
<div className="flex justify-between items-center mb-4">
<h2 className="text-lg font-semibold">Subledger Reports</h2>
{subledgerAccounts.length > 0 && (
<button
onClick={() => {
if (selectedAccount && selectedAccount.type === 'subledger') {
const startDate = new Date();
startDate.setMonth(startDate.getMonth() - 1);
handleGenerateReport(selectedAccount.id, startDate, new Date());
}
}}
className="px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700"
disabled={!selectedAccount || selectedAccount.type !== 'subledger'}
>
Generate Report for Selected Account
</button>
)}
</div>
{!reportData ? (
<p className="text-gray-500">
{selectedAccount && selectedAccount.type === 'subledger'
? 'Click "Generate Report" to create a report for the selected subledger account'
: 'Select a subledger account and generate a report'}
</p>
) : (
<div className="mt-4 p-4 bg-gray-50 rounded-md">
<h3 className="font-semibold mb-2">Report Summary</h3>
<div className="grid grid-cols-2 gap-4">
@@ -494,16 +537,31 @@ export default function TreasuryPage() {
</p>
</div>
)}
{selectedAccount.type === 'treasury' && subledgersForSelected.length > 0 && (
{selectedAccount.type === 'treasury' && (
<div>
<p className="text-sm text-gray-600 mb-2">Subledgers ({subledgersForSelected.length})</p>
<ul className="space-y-1">
{subledgersForSelected.map((sub) => (
<li key={sub.id} className="text-sm text-gray-700">
{sub.name} ({sub.accountNumber})
</li>
))}
</ul>
{subledgersForSelected.length > 0 ? (
<div className="space-y-2">
{subledgersForSelected.map((sub) => (
<div
key={sub.id}
className="p-2 bg-gray-50 rounded border border-gray-200 cursor-pointer hover:bg-gray-100"
onClick={() => setSelectedAccount(sub)}
>
<p className="text-sm font-medium text-gray-900">{sub.name}</p>
<p className="text-xs text-gray-600">
{sub.accountNumber} | Balance: {sub.balance.toLocaleString('en-US', {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
})}{' '}
{sub.currency}
</p>
</div>
))}
</div>
) : (
<p className="text-sm text-gray-500">No subledgers yet</p>
)}
</div>
)}
{selectedAccount.type === 'subledger' && (