feat: Add package type support and per-intake takenBy (#89)
## Package Type Feature - Add 'blister' and 'bottle' package types for medications - Bottle type uses totalPills for capacity and looseTablets for current stock - Blister type continues to use packCount/blistersPerPack/pillsPerBlister - Add doseUnit field for flexible dosing (mg, ml, IU, etc.) - Full UI support in medication form and detail modal ## Per-Intake TakenBy - Move takenBy from medication level to individual intakes - Each intake schedule can now be assigned to a different person - Update scheduler-utils to handle per-intake takenBy - Update SharedSchedule to filter by per-intake takenBy - Backward compatible with existing medication data ## UI Improvements - Add PasswordInput component with show/hide toggle - Centralize stockThresholds in AppContext for consistent status display - Fix SharedSchedule sync issues with per-intake takenBy - Improve mobile editing experience ## Technical - Add migrations 0004 and 0005 for schema changes - Update all relevant tests (1064 tests passing) - Maintain backward compatibility with ALTER migrations
This commit is contained in:
@@ -3,7 +3,7 @@ import { createContext, useCallback, useContext, useEffect, useMemo, useState }
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useAuth } from "../components/Auth";
|
||||
import { useCollapsedDays, useDoses, useMedications, useRefill, useSettings, useShare } from "../hooks";
|
||||
import type { Coverage, Medication, ScheduleEvent } from "../types";
|
||||
import type { Coverage, Medication, ScheduleEvent, StockThresholds } from "../types";
|
||||
import { getSystemLocale } from "../utils/formatters";
|
||||
import { buildSchedulePreview, calculateCoverage } from "../utils/schedule";
|
||||
|
||||
@@ -134,6 +134,7 @@ export interface AppContextValue {
|
||||
coverage: { all: Coverage[]; low: Coverage[] };
|
||||
coverageByMed: Record<string, Coverage>;
|
||||
depletionByMed: Record<string, number | null>;
|
||||
stockThresholds: StockThresholds;
|
||||
existingPeople: string[];
|
||||
groupedSchedule: GroupedDay[];
|
||||
pastDays: GroupedDay[];
|
||||
@@ -296,6 +297,24 @@ export function AppProvider({ children }: { children: React.ReactNode }) {
|
||||
|
||||
const coverageByMed = useMemo(() => Object.fromEntries(coverage.all.map((c) => [c.name, c])), [coverage.all]);
|
||||
|
||||
// Centralized stock thresholds for consistent status display across all components
|
||||
const stockThresholds: StockThresholds = useMemo(
|
||||
() => ({
|
||||
lowStockDays: settingsHook.settings.lowStockDays,
|
||||
normalStockDays: settingsHook.settings.normalStockDays,
|
||||
highStockDays: settingsHook.settings.highStockDays,
|
||||
criticalStockDays: settingsHook.settings.reminderDaysBefore, // Critical uses the reminder threshold
|
||||
expiryWarningDays: settingsHook.settings.expiryWarningDays,
|
||||
}),
|
||||
[
|
||||
settingsHook.settings.lowStockDays,
|
||||
settingsHook.settings.normalStockDays,
|
||||
settingsHook.settings.highStockDays,
|
||||
settingsHook.settings.reminderDaysBefore,
|
||||
settingsHook.settings.expiryWarningDays,
|
||||
]
|
||||
);
|
||||
|
||||
const existingPeople = useMemo(() => {
|
||||
const allPeople = medications.meds.flatMap((m) => m.takenBy || []);
|
||||
return [...new Set(allPeople)].filter(Boolean).sort();
|
||||
@@ -798,6 +817,7 @@ export function AppProvider({ children }: { children: React.ReactNode }) {
|
||||
coverage,
|
||||
coverageByMed,
|
||||
depletionByMed,
|
||||
stockThresholds,
|
||||
existingPeople,
|
||||
groupedSchedule,
|
||||
pastDays,
|
||||
@@ -861,6 +881,7 @@ export function AppProvider({ children }: { children: React.ReactNode }) {
|
||||
coverage,
|
||||
coverageByMed,
|
||||
depletionByMed,
|
||||
stockThresholds,
|
||||
existingPeople,
|
||||
groupedSchedule,
|
||||
pastDays,
|
||||
|
||||
Reference in New Issue
Block a user