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',
|
||||
bodyWeight: defaults.pkParams.advanced.weightBasedVd.bodyWeight,
|
||||
tmaxDelay: defaults.pkParams.advanced.foodEffect.tmaxDelay,
|
||||
phTendency: defaults.pkParams.advanced.urinePh.phTendency,
|
||||
fOral: defaults.pkParams.advanced.fOral,
|
||||
fOralPercent: String((parseFloat(defaults.pkParams.advanced.fOral) * 100).toFixed(1)),
|
||||
steadyStateDays: defaults.pkParams.advanced.steadyStateDays,
|
||||
@@ -924,12 +923,7 @@ const Settings = ({
|
||||
{/* Urine pH */}
|
||||
<div className="space-y-3">
|
||||
<div className="flex items-center gap-3">
|
||||
<Switch
|
||||
id="urinePHEnabled"
|
||||
checked={pkParams.advanced.urinePh.enabled}
|
||||
onCheckedChange={checked => updateAdvanced('urinePh', 'enabled', checked)}
|
||||
/>
|
||||
<Label htmlFor="urinePHEnabled" className="font-medium">
|
||||
<Label htmlFor="urinePHMode" className="font-medium">
|
||||
{t('urinePHTendency')}
|
||||
</Label>
|
||||
<Tooltip open={openTooltipId === 'urinePH'} onOpenChange={(open) => setOpenTooltipId(open ? 'urinePH' : null)}>
|
||||
@@ -949,38 +943,23 @@ const Settings = ({
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</div>
|
||||
{pkParams.advanced.urinePh.enabled && (
|
||||
<div className="ml-8 space-y-2">
|
||||
<div className="flex items-center gap-2">
|
||||
<Label className="text-sm font-medium">{t('urinePHValue')}</Label>
|
||||
<Tooltip open={openTooltipId === 'urinePHValue'} onOpenChange={(open) => setOpenTooltipId(open ? 'urinePHValue' : null)}>
|
||||
<TooltipTrigger asChild>
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleTooltipToggle('urinePHValue')}
|
||||
onTouchStart={handleTooltipToggle('urinePHValue')}
|
||||
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"
|
||||
aria-label={t('urinePHValueTooltip')}
|
||||
<div>
|
||||
<Select
|
||||
value={pkParams.advanced.urinePh.mode}
|
||||
onValueChange={(value: 'normal' | 'acidic' | 'alkaline') =>
|
||||
updateAdvanced('urinePh', 'mode', value)
|
||||
}
|
||||
>
|
||||
<Info className="h-4 w-4" />
|
||||
</button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side={tooltipSide}>
|
||||
<p className="text-xs max-w-xs">{tWithDefaults(t, 'urinePHValueTooltip', defaultsForT)}</p>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
<SelectTrigger id="urinePHMode">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="normal">{t('urinePHModeNormal')}</SelectItem>
|
||||
<SelectItem value="acidic">{t('urinePHModeAcidic')}</SelectItem>
|
||||
<SelectItem value="alkaline">{t('urinePHModeAlkaline')}</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</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>
|
||||
|
||||
<Separator className="my-4" />
|
||||
|
||||
@@ -26,7 +26,7 @@ const versionInfo = versionJsonDefault && Object.keys(versionJsonDefault).length
|
||||
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 APP_VERSION = versionInfo.version;
|
||||
export const BUILD_INFO = versionInfo;
|
||||
@@ -42,7 +42,7 @@ export interface AdvancedSettings {
|
||||
standardVd: { preset: 'adult' | 'child' | 'custom'; customValue: string }; // Volume of distribution (L)
|
||||
weightBasedVd: { enabled: boolean; bodyWeight: string }; // kg
|
||||
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
|
||||
steadyStateDays: string; // days of medication history to simulate
|
||||
// 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
|
||||
weightBasedVd: { enabled: false, bodyWeight: '70' }, // kg, adult average
|
||||
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
|
||||
steadyStateDays: '7' // days of prior medication history
|
||||
}
|
||||
|
||||
@@ -29,10 +29,35 @@ export const useAppState = () => {
|
||||
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({
|
||||
...defaults,
|
||||
...parsedState,
|
||||
pkParams: {...defaults.pkParams, ...parsedState.pkParams},
|
||||
pkParams: migratedPkParams,
|
||||
days: parsedState.days || defaults.days,
|
||||
uiSettings: migratedUiSettings,
|
||||
});
|
||||
|
||||
@@ -72,7 +72,8 @@ export const useSimulation = (appState: AppState) => {
|
||||
doses: templateDay.doses.map(d => ({
|
||||
id: `${d.id}-template-${i}`,
|
||||
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",
|
||||
|
||||
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",
|
||||
urinePHValueTooltip: "Dein typischer Urin-pH (sauer=schnellere Ausscheidung, alkalisch=langsamer). Standard: {{phTendency}}. Bereich: 5,5-8,0.",
|
||||
phValue: "pH-Wert",
|
||||
|
||||
@@ -133,7 +133,11 @@ export const en = {
|
||||
tmaxDelayUnit: "h",
|
||||
|
||||
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",
|
||||
urinePHValueTooltip: "Your typical urine pH (acidic=faster clearance, alkaline=slower). Default: {{phTendency}}. Range: 5.5-8.0.",
|
||||
phValue: "pH Value",
|
||||
|
||||
@@ -250,6 +250,7 @@ export const importSettings = (
|
||||
time: dose.time || '12:00',
|
||||
ldx: dose.ldx || '0',
|
||||
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
|
||||
const foodEnabled = isFed !== undefined ? isFed : pkParams.advanced.foodEffect.enabled;
|
||||
const tmaxDelay = foodEnabled ? parseFloat(pkParams.advanced.foodEffect.tmaxDelay) : 0;
|
||||
const urinePHEnabled = pkParams.advanced.urinePh.enabled;
|
||||
const phTendency = urinePHEnabled ? parseFloat(pkParams.advanced.urinePh.phTendency) : 6.0;
|
||||
const urinePHMode = pkParams.advanced.urinePh.mode;
|
||||
|
||||
// Validate base parameters
|
||||
if (isNaN(absorptionHalfLife) || absorptionHalfLife <= 0 ||
|
||||
@@ -125,20 +124,18 @@ export const calculateSingleDoseConcentration = (
|
||||
const calculationTime = adjustedTime; // Use delayed time for all kinetic calculations
|
||||
|
||||
// Apply urine pH effect on elimination half-life
|
||||
// pH < 6: acidic (faster elimination, HL ~7-9h)
|
||||
// pH 6-7: normal (HL ~10-12h)
|
||||
// pH > 7: alkaline (slower elimination, HL ~13-15h up to 34h extreme)
|
||||
// Acidic: pH < 6 (faster elimination, HL ~7-9h)
|
||||
// Normal: pH 6-7.5 (baseline elimination, HL ~10-12h)
|
||||
// Alkaline: pH > 7.5 (slower elimination, HL ~13-15h up to 34h extreme)
|
||||
let adjustedDamphHL = damphHalfLife;
|
||||
if (urinePHEnabled) {
|
||||
if (phTendency < 6.0) {
|
||||
if (urinePHMode === 'acidic') {
|
||||
// Acidic: reduce HL by ~30%
|
||||
adjustedDamphHL = damphHalfLife * 0.7;
|
||||
} else if (phTendency > 7.5) {
|
||||
} else if (urinePHMode === 'alkaline') {
|
||||
// Alkaline: increase HL by ~30-40%
|
||||
adjustedDamphHL = damphHalfLife * 1.35;
|
||||
}
|
||||
// else: normal pH 6-7.5, no adjustment
|
||||
}
|
||||
// else: normal mode, no adjustment
|
||||
|
||||
// Calculate rate constants
|
||||
const ka_ldx = Math.log(2) / absorptionHalfLife;
|
||||
|
||||
Reference in New Issue
Block a user