185 lines
7.2 KiB
Svelte

<script>
import ReusableCalendar from "$lib/components/reusable/reusable-calendar.svelte";
import ReusableEmpty from "$lib/components/reusable/reusable-empty.svelte";
import * as Dialog from "$lib/components/ui/dialog/index.js";
import * as Table from "$lib/components/ui/table/index.js";
import * as RadioGroup from "$lib/components/ui/radio-group/index.js";
import { useSearch } from "$lib/components/composable/use-search.svelte";
import { searchParam } from "$lib/components/patient/list/api/patient-list-api";
import { searchFields } from "$lib/components/patient/list/config/patient-config";
import { Button } from "$lib/components/ui/button/index.js";
import { Label } from "$lib/components/ui/label/index.js";
import { Input } from "$lib/components/ui/input/index.js";
import { Spinner } from "$lib/components/ui/spinner/index.js";
import { Checkbox } from "$lib/components/ui/checkbox/index.js";
import LinkIcon from "@lucide/svelte/icons/link";
import SearchIcon from "@lucide/svelte/icons/search";
let props = $props();
const search = useSearch(searchFields, searchParam);
let isOpen = $state(false);
let selectedPatients = $state([]);
function handleOpenChange(open) {
isOpen = open;
if (open) {
if (Array.isArray(props.formState.form.LinkTo)) {
selectedPatients = [...props.formState.form.LinkTo];
} else {
selectedPatients = [];
}
}
}
function togglePatientSelection(patient) {
const exists = selectedPatients.some(
p => p.InternalPID === patient.InternalPID
);
if (exists) {
selectedPatients = selectedPatients.filter(
p => p.InternalPID !== patient.InternalPID
);
} else {
selectedPatients = [
...selectedPatients,
{
InternalPID: patient.InternalPID,
PatientID: patient.PatientID
}
];
}
}
function confirmLink() {
props.formState.form.LinkTo = [...selectedPatients];
selectedPatients = [];
isOpen = false;
}
function isPatientSelected(patient) {
return selectedPatients.some(
p => p.InternalPID === patient.InternalPID
);
}
</script>
{#snippet Fieldset({ key, label, type })}
{#if type === "text"}
<div class="flex w-full flex-col gap-1.5">
<div class="flex justify-between items-center w-full">
<Label>{label}</Label>
</div>
<div class="relative flex flex-col items-center w-full">
<Input type="text" bind:value={search.searchQuery[key]}/>
</div>
</div>
{:else if type === "date"}
<ReusableCalendar title="Birthdate" bind:value={search.searchQuery[key]}/>
{/if}
{/snippet}
<Dialog.Root open={isOpen} onOpenChange={handleOpenChange}>
<Dialog.Trigger>
<Button variant="outline" class="size-9 rounded-l-none">
<LinkIcon />
</Button>
</Dialog.Trigger>
<Dialog.Content class="flex flex-col max-h-9/10 w-[90vw] max-w-sm sm:max-w-md md:max-w-lg lg:max-w-2xl">
<Dialog.Header class="border-b pb-4">
<Dialog.Title class="text-xl font-semibold">Link Patients</Dialog.Title>
{#if selectedPatients.length > 0}
<p class="text-sm text-muted-foreground">
{selectedPatients.length} patient{selectedPatients.length > 1 ? 's' : ''} selected
</p>
{/if}
</Dialog.Header>
<div class="space-y-4">
<div class="pb-4 border-b">
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
{#each searchFields as field}
{@render Fieldset(field)}
{/each}
</div>
</div>
<div class="flex justify-end gap-2 border-b pb-4">
<Button
variant="outline"
size="sm"
onclick={search.handleReset}
>
Reset
</Button>
<Button
size="sm"
onclick={search.handleSearch}
disabled={search.isLoading}
>
{#if search.isLoading}
<Spinner />
{:else}
Search
{/if}
</Button>
</div>
</div>
<div class="flex-1 overflow-y-auto">
{#if search.searchData.length === 0}
<div class="flex flex-col items-center justify-center text-muted-foreground">
<ReusableEmpty icon={SearchIcon} desc="Try searching from search parameters"/>
</div>
{:else}
<Table.Root>
<Table.Header>
<Table.Row class="hover:bg-transparent">
<Table.Head class="w-8"></Table.Head>
<Table.Head class="w-32">Patient ID</Table.Head>
<Table.Head class="w-full">Patient Name</Table.Head>
<Table.Head class="w-32">Birthdate</Table.Head>
<Table.Head class="w-8">Sex</Table.Head>
</Table.Row>
</Table.Header>
<Table.Body>
{#each search.searchData as patient}
<Table.Row
class="cursor-pointer hover:bg-muted/50"
onclick={() => togglePatientSelection(patient)}
>
<Table.Cell onclick={(e) => e.stopPropagation()}>
<Checkbox
class="cursor-pointer hover:bg-muted/50"
checked={isPatientSelected(patient)}
onCheckedChange={() => togglePatientSelection(patient)}
/>
</Table.Cell>
<Table.Cell class="font-medium">{patient.PatientID}</Table.Cell>
<Table.Cell>{patient.FullName}</Table.Cell>
<Table.Cell class="text-muted-foreground">
{patient.Birthdate ? patient.Birthdate.split(" ")[0] : ""}
</Table.Cell>
<Table.Cell class="font-medium">{patient.Gender}</Table.Cell>
</Table.Row>
{/each}
</Table.Body>
</Table.Root>
{/if}
</div>
<Dialog.Footer class="border-t pt-4">
<Button
size="sm"
onclick={confirmLink}
>
Link Patient
</Button>
</Dialog.Footer>
</Dialog.Content>
</Dialog.Root>