diff --git a/src/lib/components/order/ordertest/config/ordertest-config.js b/src/lib/components/order/ordertest/config/ordertest-config.js
index 619bf53..c1f6db0 100644
--- a/src/lib/components/order/ordertest/config/ordertest-config.js
+++ b/src/lib/components/order/ordertest/config/ordertest-config.js
@@ -49,7 +49,7 @@ export const detailSections = [
},
];
-export function orderTestActions(masterDetail, selectedPatient) {
+export function orderTestActions(masterDetail, selectedPatient, selectedVisit) {
return [
{
Icon: PlusIcon,
diff --git a/src/lib/components/order/ordertest/config/ordertest-form-config.js b/src/lib/components/order/ordertest/config/ordertest-form-config.js
index 26f1a46..1f6c2cd 100644
--- a/src/lib/components/order/ordertest/config/ordertest-form-config.js
+++ b/src/lib/components/order/ordertest/config/ordertest-form-config.js
@@ -5,11 +5,129 @@ import { cleanEmptyStrings } from "$lib/utils/cleanEmptyStrings";
export const orderTestSchema = z.object({});
-export const orderTestInitialForm = {};
+export const orderTestInitialForm = {
+ InternalOID: '',
+ OrderID: '',
+ PlacerID: '',
+ InternalPID: '',
+ SiteID: '',
+ PVADTID: '',
+ ReqApp: '',
+ Priority: '',
+ TrnDate: '',
+ EffDate: '',
+ Comment: '',
+ OrderAtt: '',
+ Tests: '',
+};
export const orderTestDefaultErrors = {};
-export const orderTestFormFields = [];
+export const orderTestFormFields = [
+ {
+ title: "Order Details",
+ rows: [
+ {
+ type: "row",
+ columns: [
+ {
+ key: "SiteID",
+ label: "Site",
+ required: false,
+ type: "select",
+ optionsEndpoint: `${API.BASE_URL}${API.SITE}`,
+ valueKey: "SiteID",
+ labelKey: "SiteName",
+ },
+ {
+ key: "Priority",
+ label: "Priority",
+ required: false,
+ type: "select",
+ optionsEndpoint: `${API.BASE_URL}${API.VALUESET}/order_priority`,
+ },
+ ]
+ },
+ {
+ type: "row",
+ columns: [
+ {
+ key: "PlacerID",
+ label: "Placer ID",
+ required: false,
+ type: "text",
+ },
+ {
+ key: "ReqApp",
+ label: "Requested Application",
+ required: false,
+ type: "text",
+ },
+ ]
+ },
+ {
+ type: "row",
+ columns: [
+ {
+ key: "TrnDate",
+ label: "Transaction Date",
+ required: false,
+ type: "date",
+ allowFuture: true
+ },
+ {
+ key: "EffDate",
+ label: "Effective Date",
+ required: false,
+ type: "date",
+ allowFuture: true
+ },
+ ]
+ },
+ {
+ type: "row",
+ columns: [
+ {
+ key: "Comment",
+ label: "Comment",
+ required: false,
+ type: "textarea",
+ },
+ ]
+ },
+ {
+ type: "row",
+ columns: [
+ {
+ key: "OrderAtt",
+ label: "Attachment",
+ required: false,
+ type: "fileupload",
+ },
+ ]
+ },
+ ]
+ },
+ {
+ title: "Tests",
+ rows: [
+ {
+ type: "row",
+ columns: [
+ {
+ key: "Tests",
+ label: "Search Test",
+ required: false,
+ type: "tests",
+ optionsEndpoint: `${API.BASE_URL}${API.TEST}`,
+ valueKey: 'TestSiteCode',
+ labelKey: (item) => `${item.TestSiteCode} - ${item.TestSiteName}`,
+ },
+ ]
+ },
+ ]
+ },
+];
export function getOrderTestFormActions(handlers) {
return [
diff --git a/src/lib/components/order/ordertest/modal/search-param-modal.svelte b/src/lib/components/order/ordertest/modal/search-param-modal.svelte
index ca93487..b2a8764 100644
--- a/src/lib/components/order/ordertest/modal/search-param-modal.svelte
+++ b/src/lib/components/order/ordertest/modal/search-param-modal.svelte
@@ -59,15 +59,14 @@
function handleButtonClick() {
if (tempSelectedVisit) {
- props.onConfirm(tempSelectedPatient);
+ props.onConfirm(tempSelectedPatient, tempSelectedVisit);
tempSelectedVisit = null;
}
}
- $inspect(tempSelectedVisit)
-
+
@@ -113,7 +112,7 @@
{#if props.search.searchData && props.search.searchData.length > 0}
-
+
-
+
{#if isLoadingVisit}
{:else if visitData && visitData.data?.length > 0}
-
Active Visit
Visit ID
Visit Date
+ Location
+ Doctor
{#each visitData.data as visit, i}
handleCheckboxVisit(visit)}
>
e.stopPropagation()}>
@@ -182,8 +182,23 @@
onCheckedChange={() => handleCheckboxVisit(visit)}
/>
- {visit.PVID}
- {formatUTCDate(visit.PVCreateDate)}
+ {visit.PVID}
+
+ {formatUTCDate(visit.PVCreateDate).split(' ')[0]}
+ {formatUTCDate(visit.PVCreateDate).split(' ')[1]}
+
+
+
+ {visit.LocCode ?? "-"}
+ {visit.LocFull ?? "-"}
+
+
+
+
+ {visit.AttDocContactCode ?? "-"}
+ {visit.AttDocFirstName} {visit.AttDocLastName}
+
+
{/each}
diff --git a/src/lib/components/order/ordertest/page/create-page.svelte b/src/lib/components/order/ordertest/page/create-page.svelte
index e69de29..fdedf93 100644
--- a/src/lib/components/order/ordertest/page/create-page.svelte
+++ b/src/lib/components/order/ordertest/page/create-page.svelte
@@ -0,0 +1,66 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/lib/components/order/ordertest/page/master-page.svelte b/src/lib/components/order/ordertest/page/master-page.svelte
index 4ade52e..d6923b1 100644
--- a/src/lib/components/order/ordertest/page/master-page.svelte
+++ b/src/lib/components/order/ordertest/page/master-page.svelte
@@ -14,17 +14,19 @@
import { page } from '$app/stores';
import { getPatient } from "$lib/components/patient/list/api/patient-list-api";
import { patientStore } from "$lib/components/patient/list/store/patient-store.svelte";
+ import { formatUTCDate } from "$lib/utils/formatUTCDate";
let props = $props();
let selectedPatient = $state(null);
+ let selectedVisit = $state(null);
let isLoading = $state(false);
let searchData = $state([]);
-
+$inspect(selectedPatient)
const search = useSearch(searchFields, searchParam);
let actions = $derived.by(() => {
- return orderTestActions(props.masterDetail, selectedPatient).map(action => {
+ return orderTestActions(props.masterDetail, selectedPatient, selectedVisit).map(action => {
if (action.label === 'Search Parameters') {
return { ...action, popoverContent: searchParamSnippet };
}
@@ -34,12 +36,13 @@
let activeRowId = $state(null);
- async function handlePatientConfirm(patient) {
+ async function handlePatientConfirm(patient, visit) {
selectedPatient = patient;
+ selectedVisit = visit;
isLoading = true;
try {
searchData = await getOrderList({
- InternalPID: selectedPatient.InternalPID
+ PVADTID: selectedVisit.PVADTID
});
} catch (error) {
console.error('Search failed:', error);
@@ -61,31 +64,15 @@
SexLabel: `${patient.patient.SexLabel}`,
};
console.log(transformedPatient);
- // return {
- // InternalPID: p.InternalPID,
- // PatientID: p.PatientID,
- // FullName: [p.NameFirst, p.NameMiddle, p.NameLast].filter(Boolean).join(' '),
- // Sex: p.Sex,
- // Birthdate: p.Birthdate,
- // Email: p.Email,
- // MobilePhone: p.MobilePhone,
- // SexLabel: p.SexLabel,
- // }
handlePatientConfirm(transformedPatient);
}
onMount(() => {
- // const pid = $page.url.searchParams.get('InternalPID'); //kalau dari url parameter
- // if (pid) {
- // loadPatientFromUrl(pid);
- // }
if (patientStore.pending) {
loadPatientFromUrl(patientStore.pending.InternalPID);
patientStore.pending = null;
}
})
-
- $inspect(patientStore)
{#snippet searchParamSnippet()}
@@ -131,13 +118,18 @@
{selectedPatient?.FullName}
+
+ {selectedPatient?.Age ? selectedPatient.Age.split(' ').slice(0, 2).join(' ') : 'N/A'} -
+ {selectedPatient?.SexLabel} -
+ {selectedPatient?.BirthdateConversion}
+
-
- {selectedPatient?.Birthdate}
+
+ {selectedVisit?.PVID}
-
- {selectedPatient?.SexLabel}
+
+ {formatUTCDate(selectedVisit?.PVCreateDate)}
@@ -147,7 +139,8 @@
{:else}
-
+
+
{/if}
diff --git a/src/lib/components/order/ordertest/table/ordertest-columns.js b/src/lib/components/order/ordertest/table/ordertest-columns.js
index 842a4ab..d205cf3 100644
--- a/src/lib/components/order/ordertest/table/ordertest-columns.js
+++ b/src/lib/components/order/ordertest/table/ordertest-columns.js
@@ -7,8 +7,4 @@ export const orderTestColumns = [
accessorKey: "PlacerID",
header: "Host ID",
},
- {
- accessorKey: "Priority",
- header: "Priority",
- },
];
\ No newline at end of file
diff --git a/src/lib/components/patient/reusable/form-page-container.svelte b/src/lib/components/patient/reusable/form-page-container.svelte
index 055784e..07f35e4 100644
--- a/src/lib/components/patient/reusable/form-page-container.svelte
+++ b/src/lib/components/patient/reusable/form-page-container.svelte
@@ -15,7 +15,7 @@
-
+
{@render children()}
diff --git a/src/lib/components/reusable/form/dictionary-form-renderer.svelte b/src/lib/components/reusable/form/dictionary-form-renderer.svelte
index 45c636b..ee71c76 100644
--- a/src/lib/components/reusable/form/dictionary-form-renderer.svelte
+++ b/src/lib/components/reusable/form/dictionary-form-renderer.svelte
@@ -21,6 +21,7 @@
import CornerDownLeftIcon from '@lucide/svelte/icons/corner-down-left';
import CheckIcon from "@lucide/svelte/icons/check";
import XIcon from "@lucide/svelte/icons/x";
+ import ReusableUpload from "$lib/components/reusable/reusable-upload.svelte";
let {
formState,
@@ -860,6 +861,10 @@
{isOn ? toggleOn.label : toggleOff.label}
+ {:else if type === "fileupload"}
+
+
+
{:else}
+ import * as DropdownMenu from '$lib/components/ui/dropdown-menu/index.js';
+ import * as Select from '$lib/components/ui/select/index.js';
+ import * as Popover from "$lib/components/ui/popover/index.js";
+ import { Toggle } from '$lib/components/ui/toggle/index.js';
+ import { Button } from '$lib/components/ui/button/index.js';
+ import { Input } from '$lib/components/ui/input/index.js';
+ import { Label } from '$lib/components/ui/label/index.js';
+ import { Spinner } from '$lib/components/ui/spinner/index.js';
+ import ReusableCalendar from '$lib/components/reusable/reusable-calendar.svelte';
+ import { Badge } from '$lib/components/ui/badge/index.js';
+ import * as InputGroup from '$lib/components/ui/input-group/index.js';
+ import ChevronDownIcon from '@lucide/svelte/icons/chevron-down';
+ import { Textarea } from '$lib/components/ui/textarea/index.js';
+ import MoveLeftIcon from '@lucide/svelte/icons/move-left';
+ import MoveRightIcon from '@lucide/svelte/icons/move-right';
+ import BrushCleaningIcon from '@lucide/svelte/icons/brush-cleaning';
+ import DeleteIcon from '@lucide/svelte/icons/delete';
+ import Trash2Icon from '@lucide/svelte/icons/trash-2';
+ import PlusIcon from '@lucide/svelte/icons/plus';
+ import CornerDownLeftIcon from '@lucide/svelte/icons/corner-down-left';
+ import CheckIcon from "@lucide/svelte/icons/check";
+ import XIcon from "@lucide/svelte/icons/x";
+ import ReusableUpload from "$lib/components/reusable/reusable-upload.svelte";
+ import * as Table from "$lib/components/ui/table/index.js";
+ import * as Tooltip from "$lib/components/ui/tooltip/index.js";
+
+ let {
+ formState,
+ formFields,
+ uploadErrors,
+ mode = 'create',
+ } = $props();
+
+ let searchQuery = $state({});
+
+ const leftGroups = $derived([formFields[0]]);
+ const rightGroups = $derived(formFields.slice(1));
+
+ function getFilteredOptions(key) {
+ const query = searchQuery[key] || '';
+ if (!query) return formState.selectOptions?.[key] ?? [];
+
+ return (formState.selectOptions?.[key] ?? []).filter((opt) =>
+ opt.label.toLowerCase().includes(query.toLowerCase())
+ );
+ }
+
+ async function initializeDefaultValues() {
+ for (const group of formFields) {
+ for (const row of group.rows) {
+ for (const col of row.columns) {
+ if (col.type === 'group') {
+ for (const child of col.columns) {
+ await handleDefaultValue(child);
+ }
+ } else {
+ await handleDefaultValue(col);
+ }
+ }
+ }
+ }
+ }
+
+ async function handleDefaultValue(field) {
+ if (!field.defaultValue || !field.optionsEndpoint) return;
+
+ await formState.fetchOptions(field, formState.form);
+
+ if (!formState.form[field.key]) {
+ formState.form[field.key] = field.defaultValue;
+ }
+ }
+
+ $effect(() => {
+ initializeDefaultValues();
+ });
+
+
+{#snippet Fieldset({
+ key,
+ label,
+ required,
+ type,
+ optionsEndpoint,
+ options,
+ validateOn,
+ allowFuture,
+ valueKey,
+ labelKey,
+})}
+
+
+
+ {#if required}
+
*
+ {/if}
+ {#if key === 'FormulaCode' && formState.form.FormulaInput?.length}
+ {@const inputStatus = onGetErrorStatus?.()}
+
+
Must included :
+
+
+ {#each inputStatus as item (item.value)}
+
+ {item.value}
+
+ {/each}
+
+
+ {/if}
+
+
+
+
+{/snippet}
+
+{#snippet GroupBlock(groups)}
+
+ {#each groups as group}
+
+ {#if group.title}
+
+ {group.title}
+
+ {/if}
+
+ {#each group.rows as row}
+
+ {#each row.columns as col}
+ {@render Fieldset(col)}
+ {/each}
+
+ {/each}
+
+ {/each}
+
+{/snippet}
+
+
+
+ {@render GroupBlock(leftGroups)}
+
+
+ {@render GroupBlock(rightGroups)}
+
+
\ No newline at end of file
diff --git a/src/lib/components/reusable/reusable-calendar.svelte b/src/lib/components/reusable/reusable-calendar.svelte
index 8bb204b..761d435 100644
--- a/src/lib/components/reusable/reusable-calendar.svelte
+++ b/src/lib/components/reusable/reusable-calendar.svelte
@@ -7,10 +7,12 @@
import { getLocalTimeZone, today, parseDate } from "@internationalized/date";
const id = $props.id();
- let { title, parentFunction, value = $bindable("") } = $props();
+ let { title, parentFunction, value = $bindable(""), allowFuture = false } = $props();
let open = $state(false);
let calendarValue = $state();
+ const maxValue = $derived(allowFuture ? undefined : today(getLocalTimeZone()));
+
$effect(() => {
if (value && typeof value === "string") {
try {
@@ -64,7 +66,7 @@
bind:value={calendarValue}
captionLayout="dropdown"
onValueChange={handleChange}
- maxValue={today(getLocalTimeZone())}
+ maxValue={maxValue}
/>