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

86 lines
3.1 KiB
JavaScript

// RulesScreen — promote-suggested-rules view
function RuleCard({ rule, checked, onToggle, onApply }) {
return (
<div className="rule-card">
<div className="rule-head">
<div className="rule-pattern">
<span className="pattern-prefix">payee ~=</span>
<code className="ko">"{rule.pattern}"</code>
</div>
<div className="rule-occ">
<span className="rule-num">{rule.occurrences}</span>
<span className="rule-occ-lbl">OCCURRENCES · LAST 30d</span>
</div>
<ConfidenceChip score={rule.score} tier="llm" />
</div>
<div className="rule-map">
<span className="ko">{rule.pattern}</span>
<Icon name="arrowRight" size={14} color="var(--fg-muted)" />
<span className="rule-target">{rule.target}</span>
</div>
<div className="rule-examples">
<div className="rule-ex-label">MATCHING TRANSACTIONS</div>
{rule.examples.map((ex, i) => <div key={i} className="rule-ex">{ex}</div>)}
</div>
<div className="rule-actions">
<label className="rule-promote">
<input type="checkbox" checked={checked} onChange={onToggle} />
<span>Promote on next run</span>
</label>
<div style={{ flex: 1 }}></div>
<Btn variant="primary" onClick={onApply}>APPLY RULE</Btn>
<Btn>DISMISS</Btn>
</div>
</div>
);
}
function RulesScreen({ entity }) {
const data = window.AKEFIN_DATA.ruleSuggestions;
const [promoted, setPromoted] = React.useState(new Set(data.map(r => r.id)));
const [applied, setApplied] = React.useState(new Set());
const toggle = (id) => {
setPromoted(prev => {
const next = new Set(prev);
next.has(id) ? next.delete(id) : next.add(id);
return next;
});
};
const apply = (id) => setApplied(prev => new Set([...prev, id]));
const visible = data.filter(r => !applied.has(r.id));
return (
<div className="rules-screen">
<div className="screen-head">
<div>
<h1 className="screen-title">Rule suggestions</h1>
<div className="screen-sub">{visible.length} suggested · {promoted.size} promoted on next run · last AI pass 12 minutes ago</div>
</div>
<div className="screen-actions">
<Btn><Icon name="refresh" size={13} /> RE-RUN AI PASS</Btn>
<Btn variant="primary">PROMOTE ALL</Btn>
</div>
</div>
<TermFrame title="AKEFIN — RULE PIPELINE · TIER 1" status="ok">
<span className="m">$</span> akefin rules:suggest --entity {entity === "all" ? "*" : entity} --since 30d{"\n"}
<span className="m">analysed 1,247 transactions · 5 high-frequency patterns matched ·</span>
<span style={{color:"var(--conf-rules)"}}> 218 future rows would auto-categorize</span>
</TermFrame>
<div className="rule-grid">
{visible.map(r => (
<RuleCard key={r.id} rule={r}
checked={promoted.has(r.id)}
onToggle={() => toggle(r.id)}
onApply={() => apply(r.id)} />
))}
</div>
</div>
);
}
Object.assign(window, { RulesScreen });