mirror of
https://github.com/faiztyanirh/clqms-shadcn-v1.git
synced 2026-04-27 11:25:53 +07:00
initial patient admission, adm search param
This commit is contained in:
parent
d470e18df5
commit
cca8afd359
@ -40,7 +40,6 @@ export async function searchWithParams(endpoint, searchQuery) {
|
|||||||
const url = params
|
const url = params
|
||||||
? `${API.BASE_URL}${endpoint}?${params}`
|
? `${API.BASE_URL}${endpoint}?${params}`
|
||||||
: `${API.BASE_URL}${endpoint}`;
|
: `${API.BASE_URL}${endpoint}`;
|
||||||
|
|
||||||
const res = await fetch(url);
|
const res = await fetch(url);
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
return data.data || [];
|
return data.data || [];
|
||||||
|
|||||||
@ -23,12 +23,21 @@
|
|||||||
title: "Patient",
|
title: "Patient",
|
||||||
url: "/patient",
|
url: "/patient",
|
||||||
icon: LifeBuoyIcon,
|
icon: LifeBuoyIcon,
|
||||||
|
submenus: [
|
||||||
|
{
|
||||||
|
title: "Patient List",
|
||||||
|
url: "/list",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Patient Admission",
|
||||||
|
url: "/admission",
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Order",
|
title: "Order",
|
||||||
url: "/order",
|
url: "/order",
|
||||||
icon: LifeBuoyIcon,
|
icon: LifeBuoyIcon,
|
||||||
isActive: false,
|
|
||||||
submenus: [
|
submenus: [
|
||||||
{
|
{
|
||||||
title: "Test Order",
|
title: "Test Order",
|
||||||
@ -40,20 +49,20 @@
|
|||||||
dictionary: [
|
dictionary: [
|
||||||
{
|
{
|
||||||
title: "Admission",
|
title: "Admission",
|
||||||
url: "#",
|
url: "/admission",
|
||||||
icon: LifeBuoyIcon,
|
icon: LifeBuoyIcon,
|
||||||
submenus: [
|
submenus: [
|
||||||
{
|
{
|
||||||
title: "Contact",
|
title: "Contact",
|
||||||
url: "#",
|
url: "/contact",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Location",
|
title: "Location",
|
||||||
url: "#",
|
url: "/location",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Occupation",
|
title: "Occupation",
|
||||||
url: "#",
|
url: "/occupation",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|||||||
@ -18,7 +18,7 @@ export function useSearch(searchFields, searchApiFunction) {
|
|||||||
async function handleSearch() {
|
async function handleSearch() {
|
||||||
isLoading = true;
|
isLoading = true;
|
||||||
try {
|
try {
|
||||||
searchData = await searchApiFunction(searchQuery);
|
searchData = await searchApiFunction(searchQuery);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Search failed:', error);
|
console.error('Search failed:', error);
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
@ -1,61 +1,115 @@
|
|||||||
<script>
|
<script>
|
||||||
import * as DropdownMenu from "$lib/components/ui/dropdown-menu/index.js";
|
|
||||||
import * as Sidebar from "$lib/components/ui/sidebar/index.js";
|
import * as Sidebar from "$lib/components/ui/sidebar/index.js";
|
||||||
import * as Collapsible from "$lib/components/ui/collapsible/index.js";
|
import * as Collapsible from "$lib/components/ui/collapsible/index.js";
|
||||||
|
import * as Popover from "$lib/components/ui/popover/index.js";
|
||||||
import { useSidebar } from "$lib/components/ui/sidebar/index.js";
|
import { useSidebar } from "$lib/components/ui/sidebar/index.js";
|
||||||
import EllipsisIcon from "@lucide/svelte/icons/ellipsis";
|
import { Separator } from "$lib/components/ui/separator/index.js";
|
||||||
import FolderIcon from "@lucide/svelte/icons/folder";
|
|
||||||
import ShareIcon from "@lucide/svelte/icons/share";
|
|
||||||
import Trash2Icon from "@lucide/svelte/icons/trash-2";
|
|
||||||
import ChevronRightIcon from "@lucide/svelte/icons/chevron-right";
|
import ChevronRightIcon from "@lucide/svelte/icons/chevron-right";
|
||||||
|
import { page } from "$app/stores";
|
||||||
|
|
||||||
let {
|
let {
|
||||||
dictionary,
|
dictionary,
|
||||||
} = $props();
|
} = $props();
|
||||||
|
|
||||||
const sidebar = useSidebar();
|
const sidebar = Sidebar.useSidebar();
|
||||||
|
let openPopovers = $state({});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Sidebar.Group>
|
<Sidebar.Group>
|
||||||
<Sidebar.GroupLabel>Dictionary</Sidebar.GroupLabel>
|
<Sidebar.GroupLabel>Dictionary</Sidebar.GroupLabel>
|
||||||
<Sidebar.Menu>
|
<Sidebar.Menu>
|
||||||
{#each dictionary as item (item.title)}
|
{#each dictionary as item, index}
|
||||||
<Collapsible.Root open={item.isActive}>
|
{#if sidebar.state === "expanded"}
|
||||||
<Sidebar.MenuItem>
|
<Collapsible.Root open={item.isActive} class="group/collapsible">
|
||||||
<Sidebar.MenuButton tooltipContent={item.title}>
|
{#snippet child({ props })}
|
||||||
{#snippet child({ props })}
|
<Sidebar.MenuItem {...props}>
|
||||||
<a href={item.url} {...props}>
|
<Sidebar.MenuButton tooltipContent={item.title}>
|
||||||
<item.icon />
|
{#snippet child({ props })}
|
||||||
<span>{item.title}</span>
|
{#if item.submenus?.length}
|
||||||
</a>
|
<a {...props}>
|
||||||
|
<item.icon />
|
||||||
|
<span>{item.title}</span>
|
||||||
|
</a>
|
||||||
|
{:else}
|
||||||
|
<a href={item.url} {...props}>
|
||||||
|
<item.icon />
|
||||||
|
<span>{item.title}</span>
|
||||||
|
</a>
|
||||||
|
{/if}
|
||||||
|
{/snippet}
|
||||||
|
</Sidebar.MenuButton>
|
||||||
|
{#if item.submenus?.length}
|
||||||
|
<Collapsible.Trigger>
|
||||||
|
{#snippet child({ props })}
|
||||||
|
<Sidebar.MenuAction
|
||||||
|
{...props}
|
||||||
|
class="data-[state=open]:rotate-90"
|
||||||
|
>
|
||||||
|
<ChevronRightIcon />
|
||||||
|
<span class="sr-only">Toggle</span>
|
||||||
|
</Sidebar.MenuAction>
|
||||||
|
{/snippet}
|
||||||
|
</Collapsible.Trigger>
|
||||||
|
<Collapsible.Content>
|
||||||
|
<Sidebar.MenuSub>
|
||||||
|
{#each item.submenus as subItem (subItem.title)}
|
||||||
|
<Sidebar.MenuSubItem>
|
||||||
|
<Sidebar.MenuSubButton href={`${item.url}${subItem.url}`}>
|
||||||
|
<span>{subItem.title}</span>
|
||||||
|
</Sidebar.MenuSubButton>
|
||||||
|
</Sidebar.MenuSubItem>
|
||||||
|
{/each}
|
||||||
|
</Sidebar.MenuSub>
|
||||||
|
</Collapsible.Content>
|
||||||
|
{/if}
|
||||||
|
</Sidebar.MenuItem>
|
||||||
|
{/snippet}
|
||||||
|
</Collapsible.Root>
|
||||||
|
{:else}
|
||||||
|
<Popover.Root open={openPopovers[index]} onOpenChange={(open) => openPopovers[index] = open}>
|
||||||
|
<Sidebar.MenuItem>
|
||||||
|
{#snippet trigger(props)}
|
||||||
|
<Popover.Trigger {...props}>
|
||||||
|
<Sidebar.MenuButton tooltip={item.title}>
|
||||||
|
{#if item.icon && !item.submenu}
|
||||||
|
<item.icon />
|
||||||
|
{/if}
|
||||||
|
<span>{item.title}</span>
|
||||||
|
</Sidebar.MenuButton>
|
||||||
|
</Popover.Trigger>
|
||||||
{/snippet}
|
{/snippet}
|
||||||
</Sidebar.MenuButton>
|
{@render trigger()}
|
||||||
{#if item.items?.length}
|
</Sidebar.MenuItem>
|
||||||
<Collapsible.Trigger>
|
|
||||||
{#snippet child({ props })}
|
<Popover.Content side="right" align="start" class="w-max p-1">
|
||||||
<Sidebar.MenuAction
|
<div class="space-y-1">
|
||||||
{...props}
|
{#if item.submenus && item.submenus.length > 0}
|
||||||
class="data-[state=open]:rotate-90"
|
<div class="px-2 py-1.5 text-sm font-semibold">
|
||||||
>
|
{item.title}
|
||||||
<ChevronRightIcon />
|
</div>
|
||||||
<span class="sr-only">Toggle</span>
|
<Separator />
|
||||||
</Sidebar.MenuAction>
|
{#each item.submenus || [] as submenu}
|
||||||
{/snippet}
|
<a href={submenu.url}
|
||||||
</Collapsible.Trigger>
|
onclick={() => openPopovers[index] = false}
|
||||||
<Collapsible.Content>
|
class="flex items-center rounded-md px-2 py-1.5 text-sm hover:bg-accent"
|
||||||
<Sidebar.MenuSub>
|
class:bg-accent={$page.url.pathname === submenu.url}
|
||||||
{#each item.items as subItem (subItem.title)}
|
>
|
||||||
<Sidebar.MenuSubItem>
|
{submenu.title}
|
||||||
<Sidebar.MenuSubButton href={subItem.url}>
|
</a>
|
||||||
<span>{subItem.title}</span>
|
|
||||||
</Sidebar.MenuSubButton>
|
|
||||||
</Sidebar.MenuSubItem>
|
|
||||||
{/each}
|
{/each}
|
||||||
</Sidebar.MenuSub>
|
{:else}
|
||||||
</Collapsible.Content>
|
<a href={item.url}
|
||||||
{/if}
|
onclick={() => openPopovers[index] = false}
|
||||||
</Sidebar.MenuItem>
|
class="flex items-center rounded-md px-2 py-1.5 text-sm font-semibold hover:bg-accent"
|
||||||
</Collapsible.Root>
|
class:bg-accent={$page.url.pathname === item.url}
|
||||||
|
>
|
||||||
|
{item.title}
|
||||||
|
</a>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</Popover.Content>
|
||||||
|
</Popover.Root>
|
||||||
|
{/if}
|
||||||
{/each}
|
{/each}
|
||||||
</Sidebar.Menu>
|
</Sidebar.Menu>
|
||||||
</Sidebar.Group>
|
</Sidebar.Group>
|
||||||
@ -89,7 +89,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<Separator />
|
<Separator />
|
||||||
{#each item.submenus || [] as submenu}
|
{#each item.submenus || [] as submenu}
|
||||||
<a href={submenu.url}
|
<a href={`${item.url}${submenu.url}`}
|
||||||
onclick={() => openPopovers[item.url] = false}
|
onclick={() => openPopovers[item.url] = false}
|
||||||
class="flex items-center rounded-md px-2 py-1.5 text-sm hover:bg-accent"
|
class="flex items-center rounded-md px-2 py-1.5 text-sm hover:bg-accent"
|
||||||
class:bg-accent={$page.url.pathname === submenu.url}
|
class:bg-accent={$page.url.pathname === submenu.url}
|
||||||
|
|||||||
@ -0,0 +1,26 @@
|
|||||||
|
import { API } from '$lib/config/api.js';
|
||||||
|
import { getById, searchWithParams, create, update } from '$lib/api/api-client';
|
||||||
|
|
||||||
|
export async function searchParam(searchQuery) {
|
||||||
|
return await searchWithParams(API.PATIENTS, searchQuery)
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getVisit(searchQuery) {
|
||||||
|
const { data: visit, error } = await getById(API.VISITLIST, searchQuery)
|
||||||
|
return { visit };
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getPatient(searchQuery) {
|
||||||
|
const { data: patient, error } = await getById(API.PATIENTS, searchQuery)
|
||||||
|
return { patient };
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function createPatient(newContactForm) {
|
||||||
|
// console.log(JSON.stringify(newContactForm));
|
||||||
|
return await create(API.PATIENTS, newContactForm)
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function editPatient(editContactForm) {
|
||||||
|
// console.log(JSON.stringify(editContactForm));
|
||||||
|
return await update(API.PATIENTS, editContactForm)
|
||||||
|
}
|
||||||
@ -0,0 +1,54 @@
|
|||||||
|
import PlusIcon from "@lucide/svelte/icons/plus";
|
||||||
|
import Settings2Icon from "@lucide/svelte/icons/settings-2";
|
||||||
|
|
||||||
|
export const searchFields = [
|
||||||
|
{
|
||||||
|
key: "PatientID",
|
||||||
|
label: "Patient ID",
|
||||||
|
placeholder: "",
|
||||||
|
type: "text",
|
||||||
|
defaultValue: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "Name",
|
||||||
|
label: "Patient Name",
|
||||||
|
placeholder: "",
|
||||||
|
type: "text",
|
||||||
|
defaultValue: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "Birthdate",
|
||||||
|
label: "Birthdate",
|
||||||
|
type: "date"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "Identifier",
|
||||||
|
label: "Identifier",
|
||||||
|
type: "text"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "VisitID",
|
||||||
|
label: "Visit ID",
|
||||||
|
type: "text"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "EpisodeID",
|
||||||
|
label: "Episode ID",
|
||||||
|
type: "text"
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export function admissionActions(masterDetail) {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
Icon: PlusIcon,
|
||||||
|
label: 'Add Visit',
|
||||||
|
onClick: masterDetail.enterCreate,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Icon: Settings2Icon,
|
||||||
|
label: 'Search Parameters',
|
||||||
|
popoverWidth: "w-256",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
@ -0,0 +1,74 @@
|
|||||||
|
<script>
|
||||||
|
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 ReusableCalendar from "$lib/components/reusable/reusable-calendar.svelte";
|
||||||
|
import { Spinner } from "$lib/components/ui/spinner/index.js";
|
||||||
|
import * as Select from "$lib/components/ui/select/index.js";
|
||||||
|
import ReusableDataTable from "$lib/components/reusable/reusable-data-table.svelte";
|
||||||
|
import { useSearch } from "$lib/components/composable/use-search.svelte";
|
||||||
|
import { searchFields } from "../config/admission-config";
|
||||||
|
import { searchParam } from "../api/patient-admission-api";
|
||||||
|
import { patientColumns } from "../table/patient-colums";
|
||||||
|
import ReusableEmpty from "$lib/components/reusable/reusable-empty.svelte";
|
||||||
|
|
||||||
|
let props = $props();
|
||||||
|
|
||||||
|
let activeRowId = $state(null);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="w-full h-110">
|
||||||
|
<div class="flex gap-2 h-full">
|
||||||
|
<div class="w-1/3">
|
||||||
|
<div class="space-y-2">
|
||||||
|
{#each props.searchFields as field}
|
||||||
|
{#if field.type === "text"}
|
||||||
|
<div class="space-y-2">
|
||||||
|
<Label for={field.key}>{field.label}</Label>
|
||||||
|
<Input type="text" id={field.key} placeholder={field.placeholder} bind:value={props.search.searchQuery[field.key]} autocomplete=off/>
|
||||||
|
</div>
|
||||||
|
{:else if field.type === "date"}
|
||||||
|
<div class="space-y-2">
|
||||||
|
<ReusableCalendar title={field.label} bind:value={props.search.searchQuery[field.key]}/>
|
||||||
|
</div>
|
||||||
|
{:else if field.type === "select"}
|
||||||
|
<div class="space-y-2">
|
||||||
|
<Label for={field.key}>{field.label}</Label>
|
||||||
|
<Select.Root bind:value={props.search.searchQuery[field.key]}>
|
||||||
|
<Select.Trigger id={field.key}>
|
||||||
|
<Select.Value placeholder={field.placeholder} />
|
||||||
|
</Select.Trigger>
|
||||||
|
<Select.Content>
|
||||||
|
{#each field.options as opt}
|
||||||
|
<Select.Item value={opt.value}>
|
||||||
|
{opt.label}
|
||||||
|
</Select.Item>
|
||||||
|
{/each}
|
||||||
|
</Select.Content>
|
||||||
|
</Select.Root>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
<div class="flex justify-end gap-2 mt-4">
|
||||||
|
<Button variant="outline" size="sm" class="cursor-pointer" onclick={props.search.handleReset}>Reset</Button>
|
||||||
|
<Button size="sm" class="cursor-pointer" onclick={props.search.handleSearch} disabled={props.search.isLoading}>
|
||||||
|
{#if props.isLoading}
|
||||||
|
<Spinner />
|
||||||
|
{:else}
|
||||||
|
Search
|
||||||
|
{/if}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-1 w-full h-full justify-center items-center">
|
||||||
|
{#if props.search.searchData && props.search.searchData.length > 0}
|
||||||
|
<ReusableDataTable data={props.search.searchData} columns={patientColumns} {activeRowId} rowIdKey="InternalPID"/>
|
||||||
|
{:else}
|
||||||
|
<div class="flex h-full">
|
||||||
|
<ReusableEmpty desc="Try searching from search parameters"/>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@ -0,0 +1 @@
|
|||||||
|
cr
|
||||||
@ -0,0 +1 @@
|
|||||||
|
ed
|
||||||
65
src/lib/components/patient/admission/page/master-page.svelte
Normal file
65
src/lib/components/patient/admission/page/master-page.svelte
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
<script>
|
||||||
|
import { visitColumns } from "$lib/components/patient/admission/table/visit-columns";
|
||||||
|
import { searchParam } from "$lib/components/patient/admission/api/patient-admission-api";
|
||||||
|
import { useSearch } from "$lib/components/composable/use-search.svelte";
|
||||||
|
import { searchFields, admissionActions } from "$lib/components/patient/admission/config/admission-config";
|
||||||
|
import TopbarWrapper from "$lib/components/topbar/topbar-wrapper.svelte";
|
||||||
|
import ReusableSearchParam from "$lib/components/reusable/reusable-search-param.svelte";
|
||||||
|
import SearchParamModal from "../modal/search-param-modal.svelte";
|
||||||
|
import ReusableEmpty from "$lib/components/reusable/reusable-empty.svelte";
|
||||||
|
import ReusableDataTable from "$lib/components/reusable/reusable-data-table.svelte";
|
||||||
|
|
||||||
|
let props = $props();
|
||||||
|
|
||||||
|
const search = useSearch(searchFields, searchParam);
|
||||||
|
const actions = admissionActions(props.masterDetail)
|
||||||
|
actions.find(a => a.label === 'Search Parameters').popoverContent = searchParamSnippet;
|
||||||
|
|
||||||
|
let activeRowId = $state(null);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#snippet searchParamSnippet()}
|
||||||
|
<SearchParamModal {search} {searchFields}/>
|
||||||
|
<!-- <SearchParamModal {searchFields} {searchData} bind:searchQuery={search.searchQuery} onSearch={search.handleSearch} onReset={search.handleReset} isLoading={search.isLoading}/> -->
|
||||||
|
{/snippet}
|
||||||
|
|
||||||
|
<div
|
||||||
|
role="button"
|
||||||
|
tabindex="0"
|
||||||
|
onclick={() => props.masterDetail.isFormMode && props.masterDetail.exitForm()}
|
||||||
|
onkeydown={(e) => e.key === 'Enter' && props.masterDetail.isFormMode && props.masterDetail.exitForm()}
|
||||||
|
class={`
|
||||||
|
${props.masterDetail.isMobile ? "w-full" : props.masterDetail.isFormMode ? "w-[3%] cursor-pointer" : "w-[35%]"}
|
||||||
|
transition-all duration-300 flex flex-col items-center p-2 h-full overflow-y-auto
|
||||||
|
`}
|
||||||
|
>
|
||||||
|
<div class={`flex w-full ${props.masterDetail.isFormMode ? "flex-col justify-center h-full items-center" : "flex-col justify-start h-full"}`} >
|
||||||
|
{#if props.masterDetail.isFormMode}
|
||||||
|
<span class="flex flex-col items-center justify-center gap-4 tracking-widest font-semibold select-none">
|
||||||
|
{#each "ADMISSION".split("") as c}
|
||||||
|
<span class="leading-none">{c}</span>
|
||||||
|
{/each}
|
||||||
|
</span>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
{#if !props.masterDetail.isFormMode}
|
||||||
|
<div role="button" tabindex="0" class="flex flex-1 flex-col" onclick={(e) => e.stopPropagation()} onkeydown={(e) => {
|
||||||
|
if (e.key === 'Enter' || e.key === ' ') {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
}
|
||||||
|
}}>
|
||||||
|
<TopbarWrapper {actions}/>
|
||||||
|
<div class="flex-1 w-full h-full">
|
||||||
|
<!-- {#if search.searchData.length > 0}
|
||||||
|
<ReusableDataTable data={search.searchData} columns={visitColumns} handleRowClick={props.masterDetail.select} {activeRowId} rowIdKey="InternalPID"/>
|
||||||
|
{:else} -->
|
||||||
|
<div class="flex h-full">
|
||||||
|
<ReusableEmpty desc="Try searching from search parameters"/>
|
||||||
|
</div>
|
||||||
|
<!-- {/if} -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@ -0,0 +1 @@
|
|||||||
|
vw
|
||||||
23
src/lib/components/patient/admission/table/patient-colums.js
Normal file
23
src/lib/components/patient/admission/table/patient-colums.js
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
export const patientColumns = [
|
||||||
|
{
|
||||||
|
accessorKey: "PatientID",
|
||||||
|
header: "PatientID",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessorKey: "FullName",
|
||||||
|
header: "Patient Name",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessorKey: "SexLabel",
|
||||||
|
header: "Sex",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessorKey: "Birthdate",
|
||||||
|
header: "Birthdate",
|
||||||
|
cell: ({ getValue }) => {
|
||||||
|
const value = getValue();
|
||||||
|
if (!value) return "";
|
||||||
|
return value.split(' ')[0];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
];
|
||||||
@ -0,0 +1,6 @@
|
|||||||
|
export const visitColumns = [
|
||||||
|
{
|
||||||
|
accessorKey: "PVID",
|
||||||
|
header: "Visit ID",
|
||||||
|
},
|
||||||
|
];
|
||||||
@ -1,18 +1,18 @@
|
|||||||
<script>
|
<script>
|
||||||
|
import ReusableEmpty from "$lib/components/reusable/reusable-empty.svelte";
|
||||||
|
import ReusableCalendar from "$lib/components/reusable/reusable-calendar.svelte";
|
||||||
import * as Dialog from "$lib/components/ui/dialog/index.js";
|
import * as Dialog from "$lib/components/ui/dialog/index.js";
|
||||||
|
import * as Table from "$lib/components/ui/table/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 { Button } from "$lib/components/ui/button/index.js";
|
||||||
import { Label } from "$lib/components/ui/label/index.js";
|
import { Label } from "$lib/components/ui/label/index.js";
|
||||||
|
import { Input } from "$lib/components/ui/input/index.js";
|
||||||
|
import { Checkbox } from "$lib/components/ui/checkbox/index.js";
|
||||||
|
import { Spinner } from "$lib/components/ui/spinner/index.js";
|
||||||
import BabyIcon from "@lucide/svelte/icons/baby";
|
import BabyIcon from "@lucide/svelte/icons/baby";
|
||||||
import SearchIcon from "@lucide/svelte/icons/search";
|
import SearchIcon from "@lucide/svelte/icons/search";
|
||||||
import { Input } from "$lib/components/ui/input/index.js";
|
|
||||||
import * as Table from "$lib/components/ui/table/index.js";
|
|
||||||
import { Checkbox } from "$lib/components/ui/checkbox/index.js";
|
|
||||||
import ReusableCalendar from "$lib/components/reusable/reusable-calendar.svelte";
|
|
||||||
import { searchParam } from "$lib/components/patient/api/patient-api";
|
|
||||||
import { Spinner } from "$lib/components/ui/spinner/index.js";
|
|
||||||
import { searchFields } from "../config/patient-config";
|
|
||||||
import { useSearch } from "$lib/components/composable/use-search.svelte";
|
|
||||||
import ReusableEmpty from "$lib/components/reusable/reusable-empty.svelte";
|
|
||||||
|
|
||||||
let props = $props();
|
let props = $props();
|
||||||
|
|
||||||
@ -1,19 +1,19 @@
|
|||||||
<script>
|
<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 Dialog from "$lib/components/ui/dialog/index.js";
|
||||||
import { Button } from "$lib/components/ui/button/index.js";
|
|
||||||
import { Label } from "$lib/components/ui/label/index.js";
|
|
||||||
import LinkIcon from "@lucide/svelte/icons/link";
|
|
||||||
import SearchIcon from "@lucide/svelte/icons/search";
|
|
||||||
import { Input } from "$lib/components/ui/input/index.js";
|
|
||||||
import * as Table from "$lib/components/ui/table/index.js";
|
import * as Table from "$lib/components/ui/table/index.js";
|
||||||
import * as RadioGroup from "$lib/components/ui/radio-group/index.js";
|
import * as RadioGroup from "$lib/components/ui/radio-group/index.js";
|
||||||
import { searchParam } from "$lib/components/patient/api/patient-api";
|
|
||||||
import ReusableCalendar from "$lib/components/reusable/reusable-calendar.svelte";
|
|
||||||
import { Spinner } from "$lib/components/ui/spinner/index.js";
|
|
||||||
import { searchFields } from "../config/patient-config";
|
|
||||||
import { useSearch } from "$lib/components/composable/use-search.svelte";
|
import { useSearch } from "$lib/components/composable/use-search.svelte";
|
||||||
import ReusableEmpty from "$lib/components/reusable/reusable-empty.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 { 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();
|
let props = $props();
|
||||||
|
|
||||||
@ -55,16 +55,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function confirmLink() {
|
function confirmLink() {
|
||||||
// Update form state dengan selected patients
|
|
||||||
// Store as comma-separated string or array depending on your backend
|
|
||||||
// props.formState.form.LinkTo = selectedPatients
|
|
||||||
// .map(p => p.InternalPID)
|
|
||||||
// .join(',');
|
|
||||||
|
|
||||||
// Or as array:
|
|
||||||
props.formState.form.LinkTo = [...selectedPatients];
|
props.formState.form.LinkTo = [...selectedPatients];
|
||||||
|
|
||||||
// Reset and close
|
|
||||||
selectedPatients = [];
|
selectedPatients = [];
|
||||||
isOpen = false;
|
isOpen = false;
|
||||||
}
|
}
|
||||||
@ -191,75 +183,3 @@
|
|||||||
</Dialog.Footer>
|
</Dialog.Footer>
|
||||||
</Dialog.Content>
|
</Dialog.Content>
|
||||||
</Dialog.Root>
|
</Dialog.Root>
|
||||||
|
|
||||||
<!-- <Dialog.Root bind:open={linkModalMode.open}>
|
|
||||||
<Dialog.Trigger>
|
|
||||||
<Button variant="outline" class="size-9 rounded-l-none cursor-pointer" onclick={(e) => { linkModalMode.mode = mode }}>
|
|
||||||
<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">Search Patient Link</Dialog.Title>
|
|
||||||
</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" class="cursor-pointer" onclick={resetAllFields}>Reset</Button>
|
|
||||||
<Button size="sm" class="cursor-pointer" onclick={handleSearchParam}>
|
|
||||||
{#if isLoading}
|
|
||||||
<Spinner />
|
|
||||||
{:else}
|
|
||||||
Search
|
|
||||||
{/if}
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="flex-1 overflow-auto"></div>
|
|
||||||
{#if linkToPatients.data.length === 0}
|
|
||||||
<div class="flex flex-col items-center justify-center text-muted-foreground">
|
|
||||||
<SearchIcon class="w-12 h-12 mb-4 text-primary"/>
|
|
||||||
<p class="text-sm">No results found. Try searching with different criteria.</p>
|
|
||||||
</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 linkToPatients.data as patient, i}
|
|
||||||
<Table.Row
|
|
||||||
class="cursor-pointer hover:bg-muted/50"
|
|
||||||
>
|
|
||||||
<Table.Cell>
|
|
||||||
<Checkbox
|
|
||||||
checked={selectedPatients.temporaryPatnum.some((p) => p.InternalPID === patient.InternalPID && p.PatientID === patient.PatientID)}
|
|
||||||
onCheckedChange={() => toggleId(patient.InternalPID, patient.PatientID)}
|
|
||||||
/>
|
|
||||||
</Table.Cell>
|
|
||||||
<Table.Cell class="font-medium">{patient.PatientID}</Table.Cell>
|
|
||||||
<Table.Cell class="">{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}
|
|
||||||
<Dialog.Footer class="border-t pt-4">
|
|
||||||
<Button size="sm" class="cursor-pointer" onclick={confirmLink}>Link Patient</Button>
|
|
||||||
</Dialog.Footer>
|
|
||||||
</Dialog.Content>
|
|
||||||
</Dialog.Root> -->
|
|
||||||
@ -8,7 +8,7 @@
|
|||||||
import { Spinner } from "$lib/components/ui/spinner/index.js";
|
import { Spinner } from "$lib/components/ui/spinner/index.js";
|
||||||
import { useForm } from "$lib/components/composable/use-form.svelte";
|
import { useForm } from "$lib/components/composable/use-form.svelte";
|
||||||
import { patientSchema, patientInitialForm, patientDefaultErrors, patientFormFields, getPatientFormActions } from "../config/patient-form-config";
|
import { patientSchema, patientInitialForm, patientDefaultErrors, patientFormFields, getPatientFormActions } from "../config/patient-form-config";
|
||||||
import { createPatient } from "../api/patient-api";
|
import { createPatient } from "../api/patient-list-api";
|
||||||
import * as Select from "$lib/components/ui/select/index.js";
|
import * as Select from "$lib/components/ui/select/index.js";
|
||||||
import ReusableCalendar from "$lib/components/reusable/reusable-calendar.svelte";
|
import ReusableCalendar from "$lib/components/reusable/reusable-calendar.svelte";
|
||||||
import ReusableCalendarTimepicker from "$lib/components/reusable/reusable-calendar-timepicker.svelte";
|
import ReusableCalendarTimepicker from "$lib/components/reusable/reusable-calendar-timepicker.svelte";
|
||||||
@ -1,10 +1,10 @@
|
|||||||
<script>
|
<script>
|
||||||
import { useForm } from "$lib/components/composable/use-form.svelte";
|
import { useForm } from "$lib/components/composable/use-form.svelte";
|
||||||
import { patientSchema, patientInitialForm, patientDefaultErrors, patientFormFields, getPatientFormActions } from "../config/patient-form-config";
|
import { patientSchema, patientInitialForm, patientDefaultErrors, patientFormFields, getPatientFormActions } from "$lib/components/patient/list/config/patient-form-config";
|
||||||
import { createPatient } from "../api/patient-api";
|
import { createPatient } from "$lib/components/patient/list/api/patient-list-api";
|
||||||
import FormPageContainer from "../reusable/form-page-container.svelte";
|
|
||||||
import { usePatientForm } from "$lib/components/composable/use-patient-form.svelte";
|
import { usePatientForm } from "$lib/components/composable/use-patient-form.svelte";
|
||||||
import PatientFormRenderer from "../reusable/patient-form-renderer.svelte";
|
import FormPageContainer from "$lib/components/patient/reusable/form-page-container.svelte";
|
||||||
|
import PatientFormRenderer from "$lib/components/patient/reusable/patient-form-renderer.svelte";
|
||||||
|
|
||||||
let props = $props();
|
let props = $props();
|
||||||
|
|
||||||
@ -10,7 +10,7 @@
|
|||||||
import { Spinner } from "$lib/components/ui/spinner/index.js";
|
import { Spinner } from "$lib/components/ui/spinner/index.js";
|
||||||
import { useForm } from "$lib/components/composable/use-form.svelte";
|
import { useForm } from "$lib/components/composable/use-form.svelte";
|
||||||
import { patientSchema, patientInitialForm, patientDefaultErrors, patientFormFields, getPatientFormActions } from "../config/patient-form-config";
|
import { patientSchema, patientInitialForm, patientDefaultErrors, patientFormFields, getPatientFormActions } from "../config/patient-form-config";
|
||||||
import { editPatient } from "../api/patient-api";
|
import { editPatient } from "../api/patient-list-api";
|
||||||
import * as Select from "$lib/components/ui/select/index.js";
|
import * as Select from "$lib/components/ui/select/index.js";
|
||||||
import ReusableCalendar from "$lib/components/reusable/reusable-calendar.svelte";
|
import ReusableCalendar from "$lib/components/reusable/reusable-calendar.svelte";
|
||||||
import ReusableCalendarTimepicker from "$lib/components/reusable/reusable-calendar-timepicker.svelte";
|
import ReusableCalendarTimepicker from "$lib/components/reusable/reusable-calendar-timepicker.svelte";
|
||||||
@ -1,12 +1,12 @@
|
|||||||
<script>
|
<script>
|
||||||
import { useForm } from "$lib/components/composable/use-form.svelte";
|
import { useForm } from "$lib/components/composable/use-form.svelte";
|
||||||
import { patientSchema, patientInitialForm, patientDefaultErrors, patientFormFields, getPatientFormActions } from "../config/patient-form-config";
|
import { patientSchema, patientInitialForm, patientDefaultErrors, patientFormFields, getPatientFormActions } from "$lib/components/patient/list/config/patient-form-config";
|
||||||
import { editPatient } from "../api/patient-api";
|
import { editPatient } from "$lib/components/patient/list/api/patient-list-api";
|
||||||
import FormPageContainer from "../reusable/form-page-container.svelte";
|
|
||||||
import { usePatientForm } from "$lib/components/composable/use-patient-form.svelte";
|
import { usePatientForm } from "$lib/components/composable/use-patient-form.svelte";
|
||||||
import PatientFormRenderer from "../reusable/patient-form-renderer.svelte";
|
|
||||||
import { API } from "$lib/config/api";
|
import { API } from "$lib/config/api";
|
||||||
import { untrack } from "svelte";
|
import { untrack } from "svelte";
|
||||||
|
import FormPageContainer from "$lib/components/patient/reusable/form-page-container.svelte";
|
||||||
|
import PatientFormRenderer from "$lib/components/patient/reusable/patient-form-renderer.svelte";
|
||||||
|
|
||||||
let props = $props();
|
let props = $props();
|
||||||
|
|
||||||
@ -1,12 +1,12 @@
|
|||||||
<script>
|
<script>
|
||||||
import { columns } from "$lib/components/patient/table/colums";
|
import { columns } from "$lib/components/patient/list/table/colums";
|
||||||
|
import { searchParam } from "$lib/components/patient/list/api/patient-list-api";
|
||||||
|
import { useSearch } from "$lib/components/composable/use-search.svelte";
|
||||||
|
import { searchFields, patientActions } from "$lib/components/patient/list/config/patient-config";
|
||||||
import TopbarWrapper from "$lib/components/topbar/topbar-wrapper.svelte";
|
import TopbarWrapper from "$lib/components/topbar/topbar-wrapper.svelte";
|
||||||
import ReusableSearchParam from "$lib/components/reusable/reusable-search-param.svelte";
|
import ReusableSearchParam from "$lib/components/reusable/reusable-search-param.svelte";
|
||||||
import ReusableEmpty from "$lib/components/reusable/reusable-empty.svelte";
|
import ReusableEmpty from "$lib/components/reusable/reusable-empty.svelte";
|
||||||
import { searchParam } from "$lib/components/patient/api/patient-api";
|
|
||||||
import ReusableDataTable from "$lib/components/reusable/reusable-data-table.svelte";
|
import ReusableDataTable from "$lib/components/reusable/reusable-data-table.svelte";
|
||||||
import { useSearch } from "$lib/components/composable/use-search.svelte";
|
|
||||||
import { searchFields, patientActions } from "../config/patient-config";
|
|
||||||
|
|
||||||
let props = $props();
|
let props = $props();
|
||||||
|
|
||||||
@ -1,9 +1,8 @@
|
|||||||
<script>
|
<script>
|
||||||
import TopbarWrapper from "$lib/components/topbar/topbar-wrapper.svelte";
|
import { formatUTCDate } from "$lib/utils/formatUTCDate";
|
||||||
import { formatUTCDate } from "$lib/utils/formatUTCDate";
|
|
||||||
import { getUrl } from "$lib/utils/getUrl";
|
import { getUrl } from "$lib/utils/getUrl";
|
||||||
import { detailSections, viewActions } from "../config/patient-config";
|
import { detailSections, viewActions } from "$lib/components/patient/list/config/patient-config";
|
||||||
|
import TopbarWrapper from "$lib/components/topbar/topbar-wrapper.svelte";
|
||||||
import ReusableEmpty from "$lib/components/reusable/reusable-empty.svelte";
|
import ReusableEmpty from "$lib/components/reusable/reusable-empty.svelte";
|
||||||
|
|
||||||
let props = $props();
|
let props = $props();
|
||||||
@ -1,9 +1,9 @@
|
|||||||
<script>
|
<script>
|
||||||
import TopbarWrapper from "$lib/components/topbar/topbar-wrapper.svelte";
|
|
||||||
import { Button } from "$lib/components/ui/button/index.js";
|
|
||||||
import * as DropdownMenu from "$lib/components/ui/dropdown-menu/index.js";
|
import * as DropdownMenu from "$lib/components/ui/dropdown-menu/index.js";
|
||||||
import ChevronUpIcon from "@lucide/svelte/icons/chevron-up";
|
import { Button } from "$lib/components/ui/button/index.js";
|
||||||
import { Spinner } from "$lib/components/ui/spinner/index.js";
|
import { Spinner } from "$lib/components/ui/spinner/index.js";
|
||||||
|
import TopbarWrapper from "$lib/components/topbar/topbar-wrapper.svelte";
|
||||||
|
import ChevronUpIcon from "@lucide/svelte/icons/chevron-up";
|
||||||
|
|
||||||
let {
|
let {
|
||||||
title,
|
title,
|
||||||
@ -57,26 +57,5 @@
|
|||||||
</DropdownMenu.Content>
|
</DropdownMenu.Content>
|
||||||
</DropdownMenu.Root>
|
</DropdownMenu.Root>
|
||||||
{/if}
|
{/if}
|
||||||
<!-- <DropdownMenu.Root>
|
|
||||||
<DropdownMenu.Trigger>
|
|
||||||
<Button
|
|
||||||
size="icon"
|
|
||||||
class="size-8 rounded-l-none"
|
|
||||||
disabled={props.hasErrors || props.primaryAction.formState.isSaving.current}
|
|
||||||
>
|
|
||||||
<ChevronUpIcon />
|
|
||||||
</Button>
|
|
||||||
</DropdownMenu.Trigger>
|
|
||||||
<DropdownMenu.Content collisionPadding={8}>
|
|
||||||
<DropdownMenu.Group>
|
|
||||||
<DropdownMenu.Item>
|
|
||||||
Save and Order
|
|
||||||
</DropdownMenu.Item>
|
|
||||||
<DropdownMenu.Item onclick={props.handleSave}>
|
|
||||||
Save
|
|
||||||
</DropdownMenu.Item>
|
|
||||||
</DropdownMenu.Group>
|
|
||||||
</DropdownMenu.Content>
|
|
||||||
</DropdownMenu.Root> -->
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -1,16 +1,16 @@
|
|||||||
<script>
|
<script>
|
||||||
import { Button } from "$lib/components/ui/button/index.js";
|
|
||||||
import * as DropdownMenu from "$lib/components/ui/dropdown-menu/index.js";
|
import * as DropdownMenu from "$lib/components/ui/dropdown-menu/index.js";
|
||||||
|
import * as Select from "$lib/components/ui/select/index.js";
|
||||||
|
import { Button } from "$lib/components/ui/button/index.js";
|
||||||
import { Input } from "$lib/components/ui/input/index.js";
|
import { Input } from "$lib/components/ui/input/index.js";
|
||||||
import { Label } from "$lib/components/ui/label/index.js";
|
import { Label } from "$lib/components/ui/label/index.js";
|
||||||
import ChevronUpIcon from "@lucide/svelte/icons/chevron-up";
|
|
||||||
import { Spinner } from "$lib/components/ui/spinner/index.js";
|
import { Spinner } from "$lib/components/ui/spinner/index.js";
|
||||||
import * as Select from "$lib/components/ui/select/index.js";
|
|
||||||
import ReusableCalendar from "$lib/components/reusable/reusable-calendar.svelte";
|
import ReusableCalendar from "$lib/components/reusable/reusable-calendar.svelte";
|
||||||
import ReusableCalendarTimepicker from "$lib/components/reusable/reusable-calendar-timepicker.svelte";
|
import ReusableCalendarTimepicker from "$lib/components/reusable/reusable-calendar-timepicker.svelte";
|
||||||
import CustodianModal from "../modal/custodian-modal.svelte";
|
import CustodianModal from "$lib/components/patient/list/modal/custodian-modal.svelte";
|
||||||
import LinktoModal from "../modal/linkto-modal.svelte";
|
import LinktoModal from "$lib/components/patient/list/modal/linkto-modal.svelte";
|
||||||
import ReusableUpload from "$lib/components/reusable/reusable-upload.svelte";
|
import ReusableUpload from "$lib/components/reusable/reusable-upload.svelte";
|
||||||
|
import ChevronUpIcon from "@lucide/svelte/icons/chevron-up";
|
||||||
|
|
||||||
let {
|
let {
|
||||||
formState,
|
formState,
|
||||||
|
|||||||
@ -27,7 +27,7 @@
|
|||||||
</Button>
|
</Button>
|
||||||
{/snippet}
|
{/snippet}
|
||||||
</Popover.Trigger>
|
</Popover.Trigger>
|
||||||
<Popover.Content ${props.collisionPadding ?? 0} class="w-72">
|
<Popover.Content ${props.collisionPadding ?? 0} class={props.popoverWidth ?? "w-72"}>
|
||||||
{@render props.popoverContent()}
|
{@render props.popoverContent()}
|
||||||
</Popover.Content>
|
</Popover.Content>
|
||||||
</Popover.Root>
|
</Popover.Root>
|
||||||
|
|||||||
@ -1,11 +1,14 @@
|
|||||||
export async function load({ url }) {
|
export async function load({ url }) {
|
||||||
const routeConfig = {
|
const routeConfig = {
|
||||||
'/patient': {
|
|
||||||
title: 'Patient List',
|
|
||||||
},
|
|
||||||
'/': {
|
'/': {
|
||||||
title: 'Dashboard',
|
title: 'Dashboard',
|
||||||
}
|
},
|
||||||
|
'/patient/list': {
|
||||||
|
title: 'Patient List',
|
||||||
|
},
|
||||||
|
'/patient/admission': {
|
||||||
|
title: 'Patient Admission',
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const config = routeConfig[url.pathname] || {
|
const config = routeConfig[url.pathname] || {
|
||||||
|
|||||||
34
src/routes/patient/admission/+page.svelte
Normal file
34
src/routes/patient/admission/+page.svelte
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
<script>
|
||||||
|
import { Separator } from "$lib/components/ui/separator/index.js";
|
||||||
|
import { useMasterDetail } from "$lib/components/composable/use-master-detail.svelte";
|
||||||
|
import { getVisit } from "$lib/components/patient/admission/api/patient-admission-api";
|
||||||
|
import MasterPage from "$lib/components/patient/admission/page/master-page.svelte";
|
||||||
|
import ViewPage from "$lib/components/patient/admission/page/view-page.svelte";
|
||||||
|
import CreatePage from "$lib/components/patient/admission/page/create-page.svelte";
|
||||||
|
import EditPage from "$lib/components/patient/admission/page/edit-page.svelte";
|
||||||
|
|
||||||
|
const masterDetail = useMasterDetail({
|
||||||
|
onSelect: async (row) => {
|
||||||
|
return await getVisit(row.InternalPID);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="flex w-full h-full overflow-hidden">
|
||||||
|
{#if masterDetail.showMaster}
|
||||||
|
<MasterPage {masterDetail} />
|
||||||
|
{/if}
|
||||||
|
<Separator orientation="vertical"/>
|
||||||
|
{#if masterDetail.showDetail}
|
||||||
|
<main class={`${masterDetail.isMobile ? 'w-full' : masterDetail.isFormMode ? 'w-[97%] flex flex-col items-start' : 'w-[65%]'} h-full overflow-y-auto flex flex-col items-center transition-all duration-300`}>
|
||||||
|
{#if masterDetail.mode === "view"}
|
||||||
|
<ViewPage {masterDetail}/>
|
||||||
|
{:else if masterDetail.mode === "create"}
|
||||||
|
<CreatePage {masterDetail}/>
|
||||||
|
{:else if masterDetail.mode === "edit"}
|
||||||
|
<EditPage {masterDetail}/>
|
||||||
|
{/if}
|
||||||
|
</main>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
@ -1,11 +1,11 @@
|
|||||||
<script>
|
<script>
|
||||||
import { Separator } from "$lib/components/ui/separator/index.js";
|
import { Separator } from "$lib/components/ui/separator/index.js";
|
||||||
import { useMasterDetail } from "$lib/components/composable/use-master-detail.svelte";
|
import { useMasterDetail } from "$lib/components/composable/use-master-detail.svelte";
|
||||||
import { getPatient } from "$lib/components/patient/api/patient-api";
|
import { getPatient } from "$lib/components/patient/list/api/patient-list-api";
|
||||||
import MasterPage from "$lib/components/patient/page/master-page.svelte";
|
import MasterPage from "$lib/components/patient/list/page/master-page.svelte";
|
||||||
import ViewPage from "$lib/components/patient/page/view-page.svelte";
|
import ViewPage from "$lib/components/patient/list/page/view-page.svelte";
|
||||||
import CreatePage from "$lib/components/patient/page/create-page.svelte";
|
import CreatePage from "$lib/components/patient/list/page/create-page.svelte";
|
||||||
import EditPage from "$lib/components/patient/page/edit-page.svelte";
|
import EditPage from "$lib/components/patient/list/page/edit-page.svelte";
|
||||||
|
|
||||||
const masterDetail = useMasterDetail({
|
const masterDetail = useMasterDetail({
|
||||||
onSelect: async (row) => {
|
onSelect: async (row) => {
|
||||||
Loading…
x
Reference in New Issue
Block a user