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
+ `}
+>
+
+ {#if props.masterDetail.isFormMode}
+
+ {#each "LOCATION".split("") as c}
+ {c}
+ {/each}
+
+ {/if}
+
+ {#if !props.masterDetail.isFormMode}
+
e.stopPropagation()} onkeydown={(e) => {
+ if (e.key === 'Enter' || e.key === ' ') {
+ e.preventDefault();
+ e.stopPropagation();
+ }
+ }}>
+
+
+ {#if search.searchData.length > 0}
+
+ {:else}
+
+
+
+ {/if}
+
+
+ {/if}
+
+
\ No newline at end of file
diff --git a/src/lib/components/dictionary/location/page/view-page.svelte b/src/lib/components/dictionary/location/page/view-page.svelte
new file mode 100644
index 0000000..3e0b9eb
--- /dev/null
+++ b/src/lib/components/dictionary/location/page/view-page.svelte
@@ -0,0 +1 @@
+vw
\ No newline at end of file
diff --git a/src/lib/components/dictionary/location/table/location-columns.js b/src/lib/components/dictionary/location/table/location-columns.js
new file mode 100644
index 0000000..d63e479
--- /dev/null
+++ b/src/lib/components/dictionary/location/table/location-columns.js
@@ -0,0 +1,14 @@
+export const locationColumns = [
+ {
+ accessorKey: "LocCode",
+ header: "Location Code",
+ },
+ {
+ accessorKey: "LocFull",
+ header: "Location Name",
+ },
+ {
+ accessorKey: "LocType",
+ header: "Location Type",
+ },
+];
\ No newline at end of file
diff --git a/src/lib/components/dictionary/testdef/api/testdef-api.js b/src/lib/components/dictionary/testdef/api/testdef-api.js
new file mode 100644
index 0000000..9219a84
--- /dev/null
+++ b/src/lib/components/dictionary/testdef/api/testdef-api.js
@@ -0,0 +1,18 @@
+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.TEST, searchQuery)
+}
+
+export async function getTest(searchQuery) {
+ return await getById(API.TEST, searchQuery)
+}
+
+export async function createTest(newTestForm) {
+ return await create(API.TEST, newTestForm)
+}
+
+export async function editTest(editTestForm) {
+ return await update(API.TEST, editTestForm)
+}
\ No newline at end of file
diff --git a/src/lib/components/dictionary/testdef/config/testdef-config.js b/src/lib/components/dictionary/testdef/config/testdef-config.js
new file mode 100644
index 0000000..e69de29
diff --git a/src/lib/components/dictionary/testdef/config/testdef-form-config.js b/src/lib/components/dictionary/testdef/config/testdef-form-config.js
new file mode 100644
index 0000000..94cd262
--- /dev/null
+++ b/src/lib/components/dictionary/testdef/config/testdef-form-config.js
@@ -0,0 +1,211 @@
+import { API } from "$lib/config/api";
+import EraserIcon from "@lucide/svelte/icons/eraser";
+import { z } from "zod";
+import { cleanEmptyStrings } from "$lib/utils/cleanEmptyStrings";
+
+export const testSchema = z.object({});
+
+export const admissionInitialForm = {
+ InternalPVID: "",
+ InternalPID: "",
+ PVID: "",
+ EpisodeID: "",
+ DiagCode: "",
+ Diagnosis: "",
+ ADTCode: "",
+ LocationID: "",
+ AttDoc: "",
+ RefDoc: "",
+ AdmDoc: "",
+ CnsDoc: "",
+ isDischarge: false
+};
+
+export const admissionDefaultErrors = {};
+
+export const admissionFormFields = [
+ {
+ title: "Visit Information",
+ rows: [
+ {
+ type: "row",
+ columns: [
+ // {
+ // key: "PVID",
+ // label: "Visit ID",
+ // required: false,
+ // type: "text",
+ // },
+ {
+ key: "EpisodeID",
+ label: "Episode ID",
+ required: false,
+ type: "text",
+ }
+ ]
+ }
+ ]
+ },
+ {
+ title: "Medical Team",
+ rows: [
+ {
+ type: "row",
+ columns: [
+ {
+ key: "AttDoc",
+ label: "Attended Doctor",
+ required: false,
+ type: "select",
+ optionsEndpoint: `${API.BASE_URL}${API.CONTACT}`,
+ valueKey: "ContactID",
+ labelKey: (item) => `${item.Initial} - ${item.NameFirst} ${item.NameLast}`,
+ },
+ {
+ key: "RefDoc",
+ label: "Reference Doctor",
+ required: false,
+ type: "select",
+ optionsEndpoint: `${API.BASE_URL}${API.CONTACT}`,
+ valueKey: "ContactID",
+ labelKey: (item) => `${item.Initial} - ${item.NameFirst} ${item.NameLast}`,
+ }
+ ]
+ },
+ {
+ type: "row",
+ columns: [
+ {
+ key: "AdmDoc",
+ label: "Admitted Doctor",
+ required: false,
+ type: "select",
+ optionsEndpoint: `${API.BASE_URL}${API.CONTACT}`,
+ valueKey: "ContactID",
+ labelKey: (item) => `${item.Initial} - ${item.NameFirst} ${item.NameLast}`,
+ },
+ {
+ key: "CnsDoc",
+ label: "Consulte Doctor",
+ required: false,
+ type: "select",
+ optionsEndpoint: `${API.BASE_URL}${API.CONTACT}`,
+ valueKey: "ContactID",
+ labelKey: (item) => `${item.Initial} - ${item.NameFirst} ${item.NameLast}`,
+ }
+ ]
+ }
+ ]
+ },
+ {
+ title: "Visit Classification",
+ rows: [
+ {
+ type: "row",
+ columns: [
+ {
+ key: "LocationID",
+ label: "Location",
+ required: false,
+ type: "select",
+ optionsEndpoint: `${API.BASE_URL}${API.LOCATION}`,
+ valueKey: "LocationID",
+ labelKey: (item) => `${item.LocCode} - ${item.LocFull}`,
+ },
+ {
+ key: "VisitClass",
+ label: "Visit Class",
+ required: false,
+ type: "select",
+ // optionsEndpoint: `${API.BASE_URL}${API.VALUESET}/visit_classes`,
+ }
+ ]
+ },
+ {
+ type: "row",
+ columns: [
+ {
+ key: "ServiceClass",
+ label: "Service Class",
+ required: false,
+ type: "select",
+ // optionsEndpoint: `${API.BASE_URL}${API.VALUESET}/service_classes`,
+ },
+ {
+ key: "isDischarge",
+ label: "Admission Status",
+ required: false,
+ type: "toggle",
+ defaultValue: false,
+ }
+ ]
+ }
+ ]
+ },
+ {
+ title: "Clinical Information",
+ rows: [
+ {
+ type: "row",
+ columns: [
+ {
+ key: "Diagnosis",
+ label: "Diagnosis",
+ required: false,
+ type: "textarea",
+ rows: 4,
+ maxLength: 1000,
+ }
+ ]
+ }
+ ]
+ }
+];
+
+export function getAdmissionFormActions(handlers) {
+ return [
+ {
+ Icon: EraserIcon,
+ label: 'Clear Form',
+ onClick: handlers.clearForm,
+ },
+ ];
+}
+
+const admissionTemplate = {
+ PVID: 'PVID',
+ InternalPID: 'InternalPID',
+ EpisodeID: 'EpisodeID',
+ PatDiag: {
+ DiagCode: 'DiagCode',
+ Diagnosis: 'Diagnosis',
+ },
+ PatVisitADT: {
+ ADTCode: () => 'A04',
+ LocationID: 'LocationID',
+ AttDoc: 'AttDoc',
+ RefDoc: 'RefDoc',
+ AdmDoc: 'AdmDoc',
+ CnsDoc: 'CnsDoc',
+ },
+};
+
+export function buildPayload(form, schema = admissionTemplate) {
+ const payload = {};
+
+ for (const [key, config] of Object.entries(schema)) {
+ if (typeof config === 'string') {
+ // Kirim nilai dari form, atau null jika tidak ada (agar key tetap ada)
+ payload[key] = form[config] ?? null;
+ }
+ else if (typeof config === 'function') {
+ payload[key] = config(form);
+ }
+ else if (typeof config === 'object' && config !== null) {
+ // Rekursif tanpa pengecekan panjang keys, agar objek nested selalu dibuat
+ payload[key] = buildPayload(form, config);
+ }
+ }
+
+ return cleanEmptyStrings(payload);
+}
\ No newline at end of file
diff --git a/src/lib/components/dictionary/testdef/page/create-page.svelte b/src/lib/components/dictionary/testdef/page/create-page.svelte
new file mode 100644
index 0000000..e69de29
diff --git a/src/lib/components/dictionary/testdef/page/edit-page.svelte b/src/lib/components/dictionary/testdef/page/edit-page.svelte
new file mode 100644
index 0000000..e69de29
diff --git a/src/lib/components/dictionary/testdef/page/master-page.svelte b/src/lib/components/dictionary/testdef/page/master-page.svelte
new file mode 100644
index 0000000..e69de29
diff --git a/src/lib/components/dictionary/testdef/page/view-page.svelte b/src/lib/components/dictionary/testdef/page/view-page.svelte
new file mode 100644
index 0000000..e69de29
diff --git a/src/lib/components/patient/admission/config/admission-form-config.js b/src/lib/components/patient/admission/config/admission-form-config.js
index 4f39a76..0cc2987 100644
--- a/src/lib/components/patient/admission/config/admission-form-config.js
+++ b/src/lib/components/patient/admission/config/admission-form-config.js
@@ -117,7 +117,7 @@ export const admissionFormFields = [
label: "Visit Class",
required: false,
type: "select",
- optionsEndpoint: `${API.BASE_URL}${API.VALUESET}/visit_classes`,
+ // optionsEndpoint: `${API.BASE_URL}${API.VALUESET}/visit_classes`,
}
]
},
@@ -129,7 +129,7 @@ export const admissionFormFields = [
label: "Service Class",
required: false,
type: "select",
- optionsEndpoint: `${API.BASE_URL}${API.VALUESET}/service_classes`,
+ // optionsEndpoint: `${API.BASE_URL}${API.VALUESET}/service_classes`,
},
{
key: "isDischarge",
diff --git a/src/lib/components/patient/admission/page/create-page.svelte b/src/lib/components/patient/admission/page/create-page.svelte
index d6f463d..7e4983f 100644
--- a/src/lib/components/patient/admission/page/create-page.svelte
+++ b/src/lib/components/patient/admission/page/create-page.svelte
@@ -4,6 +4,7 @@
import PatientFormRenderer from "$lib/components/patient/reusable/patient-form-renderer.svelte";
import { buildPayload } from "$lib/components/patient/admission/config/admission-form-config";
import { toast } from "svelte-sonner";
+ import ReusableAlertDialog from "$lib/components/reusable/reusable-alert-dialog.svelte";
let props = $props();
@@ -21,6 +22,19 @@
const actions = formActions(handlers);
+ let showConfirm = $state(false);
+
+ function handleExit() {
+ const ok = masterDetail.exitForm();
+ if (!ok) {
+ showConfirm = true;
+ }
+ }
+
+ function confirmDiscard() {
+ masterDetail.exitForm(true);
+ }
+
async function handleSave() {
const payload = buildPayload(formState.form);
@@ -28,7 +42,7 @@
console.log(payload);
toast('Visit Created!');
- masterDetail?.exitForm();
+ masterDetail?.exitForm(true);
}
const primaryAction = $derived({
@@ -56,4 +70,9 @@
formFields={formFields}
mode="create"
/>
-
\ No newline at end of file
+
+
+