MeshiTrack/docs/design/src/OtherPages.jsx

519 lines
28 KiB
React
Raw Normal View History

// Medium-fi placeholder pages for the remaining medicine + purchasing sections.
const { MED: M2, MEDICINES: MEDS2, CABINET: C2, REGIMENS: REG2, STORES: ST2, PRICES: PR2, PURCHASES: PU2, ACTIVITY: AC2 } = window.MESHI;
// ---- Library ----
const LibraryPage = () => {
const [q, setQ] = useState('');
const rows = MEDS2.filter(m => m.name.toLowerCase().includes(q.toLowerCase()));
return (
<div className="mt-page">
<div className="sub-toolbar">
<div className="cab-filters__search" style={{flex:1, maxWidth: 320}}>
<Icon name="search" size={13}/>
<input placeholder="Search medicines…" value={q} onChange={e=>setQ(e.target.value)} style={{width:'100%'}}/>
</div>
<div style={{display:'flex', gap: 8}}>
<button className="mt-btn mt-btn--ghost">All categories <Icon name="chevDown" size={12}/></button>
<button className="mt-btn mt-btn--ghost">All forms <Icon name="chevDown" size={12}/></button>
<button className="mt-btn mt-btn--primary"><Icon name="plus" size={12}/> Add medicine</button>
</div>
</div>
<div className="mt-card" style={{overflow:'hidden'}}>
{rows.map((m, i) => (
<div key={m.id} className="lib-row">
<div className="cab-card__swatch cab-card__swatch--sm" style={{'--c':'var(--viz-'+m.color+')'}}>
<Icon name={m.form === 'Injection' ? 'injection' : m.form === 'Capsule' ? 'capsule' : 'pill'} size={12}/>
</div>
<div style={{flex:1}}>
<div style={{fontWeight:500, fontSize:13, color:'var(--ink-strong)'}}>{m.name}</div>
<div style={{fontSize:11, color:'var(--ink-muted)'}}>{m.strength} · {m.form}</div>
</div>
<span className={'mt-pill mt-pill--' + (m.category === 'Prescription' ? 'info' : 'ghost')}>{m.category}</span>
<button className="mt-btn mt-btn--subtle"><Icon name="edit" size={12}/></button>
<button className="mt-btn mt-btn--subtle"><Icon name="trash" size={12}/></button>
</div>
))}
</div>
</div>
);
};
// ---- Regimens ----
const RegimensPage = () => (
<div className="mt-page">
<div className="sub-toolbar">
<div style={{display:'flex', gap:8}}>
<button className="mt-btn mt-btn--ghost">All regimens <Icon name="chevDown" size={12}/></button>
<button className="mt-btn mt-btn--ghost"><Icon name="trend" size={12}/> Burn rate</button>
</div>
<button className="mt-btn mt-btn--primary"><Icon name="plus" size={12}/> New regimen</button>
</div>
<div className="mt-col">
{REG2.map(r => (
<div key={r.id} className="mt-card" style={{padding: 18}}>
<div style={{display:'flex', justifyContent:'space-between', alignItems:'flex-start', gap: 16}}>
<div>
<div style={{display:'flex', alignItems:'center', gap: 8, marginBottom: 4}}>
<span style={{fontFamily:'var(--font-display)', fontSize: 18, fontWeight: 500, color:'var(--ink-strong)'}}>Aeri's {r.name}</span>
<span className="mt-pill mt-pill--ok">Active</span>
</div>
<div style={{fontSize:12, color:'var(--ink-muted)'}}>{r.items.length} medication{r.items.length>1?'s':''} · {r.time} · {r.freq}</div>
</div>
<div style={{display:'flex', gap: 6}}>
<button className="mt-btn mt-btn--ghost">Deactivate</button>
<button className="mt-btn mt-btn--subtle"><Icon name="edit" size={12}/></button>
<button className="mt-btn mt-btn--subtle"><Icon name="trash" size={12}/></button>
</div>
</div>
<div style={{display:'flex', flexWrap:'wrap', gap: 6, marginTop: 14}}>
{r.items.map(it => {
const m = M2[it.medId];
return (
<span key={it.medId} className="mt-pill mt-pill--outline" style={{padding: '4px 10px', fontSize: 11}}>
<span style={{background:'var(--viz-'+m.color+')', width:6, height:6, borderRadius:3, display:'inline-block', marginRight: 4}}/>
<strong style={{fontWeight: 500, color:'var(--ink-strong)'}}>{m.name}</strong>
<span style={{marginLeft:4, color:'var(--ink-muted)'}}>{it.qty} {it.unit}</span>
</span>
);
})}
</div>
</div>
))}
</div>
</div>
);
// ---- Organizer ----
const OrganizerPage = () => {
const [regimenId, setRegimenId] = useState(REG2[1].id);
const [days, setDays] = useState(7);
const regimen = REG2.find(r => r.id === regimenId);
// Compute inventory impact: for each item in regimen, how many units will be consumed?
const impact = regimen.items.map(it => {
const m = M2[it.medId];
const cabEntry = C2.find(c => c.medId === it.medId);
const onHand = cabEntry ? cabEntry.qty : 0;
const needed = it.qty * days;
const after = onHand - needed;
const perDay = cabEntry ? (cabEntry.perDose || 1) / (cabEntry.daysPerUnit || 1) : 1;
const daysAfter = perDay > 0 ? Math.floor(Math.max(0, after) / perDay) : 0;
const status = after < 0 ? 'short' : after < needed * 0.5 ? 'low' : 'ok';
return { m, it, onHand, needed, after, daysAfter, status, cabEntry };
});
const anyShort = impact.some(i => i.status === 'short');
const anyLow = impact.some(i => i.status === 'low');
return (
<div className="mt-page">
<div className="org-hero">
<div className="org-hero__controls">
<div>
<div style={{fontSize:10, color:'var(--ink-faint)', textTransform:'uppercase', letterSpacing:'.08em', fontWeight:500}}>Fill from regimen</div>
<select className="org-hero__select" value={regimenId} onChange={e => setRegimenId(e.target.value)}>
{REG2.map(r => <option key={r.id} value={r.id}>Aeri's {r.name}</option>)}
</select>
<div style={{fontSize:12, color:'var(--ink-muted)', marginTop: 4}}>{regimen.time} · {regimen.items.length} medicines · {regimen.freq}</div>
</div>
<div className="org-hero__divider"/>
<div>
<div style={{fontSize:10, color:'var(--ink-faint)', textTransform:'uppercase', letterSpacing:'.08em', fontWeight:500, marginBottom:8}}>Days to fill</div>
<div className="org-hero__stepper">
<button onClick={() => setDays(Math.max(1, days - 1))}></button>
<span className="num">{days}</span>
<button onClick={() => setDays(Math.min(30, days + 1))}>+</button>
</div>
<div className="org-hero__presets">
{[3, 7, 14, 30].map(d => (
<button key={d} className={'org-hero__preset' + (days === d ? ' is-active' : '')} onClick={() => setDays(d)}>{d}d</button>
))}
</div>
</div>
</div>
<div className="org-hero__summary">
<div className="org-hero__sumRow">
<div style={{fontSize:10, color:'var(--ink-faint)', textTransform:'uppercase', letterSpacing:'.08em', fontWeight:500}}>This fill will dispense</div>
<div style={{fontSize: 22, fontWeight: 600, color:'var(--ink-strong)', letterSpacing:'-0.01em'}} className="num">
{impact.reduce((a,b) => a + b.needed, 0)} <span style={{fontSize:13, fontWeight:400, color:'var(--ink-muted)'}}>units across {impact.length} medicines</span>
</div>
</div>
{anyShort ? (
<div className="org-alert org-alert--danger">
<Icon name="alert" size={14}/>
<div>
<strong>Not enough stock.</strong> {impact.filter(i => i.status === 'short').length} medicine{impact.filter(i => i.status === 'short').length > 1 ? 's are' : ' is'} short for this fill.
</div>
<button className="mt-btn mt-btn--primary">Add to shopping list</button>
</div>
) : anyLow ? (
<div className="org-alert org-alert--warn">
<Icon name="alert" size={14}/>
<div><strong>Low after fill.</strong> Some meds will drop below 50% headroom.</div>
</div>
) : (
<div className="org-alert org-alert--ok">
<Icon name="check" size={14}/>
<div><strong>Ready to dispense.</strong> Cabinet has enough stock with comfortable headroom.</div>
</div>
)}
<div style={{display:'flex', gap: 8}}>
<button className="mt-btn mt-btn--primary" disabled={anyShort}><Icon name="zap" size={12}/> Dispense {days}-day fill</button>
<button className="mt-btn mt-btn--ghost">Print label</button>
<div style={{flex:1}}/>
<button className="mt-btn mt-btn--ghost">Fill history</button>
</div>
</div>
</div>
{/* Inventory impact table */}
<div className="mt-card" style={{marginTop: 16}}>
<div className="mt-card__head">
<div>
<div className="mt-card__title">Inventory impact</div>
<div className="mt-card__sub">What this fill will take from the cabinet</div>
</div>
</div>
<div className="org-impact">
<div className="org-impact__head">
<div>Medicine</div>
<div style={{textAlign:'right'}}>On hand</div>
<div style={{textAlign:'right'}}>Needed</div>
<div>After fill</div>
<div style={{textAlign:'right'}}>Days left</div>
</div>
{impact.map(row => {
const m = row.m;
const pct = row.onHand > 0 ? Math.max(0, Math.min(100, (row.after / row.onHand) * 100)) : 0;
return (
<div key={m.id} className={'org-impact__row org-impact__row--' + row.status}>
<div style={{display:'flex', alignItems:'center', gap: 10}}>
<div className="cab-card__swatch cab-card__swatch--sm" style={{'--c':'var(--viz-'+m.color+')'}}>
<Icon name={m.form === 'Injection' ? 'injection' : m.form === 'Capsule' ? 'capsule' : 'pill'} size={12}/>
</div>
<div>
<div style={{fontWeight:500, fontSize:13, color:'var(--ink-strong)'}}>{m.name}</div>
<div style={{fontSize:11, color:'var(--ink-muted)'}}>{row.it.qty} × {days} days = {row.needed} {m.form.toLowerCase()}</div>
</div>
</div>
<div style={{textAlign:'right'}}><span className="num" style={{fontSize:14, fontWeight:600}}>{row.onHand}</span></div>
<div style={{textAlign:'right'}}><span className="num" style={{fontSize:14, color:'var(--ink-muted)'}}>{row.needed}</span></div>
<div style={{display:'flex', alignItems:'center', gap: 8}}>
<div className="org-impact__bar">
<div className="org-impact__barBg"/>
<div className="org-impact__barFill" style={{width: Math.max(0, pct) + '%', background: row.status === 'short' ? 'var(--danger)' : row.status === 'low' ? 'var(--warn)' : 'var(--ok)'}}/>
</div>
<span className="num" style={{fontSize:13, fontWeight:600, color: row.after < 0 ? 'var(--danger)' : 'var(--ink-strong)', minWidth: 38, textAlign:'right'}}>{row.after < 0 ? row.after : row.after}</span>
</div>
<div style={{textAlign:'right'}}>
{row.status === 'short'
? <span className="mt-pill mt-pill--danger">Short</span>
: <span className="num" style={{fontSize:13, color: row.status === 'low' ? 'var(--warn)' : 'var(--ink-muted)'}}>{row.daysAfter}d</span>}
</div>
</div>
);
})}
</div>
</div>
</div>
);
};
// ---- Activity ----
const ActivityPage = () => {
const { SPENDING } = window.MESHI;
return (
<div className="mt-page">
<div className="mt-card" style={{marginBottom: 16}}>
<div className="mt-card__head">
<div>
<div className="mt-card__title">Spending summary</div>
<div className="mt-card__sub">Last 6 months</div>
</div>
<div className="mt-row" style={{gap:6}}>
<button className="mt-btn mt-btn--ghost">This year <Icon name="chevDown" size={12}/></button>
<button className="mt-btn mt-btn--ghost">All medicines <Icon name="chevDown" size={12}/></button>
</div>
</div>
<div style={{padding:'18px', display:'grid', gridTemplateColumns:'2fr 1fr', gap: 20}}>
<svg viewBox="0 0 360 180" width="100%" height="180">
{SPENDING.map((s, i) => {
const max = Math.max(...SPENDING.map(x=>x.amount));
const h = (s.amount / max) * 140;
const x = 20 + i * 56;
return (
<g key={s.month}>
<rect x={x} y={160 - h} width="36" height={h} rx="3" fill="var(--brand)" opacity={0.3 + (i/SPENDING.length)*0.7}/>
<text x={x+18} y="175" textAnchor="middle" fontSize="9" fill="var(--ink-faint)">{s.month.slice(5)}</text>
</g>
);
})}
</svg>
<div className="mt-col">
<div><div style={{fontSize:10, color:'var(--ink-faint)', textTransform:'uppercase', letterSpacing:'.06em'}}>Total spent</div><div style={{fontFamily:'var(--font-display)', fontSize:28, fontWeight:500, color:'var(--ink-strong)'}} className="num">{fmtJPY(SPENDING.reduce((a,b)=>a+b.amount,0))}</div></div>
<div><div style={{fontSize:10, color:'var(--ink-faint)', textTransform:'uppercase', letterSpacing:'.06em'}}>Monthly average</div><div className="num" style={{fontSize:18, fontWeight:500}}>{fmtJPY(Math.round(SPENDING.reduce((a,b)=>a+b.amount,0)/SPENDING.length))}</div></div>
<div><div style={{fontSize:10, color:'var(--ink-faint)', textTransform:'uppercase', letterSpacing:'.06em'}}>Top medicine</div><div style={{fontSize:14, fontWeight:500}}>Semaglutide <span className="num" style={{color:'var(--ink-muted)'}}>{fmtJPY(56062)}</span></div></div>
</div>
</div>
</div>
<div className="mt-card">
<div className="mt-card__head">
<div>
<div className="mt-card__title">Cabinet activity</div>
<div className="mt-card__sub">{AC2.length} events</div>
</div>
<div className="mt-row" style={{gap:6}}>
<button className="mt-btn mt-btn--ghost">All types <Icon name="chevDown" size={12}/></button>
<button className="mt-btn mt-btn--ghost">All medicines <Icon name="chevDown" size={12}/></button>
</div>
</div>
<div style={{padding:'4px 18px 16px'}}>
{AC2.map(a => {
const m = M2[a.medId];
return (
<div key={a.id} className="act-row">
<span className="act-rail"><span className={'act-dot act-dot--'+a.type}/></span>
<span className={'mt-pill mt-pill--' + (a.type==='consumed'?'info':a.type==='added'?'ok':'warn')} style={{minWidth: 76, justifyContent:'center'}}>{a.type}</span>
<strong style={{fontSize:13, fontWeight:500, color:'var(--ink-strong)'}}>{m.name}</strong>
<span className="num" style={{color: a.delta < 0 ? 'var(--ink-muted)' : 'var(--ok)', fontSize: 13, fontWeight:500}}>{a.delta > 0?'+':''}{a.delta}</span>
<span className="num" style={{color:'var(--ink-faint)', fontSize:12}}>{a.before}{a.after}</span>
<span style={{flex:1}}/>
<span className="mono" style={{fontSize:11, color:'var(--ink-muted)'}}>{a.at}</span>
</div>
);
})}
</div>
</div>
</div>
);
};
// ---- Stores ----
const StoresPage = () => (
<div className="mt-page">
<div className="sub-toolbar">
<div style={{display:'flex', gap:8, alignItems:'center'}}>
<div className="cab-filters__search"><Icon name="search" size={13}/><input placeholder="Search stores…"/></div>
<button className="mt-btn mt-btn--ghost">All tags <Icon name="chevDown" size={12}/></button>
<label style={{display:'flex', gap:6, alignItems:'center', fontSize:12, color:'var(--ink-muted)'}}><input type="checkbox"/> Show inactive</label>
</div>
<button className="mt-btn mt-btn--primary"><Icon name="plus" size={12}/> Add store</button>
</div>
<div className="mt-grid" style={{gridTemplateColumns:'repeat(auto-fill, minmax(280px, 1fr))'}}>
{ST2.map(s => (
<div key={s.id} className="mt-card" style={{padding: 16}}>
<div style={{display:'flex', justifyContent:'space-between', alignItems:'flex-start'}}>
<div>
<div style={{fontWeight:500, fontSize:14, color:'var(--ink-strong)'}}>{s.name}</div>
<div style={{fontSize:11, color:'var(--brand)', marginTop:2}}>{s.url}</div>
</div>
<div style={{display:'flex', gap:4}}>
<button className="mt-btn mt-btn--subtle"><Icon name="edit" size={12}/></button>
</div>
</div>
<div style={{display:'flex', flexWrap:'wrap', gap: 4, marginTop: 10}}>
{s.tags.map(t => <span key={t} className="mt-pill mt-pill--ghost" style={{fontSize:10}}>{t}</span>)}
</div>
<div className="mt-divider"/>
<div style={{display:'flex', justifyContent:'space-between', fontSize:11, color:'var(--ink-muted)'}}>
<span>{PR2.filter(p=>p.store===s.id).length} prices tracked</span>
<span>{PU2.filter(p=>p.store===s.id).length} orders</span>
</div>
</div>
))}
</div>
</div>
);
// ---- Prices ----
const PricesPage = () => (
<div className="mt-page">
<div className="sub-toolbar">
<div style={{display:'flex', gap: 8}}>
<button className="mt-btn mt-btn--ghost">Semaglutide (14mg) <Icon name="chevDown" size={12}/></button>
<button className="mt-btn mt-btn--ghost">All stores <Icon name="chevDown" size={12}/></button>
</div>
<button className="mt-btn mt-btn--primary"><Icon name="plus" size={12}/> Record price</button>
</div>
<div className="mt-card" style={{marginBottom: 16}}>
<div className="mt-card__head"><div><div className="mt-card__title">Store comparison</div><div className="mt-card__sub">Best price highlighted</div></div></div>
<div className="prices-table">
<div className="prices-table__head">
<div>Store</div><div className="num">Price</div><div className="num">Per unit</div><div>Date</div>
</div>
{PR2.filter(p=>p.medId==='semaglutide').map(p => {
const s = ST2.find(s=>s.id===p.store);
const isBest = p.price/p.pkg === Math.min(...PR2.filter(x=>x.medId===p.medId).map(x=>x.price/x.pkg));
return (
<div key={p.store+p.date} className={'prices-table__row' + (isBest?' is-best':'')}>
<div style={{display:'flex', alignItems:'center', gap:8}}>
<span style={{fontWeight:500}}>{s?.name}</span>
{isBest && <span className="mt-pill mt-pill--ok" style={{fontSize:10}}>Cheapest</span>}
</div>
<div className="num">{fmtJPY(p.price)}</div>
<div className="num" style={{color:'var(--ink-muted)'}}>{fmtJPY(Math.round(p.price/p.pkg))}</div>
<div className="num" style={{color:'var(--ink-muted)'}}>{p.date}</div>
</div>
);
})}
</div>
</div>
<div className="mt-card">
<div className="mt-card__head"><div><div className="mt-card__title">All price records</div><div className="mt-card__sub">{PR2.length} entries</div></div></div>
<div className="prices-table">
<div className="prices-table__head" style={{gridTemplateColumns:'1.5fr 1fr 0.7fr 0.8fr 0.8fr 0.8fr'}}>
<div>Medicine</div><div>Store</div><div className="num">Qty</div><div className="num">Price</div><div className="num">Per unit</div><div>Date</div>
</div>
{PR2.map(p => {
const s = ST2.find(s=>s.id===p.store);
const m = M2[p.medId];
return (
<div key={p.medId+p.store+p.date} className="prices-table__row" style={{gridTemplateColumns:'1.5fr 1fr 0.7fr 0.8fr 0.8fr 0.8fr'}}>
<div style={{fontWeight:500}}>{m.name}</div>
<div>{s?.name}</div>
<div className="num">{p.pkg} {p.unit}</div>
<div className="num">{fmtJPY(p.price)}</div>
<div className="num" style={{color:'var(--ink-muted)'}}>{fmtJPY(Math.round(p.price/p.pkg))}</div>
<div className="num" style={{color:'var(--ink-muted)'}}>{p.date}</div>
</div>
);
})}
</div>
</div>
</div>
);
// ---- Refills ----
const RefillsPage = () => {
const low = C2.map(r => ({r, s: cabinetStatus(r)})).filter(x => x.s.level !== 'ok');
return (
<div className="mt-page">
<div className="mt-card" style={{marginBottom: 16}}>
<div className="mt-card__head">
<div>
<div className="mt-card__title">Refill alerts</div>
<div className="mt-card__sub">Threshold: 14 days</div>
</div>
<button className="mt-btn mt-btn--primary"><Icon name="plus" size={12}/> Generate refill list</button>
</div>
<div style={{padding:'4px 18px 16px'}}>
{low.map(({r, s}) => {
const m = M2[r.medId];
const bestPrice = PR2.filter(p=>p.medId===r.medId).sort((a,b)=> a.price/a.pkg - b.price/b.pkg)[0];
const bestStore = bestPrice && ST2.find(st=>st.id===bestPrice.store);
return (
<div key={r.medId} className="refill-row">
<div className="cab-card__swatch cab-card__swatch--sm" style={{'--c':'var(--viz-'+m.color+')'}}>
<Icon name={m.form === 'Injection' ? 'injection' : m.form === 'Capsule' ? 'capsule' : 'pill'} size={12}/>
</div>
<div style={{flex:1}}>
<div style={{fontWeight:500, color:'var(--ink-strong)'}}>{m.name} <span style={{color:'var(--ink-muted)', fontWeight:400}}>{m.strength}</span></div>
<div style={{fontSize:11, color: s.level==='critical' ? 'var(--danger)':'var(--warn)', fontWeight:500}}>{s.days} days left · {r.qty} {r.unit} in cabinet</div>
</div>
<div style={{textAlign:'right'}}>
<div style={{fontSize:11, color:'var(--ink-faint)'}}>Suggested</div>
<div className="num" style={{fontWeight:500}}>{bestPrice?.pkg || 30} units</div>
</div>
<div style={{textAlign:'right', minWidth: 140}}>
<div style={{fontSize:11, color:'var(--ink-faint)'}}>Best price</div>
<div style={{fontSize:12, fontWeight:500, color:'var(--brand)'}}>{bestStore?.name} · <span className="num">{bestPrice ? fmtJPY(bestPrice.price) : '—'}</span></div>
</div>
<button className="mt-btn mt-btn--primary">Add to list</button>
</div>
);
})}
</div>
</div>
<div className="mt-card">
<div className="mt-card__head">
<div><div className="mt-card__title">Refill lists</div><div className="mt-card__sub">Create from alerts or start blank</div></div>
<button className="mt-btn mt-btn--ghost"><Icon name="plus" size={12}/> New list</button>
</div>
<div style={{padding:'20px 18px', color:'var(--ink-muted)', fontSize:12, textAlign:'center'}}>No refill lists yet. Create one above or generate from alerts.</div>
</div>
</div>
);
};
// ---- Purchases ----
const PurchasesPage = () => (
<div className="mt-page">
<div className="sub-toolbar">
<div style={{display:'flex', gap:8}}>
<button className="mt-btn mt-btn--ghost">All statuses <Icon name="chevDown" size={12}/></button>
</div>
<button className="mt-btn mt-btn--primary"><Icon name="plus" size={12}/> Record purchase</button>
</div>
{['pending', 'received'].map(status => {
const items = PU2.filter(p => p.status === status);
if (!items.length) return null;
return (
<div key={status} style={{marginBottom: 20}}>
<div style={{fontSize:11, textTransform:'uppercase', letterSpacing:'.08em', color:'var(--ink-muted)', fontWeight:600, marginBottom: 8}}>{status === 'pending' ? 'Pending arrival' : 'Received'}</div>
<div className="mt-col">
{items.map(p => {
const s = ST2.find(s => s.id === p.store);
const total = p.items.reduce((a,i) => a + i.price, 0);
return (
<div key={p.id} className="mt-card" style={{padding: 16}}>
<div style={{display:'flex', justifyContent:'space-between', alignItems:'flex-start', marginBottom: 10}}>
<div>
<div style={{fontWeight:500, fontSize:14, color:'var(--ink-strong)'}}>{s?.name}</div>
<div className="num" style={{fontSize:11, color:'var(--ink-muted)'}}>{p.date}</div>
</div>
<span className={'mt-pill mt-pill--' + (status==='pending'?'warn':'ok')}>{status}</span>
</div>
<div style={{display:'flex', flexDirection:'column', gap:6, padding: '10px 0', borderTop:'1px dashed var(--border)'}}>
{p.items.map(i => {
const m = M2[i.medId];
return (
<div key={i.medId} style={{display:'flex', justifyContent:'space-between', fontSize:12}}>
<span>{m.name}</span>
<span style={{color:'var(--ink-muted)'}} className="num">{i.qty} {i.unit} · {fmtJPY(i.price)}</span>
</div>
);
})}
</div>
<div style={{display:'flex', justifyContent:'space-between', alignItems:'center', paddingTop: 10, borderTop:'1px solid var(--border)'}}>
<div className="num" style={{fontSize:15, fontWeight:600}}>{fmtJPY(total)}</div>
{status === 'pending' && <div style={{display:'flex', gap:6}}>
<button className="mt-btn mt-btn--primary">Mark as received</button>
<button className="mt-btn mt-btn--ghost">Cancel</button>
</div>}
</div>
</div>
);
})}
</div>
</div>
);
})}
</div>
);
// ---- Settings ----
const SettingsPage = () => (
<div className="mt-page" style={{maxWidth: 720}}>
<div className="mt-card" style={{marginBottom: 16}}>
<div className="mt-card__head"><div className="mt-card__title">Household</div></div>
<div style={{padding: 18}}>
<div className="settings-row"><span>Name</span><span style={{fontWeight:500}}>Red Panda Den</span><button className="mt-btn mt-btn--ghost">Edit</button></div>
<div className="settings-row"><span>Invite code</span><span className="mono">2496F-7CF</span><button className="mt-btn mt-btn--ghost">Regenerate</button></div>
<div className="settings-row"><span>Members</span><span>1</span><button className="mt-btn mt-btn--ghost">Invite</button></div>
</div>
</div>
<div className="mt-card" style={{marginBottom: 16}}>
<div className="mt-card__head"><div className="mt-card__title">Account</div></div>
<div style={{padding: 18}}>
<p style={{fontSize:12, color:'var(--ink-muted)'}}>Account settings are managed through Keycloak.</p>
<button className="mt-btn mt-btn--ghost">Manage Keycloak account</button>
</div>
</div>
</div>
);
Object.assign(window, { LibraryPage, RegimensPage, OrganizerPage, ActivityPage, StoresPage, PricesPage, RefillsPage, PurchasesPage, SettingsPage });