Fix isFed state for regular plan comparison line, simplified urin ph selection
This commit is contained in:
@@ -46,7 +46,6 @@ const getDefaultsForTranslation = (pkParams: any, therapeuticRange: any, uiSetti
|
|||||||
standardVdPreset: defaults.pkParams.advanced.standardVd?.preset || 'adult',
|
standardVdPreset: defaults.pkParams.advanced.standardVd?.preset || 'adult',
|
||||||
bodyWeight: defaults.pkParams.advanced.weightBasedVd.bodyWeight,
|
bodyWeight: defaults.pkParams.advanced.weightBasedVd.bodyWeight,
|
||||||
tmaxDelay: defaults.pkParams.advanced.foodEffect.tmaxDelay,
|
tmaxDelay: defaults.pkParams.advanced.foodEffect.tmaxDelay,
|
||||||
phTendency: defaults.pkParams.advanced.urinePh.phTendency,
|
|
||||||
fOral: defaults.pkParams.advanced.fOral,
|
fOral: defaults.pkParams.advanced.fOral,
|
||||||
fOralPercent: String((parseFloat(defaults.pkParams.advanced.fOral) * 100).toFixed(1)),
|
fOralPercent: String((parseFloat(defaults.pkParams.advanced.fOral) * 100).toFixed(1)),
|
||||||
steadyStateDays: defaults.pkParams.advanced.steadyStateDays,
|
steadyStateDays: defaults.pkParams.advanced.steadyStateDays,
|
||||||
@@ -924,12 +923,7 @@ const Settings = ({
|
|||||||
{/* Urine pH */}
|
{/* Urine pH */}
|
||||||
<div className="space-y-3">
|
<div className="space-y-3">
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
<Switch
|
<Label htmlFor="urinePHMode" className="font-medium">
|
||||||
id="urinePHEnabled"
|
|
||||||
checked={pkParams.advanced.urinePh.enabled}
|
|
||||||
onCheckedChange={checked => updateAdvanced('urinePh', 'enabled', checked)}
|
|
||||||
/>
|
|
||||||
<Label htmlFor="urinePHEnabled" className="font-medium">
|
|
||||||
{t('urinePHTendency')}
|
{t('urinePHTendency')}
|
||||||
</Label>
|
</Label>
|
||||||
<Tooltip open={openTooltipId === 'urinePH'} onOpenChange={(open) => setOpenTooltipId(open ? 'urinePH' : null)}>
|
<Tooltip open={openTooltipId === 'urinePH'} onOpenChange={(open) => setOpenTooltipId(open ? 'urinePH' : null)}>
|
||||||
@@ -949,38 +943,23 @@ const Settings = ({
|
|||||||
</TooltipContent>
|
</TooltipContent>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</div>
|
</div>
|
||||||
{pkParams.advanced.urinePh.enabled && (
|
<div>
|
||||||
<div className="ml-8 space-y-2">
|
<Select
|
||||||
<div className="flex items-center gap-2">
|
value={pkParams.advanced.urinePh.mode}
|
||||||
<Label className="text-sm font-medium">{t('urinePHValue')}</Label>
|
onValueChange={(value: 'normal' | 'acidic' | 'alkaline') =>
|
||||||
<Tooltip open={openTooltipId === 'urinePHValue'} onOpenChange={(open) => setOpenTooltipId(open ? 'urinePHValue' : null)}>
|
updateAdvanced('urinePh', 'mode', value)
|
||||||
<TooltipTrigger asChild>
|
}
|
||||||
<button
|
>
|
||||||
type="button"
|
<SelectTrigger id="urinePHMode">
|
||||||
onClick={handleTooltipToggle('urinePHValue')}
|
<SelectValue />
|
||||||
onTouchStart={handleTooltipToggle('urinePHValue')}
|
</SelectTrigger>
|
||||||
className="inline-flex items-center justify-center rounded-sm text-muted-foreground hover:text-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2"
|
<SelectContent>
|
||||||
aria-label={t('urinePHValueTooltip')}
|
<SelectItem value="normal">{t('urinePHModeNormal')}</SelectItem>
|
||||||
>
|
<SelectItem value="acidic">{t('urinePHModeAcidic')}</SelectItem>
|
||||||
<Info className="h-4 w-4" />
|
<SelectItem value="alkaline">{t('urinePHModeAlkaline')}</SelectItem>
|
||||||
</button>
|
</SelectContent>
|
||||||
</TooltipTrigger>
|
</Select>
|
||||||
<TooltipContent side={tooltipSide}>
|
</div>
|
||||||
<p className="text-xs max-w-xs">{tWithDefaults(t, 'urinePHValueTooltip', defaultsForT)}</p>
|
|
||||||
</TooltipContent>
|
|
||||||
</Tooltip>
|
|
||||||
</div>
|
|
||||||
<FormNumericInput
|
|
||||||
value={pkParams.advanced.urinePh.phTendency}
|
|
||||||
onChange={val => updateAdvanced('urinePh', 'phTendency', val)}
|
|
||||||
increment={0.1}
|
|
||||||
min={5.5}
|
|
||||||
max={8.0}
|
|
||||||
unit={t('phUnit')}
|
|
||||||
required={true}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Separator className="my-4" />
|
<Separator className="my-4" />
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ const versionInfo = versionJsonDefault && Object.keys(versionJsonDefault).length
|
|||||||
gitDate: 'unknown',
|
gitDate: 'unknown',
|
||||||
};
|
};
|
||||||
|
|
||||||
export const LOCAL_STORAGE_KEY = 'medPlanAssistantState_v8'; // Incremented for ageGroup + renalFunction fields
|
export const LOCAL_STORAGE_KEY = 'medPlanAssistantState_v9'; // Incremented for urinePh mode structure change
|
||||||
export const PROJECT_REPOSITORY_URL = 'https://git.11001001.org/cbaoth/med-plan-assistant';
|
export const PROJECT_REPOSITORY_URL = 'https://git.11001001.org/cbaoth/med-plan-assistant';
|
||||||
export const APP_VERSION = versionInfo.version;
|
export const APP_VERSION = versionInfo.version;
|
||||||
export const BUILD_INFO = versionInfo;
|
export const BUILD_INFO = versionInfo;
|
||||||
@@ -42,7 +42,7 @@ export interface AdvancedSettings {
|
|||||||
standardVd: { preset: 'adult' | 'child' | 'custom'; customValue: string }; // Volume of distribution (L)
|
standardVd: { preset: 'adult' | 'child' | 'custom'; customValue: string }; // Volume of distribution (L)
|
||||||
weightBasedVd: { enabled: boolean; bodyWeight: string }; // kg
|
weightBasedVd: { enabled: boolean; bodyWeight: string }; // kg
|
||||||
foodEffect: { enabled: boolean; tmaxDelay: string }; // hours
|
foodEffect: { enabled: boolean; tmaxDelay: string }; // hours
|
||||||
urinePh: { enabled: boolean; phTendency: string }; // 5.5-8.0 range
|
urinePh: { mode: 'normal' | 'acidic' | 'alkaline' }; // pH effect on elimination
|
||||||
fOral: string; // bioavailability fraction
|
fOral: string; // bioavailability fraction
|
||||||
steadyStateDays: string; // days of medication history to simulate
|
steadyStateDays: string; // days of medication history to simulate
|
||||||
// Age-specific pharmacokinetics (Research Section 5.2)
|
// Age-specific pharmacokinetics (Research Section 5.2)
|
||||||
@@ -141,7 +141,7 @@ export const getDefaultState = (): AppState => ({
|
|||||||
standardVd: { preset: 'adult', customValue: '377' }, // Adult: 377L (Roberts 2015), Child: ~150-200L
|
standardVd: { preset: 'adult', customValue: '377' }, // Adult: 377L (Roberts 2015), Child: ~150-200L
|
||||||
weightBasedVd: { enabled: false, bodyWeight: '70' }, // kg, adult average
|
weightBasedVd: { enabled: false, bodyWeight: '70' }, // kg, adult average
|
||||||
foodEffect: { enabled: false, tmaxDelay: '1.0' }, // hours delay
|
foodEffect: { enabled: false, tmaxDelay: '1.0' }, // hours delay
|
||||||
urinePh: { enabled: false, phTendency: '6.0' }, // pH scale (5.5-8.0)
|
urinePh: { mode: 'normal' }, // 'normal' (6-7.5), 'acidic' (<6), 'alkaline' (>7.5)
|
||||||
fOral: String(DEFAULT_F_ORAL), // 0.96 bioavailability
|
fOral: String(DEFAULT_F_ORAL), // 0.96 bioavailability
|
||||||
steadyStateDays: '7' // days of prior medication history
|
steadyStateDays: '7' // days of prior medication history
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,10 +29,35 @@ export const useAppState = () => {
|
|||||||
migratedUiSettings.showDayTimeOnXAxis = migratedUiSettings.showDayTimeOnXAxis ? '24h' : 'continuous';
|
migratedUiSettings.showDayTimeOnXAxis = migratedUiSettings.showDayTimeOnXAxis ? '24h' : 'continuous';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Migrate urinePh from old {enabled, phTendency} to new {mode} structure
|
||||||
|
let migratedPkParams = {...defaults.pkParams, ...parsedState.pkParams};
|
||||||
|
if (migratedPkParams.advanced) {
|
||||||
|
const oldUrinePh = migratedPkParams.advanced.urinePh as any;
|
||||||
|
if (oldUrinePh && typeof oldUrinePh === 'object' && 'enabled' in oldUrinePh) {
|
||||||
|
// Old format detected: {enabled: boolean, phTendency: string}
|
||||||
|
if (!oldUrinePh.enabled) {
|
||||||
|
migratedPkParams.advanced.urinePh = { mode: 'normal' };
|
||||||
|
} else {
|
||||||
|
const phValue = parseFloat(oldUrinePh.phTendency);
|
||||||
|
if (!isNaN(phValue)) {
|
||||||
|
if (phValue < 6.0) {
|
||||||
|
migratedPkParams.advanced.urinePh = { mode: 'acidic' };
|
||||||
|
} else if (phValue > 7.5) {
|
||||||
|
migratedPkParams.advanced.urinePh = { mode: 'alkaline' };
|
||||||
|
} else {
|
||||||
|
migratedPkParams.advanced.urinePh = { mode: 'normal' };
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
migratedPkParams.advanced.urinePh = { mode: 'normal' };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
setAppState({
|
setAppState({
|
||||||
...defaults,
|
...defaults,
|
||||||
...parsedState,
|
...parsedState,
|
||||||
pkParams: {...defaults.pkParams, ...parsedState.pkParams},
|
pkParams: migratedPkParams,
|
||||||
days: parsedState.days || defaults.days,
|
days: parsedState.days || defaults.days,
|
||||||
uiSettings: migratedUiSettings,
|
uiSettings: migratedUiSettings,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -72,7 +72,8 @@ export const useSimulation = (appState: AppState) => {
|
|||||||
doses: templateDay.doses.map(d => ({
|
doses: templateDay.doses.map(d => ({
|
||||||
id: `${d.id}-template-${i}`,
|
id: `${d.id}-template-${i}`,
|
||||||
time: d.time,
|
time: d.time,
|
||||||
ldx: d.ldx
|
ldx: d.ldx,
|
||||||
|
isFed: d.isFed // Preserve food-timing flag for proper absorption delay modeling
|
||||||
}))
|
}))
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|||||||
@@ -135,7 +135,11 @@ export const de = {
|
|||||||
tmaxDelayUnit: "h",
|
tmaxDelayUnit: "h",
|
||||||
|
|
||||||
urinePHTendency: "Urin-pH-Effekte",
|
urinePHTendency: "Urin-pH-Effekte",
|
||||||
urinePHTooltip: "Urin-pH beeinflusst Nierenrückresorption von Amphetamin. Ermöglicht pH-abhängige Halbwertszeit-Variation (7-15h Bereich). Bei Deaktivierung: neutraler pH (~11h HWZ).",
|
urinePHTooltip: "Urin-pH beeinflusst Nierenrückresorption von Amphetamin. Saurer Urin (<6) erhöht Elimination (schnellere Ausscheidung, t½ ~7-9h). Normaler pH (6-7,5) hält Basis-Elimination (~11h). Alkalischer Urin (>7,5) reduziert Elimination (langsamere Ausscheidung, t½ ~13-15h). Typischer Bereich: 5,5-8,0. Standard: Normaler pH (6-7,5).",
|
||||||
|
urinePHMode: "pH-Effekt",
|
||||||
|
urinePHModeNormal: "Normal (pH 6-7,5, t½ 11h)",
|
||||||
|
urinePHModeAcidic: "Sauer (pH <6, schnellere Elimination)",
|
||||||
|
urinePHModeAlkaline: "Alkalisch (pH >7,5, langsamere Elimination)",
|
||||||
urinePHValue: "pH-Wert",
|
urinePHValue: "pH-Wert",
|
||||||
urinePHValueTooltip: "Dein typischer Urin-pH (sauer=schnellere Ausscheidung, alkalisch=langsamer). Standard: {{phTendency}}. Bereich: 5,5-8,0.",
|
urinePHValueTooltip: "Dein typischer Urin-pH (sauer=schnellere Ausscheidung, alkalisch=langsamer). Standard: {{phTendency}}. Bereich: 5,5-8,0.",
|
||||||
phValue: "pH-Wert",
|
phValue: "pH-Wert",
|
||||||
|
|||||||
@@ -133,7 +133,11 @@ export const en = {
|
|||||||
tmaxDelayUnit: "h",
|
tmaxDelayUnit: "h",
|
||||||
|
|
||||||
urinePHTendency: "Urine pH Effects",
|
urinePHTendency: "Urine pH Effects",
|
||||||
urinePHTooltip: "Urine pH affects kidney reabsorption of amphetamine. Enables pH-dependent half-life variation (7-15h range). When disabled, assumes neutral pH (~11h HL).",
|
urinePHTooltip: "Urine pH affects kidney reabsorption of amphetamine. Acidic urine (<6) increases elimination (faster clearance, t½ ~7-9h). Normal pH (6-7.5) maintains baseline elimination (~11h). Alkaline urine (>7.5) reduces elimination (slower clearance, t½ ~13-15h). Typical range: 5.5-8.0. Default: Normal pH (6-7.5).",
|
||||||
|
urinePHMode: "pH Effect",
|
||||||
|
urinePHModeNormal: "Normal (pH 6-7.5, t½ 11h)",
|
||||||
|
urinePHModeAcidic: "Acidic (pH <6, faster elimination)",
|
||||||
|
urinePHModeAlkaline: "Alkaline (pH >7.5, slower elimination)",
|
||||||
urinePHValue: "pH Value",
|
urinePHValue: "pH Value",
|
||||||
urinePHValueTooltip: "Your typical urine pH (acidic=faster clearance, alkaline=slower). Default: {{phTendency}}. Range: 5.5-8.0.",
|
urinePHValueTooltip: "Your typical urine pH (acidic=faster clearance, alkaline=slower). Default: {{phTendency}}. Range: 5.5-8.0.",
|
||||||
phValue: "pH Value",
|
phValue: "pH Value",
|
||||||
|
|||||||
@@ -250,6 +250,7 @@ export const importSettings = (
|
|||||||
time: dose.time || '12:00',
|
time: dose.time || '12:00',
|
||||||
ldx: dose.ldx || '0',
|
ldx: dose.ldx || '0',
|
||||||
damph: dose.damph,
|
damph: dose.damph,
|
||||||
|
isFed: dose.isFed, // Explicitly preserve food-timing flag
|
||||||
}))
|
}))
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -108,8 +108,7 @@ export const calculateSingleDoseConcentration = (
|
|||||||
// Per-dose food effect takes precedence over global setting
|
// Per-dose food effect takes precedence over global setting
|
||||||
const foodEnabled = isFed !== undefined ? isFed : pkParams.advanced.foodEffect.enabled;
|
const foodEnabled = isFed !== undefined ? isFed : pkParams.advanced.foodEffect.enabled;
|
||||||
const tmaxDelay = foodEnabled ? parseFloat(pkParams.advanced.foodEffect.tmaxDelay) : 0;
|
const tmaxDelay = foodEnabled ? parseFloat(pkParams.advanced.foodEffect.tmaxDelay) : 0;
|
||||||
const urinePHEnabled = pkParams.advanced.urinePh.enabled;
|
const urinePHMode = pkParams.advanced.urinePh.mode;
|
||||||
const phTendency = urinePHEnabled ? parseFloat(pkParams.advanced.urinePh.phTendency) : 6.0;
|
|
||||||
|
|
||||||
// Validate base parameters
|
// Validate base parameters
|
||||||
if (isNaN(absorptionHalfLife) || absorptionHalfLife <= 0 ||
|
if (isNaN(absorptionHalfLife) || absorptionHalfLife <= 0 ||
|
||||||
@@ -125,20 +124,18 @@ export const calculateSingleDoseConcentration = (
|
|||||||
const calculationTime = adjustedTime; // Use delayed time for all kinetic calculations
|
const calculationTime = adjustedTime; // Use delayed time for all kinetic calculations
|
||||||
|
|
||||||
// Apply urine pH effect on elimination half-life
|
// Apply urine pH effect on elimination half-life
|
||||||
// pH < 6: acidic (faster elimination, HL ~7-9h)
|
// Acidic: pH < 6 (faster elimination, HL ~7-9h)
|
||||||
// pH 6-7: normal (HL ~10-12h)
|
// Normal: pH 6-7.5 (baseline elimination, HL ~10-12h)
|
||||||
// pH > 7: alkaline (slower elimination, HL ~13-15h up to 34h extreme)
|
// Alkaline: pH > 7.5 (slower elimination, HL ~13-15h up to 34h extreme)
|
||||||
let adjustedDamphHL = damphHalfLife;
|
let adjustedDamphHL = damphHalfLife;
|
||||||
if (urinePHEnabled) {
|
if (urinePHMode === 'acidic') {
|
||||||
if (phTendency < 6.0) {
|
// Acidic: reduce HL by ~30%
|
||||||
// Acidic: reduce HL by ~30%
|
adjustedDamphHL = damphHalfLife * 0.7;
|
||||||
adjustedDamphHL = damphHalfLife * 0.7;
|
} else if (urinePHMode === 'alkaline') {
|
||||||
} else if (phTendency > 7.5) {
|
// Alkaline: increase HL by ~30-40%
|
||||||
// Alkaline: increase HL by ~30-40%
|
adjustedDamphHL = damphHalfLife * 1.35;
|
||||||
adjustedDamphHL = damphHalfLife * 1.35;
|
|
||||||
}
|
|
||||||
// else: normal pH 6-7.5, no adjustment
|
|
||||||
}
|
}
|
||||||
|
// else: normal mode, no adjustment
|
||||||
|
|
||||||
// Calculate rate constants
|
// Calculate rate constants
|
||||||
const ka_ldx = Math.log(2) / absorptionHalfLife;
|
const ka_ldx = Math.log(2) / absorptionHalfLife;
|
||||||
|
|||||||
Reference in New Issue
Block a user