clqms-fe1/backup/tests_backup/test-modal/ValueSetRefRange.svelte

175 lines
6.6 KiB
Svelte
Raw Normal View History

<script>
import { PlusCircle, Box, X, ChevronDown, ChevronUp, Beaker, Filter } from 'lucide-svelte';
import { sexOptions, createVsetRef } from '../referenceRange.js';
import { fetchValueSetByKey } from '$lib/api/valuesets.js';
import { onMount } from 'svelte';
/**
* @typedef {Object} Props
* @property {Array} refvset - Value set reference ranges array
* @property {(refvset: Array) => void} onupdateRefvset - Update handler
*/
/** @type {Props} */
let {
refvset = [],
onupdateRefvset = () => {}
} = $props();
let expandedRanges = $state({});
let specimenTypeOptions = $state([]);
onMount(async () => {
try {
const response = await fetchValueSetByKey('specimen_type');
specimenTypeOptions = response.data?.items?.map(item => ({
value: item.itemCode,
label: item.itemValue
})) || [];
} catch (err) {
console.error('Failed to load specimen types:', err);
}
});
function addRefRange() {
const newRef = createVsetRef();
onupdateRefvset([...refvset, newRef]);
expandedRanges[refvset.length] = { specimen: false };
}
function removeRefRange(index) {
onupdateRefvset(refvset.filter((_, i) => i !== index));
delete expandedRanges[index];
}
function toggleSpecimenExpand(index) {
expandedRanges[index] = { ...expandedRanges[index], specimen: !expandedRanges[index]?.specimen };
}
</script>
<div class="space-y-3">
<div class="flex justify-between items-center">
<div class="flex items-center gap-2">
<Box class="w-5 h-5 text-primary" />
<h3 class="font-semibold">Value Set Reference Ranges</h3>
</div>
<button type="button" class="btn btn-sm btn-primary" onclick={addRefRange}>
<PlusCircle class="w-4 h-4 mr-1" />
Add Range
</button>
</div>
{#if refvset?.length === 0}
<div class="text-center py-8 bg-base-200 rounded-lg border-2 border-dashed border-base-300">
<Box class="w-12 h-12 mx-auto text-gray-400 mb-2" />
<p class="text-gray-500">No value set ranges defined</p>
<button type="button" class="btn btn-sm btn-outline mt-2" onclick={addRefRange}>
<PlusCircle class="w-4 h-4 mr-1" />
Add First Range
</button>
</div>
{/if}
{#each refvset || [] as ref, index (index)}
<div class="card bg-base-100 border-2 border-base-200 hover:border-primary/50 transition-colors">
<div class="card-body p-4">
<div class="flex justify-between items-center mb-4 pb-3 border-b border-base-200">
<span class="badge badge-primary badge-lg">Range {index + 1}</span>
<button type="button" class="btn btn-sm btn-ghost text-error" onclick={() => removeRefRange(index)}>
<X class="w-4 h-4" />
Remove
</button>
</div>
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-3">
<div class="form-control">
<span class="label-text text-xs mb-1">Sex</span>
<select class="select select-sm select-bordered w-full" bind:value={ref.Sex}>
{#each sexOptions as option (option.value)}
<option value={option.value}>{option.label}</option>
{/each}
</select>
</div>
<div class="form-control">
<span class="label-text text-xs mb-1">Age From</span>
<input type="number" min="0" max="120" class="input input-sm input-bordered w-full" bind:value={ref.AgeStart} placeholder="0" />
</div>
<div class="form-control">
<span class="label-text text-xs mb-1">Age To</span>
<input type="number" min="0" max="120" class="input input-sm input-bordered w-full" bind:value={ref.AgeEnd} placeholder="120" />
</div>
<div class="form-control">
<span class="label-text text-xs mb-1">Flag</span>
<select class="select select-sm select-bordered w-full" bind:value={ref.Flag}>
<option value="N">N - Normal</option>
<option value="A">A - Abnormal</option>
</select>
</div>
</div>
<div class="form-control mt-3">
<span class="label-text text-xs mb-1">Value Set</span>
<input type="text" class="input input-sm input-bordered w-full" bind:value={ref.RefTxt} placeholder="e.g., Positive, Negative, Borderline" />
<span class="label-text-alt text-xs text-gray-500 mt-1">Comma-separated list of allowed values</span>
</div>
<!-- Expandable: Specimen and Criteria -->
<div class="border border-base-200 rounded-lg overflow-hidden mt-3">
<button
type="button"
class="w-full px-3 py-2 bg-base-200 hover:bg-base-300 flex items-center justify-between text-sm transition-colors"
onclick={() => toggleSpecimenExpand(index)}
>
<span class="flex items-center gap-2">
<Beaker class="w-3 h-3" />
<span class="text-xs">Specimen & Criteria</span>
{#if ref.SpcType || ref.Criteria}
<span class="text-xs text-primary">(Custom)</span>
{:else}
<span class="text-xs text-gray-500">(Optional)</span>
{/if}
</span>
{#if expandedRanges[index]?.specimen}
<ChevronUp class="w-4 h-4" />
{:else}
<ChevronDown class="w-4 h-4" />
{/if}
</button>
{#if expandedRanges[index]?.specimen}
<div class="p-3 bg-base-100 space-y-3">
<div class="form-control">
<span class="label-text text-xs mb-1 flex items-center gap-1">
<Beaker class="w-3 h-3" />
Specimen Type
</span>
<select class="select select-sm select-bordered w-full" bind:value={ref.SpcType}>
<option value="">Any specimen</option>
{#each specimenTypeOptions as option}
<option value={option.value}>{option.label}</option>
{/each}
</select>
</div>
<div class="form-control">
<span class="label-text text-xs mb-1 flex items-center gap-1">
<Filter class="w-3 h-3" />
Criteria
</span>
<input
type="text"
class="input input-sm input-bordered w-full"
bind:value={ref.Criteria}
placeholder="e.g., Fasting, Morning sample"
/>
</div>
</div>
{/if}
</div>
</div>
</div>
{/each}
</div>