From a3811bba70d14033149e79f7edd3d66070ebce6b Mon Sep 17 00:00:00 2001 From: faiztyanirh Date: Wed, 18 Feb 2026 16:48:08 +0700 Subject: [PATCH] add page/feature dictionary contact --- src/lib/components/app-sidebar.svelte | 9 +- .../dictionary/contact/api/contact-api.js | 18 + .../contact/config/contact-config.js | 72 ++++ .../contact/config/contact-form-config.js | 224 +++++++++++++ .../contact/page/create-page.svelte | 54 +++ .../dictionary/contact/page/edit-page.svelte | 281 ++++++++++++++++ .../contact/page/master-page.svelte | 68 ++++ .../dictionary/contact/page/view-page.svelte | 157 +++++++++ .../contact/table/contact-columns.js | 14 + .../testdef-api.js => test/api/test-api.js} | 2 +- .../dictionary/test/config/test-config.js | 50 +++ .../test/config/test-form-config.js | 310 ++++++++++++++++++ .../dictionary/test/page/create-page.svelte | 54 +++ .../dictionary/test/page/edit-page.svelte | 73 +++++ .../dictionary/test/page/master-page.svelte | 68 ++++ .../dictionary/test/page/view-page.svelte | 91 +++++ .../dictionary/test/table/test-columns.js | 14 + .../testdef/config/testdef-config.js | 0 .../testdef/config/testdef-form-config.js | 211 ------------ .../testdef/page/create-page.svelte | 0 .../dictionary/testdef/page/edit-page.svelte | 0 .../testdef/page/master-page.svelte | 0 .../dictionary/testdef/page/view-page.svelte | 0 .../reusable/form-page-container.svelte | 7 +- .../reusable/patient-form-renderer.svelte | 3 +- .../form/dictionary-form-renderer.svelte | 48 +-- .../reusable/form/form-page-container.svelte | 9 +- src/lib/components/ui/badge/badge.svelte | 45 +++ src/lib/components/ui/badge/index.js | 2 + src/routes/+layout.server.js | 3 + src/routes/dictionary/contact/+page.svelte | 51 +++ src/routes/dictionary/test/+page.svelte | 51 +++ src/routes/dictionary/testdef/+page.svelte | 60 ---- 33 files changed, 1748 insertions(+), 301 deletions(-) create mode 100644 src/lib/components/dictionary/contact/api/contact-api.js create mode 100644 src/lib/components/dictionary/contact/config/contact-config.js create mode 100644 src/lib/components/dictionary/contact/config/contact-form-config.js create mode 100644 src/lib/components/dictionary/contact/page/create-page.svelte create mode 100644 src/lib/components/dictionary/contact/page/edit-page.svelte create mode 100644 src/lib/components/dictionary/contact/page/master-page.svelte create mode 100644 src/lib/components/dictionary/contact/page/view-page.svelte create mode 100644 src/lib/components/dictionary/contact/table/contact-columns.js rename src/lib/components/dictionary/{testdef/api/testdef-api.js => test/api/test-api.js} (90%) create mode 100644 src/lib/components/dictionary/test/config/test-config.js create mode 100644 src/lib/components/dictionary/test/config/test-form-config.js create mode 100644 src/lib/components/dictionary/test/page/create-page.svelte create mode 100644 src/lib/components/dictionary/test/page/edit-page.svelte create mode 100644 src/lib/components/dictionary/test/page/master-page.svelte create mode 100644 src/lib/components/dictionary/test/page/view-page.svelte create mode 100644 src/lib/components/dictionary/test/table/test-columns.js delete mode 100644 src/lib/components/dictionary/testdef/config/testdef-config.js delete mode 100644 src/lib/components/dictionary/testdef/config/testdef-form-config.js delete mode 100644 src/lib/components/dictionary/testdef/page/create-page.svelte delete mode 100644 src/lib/components/dictionary/testdef/page/edit-page.svelte delete mode 100644 src/lib/components/dictionary/testdef/page/master-page.svelte delete mode 100644 src/lib/components/dictionary/testdef/page/view-page.svelte create mode 100644 src/lib/components/ui/badge/badge.svelte create mode 100644 src/lib/components/ui/badge/index.js create mode 100644 src/routes/dictionary/contact/+page.svelte create mode 100644 src/routes/dictionary/test/+page.svelte delete mode 100644 src/routes/dictionary/testdef/+page.svelte 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()} +
+ +