continue create ordertest page

This commit is contained in:
faiztyanirh 2026-04-26 22:08:35 +07:00
parent 3f81d45a55
commit ee04b2e8d5

View File

@ -41,6 +41,8 @@
const leftGroups = $derived([formFields[0]]); const leftGroups = $derived([formFields[0]]);
const rightGroups = $derived(formFields.slice(1)); const rightGroups = $derived(formFields.slice(1));
let selectedTest = $state(null); let selectedTest = $state(null);
let selectedTests2 = $state([]);
let pendingTests = $state([]);
let selectedCodes = $derived( let selectedCodes = $derived(
new Set((formState.form.Tests ?? []).map(t => t.TestSiteCode)) new Set((formState.form.Tests ?? []).map(t => t.TestSiteCode))
); );
@ -67,6 +69,38 @@
return result; return result;
}); });
function toggleTest(test) {
const exists = selectedTests2.find(t => t.rawItem.TestSiteID === test.rawItem.TestSiteID);
if (exists) {
selectedTests2 = selectedTests2.filter(t => t.rawItem.TestSiteID !== test.rawItem.TestSiteID);
} else {
selectedTests2 = [...selectedTests2, test];
}
}
function isSelected(test) {
return selectedTests2.some(t => t.rawItem.TestSiteID === test.rawItem.TestSiteID);
}
function addSelected() {
for (const test of selectedTests2) {
const alreadyAdded = pendingTests.some(t => t.rawItem.TestSiteID === test.rawItem.TestSiteID);
if (!alreadyAdded) {
pendingTests = [...pendingTests, test];
}
}
selectedTests2 = [];
}
function isPending(test) {
return pendingTests.some(t => t.rawItem.TestSiteID === test.rawItem.TestSiteID);
}
function removeTest2(test) {
pendingTests = pendingTests.filter(t => t.rawItem.TestSiteID !== test.rawItem.TestSiteID);
selectedTests2 = selectedTests2.filter(t => t.rawItem.TestSiteID !== test.rawItem.TestSiteID);
}
function getFilteredOptions(key) { function getFilteredOptions(key) {
const query = searchQuery[key] || ''; const query = searchQuery[key] || '';
@ -175,7 +209,7 @@
Object.entries(testsByDiscipline).filter(([disciplineId]) => disciplineId === selectedDiscipline) Object.entries(testsByDiscipline).filter(([disciplineId]) => disciplineId === selectedDiscipline)
); );
}); });
$inspect(searchedTests) $inspect(pendingTests)
</script> </script>
{#snippet Fieldset({ {#snippet Fieldset({
@ -402,8 +436,10 @@
{@const filteredOptions = getFilteredOptions(key)} {@const filteredOptions = getFilteredOptions(key)}
<div class="flex flex-1 h-full min-h-0 w-full gap-2"> <div class="flex flex-1 h-full min-h-0 w-full gap-2">
<div class="flex flex-1 flex-col gap-2 overflow-hidden min-h-0 h-full w-full"> <div class="flex flex-1 flex-col gap-2 overflow-hidden min-h-0 h-full w-full">
<div class="shrink-0 h-18 p-1 flex gap-2 border-b-2 flex flex-col"> <div class="shrink-0 h-18 p-1 flex gap-2 flex flex-col">
<p class="text-xs font-medium text-muted-foreground uppercase tracking-wide">Test list</p> <div class="shrink-0 h-7 border-b-2 flex justify-between items-center">
<p class="text-xs font-medium text-muted-foreground uppercase tracking-wide">Test list</p>
</div>
<div class="flex gap-2"> <div class="flex gap-2">
<Select.Root <Select.Root
type="single" type="single"
@ -434,15 +470,18 @@
> >
<div class="flex items-center gap-2"> <div class="flex items-center gap-2">
<ChevronDownIcon /> <ChevronDownIcon />
<span class="text-sm font-medium">{disciplineName}</span> <span class="text-sm font-medium">{disciplineName ?? 'Unspecified'}</span>
<span class="text-xs text-muted-foreground">{tests.length} tests</span> <span class="text-xs text-muted-foreground">{tests.length} tests</span>
</div> </div>
</Collapsible.Trigger> </Collapsible.Trigger>
<Collapsible.Content> <Collapsible.Content>
<div class="py-1 px-1"> <div class="py-1 px-1">
{#each tests as test} {#each tests as test}
<div class="flex items-center gap-3 px-3 py-2 rounded-md transition-colors"> <div class="flex items-center gap-3 px-3 py-2 rounded-md transition-colors {isPending(test) ? 'opacity-40 pointer-events-none' : ''}">
<Checkbox /> <Checkbox
checked={isSelected(test)}
onCheckedChange={() => toggleTest(test)}
/>
<span class="text-xs font-semibold text-primary w-14 shrink-0">{test.rawItem.TestSiteCode}</span> <span class="text-xs font-semibold text-primary w-14 shrink-0">{test.rawItem.TestSiteCode}</span>
<Label class="text-sm cursor-pointer">{test.rawItem.TestSiteName}</Label> <Label class="text-sm cursor-pointer">{test.rawItem.TestSiteName}</Label>
</div> </div>
@ -453,27 +492,34 @@
{/each} {/each}
</div> </div>
<div class="shrink-0 p-2 border-t border-b flex items-center justify-between"> <div class="shrink-0 p-2 border-t border-b flex items-center justify-between">
<span class="text-sm">0 selected</span> <span class="text-sm">{selectedTests2.length} selected</span>
<Button size="sm" class="px-4 py-2 rounded">Add selected</Button> <Button
size="sm"
class="px-4 py-2 rounded"
onclick={addSelected}
disabled={selectedTests2.length === 0}
>
Add selected
</Button>
</div> </div>
</div> </div>
<div class="flex flex-1 flex-col overflow-hidden min-h-0 h-full w-1/2 gap-2"> <div class="flex flex-1 flex-col overflow-hidden min-h-0 h-full w-1/2 gap-2">
<div class="shrink-0 h-7 border-b-2 flex justify-between items-start"> <div class="shrink-0 h-7 border-b-2 flex justify-between items-center">
<p class="text-xs font-medium text-muted-foreground uppercase tracking-wide">Test ordered</p> <p class="text-xs font-medium text-muted-foreground uppercase tracking-wide">Test ordered</p>
<Badge variant="outline">0 test(s)</Badge> <Badge variant="outline">{pendingTests.length} test(s)</Badge>
</div> </div>
<div class="flex flex-col gap-2 p-1 flex-1 min-h-0 overflow-y-auto w-full [scrollbar-width:thin] [&::-webkit-scrollbar]:w-1"> <div class="flex flex-col gap-2 p-1 flex-1 min-h-0 overflow-y-auto w-full [scrollbar-width:thin] [&::-webkit-scrollbar]:w-1">
{#each [1,2,3,3] as x } {#each pendingTests as test, index (test.rawItem.TestSiteID) }
<InputGroup.Root class="p-1"> <InputGroup.Root class="p-1">
<InputGroup.Addon align="inline-start"> <InputGroup.Addon align="inline-start">
1 {index + 1}
</InputGroup.Addon> </InputGroup.Addon>
<InputGroup.Addon align="inline-start"> <InputGroup.Addon align="inline-start">
CREAD {test.rawItem.TestSiteCode}
</InputGroup.Addon> </InputGroup.Addon>
<InputGroup.Addon align="inline-start"> <InputGroup.Addon align="inline-start">
MCU PT. XYZ {test.rawItem.TestSiteName}
</InputGroup.Addon> </InputGroup.Addon>
<InputGroup.Input readonly /> <InputGroup.Input readonly />
<InputGroup.Addon align="inline-end"> <InputGroup.Addon align="inline-end">
@ -481,6 +527,7 @@
aria-label="Delete" aria-label="Delete"
title="Delete" title="Delete"
size="icon-xs" size="icon-xs"
onclick={() => removeTest2(test)}
> >
<Trash2Icon /> <Trash2Icon />
</InputGroup.Button> </InputGroup.Button>