fix: align frontend types and tests for react 19 (#339)
This commit is contained in:
Generated
+23
-31
@@ -11,8 +11,8 @@
|
||||
"i18next": "^25.8.13",
|
||||
"i18next-browser-languagedetector": "^8.2.1",
|
||||
"lucide-react": "^0.575.0",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"react": "^19.2.0",
|
||||
"react-dom": "^19.2.0",
|
||||
"react-i18next": "^15.4.1",
|
||||
"react-router-dom": "^7.13.1",
|
||||
"zod": "^4.3.6"
|
||||
@@ -24,8 +24,8 @@
|
||||
"@testing-library/react": "^16.3.2",
|
||||
"@testing-library/user-event": "^14.6.1",
|
||||
"@types/node": "^25.3.0",
|
||||
"@types/react": "^18.3.4",
|
||||
"@types/react-dom": "^18.3.0",
|
||||
"@types/react": "^19.2.2",
|
||||
"@types/react-dom": "^19.2.2",
|
||||
"@types/react-router-dom": "^5.3.3",
|
||||
"@vitejs/plugin-react": "^5.1.4",
|
||||
"@vitest/coverage-v8": "^4.0.18",
|
||||
@@ -1788,32 +1788,24 @@
|
||||
"undici-types": "~7.18.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/prop-types": {
|
||||
"version": "15.7.15",
|
||||
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz",
|
||||
"integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/react": {
|
||||
"version": "18.3.27",
|
||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.27.tgz",
|
||||
"integrity": "sha512-cisd7gxkzjBKU2GgdYrTdtQx1SORymWyaAFhaxQPK9bYO9ot3Y5OikQRvY0VYQtvwjeQnizCINJAenh/V7MK2w==",
|
||||
"version": "19.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.2.tgz",
|
||||
"integrity": "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/prop-types": "*",
|
||||
"csstype": "^3.2.2"
|
||||
"csstype": "^3.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/react-dom": {
|
||||
"version": "18.3.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz",
|
||||
"integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==",
|
||||
"version": "19.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.2.tgz",
|
||||
"integrity": "sha512-9KQPoO6mZCi7jcIStSnlOWn2nEF3mNmyr3rIAsGnAbQKYbRLyqmeSc39EVgtxXVia+LMT8j3knZLAZAh+xLmrw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@types/react": "^18.0.0"
|
||||
"@types/react": "^19.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/react-router": {
|
||||
@@ -2967,9 +2959,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/react": {
|
||||
"version": "18.3.1",
|
||||
"resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz",
|
||||
"integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==",
|
||||
"version": "19.2.0",
|
||||
"resolved": "https://registry.npmjs.org/react/-/react-19.2.0.tgz",
|
||||
"integrity": "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.1.0"
|
||||
@@ -2979,16 +2971,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/react-dom": {
|
||||
"version": "18.3.1",
|
||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",
|
||||
"integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==",
|
||||
"version": "19.2.0",
|
||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.0.tgz",
|
||||
"integrity": "sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.1.0",
|
||||
"scheduler": "^0.23.2"
|
||||
"scheduler": "^0.27.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^18.3.1"
|
||||
"react": "^19.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-i18next": {
|
||||
@@ -3156,9 +3148,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/scheduler": {
|
||||
"version": "0.23.2",
|
||||
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz",
|
||||
"integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==",
|
||||
"version": "0.27.0",
|
||||
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz",
|
||||
"integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.1.0"
|
||||
|
||||
@@ -30,8 +30,8 @@
|
||||
"i18next": "^25.8.13",
|
||||
"i18next-browser-languagedetector": "^8.2.1",
|
||||
"lucide-react": "^0.575.0",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"react": "^19.2.0",
|
||||
"react-dom": "^19.2.0",
|
||||
"react-i18next": "^15.4.1",
|
||||
"react-router-dom": "^7.13.1",
|
||||
"zod": "^4.3.6"
|
||||
@@ -43,8 +43,8 @@
|
||||
"@testing-library/react": "^16.3.2",
|
||||
"@testing-library/user-event": "^14.6.1",
|
||||
"@types/node": "^25.3.0",
|
||||
"@types/react": "^18.3.4",
|
||||
"@types/react-dom": "^18.3.0",
|
||||
"@types/react": "^19.2.2",
|
||||
"@types/react-dom": "^19.2.2",
|
||||
"@types/react-router-dom": "^5.3.3",
|
||||
"@vitejs/plugin-react": "^5.1.4",
|
||||
"@vitest/coverage-v8": "^4.0.18",
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// MedicationAvatar Component
|
||||
// =============================================================================
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
|
||||
export type MedicationAvatarProps = {
|
||||
name: string;
|
||||
@@ -12,8 +12,11 @@ export type MedicationAvatarProps = {
|
||||
|
||||
export function MedicationAvatar({ name, imageUrl, size = "sm" }: MedicationAvatarProps) {
|
||||
const [thumbFailed, setThumbFailed] = useState(false);
|
||||
const previousImageUrlRef = useRef(imageUrl);
|
||||
|
||||
useEffect(() => {
|
||||
if (previousImageUrlRef.current === imageUrl) return;
|
||||
previousImageUrlRef.current = imageUrl;
|
||||
setThumbFailed(false);
|
||||
}, [imageUrl]);
|
||||
|
||||
|
||||
@@ -96,9 +96,9 @@ export function MobileEditModal({
|
||||
onAddTakenByPerson,
|
||||
onRemoveTakenByPerson,
|
||||
onTakenByKeyDown,
|
||||
_onSetBlisterValue,
|
||||
_onAddBlister,
|
||||
_onRemoveBlister,
|
||||
onSetBlisterValue: _onSetBlisterValue,
|
||||
onAddBlister: _onAddBlister,
|
||||
onRemoveBlister: _onRemoveBlister,
|
||||
onSetIntakeValue,
|
||||
onAddIntake,
|
||||
onRemoveIntake,
|
||||
@@ -108,7 +108,7 @@ export function MobileEditModal({
|
||||
onDeleteMedImage,
|
||||
imageUploadError,
|
||||
onClose,
|
||||
_onResetForm,
|
||||
onResetForm: _onResetForm,
|
||||
onSaveMedication,
|
||||
}: MobileEditModalProps) {
|
||||
const { t } = useTranslation();
|
||||
@@ -402,7 +402,7 @@ export function MobileEditModal({
|
||||
<select
|
||||
className="package-type-select"
|
||||
value={form.packageType}
|
||||
onChange={(e) => onHandleValueChange("packageType", e.target.value)}
|
||||
onChange={(e) => onHandleValueChange("packageType", e.target.value as FormState["packageType"])}
|
||||
>
|
||||
<option value="blister">{t("form.packageTypeBlister")}</option>
|
||||
<option value="bottle">{t("form.packageTypeBottle")}</option>
|
||||
|
||||
@@ -21,11 +21,11 @@ import { MedicationAvatar } from "./MedicationAvatar";
|
||||
function getStockStatus(
|
||||
daysLeft: number | null,
|
||||
medsLeft: number,
|
||||
thresholds: { lowStockDays: number; normalStockDays: number; highStockDays: number; reminderDaysBefore: number }
|
||||
thresholds: { lowStockDays: number; normalStockDays: number; highStockDays: number; criticalStockDays: number }
|
||||
) {
|
||||
if (medsLeft <= 0 || daysLeft === 0) return { className: "danger", label: "status.outOfStock" };
|
||||
if (daysLeft === null) return { className: "success", label: "status.noSchedule" };
|
||||
if (daysLeft <= thresholds.reminderDaysBefore) return { className: "danger", label: "status.criticalStock" };
|
||||
if (daysLeft <= thresholds.criticalStockDays) return { className: "danger", label: "status.criticalStock" };
|
||||
if (daysLeft < thresholds.lowStockDays) return { className: "warning", label: "status.lowStock" };
|
||||
if (daysLeft >= thresholds.highStockDays) return { className: "high", label: "status.highStock" };
|
||||
return { className: "success", label: "status.normal" };
|
||||
|
||||
@@ -665,7 +665,18 @@ export function AppProvider({ children }: { children: React.ReactNode }) {
|
||||
|
||||
// Get the response text first to handle non-JSON responses
|
||||
const text = await res.text();
|
||||
let data: { error?: string; message?: string; imported?: number } = {};
|
||||
let data: {
|
||||
error?: string;
|
||||
message?: string;
|
||||
imported?:
|
||||
| {
|
||||
medications?: number;
|
||||
doseHistory?: number;
|
||||
refillHistory?: number;
|
||||
shareLinks?: number;
|
||||
}
|
||||
| number;
|
||||
} = {};
|
||||
try {
|
||||
data = text ? JSON.parse(text) : {};
|
||||
} catch {
|
||||
@@ -680,11 +691,12 @@ export function AppProvider({ children }: { children: React.ReactNode }) {
|
||||
}
|
||||
|
||||
// Show success message in UI instead of browser alert
|
||||
const importedCounts = typeof data.imported === "object" && data.imported !== null ? data.imported : null;
|
||||
setImportResult({
|
||||
medications: data.imported?.medications || 0,
|
||||
doses: data.imported?.doseHistory || 0,
|
||||
refills: data.imported?.refillHistory || 0,
|
||||
shares: data.imported?.shareLinks || 0,
|
||||
medications: importedCounts?.medications || 0,
|
||||
doses: importedCounts?.doseHistory || 0,
|
||||
refills: importedCounts?.refillHistory || 0,
|
||||
shares: importedCounts?.shareLinks || 0,
|
||||
});
|
||||
|
||||
// Reload all data
|
||||
|
||||
@@ -6,7 +6,7 @@ import { ConfirmModal, MedicationAvatar } from "../components";
|
||||
import { useAuth } from "../components/Auth";
|
||||
import { useAppContext } from "../context";
|
||||
import { useModalHistory } from "../hooks";
|
||||
import { getMedDisplayName } from "../types";
|
||||
import { type Coverage, getMedDisplayName } from "../types";
|
||||
import { formatNumber, getExpiryClass, getSystemLocale } from "../utils/formatters";
|
||||
import { expandDoseIds, getStockStatus, isDoseDismissed } from "../utils/schedule";
|
||||
import {
|
||||
|
||||
@@ -719,6 +719,7 @@ export function MedicationsPage() {
|
||||
setReadOnlyView(true);
|
||||
startEdit(med, openEditModal);
|
||||
setViewMode("form");
|
||||
scrollToTopForDesktopEdit();
|
||||
};
|
||||
setUnsavedConfirmSource(showEditModal ? "mobile-edit" : "desktop-form");
|
||||
setShowUnsavedConfirm(true);
|
||||
@@ -729,6 +730,7 @@ export function MedicationsPage() {
|
||||
setActiveTab("general");
|
||||
startEdit(med, openEditModal);
|
||||
setViewMode("form");
|
||||
scrollToTopForDesktopEdit();
|
||||
}
|
||||
|
||||
function handleNewEntryClick() {
|
||||
@@ -792,6 +794,7 @@ export function MedicationsPage() {
|
||||
setActiveTab("general");
|
||||
startEdit(medicationToEdit, openEditModal);
|
||||
setViewMode("form");
|
||||
scrollToTopForDesktopEdit();
|
||||
setPendingEditTransition(false);
|
||||
window.dispatchEvent(new Event("medassist:edit-transition-ready"));
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { Coverage } from "../types";
|
||||
import type { Coverage, PackageType } from "../types";
|
||||
import { getMedTotal as getMedTotalFromTypes } from "../types";
|
||||
import { splitCurrentBlisterStock } from "../utils/stock";
|
||||
|
||||
@@ -43,9 +43,12 @@ export function getMedTotal(med: {
|
||||
pillsPerBlister: number;
|
||||
looseTablets: number;
|
||||
stockAdjustment?: number | null;
|
||||
packageType?: string;
|
||||
packageType?: PackageType;
|
||||
}): number {
|
||||
return getMedTotalFromTypes(med);
|
||||
return getMedTotalFromTypes({
|
||||
...med,
|
||||
stockAdjustment: med.stockAdjustment ?? undefined,
|
||||
});
|
||||
}
|
||||
|
||||
export function getReminderStatusData(
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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({}) })
|
||||
|
||||
@@ -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,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,
|
||||
|
||||
@@ -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", () => {
|
||||
|
||||
@@ -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 },
|
||||
|
||||
@@ -35,9 +35,9 @@ export function splitCurrentBlisterStock(
|
||||
*/
|
||||
export function getBlisterStockFromMedication(med: Medication): BlisterStockSplit {
|
||||
const total =
|
||||
(med.packageType === "bottle"
|
||||
med.packageType === "bottle"
|
||||
? med.looseTablets + (med.stockAdjustment ?? 0)
|
||||
: med.packCount * med.blistersPerPack * med.pillsPerBlister + med.looseTablets + (med.stockAdjustment ?? 0)) ?? 0;
|
||||
: med.packCount * med.blistersPerPack * med.pillsPerBlister + med.looseTablets + (med.stockAdjustment ?? 0);
|
||||
|
||||
return splitCurrentBlisterStock(total, med.pillsPerBlister, med.looseTablets);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user