akefin-design-system/ui_kits/mobile/MobileApp.jsx
2026-05-23 11:59:45 +09:00

72 lines
3 KiB
JavaScript

// MobileApp — stateful navigation between screens for ONE device frame
function MobileApp({ initial = "queue", initialTx = null, initialEntity = "all", initialPickerOpen = false }) {
const [screen, setScreen] = React.useState(initial);
const [entity, setEntity] = React.useState(initialEntity);
const [transactions, setTransactions] = React.useState(window.AKEFIN_DATA.transactions);
const [activeTxId, setActiveTxId] = React.useState(initialTx);
const [pickerOpen, setPickerOpen] = React.useState(initialPickerOpen);
const tx = activeTxId ? transactions.find(t => t.id === activeTxId) : null;
const [account, setAccount] = React.useState(tx?.suggestedAccount || null);
React.useEffect(() => {
if (tx) setAccount(tx.suggestedAccount || null);
}, [tx?.id]);
const openTx = (id) => { setActiveTxId(id); setScreen("detail"); };
const back = () => { setScreen("queue"); setActiveTxId(null); };
const approve = () => {
setTransactions(prev => prev.filter(t => t.id !== activeTxId));
back();
};
const skip = () => {
setTransactions(prev => prev.filter(t => t.id !== activeTxId));
back();
};
return (
<div className="m-app">
<div className="m-app-body">
{screen === "queue" && <MQueueScreen transactions={transactions} entity={entity} onTap={openTx} />}
{screen === "detail" && <MDetailScreen tx={tx} onBack={back} onApprove={approve} onSkip={skip} account={account} onOpenPicker={() => setPickerOpen(true)} />}
{screen === "rules" && <MRulesScreen entity={entity} />}
{screen === "ledger" && <MLedgerScreen entity={entity} />}
{screen === "import" && <MImportScreen entity={entity} />}
</div>
<MTabBar active={screen === "detail" ? "queue" : screen} onChange={(s) => { setActiveTxId(null); setScreen(s); }} />
<MAccountPicker open={pickerOpen} onClose={() => setPickerOpen(false)}
onPick={(a) => { setAccount(a); setPickerOpen(false); }}
current={account} />
</div>
);
}
// A tiny rules screen for mobile
function MRulesScreen({ entity }) {
const rules = window.AKEFIN_DATA.ruleSuggestions;
return (
<div className="m-screen">
<MHeader eyebrow="AI SUGGESTIONS" title="Rules" />
<div className="m-list">
{rules.map(r => (
<div key={r.id} className="m-rule-card">
<div className="m-rule-top">
<code className="m-rule-pattern ko">"{r.pattern}"</code>
<MConfidenceChip score={r.score} tier="llm" />
</div>
<div className="m-rule-map">
<span className="m-arrow"></span>
<span className="mono">{r.target}</span>
</div>
<div className="m-rule-foot">
<span className="m-rule-occ"><span className="num">{r.occurrences}</span> matches · 30d</span>
<button className="m-rule-promote">Promote </button>
</div>
</div>
))}
</div>
</div>
);
}
Object.assign(window, { MobileApp, MRulesScreen });