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:
Daniel Volz
2026-01-31 23:49:11 +01:00
committed by GitHub
parent ac4b8151e4
commit 571d94bf7e
37 changed files with 2896 additions and 990 deletions
+21 -6
View File
@@ -88,7 +88,8 @@
"lowMeds": "{{count}} Medikament knapp",
"lowMeds_other": "{{count}} Medikamente knapp",
"daysLeft": "{{days}} Tag übrig",
"daysLeft_other": "{{days}} Tage übrig"
"daysLeft_other": "{{days}} Tage übrig",
"needsRefill": "Nachfüllen nötig"
}
},
"table": {
@@ -98,11 +99,16 @@
"currentPills": "Aktuelle Tabletten",
"fullBlisters": "Volle Blister",
"openBlister": "Offener Blister",
"stock": "Bestand",
"stockDetails": "Details",
"daysLeft": "Tage übrig",
"status": "Bestand",
"status": "Status",
"runsOut": "Aufgebraucht",
"autoRemind": "Auto-Erinnerung",
"expiry": "Ablaufdatum"
"expiry": "Ablaufdatum",
"pillsCount": "{{count}} Tabletten",
"pillsCount_one": "{{count}} Tablette",
"pillsCount_other": "{{count}} Tabletten"
},
"medications": {
"list": {
@@ -116,7 +122,8 @@
"blisters": "Blister pro Packung",
"pillsPerBlister": "Tabletten pro Blister",
"loose": "Lose",
"total": "Gesamt"
"total": "Gesamt",
"stock": "Bestand"
}
},
"form": {
@@ -126,11 +133,16 @@
"commercialName": "Handelsname",
"genericName": "Wirkstoff",
"takenBy": "Eingenommen von",
"packageType": "Verpackungsart",
"packageTypeBlister": "Blisterpackung",
"packageTypeBottle": "Pillendose / Behälter",
"packs": "Packungen",
"blistersPerPack": "Blister pro Packung",
"pillsPerBlister": "Tabletten pro Blister",
"totalCapacity": "Gesamtkapazität",
"currentPills": "Aktuelle Tabletten",
"loosePills": "Lose Tabletten",
"pillWeight": "Tablettengewicht (mg)",
"pillWeight": "Dosis pro Tablette",
"total": "Gesamt (Tabletten)",
"expiryDate": "Ablaufdatum",
"notes": "Notizen",
@@ -154,7 +166,9 @@
"every": "alle",
"from": "ab",
"startDate": "Datum",
"startTime": "Uhrzeit"
"startTime": "Uhrzeit",
"takenByIntake": "Eingenommen von",
"takenByEveryone": "Alle"
}
},
"planner": {
@@ -260,6 +274,7 @@
},
"status": {
"outOfStock": "Leer",
"criticalStock": "Kritisch",
"lowStock": "Niedrig",
"normal": "Normal",
"highStock": "Hoch",
+21 -6
View File
@@ -88,7 +88,8 @@
"lowMeds": "{{count}} medication low",
"lowMeds_other": "{{count}} medications low",
"daysLeft": "{{days}} day left",
"daysLeft_other": "{{days}} days left"
"daysLeft_other": "{{days}} days left",
"needsRefill": "Needs refill"
}
},
"table": {
@@ -98,11 +99,16 @@
"currentPills": "Current pills",
"fullBlisters": "Full blisters",
"openBlister": "Open blister",
"stock": "Stock",
"stockDetails": "Details",
"daysLeft": "Days left",
"status": "Stock",
"status": "Status",
"runsOut": "Runs out",
"autoRemind": "Auto-remind",
"expiry": "Expiry"
"expiry": "Expiry",
"pillsCount": "{{count}} pills",
"pillsCount_one": "{{count}} pill",
"pillsCount_other": "{{count}} pills"
},
"medications": {
"list": {
@@ -116,7 +122,8 @@
"blisters": "Blisters per pack",
"pillsPerBlister": "Pills per blister",
"loose": "Loose",
"total": "Total"
"total": "Total",
"stock": "Stock"
}
},
"form": {
@@ -126,11 +133,16 @@
"commercialName": "Commercial Name",
"genericName": "Generic Name",
"takenBy": "Taken by",
"packageType": "Package Type",
"packageTypeBlister": "Blister Pack",
"packageTypeBottle": "Pill Bottle / Container",
"packs": "Packs",
"blistersPerPack": "Blisters per pack",
"pillsPerBlister": "Pills per blister",
"totalCapacity": "Total Capacity",
"currentPills": "Current Pills",
"loosePills": "Loose pills",
"pillWeight": "Pill weight (mg)",
"pillWeight": "Dose per pill",
"total": "Total (pills)",
"expiryDate": "Expiry Date",
"notes": "Notes",
@@ -154,7 +166,9 @@
"every": "every",
"from": "from",
"startDate": "Date",
"startTime": "Time"
"startTime": "Time",
"takenByIntake": "Taken by",
"takenByEveryone": "Everyone"
}
},
"planner": {
@@ -260,6 +274,7 @@
},
"status": {
"outOfStock": "Empty",
"criticalStock": "Critical",
"lowStock": "Low",
"normal": "Normal",
"highStock": "High",