first commit
This commit is contained in:
commit
8b790b7601
86 changed files with 6348 additions and 0 deletions
86
ui_kits/web/LedgerScreen.jsx
Normal file
86
ui_kits/web/LedgerScreen.jsx
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
// LedgerScreen — per-entity account tree with balances
|
||||
|
||||
function TreeNode({ node, depth, expanded, onToggle }) {
|
||||
const indent = depth * 18;
|
||||
const isBranch = node.kind === "branch";
|
||||
return (
|
||||
<div className={`tree-node ${isBranch ? "branch" : "leaf"}`}
|
||||
onClick={() => isBranch && onToggle(node.path)}>
|
||||
<span style={{ width: indent }}></span>
|
||||
<span className="tree-chevron">
|
||||
{isBranch ? <Icon name={expanded ? "chevDown" : "chevRight"} size={12} color="var(--fg-muted)"/> : <span className="dot"></span>}
|
||||
</span>
|
||||
<span className="tree-path">
|
||||
{node.path.split(":").slice(-1)[0]}
|
||||
</span>
|
||||
<span className="tree-full">{node.path}</span>
|
||||
<span className="tree-amount"><Amount value={node.balance} ccy={node.ccy} /></span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function LedgerScreen({ entity }) {
|
||||
const data = window.AKEFIN_DATA.accountsByEntity;
|
||||
const [expanded, setExpanded] = React.useState(new Set(["Personal:Assets", "Personal:Expenses", "9TFox:Assets", "9TFox:Income"]));
|
||||
const toggle = (path) => setExpanded(prev => {
|
||||
const next = new Set(prev);
|
||||
next.has(path) ? next.delete(path) : next.add(path);
|
||||
return next;
|
||||
});
|
||||
|
||||
const entities = entity === "all" ? ["personal", "tfox", "finacode"] : [entity];
|
||||
|
||||
return (
|
||||
<div className="ledger-screen">
|
||||
<div className="screen-head">
|
||||
<div>
|
||||
<h1 className="screen-title">Ledger</h1>
|
||||
<div className="screen-sub">Read-only · synced from <code>~/akefin/ledger/</code> · git rev <code>e4a82c1</code></div>
|
||||
</div>
|
||||
<div className="screen-actions">
|
||||
<Btn><Icon name="refresh" size={13} /> PULL</Btn>
|
||||
<Btn variant="primary"><Icon name="import" size={13} /> EXPORT</Btn>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{entities.map(e => {
|
||||
const map = window.AKEFIN_DATA.entities.find(x => x.id === e);
|
||||
const accounts = data[e] || [];
|
||||
return (
|
||||
<div key={e} className="ledger-entity">
|
||||
<div className="ledger-entity-head">
|
||||
<span className="stripe" style={{ background: map.color }}></span>
|
||||
<span className="ledger-entity-name">{map.label}</span>
|
||||
<span className="ledger-entity-meta">{accounts.length} accounts · {e}-2026-03.ldgr</span>
|
||||
</div>
|
||||
<div className="tree">
|
||||
<div className="tree-head">
|
||||
<span></span>
|
||||
<span></span>
|
||||
<span>ACCOUNT</span>
|
||||
<span>FULL PATH</span>
|
||||
<span style={{textAlign:"right"}}>BALANCE</span>
|
||||
</div>
|
||||
{accounts.map(node => {
|
||||
if (node.kind === "leaf") {
|
||||
const parent = node.path.split(":").slice(0, -1).join(":");
|
||||
if (parent && parent.includes(":") && !expanded.has(parent.split(":").slice(0,2).join(":"))) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
const depth = node.path.split(":").length - 1;
|
||||
return (
|
||||
<TreeNode key={node.path} node={node} depth={depth}
|
||||
expanded={expanded.has(node.path)}
|
||||
onToggle={toggle} />
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Object.assign(window, { LedgerScreen });
|
||||
Loading…
Add table
Add a link
Reference in a new issue