clqms-fe1/src/routes/(app)/master-data/tests/test-modal/ReferenceRangeSection.svelte

243 lines
7.8 KiB
Svelte
Raw Normal View History

<script>
import { Ruler, Calculator, FileText, Box } from 'lucide-svelte';
import HelpTooltip from '$lib/components/HelpTooltip.svelte';
import NumericRefRange from './NumericRefRange.svelte';
import ThresholdRefRange from './ThresholdRefRange.svelte';
import TextRefRange from './TextRefRange.svelte';
import ValueSetRefRange from './ValueSetRefRange.svelte';
import { createNumRef, createTholdRef, createTextRef, createVsetRef } from '../referenceRange.js';
/**
* @typedef {Object} Props
* @property {Object} formData - Form data object
* @property {(formData: Object) => void} onupdateFormData - Update handler
*/
/** @type {Props} */
let {
formData = $bindable({}),
onupdateFormData = () => {}
} = $props();
// Ensure all reference range items have defined values, never undefined
function normalizeRefNum(ref) {
return {
Sex: ref.Sex ?? '2',
LowSign: ref.LowSign ?? 'GE',
HighSign: ref.HighSign ?? 'LE',
Low: ref.Low ?? null,
High: ref.High ?? null,
AgeStart: ref.AgeStart ?? 0,
AgeEnd: ref.AgeEnd ?? 120,
Flag: ref.Flag ?? 'N',
Interpretation: ref.Interpretation ?? 'Normal',
SpcType: ref.SpcType ?? '',
Criteria: ref.Criteria ?? ''
};
}
function normalizeRefThold(ref) {
return {
Sex: ref.Sex ?? '2',
LowSign: ref.LowSign ?? 'GE',
HighSign: ref.HighSign ?? 'LE',
Low: ref.Low ?? null,
High: ref.High ?? null,
AgeStart: ref.AgeStart ?? 0,
AgeEnd: ref.AgeEnd ?? 120,
Flag: ref.Flag ?? 'N',
Interpretation: ref.Interpretation ?? 'Normal',
SpcType: ref.SpcType ?? '',
Criteria: ref.Criteria ?? ''
};
}
function normalizeRefTxt(ref) {
return {
Sex: ref.Sex ?? '2',
AgeStart: ref.AgeStart ?? 0,
AgeEnd: ref.AgeEnd ?? 120,
RefTxt: ref.RefTxt ?? '',
Flag: ref.Flag ?? 'N',
SpcType: ref.SpcType ?? '',
Criteria: ref.Criteria ?? ''
};
}
function normalizeRefVset(ref) {
return {
Sex: ref.Sex ?? '2',
AgeStart: ref.AgeStart ?? 0,
AgeEnd: ref.AgeEnd ?? 120,
RefTxt: ref.RefTxt ?? '',
Flag: ref.Flag ?? 'N',
SpcType: ref.SpcType ?? '',
Criteria: ref.Criteria ?? ''
};
}
// Reactive normalized data
let normalizedRefnum = $derived((formData.refnum || []).map(normalizeRefNum));
let normalizedRefthold = $derived((formData.refthold || []).map(normalizeRefThold));
let normalizedReftxt = $derived((formData.reftxt || []).map(normalizeRefTxt));
let normalizedRefvset = $derived((formData.refvset || []).map(normalizeRefVset));
function updateRefRangeType(type) {
let newFormData = {
...formData,
refRangeType: type,
refnum: [],
refthold: [],
reftxt: [],
refvset: []
};
// Initialize the selected type
if (type === 'num') {
newFormData.refnum = [createNumRef()];
} else if (type === 'thold') {
newFormData.refthold = [createTholdRef()];
} else if (type === 'text') {
newFormData.reftxt = [createTextRef()];
} else if (type === 'vset') {
newFormData.refvset = [createVsetRef()];
}
onupdateFormData(newFormData);
}
function updateRefnum(refnum) {
onupdateFormData({ ...formData, refnum });
}
function updateRefthold(refthold) {
onupdateFormData({ ...formData, refthold });
}
function updateReftxt(reftxt) {
onupdateFormData({ ...formData, reftxt });
}
function updateRefvset(refvset) {
onupdateFormData({ ...formData, refvset });
}
</script>
<div class="space-y-3">
<!-- Reference Range Type Selection -->
<div class="bg-base-100 rounded-lg border border-base-200 p-4">
<div class="flex items-center gap-2 mb-3">
<Ruler class="w-5 h-5 text-primary" />
<h3 class="font-semibold">Reference Range Type</h3>
<HelpTooltip
text="Choose how to define normal/abnormal ranges for this test."
title="Reference Range Help"
/>
</div>
<div class="flex flex-wrap gap-3">
<label class="label cursor-pointer gap-2 p-3 bg-base-200 rounded-lg hover:bg-base-300 transition-colors flex-1 min-w-[100px]">
<input
type="radio"
name="refRangeType"
class="radio radio-primary"
value="none"
checked={formData.refRangeType === 'none'}
onchange={() => updateRefRangeType('none')}
/>
<div class="flex flex-col">
<span class="label-text font-medium">None</span>
<span class="text-xs text-gray-500">No reference range</span>
</div>
</label>
<label class="label cursor-pointer gap-2 p-3 bg-base-200 rounded-lg hover:bg-base-300 transition-colors flex-1 min-w-[100px]">
<input
type="radio"
name="refRangeType"
class="radio radio-primary"
value="num"
checked={formData.refRangeType === 'num'}
onchange={() => updateRefRangeType('num')}
/>
<div class="flex flex-col">
<span class="label-text font-medium flex items-center gap-1">
Numeric
<Calculator class="w-3 h-3" />
</span>
<span class="text-xs text-gray-500">Range (e.g., 70-100)</span>
</div>
</label>
<label class="label cursor-pointer gap-2 p-3 bg-base-200 rounded-lg hover:bg-base-300 transition-colors flex-1 min-w-[100px]">
<input
type="radio"
name="refRangeType"
class="radio radio-primary"
value="thold"
checked={formData.refRangeType === 'thold'}
onchange={() => updateRefRangeType('thold')}
/>
<div class="flex flex-col">
<span class="label-text font-medium flex items-center gap-1">
Threshold
<Ruler class="w-3 h-3" />
</span>
<span class="text-xs text-gray-500">Limit values</span>
</div>
</label>
<label class="label cursor-pointer gap-2 p-3 bg-base-200 rounded-lg hover:bg-base-300 transition-colors flex-1 min-w-[100px]">
<input
type="radio"
name="refRangeType"
class="radio radio-primary"
value="text"
checked={formData.refRangeType === 'text'}
onchange={() => updateRefRangeType('text')}
/>
<div class="flex flex-col">
<span class="label-text font-medium flex items-center gap-1">
Text
<FileText class="w-3 h-3" />
</span>
<span class="text-xs text-gray-500">Descriptive</span>
</div>
</label>
<label class="label cursor-pointer gap-2 p-3 bg-base-200 rounded-lg hover:bg-base-300 transition-colors flex-1 min-w-[100px]">
<input
type="radio"
name="refRangeType"
class="radio radio-primary"
value="vset"
checked={formData.refRangeType === 'vset'}
onchange={() => updateRefRangeType('vset')}
/>
<div class="flex flex-col">
<span class="label-text font-medium flex items-center gap-1">
Value Set
<Box class="w-3 h-3" />
</span>
<span class="text-xs text-gray-500">Predefined values</span>
</div>
</label>
</div>
</div>
<!-- Numeric Reference Ranges -->
{#if formData.refRangeType === 'num'}
<NumericRefRange refnum={normalizedRefnum} onupdateRefnum={updateRefnum} />
{/if}
<!-- Threshold Reference Ranges -->
{#if formData.refRangeType === 'thold'}
<ThresholdRefRange refthold={normalizedRefthold} onupdateRefthold={updateRefthold} />
{/if}
<!-- Text Reference Ranges -->
{#if formData.refRangeType === 'text'}
<TextRefRange reftxt={normalizedReftxt} onupdateReftxt={updateReftxt} />
{/if}
<!-- Value Set Reference Ranges -->
{#if formData.refRangeType === 'vset'}
<ValueSetRefRange refvset={normalizedRefvset} onupdateRefvset={updateRefvset} />
{/if}
</div>