125 lines
4.9 KiB
Svelte
125 lines
4.9 KiB
Svelte
|
|
<script>
|
||
|
|
import { PlusCircle, Ruler, X } from 'lucide-svelte';
|
||
|
|
import { signOptions, flagOptions, sexOptions, createTholdRef } from '../referenceRange.js';
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @typedef {Object} Props
|
||
|
|
* @property {Array} refthold - Threshold reference ranges array
|
||
|
|
* @property {(refthold: Array) => void} onupdateRefthold - Update handler
|
||
|
|
*/
|
||
|
|
|
||
|
|
/** @type {Props} */
|
||
|
|
let {
|
||
|
|
refthold = [],
|
||
|
|
onupdateRefthold = () => {}
|
||
|
|
} = $props();
|
||
|
|
|
||
|
|
function addRefRange() {
|
||
|
|
const newRef = createTholdRef();
|
||
|
|
onupdateRefthold([...refthold, newRef]);
|
||
|
|
}
|
||
|
|
|
||
|
|
function removeRefRange(index) {
|
||
|
|
onupdateRefthold(refthold.filter((_, i) => i !== index));
|
||
|
|
}
|
||
|
|
</script>
|
||
|
|
|
||
|
|
<div class="space-y-4">
|
||
|
|
<div class="flex justify-between items-center">
|
||
|
|
<div class="flex items-center gap-2">
|
||
|
|
<Ruler class="w-5 h-5 text-primary" />
|
||
|
|
<h3 class="font-semibold">Threshold 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 refthold?.length === 0}
|
||
|
|
<div class="text-center py-8 bg-base-200 rounded-lg border-2 border-dashed border-base-300">
|
||
|
|
<Ruler class="w-12 h-12 mx-auto text-gray-400 mb-2" />
|
||
|
|
<p class="text-gray-500">No threshold 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 refthold || [] 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}>
|
||
|
|
{#each flagOptions as option (option.value)}
|
||
|
|
<option value={option.value}>{option.label} - {option.description}</option>
|
||
|
|
{/each}
|
||
|
|
</select>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div class="grid grid-cols-1 sm:grid-cols-2 gap-3 mt-3">
|
||
|
|
<div class="form-control">
|
||
|
|
<span class="label-text text-xs mb-1">Lower Value</span>
|
||
|
|
<div class="flex gap-2">
|
||
|
|
<select class="select select-sm select-bordered w-20" bind:value={ref.LowSign}>
|
||
|
|
{#each signOptions as option (option.value)}
|
||
|
|
<option value={option.value}>{option.label}</option>
|
||
|
|
{/each}
|
||
|
|
</select>
|
||
|
|
<input type="number" step="0.01" class="input input-sm input-bordered flex-1" bind:value={ref.Low} placeholder="e.g., 5" />
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div class="form-control">
|
||
|
|
<span class="label-text text-xs mb-1">Upper Value</span>
|
||
|
|
<div class="flex gap-2">
|
||
|
|
<select class="select select-sm select-bordered w-20" bind:value={ref.HighSign}>
|
||
|
|
{#each signOptions as option (option.value)}
|
||
|
|
<option value={option.value}>{option.label}</option>
|
||
|
|
{/each}
|
||
|
|
</select>
|
||
|
|
<input type="number" step="0.01" class="input input-sm input-bordered flex-1" bind:value={ref.High} placeholder="e.g., 10" />
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div class="form-control mt-3">
|
||
|
|
<span class="label-text text-xs mb-1">Interpretation</span>
|
||
|
|
<input type="text" class="input input-sm input-bordered w-full" bind:value={ref.Interpretation} placeholder="e.g., Alert threshold" />
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
{/each}
|
||
|
|
</div>
|