diff --git a/src/lib/components/app-sidebar.svelte b/src/lib/components/app-sidebar.svelte
index 85caeaa..4c1a0aa 100644
--- a/src/lib/components/app-sidebar.svelte
+++ b/src/lib/components/app-sidebar.svelte
@@ -10,6 +10,9 @@
import SendIcon from "@lucide/svelte/icons/send";
import Settings2Icon from "@lucide/svelte/icons/settings-2";
import SquareTerminalIcon from "@lucide/svelte/icons/square-terminal";
+ import ArchiveIcon from "@lucide/svelte/icons/archive";
+ import FlaskConicalIcon from "@lucide/svelte/icons/flask-conical";
+ import BrickWallIcon from "@lucide/svelte/icons/brick-wall";
const data = {
user: {
@@ -73,7 +76,7 @@
{
title: "Sample",
url: "/dictionary",
- icon: BookOpenIcon,
+ icon: ArchiveIcon,
submenus: [
{
title: "Container",
@@ -84,7 +87,7 @@
{
title: "Organization",
url: "/dictionary",
- icon: BookOpenIcon,
+ icon: BrickWallIcon,
submenus: [
{
title: "Account",
@@ -111,7 +114,7 @@
{
title: "Test",
url: "/dictionary/test",
- icon: BookOpenIcon,
+ icon: FlaskConicalIcon,
},
]
};
diff --git a/src/lib/components/dictionary/contact/api/contact-api.js b/src/lib/components/dictionary/contact/api/contact-api.js
new file mode 100644
index 0000000..d731a34
--- /dev/null
+++ b/src/lib/components/dictionary/contact/api/contact-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 getContacts(searchQuery) {
+ return await searchWithParams(API.CONTACT, searchQuery)
+}
+
+export async function getContact(searchQuery) {
+ return await getById(API.CONTACT, searchQuery)
+}
+
+export async function createContact(newContactForm) {
+ return await create(API.CONTACT, newContactForm)
+}
+
+export async function editContact(editContactForm) {
+ return await update(API.CONTACT, editContactForm)
+}
\ No newline at end of file
diff --git a/src/lib/components/dictionary/contact/config/contact-config.js b/src/lib/components/dictionary/contact/config/contact-config.js
new file mode 100644
index 0000000..3325e7d
--- /dev/null
+++ b/src/lib/components/dictionary/contact/config/contact-config.js
@@ -0,0 +1,72 @@
+import PlusIcon from "@lucide/svelte/icons/plus";
+import Settings2Icon from "@lucide/svelte/icons/settings-2";
+import PencilIcon from "@lucide/svelte/icons/pencil";
+import { API } from "$lib/config/api";
+
+export const searchFields = [
+ {
+ key: "Initial",
+ label: "Initial",
+ type: "text",
+ },
+];
+
+export const detailSections = [
+ {
+ title: "",
+ class: "grid grid-cols-1 md:grid-cols-2 gap-4",
+ groups: [
+ {
+ class: "space-y-3",
+ fields: [
+ { key: "Title", label: "Title" },
+ { key: "Initial", label: "Initial" },
+ { key: "NameFirst", label: "First Name" },
+ { key: "NameLast", label: "Last Name" },
+ { key: "Birthdate", label: "Birthdate" },
+ ]
+ },
+ {
+ class: "space-y-3",
+ fields: [
+ { key: "EmailAddress1", label: "Email Address 1" },
+ { key: "EmailAddress2", label: "Email Address 2" },
+ { key: "Phone", label: "Phone" },
+ { key: "MobilePhone1", label: "Mobile Phone 1" },
+ { key: "MobilePhone2", label: "Mobile Phone 2" },
+ ]
+ }
+ ]
+ },
+ {
+ class: "grid grid-cols-2 gap-4 items-center",
+ fields: [
+ { key: "Specialty", label: "Specialty" },
+ { key: "SubSpecialty", label: "Sub Specialty" },
+ ]
+ },
+];
+
+export function contactActions(masterDetail) {
+ return [
+ {
+ Icon: PlusIcon,
+ label: 'Add Contact',
+ onClick: () => masterDetail.enterCreate(),
+ },
+ {
+ Icon: Settings2Icon,
+ label: 'Search Parameters',
+ },
+ ];
+}
+
+export function viewActions(handlers){
+ return [
+ {
+ Icon: PencilIcon,
+ label: 'Edit Contact',
+ onClick: handlers.editContact,
+ },
+ ]
+}
\ No newline at end of file
diff --git a/src/lib/components/dictionary/contact/config/contact-form-config.js b/src/lib/components/dictionary/contact/config/contact-form-config.js
new file mode 100644
index 0000000..f13406c
--- /dev/null
+++ b/src/lib/components/dictionary/contact/config/contact-form-config.js
@@ -0,0 +1,224 @@
+import { API } from "$lib/config/api";
+import EraserIcon from "@lucide/svelte/icons/eraser";
+import { z } from "zod";
+
+export const contactSchema = z.object({
+ NameFirst: z.string().min(1, "Required"),
+ Initial: z.string().min(1, "Required"),
+});
+
+export const contactInitialForm = {
+ ContactID: '',
+ NameFirst: '',
+ NameLast: '',
+ Title: '',
+ Initial: '',
+ Birthdate: '',
+ EmailAddress1: '',
+ EmailAddress2: '',
+ Phone: '',
+ MobilePhone1: '',
+ MobilePhone2: '',
+ Specialty: '',
+ SubSpecialty: '',
+};
+
+export const contactDetailInitialForm = {
+ SiteID: '',
+ ContactDetID: '',
+ ContactCode: '',
+ ContactEmail: '',
+ OccupationID: '',
+ JobTitle: '',
+ Department: '',
+};
+
+export const contactDefaultErrors = {
+ NameFirst: "Required",
+ Initial: "Required",
+};
+
+export const contactFormFields = [
+ {
+ title: "Personal Information",
+ rows: [
+ {
+ type: "row",
+ columns: [
+ {
+ key: "NameFirst",
+ label: "First Name",
+ required: true,
+ type: "text",
+ validateOn: ["input"]
+ },
+ {
+ key: "NameLast",
+ label: "Last Name",
+ required: false,
+ type: "text",
+ },
+ ]
+ },
+ {
+ type: "row",
+ columns: [
+ {
+ key: "Title",
+ label: "Title",
+ required: false,
+ type: "text",
+ },
+ {
+ key: "Initial",
+ label: "Initial",
+ required: true,
+ type: "text",
+ validateOn: ["input"]
+ },
+ ]
+ },
+ {
+ type: "row",
+ columns: [
+ {
+ key: "Birthdate",
+ label: "Birthdate",
+ required: false,
+ type: "date",
+ fullWidth: false
+ },
+ ]
+ },
+ ]
+ },
+ {
+ title: "Contact Information",
+ rows: [
+ {
+ type: "row",
+ columns: [
+ {
+ key: "EmailAddress1",
+ label: "Email Address 1",
+ required: false,
+ type: "text",
+ },
+ {
+ key: "EmailAddress2",
+ label: "Email Address 2",
+ required: false,
+ type: "text",
+ },
+ ]
+ },
+ {
+ type: "row",
+ columns: [
+ {
+ key: "MobilePhone1",
+ label: "Mobile Phone 1",
+ required: false,
+ type: "text",
+ },
+ {
+ key: "MobilePhone2",
+ label: "Mobile Phone 2",
+ required: false,
+ type: "text",
+ },
+ {
+ key: "Phone",
+ label: "Phone",
+ required: false,
+ type: "text",
+ },
+ ]
+ },
+ ]
+ },
+ {
+ title: "Professional Detail",
+ rows: [
+ {
+ type: "row",
+ columns: [
+ {
+ key: "Specialty",
+ label: "Specialty",
+ required: false,
+ type: "text",
+ },
+ {
+ key: "SubSpecialty",
+ label: "Sub Specialty",
+ required: false,
+ type: "text",
+ },
+ ]
+ },
+ ]
+ }
+];
+
+export const contactDetailFormFields = [
+ {
+ rows: [
+ {
+ type: "row",
+ columns: [
+ {
+ key: "SiteID",
+ label: "Site",
+ required: false,
+ type: "select",
+ optionsEndpoint: `${API.BASE_URL}${API.SITE}`,
+ valueKey: "SiteID",
+ labelKey: "SiteName",
+ },
+ { key: "ContactCode", label: "Code", required: false, type: "text" },
+ ]
+ },
+ {
+ type: "row",
+ columns: [
+ {
+ key: "Department",
+ label: "Department",
+ required: false,
+ type: "select",
+ optionsEndpoint: `${API.BASE_URL}${API.DEPARTMENT}`,
+ valueKey: "DepartmentID",
+ labelKey: "DepartmentName",
+ },
+ {
+ key: "OccupationID",
+ label: "Occupation",
+ required: false,
+ type: "select",
+ optionsEndpoint: `${API.BASE_URL}${API.OCCUPATION}`,
+ valueKey: "OccupationID",
+ labelKey: "OccText",
+ },
+ ]
+ },
+ {
+ type: "row",
+ columns: [
+ { key: "JobTitle", label: "Job Title", required: false, type: "text" },
+ { key: "ContactEmail", label: "Email", required: false, type: "text" },
+ ]
+ }
+ ]
+ }
+];
+
+export function getContactFormActions(handlers) {
+ return [
+ {
+ Icon: EraserIcon,
+ label: 'Clear Form',
+ onClick: handlers.clearForm,
+ },
+ ];
+}
\ No newline at end of file
diff --git a/src/lib/components/dictionary/contact/page/create-page.svelte b/src/lib/components/dictionary/contact/page/create-page.svelte
new file mode 100644
index 0000000..b2b1ef3
--- /dev/null
+++ b/src/lib/components/dictionary/contact/page/create-page.svelte
@@ -0,0 +1,54 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/lib/components/dictionary/contact/page/edit-page.svelte b/src/lib/components/dictionary/contact/page/edit-page.svelte
new file mode 100644
index 0000000..428ffd8
--- /dev/null
+++ b/src/lib/components/dictionary/contact/page/edit-page.svelte
@@ -0,0 +1,281 @@
+
+
+
+
+
+
+
+
+ {#if showDetailForm}
+
+
+
+
+
+
+
+
+
+ {/if}
+ {#each masterDetail.selectedItem?.data?.Details as contactdetail, index}
+
+
+
+
+
+ {contactdetail.ContactCode || "null"}
+
+
+ {contactdetail.ContactEmail || "null"}
+
+
+
+
+ {getLabel('SiteID', contactdetail.SiteID)}
+
+
+
+
+
+
+
+
+
+
+
+
+ Department
+
+
+ {getLabel('Department', contactdetail.Department)}
+
+
+
+
+ Job Title
+
+
+ {contactdetail.JobTitle || "-"}
+
+
+
+
+ Occupation
+
+
+
+ {getLabel('OccupationID', contactdetail.OccupationID)}
+
+
+
+
+
+ {/each}
+
+
+
+
+
\ No newline at end of file
diff --git a/src/lib/components/dictionary/contact/page/master-page.svelte b/src/lib/components/dictionary/contact/page/master-page.svelte
new file mode 100644
index 0000000..8f064bd
--- /dev/null
+++ b/src/lib/components/dictionary/contact/page/master-page.svelte
@@ -0,0 +1,68 @@
+
+
+{#snippet searchParamSnippet()}
+
+{/snippet}
+
+
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 "CONTACT".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/contact/page/view-page.svelte b/src/lib/components/dictionary/contact/page/view-page.svelte
new file mode 100644
index 0000000..08df044
--- /dev/null
+++ b/src/lib/components/dictionary/contact/page/view-page.svelte
@@ -0,0 +1,157 @@
+
+
+{#snippet Fieldset({ value, label, isUTCDate = false })}
+
+
+ {label}
+
+
+ {#if isUTCDate}
+ {formatUTCDate(value)}
+ {:else}
+ {value ?? "-"}
+ {/if}
+
+
+{/snippet}
+
+{#if masterDetail.selectedItem}
+
+
+
+ {#each detailSections as section}
+
+ {#if section.groups}
+
+ {#each section.groups as group}
+
+
+ {#each group.fields as field}
+ {@render Fieldset({
+ label: field.label,
+ value: getFieldValue(field),
+ isUTCDate: field.isUTCDate
+ })}
+ {/each}
+
+
+ {/each}
+
+ {:else}
+
+ {#each section.fields as field}
+ {@render Fieldset({
+ label: field.label,
+ value: getFieldValue(field),
+ isUTCDate: field.isUTCDate
+ })}
+ {/each}
+
+ {/if}
+
+ {/each}
+
+
+
+
+
+
+ {#each masterDetail.selectedItem?.data?.Details as contactdetail}
+
+
+
+
+
+ {contactdetail.ContactCode}
+
+
+ {contactdetail.ContactEmail}
+
+
+
+ Site {contactdetail.SiteID}
+
+
+
+
+
+
+
+ Department
+
+
+ {contactdetail.Department || "-"}
+
+
+
+
+ Job Title
+
+
+ {contactdetail.JobTitle || "-"}
+
+
+
+
+ Occupation
+
+
+ {contactdetail.OccupationID || "-"}
+
+
+
+
+
+ {/each}
+
+
+{:else}
+
+{/if}
\ No newline at end of file
diff --git a/src/lib/components/dictionary/contact/table/contact-columns.js b/src/lib/components/dictionary/contact/table/contact-columns.js
new file mode 100644
index 0000000..2c405c1
--- /dev/null
+++ b/src/lib/components/dictionary/contact/table/contact-columns.js
@@ -0,0 +1,14 @@
+export const contactColumns = [
+ {
+ accessorKey: "Initial",
+ header: "Initial",
+ },
+ {
+ accessorKey: "NameFirst",
+ header: "Contact Name",
+ },
+ {
+ accessorKey: "Specialty",
+ header: "Specialty",
+ },
+];
\ No newline at end of file
diff --git a/src/lib/components/dictionary/testdef/api/testdef-api.js b/src/lib/components/dictionary/test/api/test-api.js
similarity index 90%
rename from src/lib/components/dictionary/testdef/api/testdef-api.js
rename to src/lib/components/dictionary/test/api/test-api.js
index 9219a84..7822b1d 100644
--- a/src/lib/components/dictionary/testdef/api/testdef-api.js
+++ b/src/lib/components/dictionary/test/api/test-api.js
@@ -1,7 +1,7 @@
import { API } from '$lib/config/api.js';
import { getById, searchWithParams, create, update } from '$lib/api/api-client';
-export async function searchParam(searchQuery) {
+export async function getTests(searchQuery) {
return await searchWithParams(API.TEST, searchQuery)
}
diff --git a/src/lib/components/dictionary/test/config/test-config.js b/src/lib/components/dictionary/test/config/test-config.js
new file mode 100644
index 0000000..52bb302
--- /dev/null
+++ b/src/lib/components/dictionary/test/config/test-config.js
@@ -0,0 +1,50 @@
+import PlusIcon from "@lucide/svelte/icons/plus";
+import Settings2Icon from "@lucide/svelte/icons/settings-2";
+import PencilIcon from "@lucide/svelte/icons/pencil";
+import { API } from "$lib/config/api";
+
+export const searchFields = [
+ {
+ key: "TestSiteCode",
+ label: "Test Code",
+ type: "text",
+ },
+ {
+ key: "TestSiteName",
+ label: "Test Name",
+ type: "text",
+ },
+ {
+ key: "TestType",
+ label: "Test Type",
+ type: "select",
+ optionsEndpoint: `${API.BASE_URL}${API.VALUESET}/test_type`,
+ },
+
+];
+
+export const detailSections = [];
+
+export function testActions(masterDetail) {
+ return [
+ {
+ Icon: PlusIcon,
+ label: 'Add Test',
+ onClick: () => masterDetail.enterCreate(),
+ },
+ {
+ Icon: Settings2Icon,
+ label: 'Search Parameters',
+ },
+ ];
+}
+
+export function viewActions(handlers){
+ return [
+ {
+ Icon: PencilIcon,
+ label: 'Edit Test',
+ onClick: handlers.editTest,
+ },
+ ]
+}
\ No newline at end of file
diff --git a/src/lib/components/dictionary/test/config/test-form-config.js b/src/lib/components/dictionary/test/config/test-form-config.js
new file mode 100644
index 0000000..5d128c3
--- /dev/null
+++ b/src/lib/components/dictionary/test/config/test-form-config.js
@@ -0,0 +1,310 @@
+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 testInitialForm = {
+ TestSiteID: "",
+ SiteID: "",
+ TestSiteCode: "",
+ TestSiteName: "",
+ TestType: "",
+ Description: "",
+ DisciplineID: "",
+ DepartmentID: "",
+ ResultType: "",
+ RefType: "",
+ Vset: "",
+ Unit1: "",
+ Factor: "",
+ Unit2: "",
+ Decimal: "",
+ ReqQty: "",
+ ReqQtyUnit: "",
+ CollReq: "",
+ Method: "",
+ ExpectedTXT: "",
+ SeqScr: "",
+ SeqRpt: "",
+ VisibleScr: "",
+ VisibleRpt: "",
+ CountStat: "",
+ Level: "",
+};
+
+export const testDefaultErrors = {};
+
+export const testFormFields = [
+ {
+ title: "Basic Information",
+ rows: [
+ {
+ type: "row",
+ columns: [
+ {
+ key: "SiteID",
+ label: "Site ID",
+ required: false,
+ type: "select",
+ optionsEndpoint: `${API.BASE_URL}${API.SITE}`,
+ valueKey: "SiteID",
+ labelKey: (item) => `${item.SiteCode} - ${item.SiteName}`,
+ },
+ {
+ key: "TestSiteCode",
+ label: "Test Code",
+ required: true,
+ type: "text",
+ validateOn: ["input"]
+ }
+ ]
+ },
+ {
+ type: "row",
+ columns: [
+ {
+ key: "TestSiteName",
+ label: "Test Name",
+ required: true,
+ type: "text",
+ validateOn: ["input"]
+ },
+ {
+ key: "TestType",
+ label: "Test Type",
+ required: true,
+ type: "text",
+ validateOn: ["input"]
+ }
+ ]
+ },
+ {
+ type: "row",
+ columns: [
+ {
+ key: "Description",
+ label: "Description",
+ required: false,
+ type: "textarea",
+ },
+ ]
+ },
+ ]
+ },
+ {
+ title: "Organizational Assignment",
+ rows: [
+ {
+ type: "row",
+ columns: [
+ {
+ key: "DisciplineID",
+ label: "Discipline",
+ required: false,
+ type: "select",
+ optionsEndpoint: `${API.BASE_URL}${API.DISCIPLINE}`,
+ valueKey: "DisciplineID",
+ labelKey: "DisciplineName",
+ },
+ {
+ key: "DepartmentID",
+ label: "Department",
+ required: false,
+ type: "select",
+ optionsEndpoint: `${API.BASE_URL}${API.DEPARTMENT}`,
+ valueKey: "DepartmentID",
+ labelKey: "DepartmentName",
+ },
+ ]
+ },
+ ]
+ },
+ {
+ title: "Result Configuration",
+ rows: [
+ {
+ type: "row",
+ columns: [
+ {
+ key: "ResultType",
+ label: "Result Type",
+ required: true,
+ type: "select",
+ optionsEndpoint: `${API.BASE_URL}${API.VALUESET}/result_type`,
+ },
+ {
+ key: "RefType",
+ label: "Reference Type",
+ required: true,
+ type: "select",
+ optionsEndpoint: `${API.BASE_URL}${API.VALUESET}/reference_type`,
+ }
+ ]
+ },
+ {
+ type: "row",
+ columns: [
+ {
+ key: "VSet",
+ label: "Value Set",
+ required: false,
+ type: "select",
+ optionsEndpoint: `${API.BASE_URL}${API.VALUESET}/service_classes`,
+ },
+ ]
+ },
+ {
+ type: "row",
+ columns: [
+ {
+ key: "Unit1",
+ label: "Unit 1",
+ required: false,
+ type: "text",
+ },
+ {
+ key: "Factor",
+ label: "Factor",
+ required: false,
+ type: "text",
+ },
+ {
+ key: "Unit2",
+ label: "Unit 2",
+ required: false,
+ type: "text",
+ },
+ {
+ key: "Decimal",
+ label: "Decimal",
+ required: false,
+ type: "text",
+ },
+ ]
+ },
+ {
+ type: "row",
+ columns: [
+ {
+ key: "ExpectedTAT",
+ label: "Expected TAT",
+ required: false,
+ type: "select",
+ },
+ ]
+ },
+ ]
+ },
+ {
+ title: "Specimen Requirements",
+ rows: [
+ {
+ type: "row",
+ columns: [
+ {
+ key: "ReqQty",
+ label: "Required Quantity",
+ required: false,
+ type: "text",
+ },
+ {
+ key: "CollReq",
+ label: "Collection Requirement",
+ required: false,
+ type: "text",
+ },
+ ]
+ },
+ {
+ type: "row",
+ columns: [
+ {
+ key: "ReqQtyUnit",
+ label: "Quantity Unit",
+ required: false,
+ type: "text",
+ },
+ {
+ key: "Method",
+ label: "Method",
+ required: false,
+ type: "text",
+ },
+ ]
+ },
+ ]
+ },
+ {
+ title: "Display Settings",
+ rows: [
+ {
+ type: "row",
+ columns: [
+ {
+ key: "SeqScr",
+ label: "Sequence on Screen",
+ required: false,
+ type: "text",
+ },
+ {
+ key: "VisibleScr",
+ label: "Visible on Screen",
+ required: false,
+ type: "text",
+ },
+ ]
+ },
+ {
+ type: "row",
+ columns: [
+ {
+ key: "SeqRpt",
+ label: "Sequence on Report",
+ required: false,
+ type: "text",
+ },
+ {
+ key: "VisibleRpt",
+ label: "Visible on Report",
+ required: false,
+ type: "text",
+ },
+ ]
+ },
+ ]
+ },
+ {
+ title: "Other Settings",
+ rows: [
+ {
+ type: "row",
+ columns: [
+ {
+ key: "CountStat",
+ label: "Statistic",
+ required: false,
+ type: "text",
+ },
+ {
+ key: "Level",
+ label: "Level",
+ required: false,
+ type: "text",
+ },
+ ]
+ },
+ ]
+ },
+];
+
+export function getTestFormActions(handlers) {
+ return [
+ {
+ Icon: EraserIcon,
+ label: 'Clear Form',
+ onClick: handlers.clearForm,
+ },
+ ];
+}
\ No newline at end of file
diff --git a/src/lib/components/dictionary/test/page/create-page.svelte b/src/lib/components/dictionary/test/page/create-page.svelte
new file mode 100644
index 0000000..b310016
--- /dev/null
+++ b/src/lib/components/dictionary/test/page/create-page.svelte
@@ -0,0 +1,54 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/lib/components/dictionary/test/page/edit-page.svelte b/src/lib/components/dictionary/test/page/edit-page.svelte
new file mode 100644
index 0000000..d1b0c29
--- /dev/null
+++ b/src/lib/components/dictionary/test/page/edit-page.svelte
@@ -0,0 +1,73 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/lib/components/dictionary/test/page/master-page.svelte b/src/lib/components/dictionary/test/page/master-page.svelte
new file mode 100644
index 0000000..5ebc759
--- /dev/null
+++ b/src/lib/components/dictionary/test/page/master-page.svelte
@@ -0,0 +1,68 @@
+
+
+{#snippet searchParamSnippet()}
+
+{/snippet}
+
+ 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 "TEST".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/test/page/view-page.svelte b/src/lib/components/dictionary/test/page/view-page.svelte
new file mode 100644
index 0000000..b5a7959
--- /dev/null
+++ b/src/lib/components/dictionary/test/page/view-page.svelte
@@ -0,0 +1,91 @@
+
+
+{#snippet Fieldset({ value, label, isUTCDate = false })}
+
+
+ {label}
+
+
+ {#if isUTCDate}
+ {formatUTCDate(value)}
+ {:else}
+ {value ?? "-"}
+ {/if}
+
+
+{/snippet}
+
+{#if masterDetail.selectedItem}
+
+
+
+ {#each detailSections as section}
+
+ {#if section.groups}
+
+ {#each section.groups as group}
+
+
+ {#each group.fields as field}
+ {@render Fieldset({
+ label: field.label,
+ value: getFieldValue(field),
+ isUTCDate: field.isUTCDate
+ })}
+ {/each}
+
+
+ {/each}
+
+ {:else}
+
+ {#each section.fields as field}
+ {@render Fieldset({
+ label: field.label,
+ value: getFieldValue(field),
+ isUTCDate: field.isUTCDate
+ })}
+ {/each}
+
+ {/if}
+
+ {/each}
+
+
+{:else}
+
+{/if}
\ No newline at end of file
diff --git a/src/lib/components/dictionary/test/table/test-columns.js b/src/lib/components/dictionary/test/table/test-columns.js
new file mode 100644
index 0000000..8ba6b8d
--- /dev/null
+++ b/src/lib/components/dictionary/test/table/test-columns.js
@@ -0,0 +1,14 @@
+export const testColumns = [
+ {
+ accessorKey: "TestSiteCode",
+ header: "Test Code",
+ },
+ {
+ accessorKey: "TestSiteName",
+ header: "Test Name",
+ },
+ {
+ accessorKey: "TestType",
+ header: "Test Type",
+ },
+];
\ 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
deleted file mode 100644
index e69de29..0000000
diff --git a/src/lib/components/dictionary/testdef/config/testdef-form-config.js b/src/lib/components/dictionary/testdef/config/testdef-form-config.js
deleted file mode 100644
index 94cd262..0000000
--- a/src/lib/components/dictionary/testdef/config/testdef-form-config.js
+++ /dev/null
@@ -1,211 +0,0 @@
-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
deleted file mode 100644
index e69de29..0000000
diff --git a/src/lib/components/dictionary/testdef/page/edit-page.svelte b/src/lib/components/dictionary/testdef/page/edit-page.svelte
deleted file mode 100644
index e69de29..0000000
diff --git a/src/lib/components/dictionary/testdef/page/master-page.svelte b/src/lib/components/dictionary/testdef/page/master-page.svelte
deleted file mode 100644
index e69de29..0000000
diff --git a/src/lib/components/dictionary/testdef/page/view-page.svelte b/src/lib/components/dictionary/testdef/page/view-page.svelte
deleted file mode 100644
index e69de29..0000000
diff --git a/src/lib/components/patient/reusable/form-page-container.svelte b/src/lib/components/patient/reusable/form-page-container.svelte
index 059dd64..055784e 100644
--- a/src/lib/components/patient/reusable/form-page-container.svelte
+++ b/src/lib/components/patient/reusable/form-page-container.svelte
@@ -17,8 +17,11 @@
- {@render children()}
-
+
+ {@render children()}
+
+
+