diff --git a/src/lib/components/dictionary/account/config/account-config.js b/src/lib/components/dictionary/account/config/account-config.js index e69de29..d1d5690 100644 --- a/src/lib/components/dictionary/account/config/account-config.js +++ b/src/lib/components/dictionary/account/config/account-config.js @@ -0,0 +1,97 @@ +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: "Parent", + label: "Parent Account", + type: "select", + optionsEndpoint: `${API.BASE_URL}${API.ACCOUNT}`, + valueKey: "AccountID", + labelKey: "AccountName", + }, + { + key: "AccountName", + label: "Account Name", + type: "text", + }, +]; + +export const detailSections = [ + { + class: "grid grid-cols-2 gap-4 items-center", + fields: [ + { key: "Parent", label: "Parent" }, + { key: "AccountName", label: "Account Name" }, + { key: "Initial", label: "Initial" }, + ] + }, + { + title: "", + class: "grid grid-cols-2 gap-4", + groups: [ + { + class: "space-y-3", + fields: [ + { key: "Country", label: "Country" }, + { key: "Province", label: "Province" }, + { key: "City", label: "City" }, + ] + }, + { + class: "space-y-3", + fields: [ + { key: "Street_1", label: "Street 1" }, + { key: "Street_2", label: "Street 2" }, + { key: "Street_3", label: "Street 3" }, + { key: "ZIP", label: "ZIP" }, + ] + } + ] + }, + { + class: "grid grid-cols-2 gap-4 items-center", + groups: [ + { + class: "space-y-3", + fields: [ + { key: "EmailAddress1", label: "Email Address 1" }, + { key: "EmailAddress2", label: "Email Address 2" }, + ] + }, + { + class: "space-y-3", + fields: [ + { key: "Phone", label: "Phone" }, + { key: "Fax", label: "Fax" }, + ] + } + ] + }, +]; + +export function accountActions(masterDetail) { + return [ + { + Icon: PlusIcon, + label: 'Add Account', + onClick: () => masterDetail.enterCreate(), + }, + { + Icon: Settings2Icon, + label: 'Search Parameters', + }, + ]; +} + +export function viewActions(handlers){ + return [ + { + Icon: PencilIcon, + label: 'Edit Account', + onClick: handlers.editAccount, + }, + ] +} \ No newline at end of file diff --git a/src/lib/components/dictionary/account/config/account-form-config.js b/src/lib/components/dictionary/account/config/account-form-config.js new file mode 100644 index 0000000..543f5af --- /dev/null +++ b/src/lib/components/dictionary/account/config/account-form-config.js @@ -0,0 +1,198 @@ +import { API } from "$lib/config/api"; +import EraserIcon from "@lucide/svelte/icons/eraser"; +import { z } from "zod"; + +export const accountSchema = z.object({ + Initial: z.string().min(1, "Required"), + AccountName: z.string().min(1, "Required"), +}); + +export const accountInitialForm = { + AccountID: '', + ParentAccount: '', + AccountName: '', + Initial: '', + Country: '', + Province: '', + City: '', + ZIP: '', + Street_1: '', + Street_2: '', + Street_3: '', + EmailAddress1: '', + EmailAddress2: '', + Phone: '', + Fax: '', +}; + +export const accountDefaultErrors = { + Initial: "Required", + AccountName: "Required", +}; + +export const accountFormFields = [ + { + title: "Basic Information", + rows: [ + { + type: "row", + columns: [ + { + key: "ParentAccount", + label: "Parent Account", + required: false, + type: "select", + optionsEndpoint: `${API.BASE_URL}${API.ACCOUNT}`, + valueKey: "AccountID", + labelKey: "AccountName", + fullWidth: false + }, + ] + }, + { + type: "row", + columns: [ + { + key: "Initial", + label: "Initial", + required: true, + type: "text", + validateOn: ["input"] + }, + { + key: "AccountName", + label: "Account Name", + required: true, + type: "text", + validateOn: ["input"] + }, + ] + }, + ] + }, + { + title: "Address Detail", + rows: [ + { + type: "row", + columns: [ + { + key: "Country", + label: "Country", + required: false, + type: "select", + optionsEndpoint: `${API.BASE_URL}${API.VALUESET}/country`, + }, + { + key: "Street1", + label: "Street 1", + required: false, + type: "text", + }, + ] + }, + { + type: "row", + columns: [ + { + key: "Province", + label: "Province", + required: false, + type: "select", + optionsEndpoint: `${API.BASE_URL}${API.PROVINCE}`, + }, + { + key: "Street2", + label: "Street 2", + required: false, + type: "text", + } + ] + }, + { + type: "row", + columns: [ + { + key: "City", + label: "City", + required: false, + type: "select", + optionsEndpoint: `${API.BASE_URL}${API.CITY}`, + dependsOn: "Province", + endpointParamKey: "ProvinceID" + }, + { + key: "Street3", + label: "Street 3", + required: false, + type: "text", + } + ] + }, + { + type: "row", + columns: [ + { + key: "ZIP", + label: "ZIP", + required: false, + type: "text", + validateOn: ["input"], + fullWidth: false + }, + ] + }, + ] + }, + { + title: "Contact Information", + rows: [ + { + type: "row", + columns: [ + { + key: "EmailAddress1", + label: "Email Address 1", + required: false, + type: "text", + validateOn: ["input"] + }, + { + key: "Phone", + label: "Phone", + required: false, + type: "text", + }, + ] + }, + { + type: "row", + columns: [ + { + key: "EmailAddress2", + label: "Email Address 2", + required: false, + type: "text", + validateOn: ["input"] + }, + { + key: "Fax", + label: "Fax", + required: false, + type: "text", + } + ] + }, + ] + }, +]; + +export function getAccountFormActions(handlers) { + return [ + { + Icon: EraserIcon, + label: 'Clear Form', + onClick: handlers.clearForm, + }, + ]; +} \ No newline at end of file diff --git a/src/lib/components/dictionary/account/page/create-page.svelte b/src/lib/components/dictionary/account/page/create-page.svelte new file mode 100644 index 0000000..1ec3666 --- /dev/null +++ b/src/lib/components/dictionary/account/page/create-page.svelte @@ -0,0 +1,54 @@ + + + + + + + \ No newline at end of file diff --git a/src/lib/components/dictionary/account/page/edit-page.svelte b/src/lib/components/dictionary/account/page/edit-page.svelte new file mode 100644 index 0000000..aaff3bf --- /dev/null +++ b/src/lib/components/dictionary/account/page/edit-page.svelte @@ -0,0 +1,85 @@ + + + + + + + \ No newline at end of file diff --git a/src/lib/components/dictionary/account/page/master-page.svelte b/src/lib/components/dictionary/account/page/master-page.svelte new file mode 100644 index 0000000..ad12e27 --- /dev/null +++ b/src/lib/components/dictionary/account/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 "ACCOUNT".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/account/page/view-page.svelte b/src/lib/components/dictionary/account/page/view-page.svelte new file mode 100644 index 0000000..42435df --- /dev/null +++ b/src/lib/components/dictionary/account/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/account/table/account-columns.js b/src/lib/components/dictionary/account/table/account-columns.js new file mode 100644 index 0000000..e50dac4 --- /dev/null +++ b/src/lib/components/dictionary/account/table/account-columns.js @@ -0,0 +1,14 @@ +export const accountColumns = [ + { + accessorKey: "Initial", + header: "Initial", + }, + { + accessorKey: "AccountName", + header: "Account Name", + }, + { + accessorKey: "ParentAccount", + header: "Parent Account", + }, +]; \ No newline at end of file diff --git a/src/lib/components/dictionary/department/api/department-api.js b/src/lib/components/dictionary/department/api/department-api.js new file mode 100644 index 0000000..b9b032f --- /dev/null +++ b/src/lib/components/dictionary/department/api/department-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 getDepartments(searchQuery) { + return await searchWithParams(API.DEPARTMENT, searchQuery) +} + +export async function getDepartment(searchQuery) { + return await getById(API.DEPARTMENT, searchQuery) +} + +export async function createDepartment(newDepartmentForm) { + return await create(API.DEPARTMENT, newDepartmentForm) +} + +export async function editDepartment(editDepartmentForm) { + return await update(API.DEPARTMENT, editDepartmentForm) +} \ No newline at end of file diff --git a/src/lib/components/dictionary/department/config/department-config.js b/src/lib/components/dictionary/department/config/department-config.js new file mode 100644 index 0000000..e2206e3 --- /dev/null +++ b/src/lib/components/dictionary/department/config/department-config.js @@ -0,0 +1,53 @@ +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: "DepartmentCode", + label: "Department Code", + type: "text", + }, + { + key: "DepartmentName", + label: "Department Name", + type: "text", + }, +]; + +export const detailSections = [ + { + class: "grid grid-cols-2 gap-4 items-center", + fields: [ + { key: "SiteID", label: "Site" }, + { key: "DisciplineID", label: "Discipline" }, + { key: "DepartmentCode", label: "Department Code" }, + { key: "DepartmentName", label: "Department Name" }, + ] + }, +]; + +export function departmentActions(masterDetail) { + return [ + { + Icon: PlusIcon, + label: 'Add Department', + onClick: () => masterDetail.enterCreate(), + }, + { + Icon: Settings2Icon, + label: 'Search Parameters', + }, + ]; +} + +export function viewActions(handlers){ + return [ + { + Icon: PencilIcon, + label: 'Edit Department', + onClick: handlers.editDepartment, + }, + ] +} \ No newline at end of file diff --git a/src/lib/components/dictionary/department/config/department-form-config.js b/src/lib/components/dictionary/department/config/department-form-config.js new file mode 100644 index 0000000..67fb7c3 --- /dev/null +++ b/src/lib/components/dictionary/department/config/department-form-config.js @@ -0,0 +1,81 @@ +import { API } from "$lib/config/api"; +import EraserIcon from "@lucide/svelte/icons/eraser"; +import { z } from "zod"; + +export const departmentSchema = z.object({ + DepartmentCode: z.string().min(1, "Required"), + DepartmentName: z.string().min(1, "Required"), +}); + +export const departmentInitialForm = { + DepartmentID: '', + SiteID: '', + DisciplineID: '', + DepartmentCode: '', + DepartmentName: '', +}; + +export const departmentDefaultErrors = { + DepartmentCode: "Required", + DepartmentName: "Required", +}; + +export const departmentFormFields = [ + { + title: "Basic Information", + rows: [ + { + type: "row", + columns: [ + { + key: "SiteID", + label: "Site", + required: false, + type: "select", + optionsEndpoint: `${API.BASE_URL}${API.SITE}`, + valueKey: "SiteID", + labelKey: "SiteName", + }, + { + key: "DisciplineID", + label: "Discipline", + required: false, + type: "select", + optionsEndpoint: `${API.BASE_URL}${API.DISCIPLINE}`, + valueKey: "DisciplineID", + labelKey: "DisciplineName", + }, + ] + }, + { + type: "row", + columns: [ + { + key: "DepartmentCode", + label: "Department Code", + required: true, + type: "text", + validateOn: ["input"] + }, + { + key: "DepartmentName", + label: "Department Name", + required: true, + type: "text", + validateOn: ["input"] + }, + ] + }, + ] + }, +]; + +export function getDepartmentFormActions(handlers) { + return [ + { + Icon: EraserIcon, + label: 'Clear Form', + onClick: handlers.clearForm, + }, + ]; +} \ No newline at end of file diff --git a/src/lib/components/dictionary/department/page/create-page.svelte b/src/lib/components/dictionary/department/page/create-page.svelte new file mode 100644 index 0000000..b05a0f6 --- /dev/null +++ b/src/lib/components/dictionary/department/page/create-page.svelte @@ -0,0 +1,54 @@ + + + + + + + \ No newline at end of file diff --git a/src/lib/components/dictionary/department/page/edit-page.svelte b/src/lib/components/dictionary/department/page/edit-page.svelte new file mode 100644 index 0000000..0411b91 --- /dev/null +++ b/src/lib/components/dictionary/department/page/edit-page.svelte @@ -0,0 +1,73 @@ + + + + + + + \ No newline at end of file diff --git a/src/lib/components/dictionary/department/page/master-page.svelte b/src/lib/components/dictionary/department/page/master-page.svelte new file mode 100644 index 0000000..5fee30b --- /dev/null +++ b/src/lib/components/dictionary/department/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 "DEPARTMENT".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/department/page/view-page.svelte b/src/lib/components/dictionary/department/page/view-page.svelte new file mode 100644 index 0000000..d849226 --- /dev/null +++ b/src/lib/components/dictionary/department/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/department/table/department-columns.js b/src/lib/components/dictionary/department/table/department-columns.js new file mode 100644 index 0000000..4137055 --- /dev/null +++ b/src/lib/components/dictionary/department/table/department-columns.js @@ -0,0 +1,10 @@ +export const departmentColumns = [ + { + accessorKey: "DepartmentCode", + header: "Department Code", + }, + { + accessorKey: "DepartmentName", + header: "Department Name", + }, +]; \ No newline at end of file diff --git a/src/lib/components/dictionary/discipline/api/discipline-api.js b/src/lib/components/dictionary/discipline/api/discipline-api.js new file mode 100644 index 0000000..345c51a --- /dev/null +++ b/src/lib/components/dictionary/discipline/api/discipline-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 getDisciplines(searchQuery) { + return await searchWithParams(API.DISCIPLINE, searchQuery) +} + +export async function getDiscipline(searchQuery) { + return await getById(API.DISCIPLINE, searchQuery) +} + +export async function createDiscipline(newDisciplineForm) { + return await create(API.DISCIPLINE, newDisciplineForm) +} + +export async function editDiscipline(editDisciplineForm) { + return await update(API.DISCIPLINE, editDisciplineForm) +} \ No newline at end of file diff --git a/src/lib/components/dictionary/discipline/config/discipline-config.js b/src/lib/components/dictionary/discipline/config/discipline-config.js new file mode 100644 index 0000000..086ca81 --- /dev/null +++ b/src/lib/components/dictionary/discipline/config/discipline-config.js @@ -0,0 +1,53 @@ +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: "DisciplineCode", + label: "Discipline Code", + type: "text", + }, + { + key: "DisciplineName", + label: "Discipline Name", + type: "text", + }, +]; + +export const detailSections = [ + { + class: "grid grid-cols-2 gap-4 items-center", + fields: [ + { key: "SiteID", label: "Site" }, + { key: "Parent", label: "Parent" }, + { key: "DisciplineCode", label: "Discipline Code" }, + { key: "DisciplineName", label: "Discipline Name" }, + ] + }, +]; + +export function disciplineActions(masterDetail) { + return [ + { + Icon: PlusIcon, + label: 'Add Discipline', + onClick: () => masterDetail.enterCreate(), + }, + { + Icon: Settings2Icon, + label: 'Search Parameters', + }, + ]; +} + +export function viewActions(handlers){ + return [ + { + Icon: PencilIcon, + label: 'Edit Discipline', + onClick: handlers.editDiscipline, + }, + ] +} \ No newline at end of file diff --git a/src/lib/components/dictionary/discipline/config/discipline-form-config.js b/src/lib/components/dictionary/discipline/config/discipline-form-config.js new file mode 100644 index 0000000..92e97d4 --- /dev/null +++ b/src/lib/components/dictionary/discipline/config/discipline-form-config.js @@ -0,0 +1,81 @@ +import { API } from "$lib/config/api"; +import EraserIcon from "@lucide/svelte/icons/eraser"; +import { z } from "zod"; + +export const disciplineSchema = z.object({ + DisciplineCode: z.string().min(1, "Required"), + DisciplineName: z.string().min(1, "Required"), +}); + +export const disciplineInitialForm = { + DisciplineID: '', + SiteID: '', + Parent: '', + DisciplineCode: '', + DisciplineName: '', +}; + +export const disciplineDefaultErrors = { + DisciplineCode: "Required", + DisciplineName: "Required", +}; + +export const disciplineFormFields = [ + { + title: "Basic Information", + rows: [ + { + type: "row", + columns: [ + { + key: "SiteID", + label: "Site", + required: false, + type: "select", + optionsEndpoint: `${API.BASE_URL}${API.SITE}`, + valueKey: "SiteID", + labelKey: "SiteName", + }, + { + key: "Parent", + label: "Parent", + required: false, + type: "select", + optionsEndpoint: `${API.BASE_URL}${API.DISCIPLINE}`, + valueKey: "DisciplineID", + labelKey: "DisciplineName", + }, + ] + }, + { + type: "row", + columns: [ + { + key: "DisciplineCode", + label: "Discipline Code", + required: true, + type: "text", + validateOn: ["input"] + }, + { + key: "DisciplineName", + label: "Discipline Name", + required: true, + type: "text", + validateOn: ["input"] + }, + ] + }, + ] + }, +]; + +export function getDisciplineFormActions(handlers) { + return [ + { + Icon: EraserIcon, + label: 'Clear Form', + onClick: handlers.clearForm, + }, + ]; +} \ No newline at end of file diff --git a/src/lib/components/dictionary/discipline/page/create-page.svelte b/src/lib/components/dictionary/discipline/page/create-page.svelte new file mode 100644 index 0000000..eff86c3 --- /dev/null +++ b/src/lib/components/dictionary/discipline/page/create-page.svelte @@ -0,0 +1,54 @@ + + + + + + + \ No newline at end of file diff --git a/src/lib/components/dictionary/discipline/page/edit-page.svelte b/src/lib/components/dictionary/discipline/page/edit-page.svelte new file mode 100644 index 0000000..e2f0880 --- /dev/null +++ b/src/lib/components/dictionary/discipline/page/edit-page.svelte @@ -0,0 +1,73 @@ + + + + + + + \ No newline at end of file diff --git a/src/lib/components/dictionary/discipline/page/master-page.svelte b/src/lib/components/dictionary/discipline/page/master-page.svelte new file mode 100644 index 0000000..454dc9f --- /dev/null +++ b/src/lib/components/dictionary/discipline/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 "DISCIPLINE".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/discipline/page/view-page.svelte b/src/lib/components/dictionary/discipline/page/view-page.svelte new file mode 100644 index 0000000..fd53235 --- /dev/null +++ b/src/lib/components/dictionary/discipline/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/discipline/table/discipline-columns.js b/src/lib/components/dictionary/discipline/table/discipline-columns.js new file mode 100644 index 0000000..f8bc3f9 --- /dev/null +++ b/src/lib/components/dictionary/discipline/table/discipline-columns.js @@ -0,0 +1,10 @@ +export const disciplineColumns = [ + { + accessorKey: "DisciplineCode", + header: "Discipline Code", + }, + { + accessorKey: "DisciplineName", + header: "Discipline Name", + }, +]; \ No newline at end of file diff --git a/src/lib/components/dictionary/location/page/edit-page.svelte b/src/lib/components/dictionary/location/page/edit-page.svelte index 0620895..ae396ff 100644 --- a/src/lib/components/dictionary/location/page/edit-page.svelte +++ b/src/lib/components/dictionary/location/page/edit-page.svelte @@ -41,7 +41,7 @@ key: "City", optionsEndpoint: `${API.BASE_URL}${API.CITY}`, dependsOn: "Province", - endpointParamKey: "Parent" + endpointParamKey: "ProvinceID" }, formState.form ); diff --git a/src/lib/components/dictionary/site/api/site-api.js b/src/lib/components/dictionary/site/api/site-api.js new file mode 100644 index 0000000..cb61a4c --- /dev/null +++ b/src/lib/components/dictionary/site/api/site-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 getSites(searchQuery) { + return await searchWithParams(API.SITE, searchQuery) +} + +export async function getSite(searchQuery) { + return await getById(API.SITE, searchQuery) +} + +export async function createSite(newSiteForm) { + return await create(API.SITE, newSiteForm) +} + +export async function editSite(editSiteForm) { + return await update(API.SITE, editSiteForm) +} \ No newline at end of file diff --git a/src/lib/components/dictionary/site/config/site-config.js b/src/lib/components/dictionary/site/config/site-config.js new file mode 100644 index 0000000..3ea77ab --- /dev/null +++ b/src/lib/components/dictionary/site/config/site-config.js @@ -0,0 +1,71 @@ +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: "SiteCode", + label: "Site Code", + type: "text", + }, + { + key: "SiteName", + label: "Site Name", + type: "text", + }, +]; + +export const detailSections = [ + { + class: "grid grid-cols-2 gap-4 items-center", + fields: [ + { key: "AccountID", label: "Account" }, + { key: "Parent", label: "Parent Account" }, + { key: "SiteCode", label: "Site Code" }, + { key: "SiteName", label: "Site Name" }, + ] + }, + { + title: "", + class: "grid grid-cols-2 gap-4", + groups: [ + { + class: "space-y-3", + fields: [ + { key: "SiteType", label: "Site Type" }, + ] + }, + { + class: "space-y-3", + fields: [ + { key: "SiteClass", label: "Site Class" }, + ] + } + ] + }, +]; + +export function siteActions(masterDetail) { + return [ + { + Icon: PlusIcon, + label: 'Add Site', + onClick: () => masterDetail.enterCreate(), + }, + { + Icon: Settings2Icon, + label: 'Search Parameters', + }, + ]; +} + +export function viewActions(handlers){ + return [ + { + Icon: PencilIcon, + label: 'Edit Site', + onClick: handlers.editSite, + }, + ] +} \ No newline at end of file diff --git a/src/lib/components/dictionary/site/config/site-form-config.js b/src/lib/components/dictionary/site/config/site-form-config.js new file mode 100644 index 0000000..d9cd897 --- /dev/null +++ b/src/lib/components/dictionary/site/config/site-form-config.js @@ -0,0 +1,107 @@ +import { API } from "$lib/config/api"; +import EraserIcon from "@lucide/svelte/icons/eraser"; +import { z } from "zod"; + +export const siteSchema = z.object({ + SiteCode: z.string().min(1, "Required"), + SiteName: z.string().min(1, "Required"), +}); + +export const siteInitialForm = { + SiteID: '', + AccountID: '', + Parent: '', + SiteCode: '', + SiteName: '', + SiteType: '', + SiteClass: '', +}; + +export const siteDefaultErrors = { + SiteCode: "Required", + SiteName: "Required", +}; + +export const siteFormFields = [ + { + title: "Basic Information", + rows: [ + { + type: "row", + columns: [ + { + key: "AccountID", + label: "Account", + required: false, + type: "select", + optionsEndpoint: `${API.BASE_URL}${API.ACCOUNT}`, + valueKey: "AccountID", + labelKey: "AccountName", + }, + { + key: "Parent", + label: "Parent", + required: false, + type: "select", + optionsEndpoint: `${API.BASE_URL}${API.ACCOUNT}`, + valueKey: "AccountID", + labelKey: "AccountName", + }, + ] + }, + { + type: "row", + columns: [ + { + key: "SiteCode", + label: "Site Code", + required: true, + type: "text", + validateOn: ["input"] + }, + { + key: "SiteName", + label: "Site Name", + required: true, + type: "text", + validateOn: ["input"] + }, + ] + }, + ] + }, + { + title: "Site Classification", + rows: [ + { + type: "row", + columns: [ + { + key: "SiteType", + label: "Site Type", + required: false, + type: "select", + optionsEndpoint: `${API.BASE_URL}${API.VALUESET}/site_type`, + }, + { + key: "SiteClass", + label: "Site Class", + required: false, + type: "select", + optionsEndpoint: `${API.BASE_URL}${API.VALUESET}/site_class`, + }, + ] + }, + ] + }, +]; + +export function getSiteFormActions(handlers) { + return [ + { + Icon: EraserIcon, + label: 'Clear Form', + onClick: handlers.clearForm, + }, + ]; +} \ No newline at end of file diff --git a/src/lib/components/dictionary/site/page/create-page.svelte b/src/lib/components/dictionary/site/page/create-page.svelte new file mode 100644 index 0000000..40bcf16 --- /dev/null +++ b/src/lib/components/dictionary/site/page/create-page.svelte @@ -0,0 +1,54 @@ + + + + + + + \ No newline at end of file diff --git a/src/lib/components/dictionary/site/page/edit-page.svelte b/src/lib/components/dictionary/site/page/edit-page.svelte new file mode 100644 index 0000000..f837a63 --- /dev/null +++ b/src/lib/components/dictionary/site/page/edit-page.svelte @@ -0,0 +1,73 @@ + + + + + + + \ No newline at end of file diff --git a/src/lib/components/dictionary/site/page/master-page.svelte b/src/lib/components/dictionary/site/page/master-page.svelte new file mode 100644 index 0000000..981915a --- /dev/null +++ b/src/lib/components/dictionary/site/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 "SITE".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/site/page/view-page.svelte b/src/lib/components/dictionary/site/page/view-page.svelte new file mode 100644 index 0000000..d7dbe7e --- /dev/null +++ b/src/lib/components/dictionary/site/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/site/table/site-columns.js b/src/lib/components/dictionary/site/table/site-columns.js new file mode 100644 index 0000000..c332dad --- /dev/null +++ b/src/lib/components/dictionary/site/table/site-columns.js @@ -0,0 +1,10 @@ +export const siteColumns = [ + { + accessorKey: "SiteCode", + header: "Site Code", + }, + { + accessorKey: "SiteName", + header: "Site Name", + }, +]; \ No newline at end of file diff --git a/src/lib/components/dictionary/workstation/api/workstation-api.js b/src/lib/components/dictionary/workstation/api/workstation-api.js new file mode 100644 index 0000000..792b793 --- /dev/null +++ b/src/lib/components/dictionary/workstation/api/workstation-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 getWorkstations(searchQuery) { + return await searchWithParams(API.WORKSTATION, searchQuery) +} + +export async function getWorkstation(searchQuery) { + return await getById(API.WORKSTATION, searchQuery) +} + +export async function createWorkstation(newWorkstationForm) { + return await create(API.WORKSTATION, newWorkstationForm) +} + +export async function editWorkstation(editWorkstationForm) { + return await update(API.WORKSTATION, editWorkstationForm) +} \ No newline at end of file diff --git a/src/lib/components/dictionary/workstation/config/workstation-config.js b/src/lib/components/dictionary/workstation/config/workstation-config.js new file mode 100644 index 0000000..6140bb2 --- /dev/null +++ b/src/lib/components/dictionary/workstation/config/workstation-config.js @@ -0,0 +1,53 @@ +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: "WorkstationCode", + label: "Workstation Code", + type: "text", + }, + { + key: "WorkstationName", + label: "Workstation Name", + type: "text", + }, +]; + +export const detailSections = [ + { + class: "grid grid-cols-2 gap-4 items-center", + fields: [ + { key: "DepartmentID", label: "Department" }, + { key: "Type", label: "Type" }, + { key: "WorkstationCode", label: "Workstation Code" }, + { key: "WorkstationName", label: "Workstation Name" }, + ] + }, +]; + +export function workstationActions(masterDetail) { + return [ + { + Icon: PlusIcon, + label: 'Add Workstation', + onClick: () => masterDetail.enterCreate(), + }, + { + Icon: Settings2Icon, + label: 'Search Parameters', + }, + ]; +} + +export function viewActions(handlers){ + return [ + { + Icon: PencilIcon, + label: 'Edit Workstation', + onClick: handlers.editWorkstation, + }, + ] +} \ No newline at end of file diff --git a/src/lib/components/dictionary/workstation/config/workstation-form-config.js b/src/lib/components/dictionary/workstation/config/workstation-form-config.js new file mode 100644 index 0000000..680df9e --- /dev/null +++ b/src/lib/components/dictionary/workstation/config/workstation-form-config.js @@ -0,0 +1,107 @@ +import { API } from "$lib/config/api"; +import EraserIcon from "@lucide/svelte/icons/eraser"; +import { z } from "zod"; + +export const workstationSchema = z.object({ + WorkstationCode: z.string().min(1, "Required"), + WorkstationName: z.string().min(1, "Required"), +}); + +export const workstationInitialForm = { + WorkstationID: '', + DepartmentID: '', + WorkstationCode: '', + WorkstationName: '', + Type: '', + LinkTo: '', + Enable: '', +}; + +export const workstationDefaultErrors = { + WorkstationCode: "Required", + WorkstationName: "Required", +}; + +export const workstationFormFields = [ + { + title: "Basic Information", + rows: [ + { + type: "row", + columns: [ + { + key: "DepartmentID", + label: "Department", + required: false, + type: "select", + optionsEndpoint: `${API.BASE_URL}${API.DEPARTMENT}`, + valueKey: "DepartmentID", + labelKey: "DepartmentName", + }, + { + key: "Type", + label: "Type", + required: false, + type: "select", + optionsEndpoint: `${API.BASE_URL}${API.VALUESET}/ws_type`, + }, + ] + }, + { + type: "row", + columns: [ + { + key: "WorkstationCode", + label: "Workstation Code", + required: true, + type: "text", + validateOn: ["input"] + }, + { + key: "WorkstationName", + label: "Workstation Name", + required: true, + type: "text", + validateOn: ["input"] + }, + ] + }, + ] + }, + { + title: "Workstation Configuration", + rows: [ + { + type: "row", + columns: [ + { + key: "LinkTo", + label: "LinkTo", + required: false, + type: "select", + optionsEndpoint: `${API.BASE_URL}${API.WORKSTATION}`, + valueKey: "WorkstationID", + labelKey: "WorkstationName", + }, + { + key: "Enable", + label: "Enable", + required: false, + type: "select", + optionsEndpoint: `${API.BASE_URL}${API.VALUESET}/enable_disable`, + }, + ] + }, + ] + } +]; + +export function getWorkstationFormActions(handlers) { + return [ + { + Icon: EraserIcon, + label: 'Clear Form', + onClick: handlers.clearForm, + }, + ]; +} \ No newline at end of file diff --git a/src/lib/components/dictionary/workstation/page/create-page.svelte b/src/lib/components/dictionary/workstation/page/create-page.svelte new file mode 100644 index 0000000..a8d509a --- /dev/null +++ b/src/lib/components/dictionary/workstation/page/create-page.svelte @@ -0,0 +1,54 @@ + + + + + + + \ No newline at end of file diff --git a/src/lib/components/dictionary/workstation/page/edit-page.svelte b/src/lib/components/dictionary/workstation/page/edit-page.svelte new file mode 100644 index 0000000..7a13800 --- /dev/null +++ b/src/lib/components/dictionary/workstation/page/edit-page.svelte @@ -0,0 +1,73 @@ + + + + + + + \ No newline at end of file diff --git a/src/lib/components/dictionary/workstation/page/master-page.svelte b/src/lib/components/dictionary/workstation/page/master-page.svelte new file mode 100644 index 0000000..29e0683 --- /dev/null +++ b/src/lib/components/dictionary/workstation/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 "WORKSTATION".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/workstation/page/view-page.svelte b/src/lib/components/dictionary/workstation/page/view-page.svelte new file mode 100644 index 0000000..9399af3 --- /dev/null +++ b/src/lib/components/dictionary/workstation/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/workstation/table/workstation-columns.js b/src/lib/components/dictionary/workstation/table/workstation-columns.js new file mode 100644 index 0000000..b155ef1 --- /dev/null +++ b/src/lib/components/dictionary/workstation/table/workstation-columns.js @@ -0,0 +1,10 @@ +export const workstationColumns = [ + { + accessorKey: "WorkstationCode", + header: "Workstation Code", + }, + { + accessorKey: "WorkstationName", + header: "Workstation Name", + }, +]; \ No newline at end of file diff --git a/src/routes/+layout.server.js b/src/routes/+layout.server.js index b4e50cc..b608f3f 100644 --- a/src/routes/+layout.server.js +++ b/src/routes/+layout.server.js @@ -9,6 +9,30 @@ export async function load({ url }) { '/patient/admission': { title: 'Patient Admission', }, + '/dictionary/location': { + title: 'Location' + }, + '/dictionary/occupation': { + title: 'Occupation' + }, + '/dictionary/container': { + title: 'Container' + }, + '/dictionary/account': { + title: 'Account' + }, + '/dictionary/site': { + title: 'Site' + }, + '/dictionary/discipline': { + title: 'Discipline' + }, + '/dictionary/department': { + title: 'Department' + }, + '/dictionary/workstation': { + title: 'Workstation' + }, }; const config = routeConfig[url.pathname] || { diff --git a/src/routes/dictionary/account/+page.svelte b/src/routes/dictionary/account/+page.svelte index bd21290..3dc4aac 100644 --- a/src/routes/dictionary/account/+page.svelte +++ b/src/routes/dictionary/account/+page.svelte @@ -1 +1,51 @@ -acc \ No newline at end of file + + +
+ {#if masterDetail.showMaster} + + {/if} + + {#if masterDetail.showDetail} +
+ {#if masterDetail.mode === "view"} + + {:else if masterDetail.mode === "create"} + + {:else if masterDetail.mode === "edit"} + + {/if} +
+ {/if} +
\ No newline at end of file diff --git a/src/routes/dictionary/department/+page.svelte b/src/routes/dictionary/department/+page.svelte new file mode 100644 index 0000000..757921d --- /dev/null +++ b/src/routes/dictionary/department/+page.svelte @@ -0,0 +1,51 @@ + + +
+ {#if masterDetail.showMaster} + + {/if} + + {#if masterDetail.showDetail} +
+ {#if masterDetail.mode === "view"} + + {:else if masterDetail.mode === "create"} + + {:else if masterDetail.mode === "edit"} + + {/if} +
+ {/if} +
\ No newline at end of file diff --git a/src/routes/dictionary/discipline/+page.svelte b/src/routes/dictionary/discipline/+page.svelte new file mode 100644 index 0000000..5f75961 --- /dev/null +++ b/src/routes/dictionary/discipline/+page.svelte @@ -0,0 +1,51 @@ + + +
+ {#if masterDetail.showMaster} + + {/if} + + {#if masterDetail.showDetail} +
+ {#if masterDetail.mode === "view"} + + {:else if masterDetail.mode === "create"} + + {:else if masterDetail.mode === "edit"} + + {/if} +
+ {/if} +
\ No newline at end of file diff --git a/src/routes/dictionary/site/+page.svelte b/src/routes/dictionary/site/+page.svelte new file mode 100644 index 0000000..db032a9 --- /dev/null +++ b/src/routes/dictionary/site/+page.svelte @@ -0,0 +1,51 @@ + + +
+ {#if masterDetail.showMaster} + + {/if} + + {#if masterDetail.showDetail} +
+ {#if masterDetail.mode === "view"} + + {:else if masterDetail.mode === "create"} + + {:else if masterDetail.mode === "edit"} + + {/if} +
+ {/if} +
\ No newline at end of file diff --git a/src/routes/dictionary/workstation/+page.svelte b/src/routes/dictionary/workstation/+page.svelte new file mode 100644 index 0000000..a9b05bc --- /dev/null +++ b/src/routes/dictionary/workstation/+page.svelte @@ -0,0 +1,51 @@ + + +
+ {#if masterDetail.showMaster} + + {/if} + + {#if masterDetail.showDetail} +
+ {#if masterDetail.mode === "view"} + + {:else if masterDetail.mode === "create"} + + {:else if masterDetail.mode === "edit"} + + {/if} +
+ {/if} +
\ No newline at end of file