diff --git a/src/lib/components/app-sidebar.svelte b/src/lib/components/app-sidebar.svelte index c08ce6b..85caeaa 100644 --- a/src/lib/components/app-sidebar.svelte +++ b/src/lib/components/app-sidebar.svelte @@ -72,45 +72,45 @@ }, { title: "Sample", - url: "#", + url: "/dictionary", icon: BookOpenIcon, submenus: [ { title: "Container", - url: "#", + url: "/container", }, ], }, { title: "Organization", - url: "#", + url: "/dictionary", icon: BookOpenIcon, submenus: [ { title: "Account", - url: "#", + url: "/account", }, { title: "Site", - url: "#", + url: "/site", }, { title: "Discipline", - url: "#", + url: "/discipline", }, { title: "Department", - url: "#", + url: "/department", }, { title: "Workstation", - url: "#", + url: "/workstation", }, ], }, { title: "Test", - url: "/testdef", + url: "/dictionary/test", icon: BookOpenIcon, }, ] diff --git a/src/lib/components/dictionary/container/api/container-api.js b/src/lib/components/dictionary/container/api/container-api.js new file mode 100644 index 0000000..3bddca3 --- /dev/null +++ b/src/lib/components/dictionary/container/api/container-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 getContainers(searchQuery) { + return await searchWithParams(API.CONTAINER, searchQuery) +} + +export async function getContainer(searchQuery) { + return await getById(API.CONTAINER, searchQuery) +} + +export async function createContainer(newContainerForm) { + return await create(API.CONTAINER, newContainerForm) +} + +export async function editContainer(editContainerForm) { + return await update(API.CONTAINER, editContainerForm) +} \ No newline at end of file diff --git a/src/lib/components/dictionary/container/config/container-config.js b/src/lib/components/dictionary/container/config/container-config.js new file mode 100644 index 0000000..4a7854c --- /dev/null +++ b/src/lib/components/dictionary/container/config/container-config.js @@ -0,0 +1,60 @@ +import PlusIcon from "@lucide/svelte/icons/plus"; +import Settings2Icon from "@lucide/svelte/icons/settings-2"; +import PencilIcon from "@lucide/svelte/icons/pencil"; + +export const searchFields = [ + { + key: "ConCode", + label: "Container Code", + type: "text", + }, + { + key: "ConName", + label: "Container Name", + type: "text", + }, +]; + +export const detailSections = [ + { + class: "grid grid-cols-2 gap-4 items-center", + fields: [ + { key: "SiteID", label: "Site" }, + { key: "ConCode", label: "Container Code" }, + { key: "ConName", label: "Container Name" }, + { key: "ConDesc", label: "Description" }, + ] + }, + { + class: "grid grid-cols-2 gap-4 items-center", + fields: [ + { key: "ConClass", label: "Container Class" }, + { key: "Color", label: "Color" }, + { key: "Additive", label: "Additive" }, + ] + }, +]; + +export function containerActions(masterDetail) { + return [ + { + Icon: PlusIcon, + label: 'Add Location', + onClick: () => masterDetail.enterCreate(), + }, + { + Icon: Settings2Icon, + label: 'Search Parameters', + }, + ]; +} + +export function viewActions(handlers){ + return [ + { + Icon: PencilIcon, + label: 'Edit Container', + onClick: handlers.editContainer, + }, + ] +} \ No newline at end of file diff --git a/src/lib/components/dictionary/container/config/container-form-config.js b/src/lib/components/dictionary/container/config/container-form-config.js new file mode 100644 index 0000000..a5a20f4 --- /dev/null +++ b/src/lib/components/dictionary/container/config/container-form-config.js @@ -0,0 +1,117 @@ +import { API } from "$lib/config/api"; +import EraserIcon from "@lucide/svelte/icons/eraser"; +import { z } from "zod"; + +export const containerSchema = z.object({ + ConCode: z.string().min(1, "Required"), + ConName: z.string().min(1, "Required"), +}); + +export const containerInitialForm = { + ConDefID: '', + SiteID: '', + ConCode: '', + ConName: '', + ConDesc: '', + Additive: '', + ConClass: '', + Color: '', +}; + +export const containerDefaultErrors = { + ConCode: "Required", + ConName: "Required", +}; + +export const containerFormFields = [ + { + title: "Basic Information", + rows: [ + { + type: "row", + columns: [ + { + key: "SiteID", + label: "Site", + required: false, + type: "select", + optionsEndpoint: `${API.BASE_URL}${API.SITE}`, + valueKey: "SiteID", + labelKey: (item) => `${item.SiteCode} - ${item.SiteName}`, + }, + { + key: "ConCode", + label: "Container Code", + required: true, + type: "text", + validateOn: ["input"] + }, + ] + }, + { + type: "row", + columns: [ + { + key: "ConName", + label: "Container Name", + required: true, + type: "text", + validateOn: ["input"] + }, + { + key: "ConDesc", + label: "Description", + required: false, + type: "textarea", + }, + ] + } + ] + }, + { + title: "Container Properties", + rows: [ + { + type: "row", + columns: [ + { + key: "ConClass", + label: "Container Class", + required: false, + type: "select", + optionsEndpoint: `${API.BASE_URL}${API.VALUESET}/container_class`, + }, + { + key: "Color", + label: "Color", + required: false, + type: "select", + optionsEndpoint: `${API.BASE_URL}${API.VALUESET}/container_cap_color`, + }, + ] + }, + { + type: "row", + columns: [ + { + key: "Additive", + label: "Additive", + required: false, + type: "select", + optionsEndpoint: `${API.BASE_URL}${API.VALUESET}/additive`, + }, + ] + } + ] + }, +]; + +export function getContainerFormActions(handlers) { + return [ + { + Icon: EraserIcon, + label: 'Clear Form', + onClick: handlers.clearForm, + }, + ]; +} \ No newline at end of file diff --git a/src/lib/components/dictionary/container/page/create-page.svelte b/src/lib/components/dictionary/container/page/create-page.svelte new file mode 100644 index 0000000..b86351d --- /dev/null +++ b/src/lib/components/dictionary/container/page/create-page.svelte @@ -0,0 +1,54 @@ + + + + + + + \ No newline at end of file diff --git a/src/lib/components/dictionary/container/page/edit-page.svelte b/src/lib/components/dictionary/container/page/edit-page.svelte new file mode 100644 index 0000000..f4629db --- /dev/null +++ b/src/lib/components/dictionary/container/page/edit-page.svelte @@ -0,0 +1,73 @@ + + + + + + + \ No newline at end of file diff --git a/src/lib/components/dictionary/container/page/master-page.svelte b/src/lib/components/dictionary/container/page/master-page.svelte new file mode 100644 index 0000000..013b893 --- /dev/null +++ b/src/lib/components/dictionary/container/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 "CONTAINER".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/container/page/view-page.svelte b/src/lib/components/dictionary/container/page/view-page.svelte new file mode 100644 index 0000000..7b9985b --- /dev/null +++ b/src/lib/components/dictionary/container/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/container/table/container-columns.js b/src/lib/components/dictionary/container/table/container-columns.js new file mode 100644 index 0000000..60a51db --- /dev/null +++ b/src/lib/components/dictionary/container/table/container-columns.js @@ -0,0 +1,10 @@ +export const containerColumns = [ + { + accessorKey: "ConCode", + header: "Container Code", + }, + { + accessorKey: "ConName", + header: "Container Name", + }, +]; \ No newline at end of file diff --git a/src/lib/components/nav-dictionary.svelte b/src/lib/components/nav-dictionary.svelte index b2149c8..79740ec 100644 --- a/src/lib/components/nav-dictionary.svelte +++ b/src/lib/components/nav-dictionary.svelte @@ -66,7 +66,7 @@ {/snippet} {:else} - openPopovers[item.url] = open}> + openPopovers[index] = open}> {#snippet trigger(props)} @@ -90,7 +90,7 @@ {#each item.submenus || [] as submenu} openPopovers[item.url] = false} + onclick={() => openPopovers[index] = false} class="flex items-center rounded-md px-2 py-1.5 text-sm hover:bg-accent" class:bg-accent={$page.url.pathname === submenu.url} > @@ -99,7 +99,7 @@ {/each} {:else} openPopovers[item.url] = false} + onclick={() => openPopovers[index] = false} class="flex items-center rounded-md px-2 py-1.5 text-sm font-semibold hover:bg-accent" class:bg-accent={$page.url.pathname === item.url} > diff --git a/src/lib/components/nav-main.svelte b/src/lib/components/nav-main.svelte index 582843b..b39e492 100644 --- a/src/lib/components/nav-main.svelte +++ b/src/lib/components/nav-main.svelte @@ -66,7 +66,7 @@ {/snippet} {:else} - openPopovers[item.url] = open}> + openPopovers[index] = open}> {#snippet trigger(props)} @@ -90,7 +90,7 @@ {#each item.submenus || [] as submenu} openPopovers[item.url] = false} + onclick={() => openPopovers[index] = false} class="flex items-center rounded-md px-2 py-1.5 text-sm hover:bg-accent" class:bg-accent={$page.url.pathname === submenu.url} > @@ -99,7 +99,7 @@ {/each} {:else} openPopovers[item.url] = false} + onclick={() => openPopovers[index] = false} class="flex items-center rounded-md px-2 py-1.5 text-sm font-semibold hover:bg-accent" class:bg-accent={$page.url.pathname === item.url} > diff --git a/src/routes/dictionary/container/+page.svelte b/src/routes/dictionary/container/+page.svelte new file mode 100644 index 0000000..2edb635 --- /dev/null +++ b/src/routes/dictionary/container/+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