Update migrated js to ts and shadcn

This commit is contained in:
2025-11-26 20:00:39 +00:00
parent d5938046a2
commit 551ba9fd62
51 changed files with 1702 additions and 937 deletions

View File

@@ -1,15 +1,21 @@
import { timeToMinutes } from './timeUtils.js';
import { calculateSingleDoseConcentration } from './pharmacokinetics.js';
import { timeToMinutes } from './timeUtils';
import { calculateSingleDoseConcentration } from './pharmacokinetics';
import type { Dose, Deviation, SteadyStateConfig, PkParams, ConcentrationPoint } from '../constants/defaults';
interface DoseWithTime extends Omit<Dose, 'time'> {
time: number;
isPlan?: boolean;
}
export const calculateCombinedProfile = (
doseSchedule,
deviationList = [],
correction = null,
steadyStateConfig,
simulationDays,
pkParams
) => {
const dataPoints = [];
doseSchedule: Dose[],
deviationList: Deviation[] = [],
correction: Deviation | null = null,
steadyStateConfig: SteadyStateConfig,
simulationDays: string,
pkParams: PkParams
): ConcentrationPoint[] => {
const dataPoints: ConcentrationPoint[] = [];
const timeStepHours = 0.25;
const totalHours = (parseInt(simulationDays, 10) || 3) * 24;
const daysToSimulate = Math.min(parseInt(steadyStateConfig.daysOnMedication, 10) || 0, 5);
@@ -17,13 +23,21 @@ export const calculateCombinedProfile = (
for (let t = 0; t <= totalHours; t += timeStepHours) {
let totalLdx = 0;
let totalDamph = 0;
let allDoses = [];
const allDoses: DoseWithTime[] = [];
const maxDayOffset = (parseInt(simulationDays, 10) || 3) - 1;
for (let day = -daysToSimulate; day <= maxDayOffset; day++) {
const dayOffset = day * 24 * 60;
doseSchedule.forEach(d => {
// Skip doses with empty or invalid time values
const timeStr = String(d.time || '').trim();
const doseStr = String(d.dose || '').trim();
const doseNum = parseFloat(doseStr);
if (!timeStr || timeStr === '' || !doseStr || doseStr === '' || doseNum === 0 || isNaN(doseNum)) {
return;
}
allDoses.push({ ...d, time: timeToMinutes(d.time) + dayOffset, isPlan: true });
});
}
@@ -34,6 +48,14 @@ export const calculateCombinedProfile = (
}
currentDeviations.forEach(dev => {
// Skip deviations with empty or invalid time values
const timeStr = String(dev.time || '').trim();
const doseStr = String(dev.dose || '').trim();
const doseNum = parseFloat(doseStr);
if (!timeStr || timeStr === '' || !doseStr || doseStr === '' || doseNum === 0 || isNaN(doseNum)) {
return;
}
const devTime = timeToMinutes(dev.time) + (dev.dayOffset || 0) * 24 * 60;
if (!dev.isAdditional) {
const closestDoseIndex = allDoses.reduce((closest, dose, index) => {

View File

@@ -1,7 +1,16 @@
import { LDX_TO_DAMPH_CONVERSION_FACTOR } from '../constants/defaults.js';
import { LDX_TO_DAMPH_CONVERSION_FACTOR, type PkParams } from '../constants/defaults';
interface ConcentrationResult {
ldx: number;
damph: number;
}
// Pharmacokinetic calculations
export const calculateSingleDoseConcentration = (dose, timeSinceDoseHours, pkParams) => {
export const calculateSingleDoseConcentration = (
dose: string,
timeSinceDoseHours: number,
pkParams: PkParams
): ConcentrationResult => {
const numDose = parseFloat(dose) || 0;
if (timeSinceDoseHours < 0 || numDose <= 0) return { ldx: 0, damph: 0 };

View File

@@ -1,14 +1,24 @@
import { timeToMinutes } from './timeUtils.js';
import { calculateCombinedProfile } from './calculations.js';
import { timeToMinutes } from './timeUtils';
import { calculateCombinedProfile } from './calculations';
import type { Dose, Deviation, SteadyStateConfig, PkParams } from '../constants/defaults';
interface SuggestionResult {
text?: string;
time?: string;
dose?: string;
isAdditional?: boolean;
originalDose?: string;
dayOffset?: number;
}
export const generateSuggestion = (
doses,
deviations,
doseIncrement,
simulationDays,
steadyStateConfig,
pkParams
) => {
doses: Dose[],
deviations: Deviation[],
doseIncrement: string,
simulationDays: string,
steadyStateConfig: SteadyStateConfig,
pkParams: PkParams
): SuggestionResult | null => {
if (deviations.length === 0) {
return null;
}
@@ -18,12 +28,23 @@ export const generateSuggestion = (
(timeToMinutes(b.time) + (b.dayOffset || 0) * 1440)
).pop();
if (!lastDeviation) return null;
const deviationTimeTotalMinutes = timeToMinutes(lastDeviation.time) + (lastDeviation.dayOffset || 0) * 1440;
let nextDose = null;
type DoseWithOffset = Dose & { dayOffset: number };
let nextDose: DoseWithOffset | null = null;
let minDiff = Infinity;
doses.forEach(d => {
// Skip doses with empty or invalid time/dose values
const timeStr = String(d.time || '').trim();
const doseStr = String(d.dose || '').trim();
const doseNum = parseFloat(doseStr);
if (!timeStr || timeStr === '' || !doseStr || doseStr === '' || doseNum === 0 || isNaN(doseNum)) {
return;
}
const doseTimeInMinutes = timeToMinutes(d.time);
for (let i = 0; i < (parseInt(simulationDays, 10) || 1); i++) {
const absoluteTime = doseTimeInMinutes + i * 1440;
@@ -39,11 +60,14 @@ export const generateSuggestion = (
return { text: "Keine passende nächste Dosis für Korrektur gefunden." };
}
// Type assertion after null check
const confirmedNextDose: DoseWithOffset = nextDose;
const numDoseIncrement = parseFloat(doseIncrement) || 1;
const idealProfile = calculateCombinedProfile(doses, [], null, steadyStateConfig, simulationDays, pkParams);
const deviatedProfile = calculateCombinedProfile(doses, deviations, null, steadyStateConfig, simulationDays, pkParams);
const nextDoseTimeHours = (timeToMinutes(nextDose.time) + (nextDose.dayOffset || 0) * 1440) / 60;
const nextDoseTimeHours = (timeToMinutes(confirmedNextDose.time) + (confirmedNextDose.dayOffset || 0) * 1440) / 60;
const idealConcentration = idealProfile.find(p => Math.abs(p.timeHours - nextDoseTimeHours) < 0.1)?.damph || 0;
const deviatedConcentration = deviatedProfile.find(p => Math.abs(p.timeHours - nextDoseTimeHours) < 0.1)?.damph || 0;
@@ -56,14 +80,14 @@ export const generateSuggestion = (
const doseAdjustmentFactor = 0.5;
let doseChange = concentrationDifference / doseAdjustmentFactor;
doseChange = Math.round(doseChange / numDoseIncrement) * numDoseIncrement;
let suggestedDoseValue = (parseFloat(nextDose.dose) || 0) + doseChange;
let suggestedDoseValue = (parseFloat(confirmedNextDose.dose) || 0) + doseChange;
suggestedDoseValue = Math.max(0, Math.min(70, suggestedDoseValue));
return {
time: nextDose.time,
time: confirmedNextDose.time,
dose: String(suggestedDoseValue),
isAdditional: false,
originalDose: nextDose.dose,
dayOffset: nextDose.dayOffset
originalDose: confirmedNextDose.dose,
dayOffset: confirmedNextDose.dayOffset
};
};

View File

@@ -1,5 +1,5 @@
// --- Helper Functions ---
export const timeToMinutes = (timeStr) => {
// Time utility functions
export const timeToMinutes = (timeStr: string): number => {
if (!timeStr || !timeStr.includes(':')) return 0;
const [hours, minutes] = timeStr.split(':').map(Number);
return hours * 60 + minutes;