feat: add totalPills to medication and planner rows for improved stock tracking

This commit is contained in:
Daniel Volz
2025-12-21 00:12:47 +01:00
parent 522223cb01
commit 4ffbcef877
3 changed files with 20 additions and 6 deletions
+2
View File
@@ -261,6 +261,7 @@ export async function medicationRoutes(app: FastifyInstance) {
const packCount = row.packCount ?? 1; const packCount = row.packCount ?? 1;
const stripsPerPack = row.stripsPerPack ?? row.strips ?? 1; const stripsPerPack = row.stripsPerPack ?? row.strips ?? 1;
const looseTablets = row.looseTablets ?? 0; const looseTablets = row.looseTablets ?? 0;
const totalPills = row.count;
const stripsNeeded = tabsPerStrip > 0 ? Math.ceil(usageTotal / tabsPerStrip) : 0; const stripsNeeded = tabsPerStrip > 0 ? Math.ceil(usageTotal / tabsPerStrip) : 0;
const stripsAvailable = packCount * stripsPerPack + (tabsPerStrip > 0 ? looseTablets / tabsPerStrip : 0); const stripsAvailable = packCount * stripsPerPack + (tabsPerStrip > 0 ? looseTablets / tabsPerStrip : 0);
@@ -268,6 +269,7 @@ export async function medicationRoutes(app: FastifyInstance) {
return { return {
medicationId: row.id, medicationId: row.id,
medicationName: row.name, medicationName: row.name,
totalPills,
plannerUsage: usageTotal, plannerUsage: usageTotal,
stripSize: tabsPerStrip, stripSize: tabsPerStrip,
stripsNeeded, stripsNeeded,
+7 -4
View File
@@ -5,6 +5,7 @@ import { updateReminderSentTime } from "../services/reminder-scheduler.js";
type PlannerRow = { type PlannerRow = {
medicationId: number; medicationId: number;
medicationName: string; medicationName: string;
totalPills: number;
plannerUsage: number; plannerUsage: number;
stripSize: number; stripSize: number;
stripsNeeded: number; stripsNeeded: number;
@@ -68,7 +69,8 @@ export async function plannerRoutes(app: FastifyInstance) {
(row) => ` (row) => `
<tr> <tr>
<td style="padding: 10px 12px; border-bottom: 1px solid #e5e7eb; white-space: nowrap;">${row.medicationName}</td> <td style="padding: 10px 12px; border-bottom: 1px solid #e5e7eb; white-space: nowrap;">${row.medicationName}</td>
<td style="padding: 10px 12px; border-bottom: 1px solid #e5e7eb; text-align: center; white-space: nowrap;"><strong>${row.plannerUsage}</strong> pills</td> <td style="padding: 10px 12px; border-bottom: 1px solid #e5e7eb; text-align: center; white-space: nowrap;"><strong>${row.totalPills}</strong></td>
<td style="padding: 10px 12px; border-bottom: 1px solid #e5e7eb; text-align: center; white-space: nowrap;"><strong>${row.plannerUsage}</strong></td>
<td style="padding: 10px 12px; border-bottom: 1px solid #e5e7eb; text-align: center; white-space: nowrap;">${row.stripsNeeded} × ${row.stripSize}</td> <td style="padding: 10px 12px; border-bottom: 1px solid #e5e7eb; text-align: center; white-space: nowrap;">${row.stripsNeeded} × ${row.stripSize}</td>
<td style="padding: 10px 12px; border-bottom: 1px solid #e5e7eb; text-align: center; white-space: nowrap;">${row.stripsAvailable}</td> <td style="padding: 10px 12px; border-bottom: 1px solid #e5e7eb; text-align: center; white-space: nowrap;">${row.stripsAvailable}</td>
<td style="padding: 10px 12px; border-bottom: 1px solid #e5e7eb; text-align: center; white-space: nowrap;"> <td style="padding: 10px 12px; border-bottom: 1px solid #e5e7eb; text-align: center; white-space: nowrap;">
@@ -77,7 +79,7 @@ export async function plannerRoutes(app: FastifyInstance) {
? "background: #d1fae5; color: #065f46;" ? "background: #d1fae5; color: #065f46;"
: "background: #fee2e2; color: #991b1b;" : "background: #fee2e2; color: #991b1b;"
}"> }">
${row.enough ? "✓ OK" : "⚠ Low"} ${row.enough ? "✓ OK" : "✗ Out of Stock"}
</span> </span>
</td> </td>
</tr> </tr>
@@ -108,10 +110,11 @@ export async function plannerRoutes(app: FastifyInstance) {
</div> </div>
<div style="overflow-x: auto; -webkit-overflow-scrolling: touch;"> <div style="overflow-x: auto; -webkit-overflow-scrolling: touch;">
<table style="width: 100%; border-collapse: collapse; background: white; min-width: 500px;"> <table style="width: 100%; border-collapse: collapse; background: white; min-width: 550px;">
<thead> <thead>
<tr style="background: #f3f4f6;"> <tr style="background: #f3f4f6;">
<th style="padding: 10px 12px; text-align: left; font-size: 11px; text-transform: uppercase; color: #6b7280; letter-spacing: 0.05em; white-space: nowrap;">Medication</th> <th style="padding: 10px 12px; text-align: left; font-size: 11px; text-transform: uppercase; color: #6b7280; letter-spacing: 0.05em; white-space: nowrap;">Medication</th>
<th style="padding: 10px 12px; text-align: center; font-size: 11px; text-transform: uppercase; color: #6b7280; letter-spacing: 0.05em; white-space: nowrap;">Stock</th>
<th style="padding: 10px 12px; text-align: center; font-size: 11px; text-transform: uppercase; color: #6b7280; letter-spacing: 0.05em; white-space: nowrap;">Usage</th> <th style="padding: 10px 12px; text-align: center; font-size: 11px; text-transform: uppercase; color: #6b7280; letter-spacing: 0.05em; white-space: nowrap;">Usage</th>
<th style="padding: 10px 12px; text-align: center; font-size: 11px; text-transform: uppercase; color: #6b7280; letter-spacing: 0.05em; white-space: nowrap;">Needed</th> <th style="padding: 10px 12px; text-align: center; font-size: 11px; text-transform: uppercase; color: #6b7280; letter-spacing: 0.05em; white-space: nowrap;">Needed</th>
<th style="padding: 10px 12px; text-align: center; font-size: 11px; text-transform: uppercase; color: #6b7280; letter-spacing: 0.05em; white-space: nowrap;">Available</th> <th style="padding: 10px 12px; text-align: center; font-size: 11px; text-transform: uppercase; color: #6b7280; letter-spacing: 0.05em; white-space: nowrap;">Available</th>
@@ -135,7 +138,7 @@ Supply overview from ${fromDate} to ${untilDate}
${summaryText} ${summaryText}
${rows.map((r) => `${r.medicationName}: ${r.plannerUsage} pills needed, ${r.stripsAvailable} blisters available (${r.stripsNeeded} needed) - ${r.enough ? "Enough" : "OUT OF STOCK"}`).join("\n")} ${rows.map((r) => `${r.medicationName}: ${r.totalPills} pills in stock, ${r.plannerUsage} pills needed, ${r.stripsAvailable} blisters available (${r.stripsNeeded} needed) - ${r.enough ? "Enough" : "OUT OF STOCK"}`).join("\n")}
--- ---
Sent from MedAssist Medication Planner`; Sent from MedAssist Medication Planner`;
+11 -2
View File
@@ -28,6 +28,7 @@ type Medication = {
type PlannerRow = { type PlannerRow = {
medicationId: number; medicationId: number;
medicationName: string; medicationName: string;
totalPills: number;
plannerUsage: number; plannerUsage: number;
stripSize: number; stripSize: number;
stripsNeeded: number; stripsNeeded: number;
@@ -495,12 +496,20 @@ export default function App() {
setTheme((prev) => (prev === "dark" ? "light" : "dark")); setTheme((prev) => (prev === "dark" ? "light" : "dark"));
} }
// Page titles based on current route
const pageInfo = {
"/dashboard": { eyebrow: "MedAssist · Overview", title: "Dashboard" },
"/medications": { eyebrow: "MedAssist · Inventory", title: "Manage Medications" },
"/planner": { eyebrow: "MedAssist · Planner", title: "Demand Calculator" },
"/settings": { eyebrow: "MedAssist · Configuration", title: "Settings" },
}[currentPath] || { eyebrow: "MedAssist · Overview", title: "Dashboard" };
return ( return (
<main className="page"> <main className="page">
<header className="hero"> <header className="hero">
<div> <div>
<p className="eyebrow">Medassist · Planner</p> <p className="eyebrow">{pageInfo.eyebrow}</p>
<h1>Manage medication plans</h1> <h1>{pageInfo.title}</h1>
</div> </div>
<div className="header-actions"> <div className="header-actions">
<div className="tabs"> <div className="tabs">