fix: align frontend types and tests for react 19 (#339)

This commit is contained in:
Daniel Volz
2026-02-27 01:01:48 +01:00
committed by GitHub
parent 6b27d234d9
commit cc22f80209
23 changed files with 166 additions and 74 deletions
@@ -1,5 +1,5 @@
import { fireEvent, render, screen } from "@testing-library/react";
import { describe, expect, it, vi } from "vitest";
import { beforeEach, describe, expect, it, vi } from "vitest";
import { Lightbox } from "../../components/Lightbox";
describe("Lightbox", () => {
@@ -55,6 +55,8 @@ const defaultProps = {
onRefillPacksChange: vi.fn(),
refillLoose: 0,
onRefillLooseChange: vi.fn(),
usePrescriptionRefill: false,
onUsePrescriptionRefillChange: vi.fn(),
refillSaving: false,
refillHistory: [] as RefillEntry[],
refillHistoryExpanded: false,
@@ -324,7 +326,7 @@ describe("MedDetailModal with refill modal", () => {
const submitBtn = document.querySelector(".refill-modal .modal-footer .success") as HTMLButtonElement;
fireEvent.click(submitBtn);
expect(onSubmitRefill).toHaveBeenCalledWith(mockMedication.id, undefined);
expect(onSubmitRefill).toHaveBeenCalledWith(mockMedication.id, false);
});
it("disables refill submit button when no pills are entered", () => {
@@ -589,7 +591,7 @@ describe("MedDetailModal with refill history", () => {
it("shows refill history when expanded", () => {
const refillHistory: RefillEntry[] = [
{ id: 1, medicationId: 1, timestamp: new Date().toISOString(), packsAdded: 1, looseAdded: 0 },
{ id: 1, refillDate: new Date().toISOString(), packsAdded: 1, loosePillsAdded: 0 },
];
render(<MedDetailModal {...defaultProps} refillHistory={refillHistory} refillHistoryExpanded={true} />);
@@ -602,7 +604,7 @@ describe("MedDetailModal with refill history", () => {
it("calls onRefillHistoryExpandedChange when toggle clicked", () => {
const onRefillHistoryExpandedChange = vi.fn();
const refillHistory: RefillEntry[] = [
{ id: 1, medicationId: 1, timestamp: new Date().toISOString(), packsAdded: 1, looseAdded: 0 },
{ id: 1, refillDate: new Date().toISOString(), packsAdded: 1, loosePillsAdded: 0 },
];
render(
@@ -1,4 +1,5 @@
import { fireEvent, render, screen } from "@testing-library/react";
import type { FormEvent } from "react";
import { beforeEach, describe, expect, it, vi } from "vitest";
import { MobileEditModal } from "../../components/MobileEditModal";
import type { FormState } from "../../types";
@@ -78,6 +79,7 @@ const defaultProps = {
meds: [],
onUploadMedImage: vi.fn(),
onDeleteMedImage: vi.fn(),
imageUploadError: null,
onClose: vi.fn(),
onResetForm: vi.fn(),
onSaveMedication: vi.fn(),
@@ -383,7 +385,7 @@ describe("MobileEditModal form submission", () => {
});
it("calls onSaveMedication when form submitted", () => {
const onSaveMedication = vi.fn((e: Event) => e.preventDefault());
const onSaveMedication = vi.fn((e: FormEvent) => e.preventDefault());
const validForm = { ...defaultForm, name: "TestMed" };
render(<MobileEditModal {...defaultProps} form={validForm} onSaveMedication={onSaveMedication} />);
@@ -15,6 +15,7 @@ const mockMedication: Medication = {
id: 1,
name: "Test Med",
genericName: "Generic Name",
packageType: "blister",
packCount: 1,
blistersPerPack: 1,
pillsPerBlister: 30,
@@ -51,6 +51,7 @@ const meds: Medication[] = [
id: 11,
name: "Aspirin",
takenBy: ["Max", "Anna"],
packageType: "blister",
packCount: 1,
blistersPerPack: 1,
pillsPerBlister: 10,
+14 -1
View File
@@ -196,7 +196,20 @@ describe("useMedications", () => {
it("allows setting meds directly", () => {
const { result } = renderHook(() => useMedications());
const newMeds: Array<Pick<Medication, "id" | "name">> = [{ id: 1, name: "NewMed" }];
const newMeds: Medication[] = [
{
id: 1,
name: "NewMed",
packageType: "blister",
packCount: 1,
blistersPerPack: 1,
pillsPerBlister: 30,
looseTablets: 0,
takenBy: [],
blisters: [],
updatedAt: null,
},
];
act(() => {
result.current.setMeds(newMeds);
+8 -4
View File
@@ -184,6 +184,7 @@ describe("useRefill", () => {
pillsPerBlister: 10,
looseTablets: 5,
takenBy: [],
packageType: "blister",
blisters: [],
updatedAt: null,
};
@@ -241,6 +242,7 @@ describe("useRefill", () => {
pillsPerBlister: 10,
looseTablets: 5,
takenBy: [],
packageType: "blister",
blisters: [],
updatedAt: null,
};
@@ -267,6 +269,7 @@ describe("useRefill", () => {
pillsPerBlister: 10,
looseTablets: 5,
takenBy: [],
packageType: "blister",
blisters: [],
updatedAt: null,
};
@@ -300,6 +303,7 @@ describe("useRefill", () => {
pillsPerBlister: 10,
looseTablets: 5,
takenBy: [],
packageType: "blister",
blisters: [],
updatedAt: null,
};
@@ -368,7 +372,7 @@ describe("useRefill", () => {
// newStockAdjustment = 149 - 150 = -1
// → getMedTotal = 150 + (-1) = 149 ✓
const fetchCall = (global.fetch as ReturnType<typeof vi.fn>).mock.calls.find(
(call: [string, RequestInit]) => call[0] === "/api/medications/4/stock-adjustment"
(call) => call[0] === "/api/medications/4/stock-adjustment"
);
expect(fetchCall).toBeDefined();
const body = JSON.parse(fetchCall![1].body as string);
@@ -420,7 +424,7 @@ describe("useRefill", () => {
// baseTotal = getPackageSize(blister) = 25
// newStockAdjustment = 25 - 25 = 0
const fetchCall = (global.fetch as ReturnType<typeof vi.fn>).mock.calls.find(
(call: [string, RequestInit]) => call[0] === "/api/medications/2/stock-adjustment"
(call) => call[0] === "/api/medications/2/stock-adjustment"
);
expect(fetchCall).toBeDefined();
const body = JSON.parse(fetchCall![1].body as string);
@@ -462,7 +466,7 @@ describe("useRefill", () => {
});
const fetchCall = (global.fetch as ReturnType<typeof vi.fn>).mock.calls.find(
(call: [string, RequestInit]) => call[0] === "/api/medications/5/stock-adjustment"
(call) => call[0] === "/api/medications/5/stock-adjustment"
);
expect(fetchCall).toBeDefined();
const body = JSON.parse(fetchCall![1].body as string);
@@ -507,7 +511,7 @@ describe("useRefill", () => {
});
const fetchCall = (global.fetch as ReturnType<typeof vi.fn>).mock.calls.find(
(call: [string, RequestInit]) => call[0] === "/api/medications/6/stock-adjustment"
(call) => call[0] === "/api/medications/6/stock-adjustment"
);
expect(fetchCall).toBeDefined();
const body = JSON.parse(fetchCall![1].body as string);
+2 -2
View File
@@ -281,13 +281,13 @@ describe("useSettings", () => {
it("refreshes reminder status on interval", async () => {
let refreshCallback: (() => void) | null = null;
const nativeSetInterval = global.setInterval;
vi.spyOn(global, "setInterval").mockImplementation((handler: TimerHandler, timeout?: number) => {
vi.spyOn(global, "setInterval").mockImplementation(((handler: TimerHandler, timeout?: number) => {
if (timeout === 30000) {
refreshCallback = handler as () => void;
return 1 as unknown as ReturnType<typeof setInterval>;
}
return nativeSetInterval(handler, timeout);
});
}) as typeof setInterval);
(global.fetch as ReturnType<typeof vi.fn>)
.mockResolvedValueOnce({ ok: true, json: () => Promise.resolve({}) })
+9 -1
View File
@@ -12,7 +12,7 @@ describe("useShare", () => {
vi.useFakeTimers();
mockAlert = vi.fn();
global.alert = mockAlert;
global.alert = mockAlert as unknown as typeof global.alert;
mockClipboard = { writeText: vi.fn().mockResolvedValue(undefined) };
Object.defineProperty(navigator, "clipboard", {
@@ -59,6 +59,7 @@ describe("useShare", () => {
id: 1,
name: "Med1",
takenBy: ["Alice", "Bob"],
packageType: "blister",
packCount: 1,
blistersPerPack: 1,
pillsPerBlister: 10,
@@ -70,6 +71,7 @@ describe("useShare", () => {
id: 2,
name: "Med2",
takenBy: ["Bob", "Charlie"],
packageType: "blister",
packCount: 1,
blistersPerPack: 1,
pillsPerBlister: 10,
@@ -103,6 +105,7 @@ describe("useShare", () => {
id: 1,
name: "Med1",
takenBy: ["Alice"],
packageType: "blister",
packCount: 1,
blistersPerPack: 1,
pillsPerBlister: 10,
@@ -128,6 +131,7 @@ describe("useShare", () => {
id: 1,
name: "Med1",
takenBy: ["Alice"],
packageType: "blister",
packCount: 1,
blistersPerPack: 1,
pillsPerBlister: 10,
@@ -168,6 +172,7 @@ describe("useShare", () => {
id: 1,
name: "Med1",
takenBy: ["Alice"],
packageType: "blister",
packCount: 1,
blistersPerPack: 1,
pillsPerBlister: 10,
@@ -199,6 +204,7 @@ describe("useShare", () => {
id: 1,
name: "Med1",
takenBy: ["Alice"],
packageType: "blister",
packCount: 1,
blistersPerPack: 1,
pillsPerBlister: 10,
@@ -270,6 +276,7 @@ describe("useShare", () => {
id: 1,
name: "Med1",
takenBy: ["Alice"],
packageType: "blister",
packCount: 1,
blistersPerPack: 1,
pillsPerBlister: 10,
@@ -308,6 +315,7 @@ describe("useShare", () => {
id: 1,
name: "Med1",
takenBy: ["Alice"],
packageType: "blister",
packCount: 1,
blistersPerPack: 1,
pillsPerBlister: 10,
+1 -1
View File
@@ -1,5 +1,5 @@
import "@testing-library/jest-dom";
import { vi } from "vitest";
import { beforeEach, vi } from "vitest";
// Mock fetch globally
global.fetch = vi.fn();
@@ -190,6 +190,7 @@ describe("getBlisterStock", () => {
const med: Medication = {
id: 1,
name: "Test Med",
packageType: "blister",
packCount: 1,
blistersPerPack: 2,
pillsPerBlister: 10,
@@ -209,6 +210,7 @@ describe("getBlisterStock", () => {
const med: Medication = {
id: 1,
name: "Test Med",
packageType: "blister",
packCount: 1,
blistersPerPack: 1,
pillsPerBlister: 10,
+6 -5
View File
@@ -17,22 +17,22 @@ describe("generateICS", () => {
mockRemoveChild = vi.fn();
mockClick = vi.fn();
global.URL.createObjectURL = mockCreateObjectURL;
global.URL.revokeObjectURL = mockRevokeObjectURL;
global.URL.createObjectURL = mockCreateObjectURL as unknown as typeof URL.createObjectURL;
global.URL.revokeObjectURL = mockRevokeObjectURL as unknown as typeof URL.revokeObjectURL;
vi.spyOn(document.body, "appendChild").mockImplementation((node) => {
mockAppendChild(node);
(mockAppendChild as unknown as (child: Node) => void)(node);
createdLink = node as HTMLAnchorElement;
return node;
});
vi.spyOn(document.body, "removeChild").mockImplementation(mockRemoveChild);
vi.spyOn(document.body, "removeChild").mockImplementation(mockRemoveChild as unknown as (child: Node) => Node);
// Mock createElement to track the created anchor
const originalCreateElement = document.createElement.bind(document);
vi.spyOn(document, "createElement").mockImplementation((tag) => {
const element = originalCreateElement(tag);
if (tag === "a") {
element.click = mockClick;
element.click = mockClick as unknown as () => void;
}
return element;
});
@@ -63,6 +63,7 @@ describe("generateICS", () => {
notes: "Take with food",
updatedAt: null,
...overrides,
packageType: overrides?.packageType ?? "blister",
});
it("creates and downloads ICS file", () => {
+46 -1
View File
@@ -42,6 +42,7 @@ describe("buildSchedulePreview", () => {
pillsPerBlister: 30,
looseTablets: 0,
takenBy: ["John"],
packageType: "blister",
blisters: [
{
usage: 1,
@@ -68,6 +69,7 @@ describe("buildSchedulePreview", () => {
pillsPerBlister: 30,
looseTablets: 0,
takenBy: [],
packageType: "blister",
blisters: [
{
usage: 1,
@@ -95,6 +97,7 @@ describe("buildSchedulePreview", () => {
pillsPerBlister: 30,
looseTablets: 0,
takenBy: [],
packageType: "blister",
blisters: [
{
usage: 1,
@@ -121,6 +124,7 @@ describe("buildSchedulePreview", () => {
pillsPerBlister: 30,
looseTablets: 0,
takenBy: [],
packageType: "blister",
blisters: [
{
usage: 1,
@@ -138,6 +142,7 @@ describe("buildSchedulePreview", () => {
pillsPerBlister: 30,
looseTablets: 0,
takenBy: [],
packageType: "blister",
blisters: [
{
usage: 1,
@@ -167,6 +172,7 @@ describe("buildSchedulePreview", () => {
pillsPerBlister: 30,
looseTablets: 0,
takenBy: [],
packageType: "blister",
blisters: [{ usage: 1, every: 1, start: "2024-03-10T09:00:00" }],
updatedAt: null,
},
@@ -181,6 +187,7 @@ describe("buildSchedulePreview", () => {
pillsPerBlister: 30,
looseTablets: 0,
takenBy: [],
packageType: "blister",
blisters: [{ usage: 1, every: 1, start: "2024-03-10T21:00:00" }],
updatedAt: new Date("2024-03-15T10:00:00Z").toISOString(),
},
@@ -208,6 +215,7 @@ describe("buildSchedulePreview", () => {
pillsPerBlister: 30,
looseTablets: 0,
takenBy: [],
packageType: "blister",
blisters: [{ usage: 1, every: 1, start: "2024-03-14T15:30:00" }],
updatedAt: null,
},
@@ -249,6 +257,7 @@ describe("calculateCoverage", () => {
pillsPerBlister: 30,
looseTablets: 0,
takenBy: [],
packageType: "blister",
blisters: [
{
usage: 1,
@@ -260,7 +269,7 @@ describe("calculateCoverage", () => {
},
];
const events = [{ medName: "TestMed", when: Date.now() }];
const events = [{ medName: "TestMed", when: Date.now(), id: "test-dose-id" }];
const result = calculateCoverage(meds, events, "en", 7, "automatic", new Set());
expect(result.all).toHaveLength(1);
@@ -278,6 +287,7 @@ describe("calculateCoverage", () => {
pillsPerBlister: 30,
looseTablets: 0,
takenBy: [],
packageType: "blister",
blisters: [],
updatedAt: null,
},
@@ -301,6 +311,7 @@ describe("calculateCoverage", () => {
pillsPerBlister: 30,
looseTablets: 0,
takenBy: [],
packageType: "blister",
blisters: [], // Empty blisters — intakes should be used instead
intakes: [
{
@@ -334,6 +345,7 @@ describe("calculateCoverage", () => {
pillsPerBlister: 60,
looseTablets: 0,
takenBy: ["Alice", "Bob"],
packageType: "blister",
blisters: [],
intakes: [
{
@@ -377,6 +389,7 @@ describe("calculateCoverage", () => {
pillsPerBlister: 30,
looseTablets: 0,
takenBy: [],
packageType: "blister",
blisters: [
{
usage: 1,
@@ -406,6 +419,7 @@ describe("calculateCoverage", () => {
pillsPerBlister: 30,
looseTablets: 5,
takenBy: [],
packageType: "blister",
blisters: [
{
usage: 1,
@@ -431,6 +445,7 @@ describe("calculateCoverage", () => {
pillsPerBlister: 30,
looseTablets: 0,
takenBy: [],
packageType: "blister",
blisters: [
{
usage: 1,
@@ -458,6 +473,7 @@ describe("calculateCoverage", () => {
pillsPerBlister: 30,
looseTablets: 0,
takenBy: ["Alice", "Bob"],
packageType: "blister",
blisters: [
{
usage: 1,
@@ -495,6 +511,7 @@ describe("calculateCoverage", () => {
stockAdjustment: -83, // 196 - 83 = 113 pills
lastStockCorrectionAt: correctionTime.toISOString(),
takenBy: [],
packageType: "blister",
blisters: [
{
usage: 1,
@@ -533,6 +550,7 @@ describe("calculateCoverage", () => {
stockAdjustment: -7, // 30 - 7 = 23 pills
lastStockCorrectionAt: correctionTime.toISOString(),
takenBy: [],
packageType: "blister",
blisters: [
{
usage: 1,
@@ -576,6 +594,7 @@ describe("calculateCoverage", () => {
stockAdjustment: -7, // 30 - 7 = 23 pills
lastStockCorrectionAt: correctionTime.toISOString(),
takenBy: [],
packageType: "blister",
blisters: [
{
usage: 1,
@@ -615,6 +634,7 @@ describe("calculateCoverage", () => {
stockAdjustment: -5, // 30 - 5 = 25 pills
lastStockCorrectionAt: correctionTime.toISOString(),
takenBy: [],
packageType: "blister",
blisters: [
{
usage: 1,
@@ -652,6 +672,7 @@ describe("calculateCoverage", () => {
stockAdjustment: -5,
lastStockCorrectionAt: correctionTime.toISOString(),
takenBy: [],
packageType: "blister",
blisters: [
{
usage: 1,
@@ -685,6 +706,7 @@ describe("calculateCoverage", () => {
pillsPerBlister: 30,
looseTablets: 0,
takenBy: [],
packageType: "blister",
blisters: [
{
usage: 1,
@@ -727,6 +749,7 @@ describe("calculateCoverage", () => {
pillsPerBlister: 30,
looseTablets: 0,
takenBy: [],
packageType: "blister",
blisters: [
{
usage: 1,
@@ -766,6 +789,7 @@ describe("calculateCoverage", () => {
pillsPerBlister: 30,
looseTablets: 0,
takenBy: [],
packageType: "blister",
blisters: [
{
usage: 1,
@@ -808,6 +832,7 @@ describe("calculateCoverage", () => {
stockAdjustment: -85, // 196 - 85 = 111 pills
lastStockCorrectionAt: correctionTime.toISOString(),
takenBy: [],
packageType: "blister",
blisters: [
{
usage: 1,
@@ -848,6 +873,7 @@ describe("calculateCoverage", () => {
stockAdjustment: -85, // 196 - 85 = 111 pills
lastStockCorrectionAt: correctionTime.toISOString(),
takenBy: [],
packageType: "blister",
blisters: [
{
usage: 1,
@@ -888,6 +914,7 @@ describe("calculateCoverage", () => {
stockAdjustment: -7, // 30 - 7 = 23 pills
lastStockCorrectionAt: correctionTime.toISOString(),
takenBy: [],
packageType: "blister",
blisters: [
{
usage: 1,
@@ -926,6 +953,7 @@ describe("calculateCoverage", () => {
pillsPerBlister: 30,
looseTablets: 0,
takenBy: [],
packageType: "blister",
blisters: [
{
usage: 1,
@@ -971,6 +999,7 @@ describe("calculateCoverage", () => {
stockAdjustment: -85, // 196 - 85 = 111
lastStockCorrectionAt: correctionTime.toISOString(),
takenBy: [],
packageType: "blister",
blisters: [{ usage: 1, every: 1, start: "2024-01-01T08:00:00" }],
updatedAt: correctionTime.toISOString(),
},
@@ -984,6 +1013,7 @@ describe("calculateCoverage", () => {
stockAdjustment: -10, // 30 - 10 = 20
lastStockCorrectionAt: correctionTime.toISOString(),
takenBy: [],
packageType: "blister",
blisters: [{ usage: 1, every: 1, start: "2024-01-01T09:00:00" }],
updatedAt: correctionTime.toISOString(),
},
@@ -997,6 +1027,7 @@ describe("calculateCoverage", () => {
stockAdjustment: -2, // 10 - 2 = 8
lastStockCorrectionAt: correctionTime.toISOString(),
takenBy: [],
packageType: "blister",
blisters: [{ usage: 1, every: 7, start: "2024-01-05T10:00:00" }],
updatedAt: correctionTime.toISOString(),
},
@@ -1040,6 +1071,7 @@ describe("calculateCoverage", () => {
pillsPerBlister: 30,
looseTablets: 0,
takenBy: ["Daniel"],
packageType: "blister",
blisters: [
{
usage: 1,
@@ -1083,6 +1115,7 @@ describe("calculateCoverage", () => {
pillsPerBlister: 30,
looseTablets: 0,
takenBy: ["Daniel"],
packageType: "blister",
blisters: [
{
usage: 1,
@@ -1114,8 +1147,10 @@ describe("calculateCoverage", () => {
describe("getStockStatus", () => {
const thresholds: StockThresholds = {
lowStockDays: 30,
criticalStockDays: 7,
normalStockDays: 90,
highStockDays: 180,
expiryWarningDays: 30,
};
it("returns out-of-stock when medsLeft is 0", () => {
@@ -1160,6 +1195,7 @@ describe("getStockStatus", () => {
criticalStockDays: 7,
normalStockDays: 90,
highStockDays: 180,
expiryWarningDays: 30,
};
const result = getStockStatus(5, 10, thresholdsWithCritical);
@@ -1603,6 +1639,7 @@ describe("dose tracking survives medication edits (regression)", () => {
pillsPerBlister: 30,
looseTablets: 0,
takenBy: [],
packageType: "blister",
blisters: [{ usage: 1, every: 1, start: "2024-03-10T09:00:00" }],
updatedAt: null,
},
@@ -1636,6 +1673,7 @@ describe("dose tracking survives medication edits (regression)", () => {
pillsPerBlister: 30,
looseTablets: 0,
takenBy: [],
packageType: "blister",
blisters: [{ usage: 1, every: 1, start: "2024-03-10T21:00:00" }],
updatedAt: new Date("2024-03-15T10:00:00Z").toISOString(),
},
@@ -1667,6 +1705,7 @@ describe("dose tracking survives medication edits (regression)", () => {
pillsPerBlister: 30,
looseTablets: 0,
takenBy: [],
packageType: "blister",
blisters: [{ usage: 1, every: 1, start: "2024-03-10T09:00:00" }],
updatedAt: new Date("2024-03-15T10:00:00Z").toISOString(), // Just edited!
},
@@ -1694,6 +1733,7 @@ describe("dose tracking survives medication edits (regression)", () => {
pillsPerBlister: 30,
looseTablets: 0,
takenBy: [],
packageType: "blister",
blisters: [{ usage: 1, every: 1, start: "2024-03-15T09:00:00" }],
updatedAt: null,
},
@@ -1724,6 +1764,7 @@ describe("dose tracking survives medication edits (regression)", () => {
pillsPerBlister: 30,
looseTablets: 0,
takenBy: [],
packageType: "blister",
blisters: [{ usage: 1, every: 1, start: "2024-03-10T09:00:00" }],
updatedAt: new Date("2024-03-15T10:00:00Z").toISOString(),
dismissedUntil: "2024-03-14", // Dismissed through yesterday
@@ -1751,6 +1792,7 @@ describe("dose tracking survives medication edits (regression)", () => {
pillsPerBlister: 30,
looseTablets: 0,
takenBy: [],
packageType: "blister",
blisters: [{ usage: 1, every: 1, start: "2024-03-10T09:00:00" }],
updatedAt: new Date("2024-03-15T10:00:00Z").toISOString(), // Just edited!
},
@@ -1762,6 +1804,7 @@ describe("dose tracking survives medication edits (regression)", () => {
pillsPerBlister: 30,
looseTablets: 0,
takenBy: [],
packageType: "blister",
blisters: [{ usage: 1, every: 1, start: "2024-03-10T08:00:00" }],
updatedAt: null,
},
@@ -1799,6 +1842,7 @@ describe("dose tracking survives medication edits (regression)", () => {
pillsPerBlister: 30,
looseTablets: 0,
takenBy: ["Alice", "Bob"],
packageType: "blister",
blisters: [],
intakes: [
{ usage: 1, every: 1, start: "2024-03-10T09:00:00", takenBy: "Alice", intakeRemindersEnabled: false },
@@ -1836,6 +1880,7 @@ describe("dose tracking survives medication edits (regression)", () => {
pillsPerBlister: 30,
looseTablets: 0,
takenBy: ["Alice", "Bob"],
packageType: "blister",
blisters: [],
intakes: [
{ usage: 1, every: 1, start: "2024-03-10T21:00:00", takenBy: "Alice", intakeRemindersEnabled: false },