// 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 (
Fill from regimen
{regimen.time} · {regimen.items.length} medicines · {regimen.freq}
Days to fill
{days}
{[3, 7, 14, 30].map(d => (
))}
This fill will dispense
{impact.reduce((a,b) => a + b.needed, 0)} units across {impact.length} medicines
{anyShort ? (
Not enough stock. {impact.filter(i => i.status === 'short').length} medicine{impact.filter(i => i.status === 'short').length > 1 ? 's are' : ' is'} short for this fill.
) : anyLow ? (
Low after fill. Some meds will drop below 50% headroom.
) : (
Ready to dispense. Cabinet has enough stock with comfortable headroom.
)}
{/* Inventory impact table */}
Inventory impact
What this fill will take from the cabinet
Medicine
On hand
Needed
After fill
Days left
{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 (
{m.name}
{row.it.qty} × {days} days = {row.needed} {m.form.toLowerCase()}
{row.onHand}
−{row.needed}
{row.after < 0 ? row.after : row.after}
{row.status === 'short'
? Short
: {row.daysAfter}d}
);
})}
);
};
// ---- Activity ----
const ActivityPage = () => {
const { SPENDING } = window.MESHI;
return (
Spending summary
Last 6 months
Total spent
{fmtJPY(SPENDING.reduce((a,b)=>a+b.amount,0))}
Monthly average
{fmtJPY(Math.round(SPENDING.reduce((a,b)=>a+b.amount,0)/SPENDING.length))}
Top medicine
Semaglutide {fmtJPY(56062)}
Cabinet activity
{AC2.length} events
{AC2.map(a => {
const m = M2[a.medId];
return (
{a.type}
{m.name}
{a.delta > 0?'+':''}{a.delta}
{a.before}→{a.after}
{a.at}
);
})}
);
};
// ---- Stores ----
const StoresPage = () => (
{ST2.map(s => (
{s.tags.map(t => {t})}
{PR2.filter(p=>p.store===s.id).length} prices tracked
{PU2.filter(p=>p.store===s.id).length} orders
))}
);
// ---- Prices ----
const PricesPage = () => (
Store comparison
Best price highlighted
{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 (
{s?.name}
{isBest && Cheapest}
{fmtJPY(p.price)}
{fmtJPY(Math.round(p.price/p.pkg))}
{p.date}
);
})}
All price records
{PR2.length} entries
Medicine
Store
Qty
Price
Per unit
Date
{PR2.map(p => {
const s = ST2.find(s=>s.id===p.store);
const m = M2[p.medId];
return (
{m.name}
{s?.name}
{p.pkg} {p.unit}
{fmtJPY(p.price)}
{fmtJPY(Math.round(p.price/p.pkg))}
{p.date}
);
})}
);
// ---- Refills ----
const RefillsPage = () => {
const low = C2.map(r => ({r, s: cabinetStatus(r)})).filter(x => x.s.level !== 'ok');
return (
Refill alerts
Threshold: 14 days
{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 (
{m.name} {m.strength}
{s.days} days left · {r.qty} {r.unit} in cabinet
Suggested
{bestPrice?.pkg || 30} units
Best price
{bestStore?.name} · {bestPrice ? fmtJPY(bestPrice.price) : '—'}
);
})}
Refill lists
Create from alerts or start blank
No refill lists yet. Create one above or generate from alerts.
);
};
// ---- Purchases ----
const PurchasesPage = () => (
{['pending', 'received'].map(status => {
const items = PU2.filter(p => p.status === status);
if (!items.length) return null;
return (
{status === 'pending' ? 'Pending arrival' : 'Received'}
{items.map(p => {
const s = ST2.find(s => s.id === p.store);
const total = p.items.reduce((a,i) => a + i.price, 0);
return (
{p.items.map(i => {
const m = M2[i.medId];
return (
{m.name}
{i.qty} {i.unit} · {fmtJPY(i.price)}
);
})}
{fmtJPY(total)}
{status === 'pending' &&
}
);
})}
);
})}
);
// ---- Settings ----
const SettingsPage = () => (
NameRed Panda Den
Invite code2496F-7CF
Members1
Account settings are managed through Keycloak.
);
Object.assign(window, { LibraryPage, RegimensPage, OrganizerPage, ActivityPage, StoresPage, PricesPage, RefillsPage, PurchasesPage, SettingsPage });