diff --git a/src/lib/components/composable/useMasterDetail.svelte.js b/src/lib/components/composable/use-master-detail.svelte.js similarity index 94% rename from src/lib/components/composable/useMasterDetail.svelte.js rename to src/lib/components/composable/use-master-detail.svelte.js index a82613f..c697f30 100644 --- a/src/lib/components/composable/useMasterDetail.svelte.js +++ b/src/lib/components/composable/use-master-detail.svelte.js @@ -1,4 +1,4 @@ -import { useResponsive } from "./useResponsive.svelte.js"; +import { useResponsive } from "./use-responsive.svelte.js"; export function useMasterDetail(options = {}) { const { confirmMessage = "You have unsaved changes. Discard them?", onSelect = null, } = options; @@ -7,13 +7,11 @@ export function useMasterDetail(options = {}) { let mode = $state("view"); let isLoadingDetail = $state(false); - // Form state let form = $state({}); let formSnapshot = $state({}); const { isMobile } = useResponsive(); - // Derived states const isFormMode = $derived(mode === "create" || mode === "edit"); const showMaster = $derived(!isMobile || (mode === "view" && !selectedItem)); @@ -29,7 +27,6 @@ export function useMasterDetail(options = {}) { JSON.stringify(form) !== JSON.stringify(formSnapshot) ); - // Actions async function select(item) { mode = "view"; @@ -60,7 +57,6 @@ export function useMasterDetail(options = {}) { if (!selectedItem) return; mode = "edit"; - // Auto exclude 'id' or use custom mapping const formData = mapToForm ? mapToForm(selectedItem) : (() => { diff --git a/src/lib/components/composable/useResponsive.svelte.js b/src/lib/components/composable/use-responsive.svelte.js similarity index 100% rename from src/lib/components/composable/useResponsive.svelte.js rename to src/lib/components/composable/use-responsive.svelte.js diff --git a/src/lib/components/composable/useSearch.svelte.js b/src/lib/components/composable/use-search.svelte.js similarity index 100% rename from src/lib/components/composable/useSearch.svelte.js rename to src/lib/components/composable/use-search.svelte.js diff --git a/src/lib/components/patient/modal/custodian-modal.svelte b/src/lib/components/patient/modal/custodian-modal.svelte index 2801fb1..247ba7f 100644 --- a/src/lib/components/patient/modal/custodian-modal.svelte +++ b/src/lib/components/patient/modal/custodian-modal.svelte @@ -11,7 +11,7 @@ import { searchParam } from "$lib/components/patient/api/patient-api"; import { Spinner } from "$lib/components/ui/spinner/index.js"; import { searchFields } from "../config/patient-config"; - import { useSearch } from "$lib/components/composable/useSearch.svelte"; + import { useSearch } from "$lib/components/composable/use-search.svelte"; import ReusableEmpty from "$lib/components/reusable/reusable-empty.svelte"; let props = $props(); @@ -38,10 +38,8 @@ } function confirmCustodian() { - // Update form state dengan selected patient props.formState.form.Custodian = { ...selectedPatient }; - // Reset and close selectedPatient = { InternalPID: null, PatientID: null }; isOpen = false; } diff --git a/src/lib/components/patient/modal/linkto-modal.svelte b/src/lib/components/patient/modal/linkto-modal.svelte index 9703cf4..07d4443 100644 --- a/src/lib/components/patient/modal/linkto-modal.svelte +++ b/src/lib/components/patient/modal/linkto-modal.svelte @@ -11,7 +11,7 @@ import ReusableCalendar from "$lib/components/reusable/reusable-calendar.svelte"; import { Spinner } from "$lib/components/ui/spinner/index.js"; import { searchFields } from "../config/patient-config"; - import { useSearch } from "$lib/components/composable/useSearch.svelte"; + import { useSearch } from "$lib/components/composable/use-search.svelte"; import ReusableEmpty from "$lib/components/reusable/reusable-empty.svelte"; import { Checkbox } from "$lib/components/ui/checkbox/index.js"; @@ -26,33 +26,12 @@ isOpen = open; if (open) { - // Populate existing linked patients when opening if (Array.isArray(props.formState.form.LinkTo)) { selectedPatients = [...props.formState.form.LinkTo]; } else { selectedPatients = []; } } - - // if (open) { - // // Populate existing linked patients when opening - // if (props.formState.form.LinkTo) { - // // Assuming LinkTo is comma-separated InternalPIDs or array - // const linkTo = props.formState.form.LinkTo; - // if (typeof linkTo === 'string') { - // // Parse comma-separated string to array - // selectedPatients = linkTo.split(',') - // .filter(Boolean) - // .map(id => ({ InternalPID: id.trim() })); - // } else if (Array.isArray(linkTo)) { - // selectedPatients = [...linkTo]; - // } else { - // selectedPatients = []; - // } - // } else { - // selectedPatients = []; - // } - // } } function togglePatientSelection(patient) { diff --git a/src/lib/components/patient/page/create-page.svelte b/src/lib/components/patient/page/create-page.svelte index cc42426..cab3bab 100644 --- a/src/lib/components/patient/page/create-page.svelte +++ b/src/lib/components/patient/page/create-page.svelte @@ -1,5 +1,4 @@ diff --git a/src/lib/components/patient/page/edit-page copy.svelte b/src/lib/components/patient/page/edit-page copy.svelte new file mode 100644 index 0000000..1cb592d --- /dev/null +++ b/src/lib/components/patient/page/edit-page copy.svelte @@ -0,0 +1,523 @@ + + +{#snippet Fieldset({ key, label, required, type, optionsEndpoint, options, validateOn, dependsOn, endpointParamKey })} +
+
+ + {#if required} + * + {/if} +
+ +
+ {#if type === "input" || type === "email" || type === "number"} + { + if (validateOn?.includes("input")) { + formState.validateField(key); + } + }} + onblur={() => { + if (validateOn?.includes("blur")) { + validateFieldAsync(key); + } + }} + /> + {:else if type === "date"} + { + formState.form[key] = dateStr; + if (validateOn?.includes("input")) { + formState.validateField(key, dateStr, false); + } + }} + /> + {:else if type === "datetime"} + + + {:else if type === "textarea"} + + {:else if type === "select"} + {@const selectedLabel = formState.selectOptions[key]?.find(opt => opt.value === formState.form[key])?.label || "Choose"} + {@const filteredOptions = getFilteredOptions(key)} + { + formState.form[key] = val; + if (validateOn?.includes("input")) { + formState.validateField(key, formState.form[key], false); + } + if (key === "Province") { + formState.form.City = ""; + formState.selectOptions.City = []; + formState.lastFetched.City = null; + } + }} + onOpenChange={(open) => { + if (open && optionsEndpoint) { + formState.fetchOptions({ key, optionsEndpoint, dependsOn, endpointParamKey}, formState.form ); + } + }} + > + + {selectedLabel} + + +
+ +
+ {#if formState.loadingOptions[key]} + Loading... + {:else} + {#if !required} + - None - + {/if} + {#each filteredOptions as option} + + {option.label} + + {/each} + {/if} +
+
+ {:else if type === "identity"} + {@const selectedLabel = formState.selectOptions[key]?.find(opt => opt.value === formState.form.PatIdt.IdentifierType)?.label || "Choose"} +
+ { + if (open && optionsEndpoint) { + formState.fetchOptions({ key, optionsEndpoint}); + } + }} + onValueChange={(val) => { + formState.form.PatIdt = { + IdentifierType: val, + Identifier:'' + }; + }} + > + + {selectedLabel} + + + {#if formState.loadingOptions[key]} + Loading... + {:else} + {#if !required} + - None - + {/if} + {#each formState.selectOptions[key] ?? [] as option} + + {option.label} + + {/each} + {/if} + + + +
+ {:else if type === "custodian"} +
+ + +
+ {:else if type === "linkto"} +
+ + +
+ {:else if type === "fileupload"} +
+ + {#if Object.keys(uploadErrors).length > 0} +
+ {#each Object.entries(uploadErrors) as [file, msg]} + {msg} + {/each} +
+ {/if} +
+ {:else} + + {/if} + +
+ + {#if isChecking[key]} +
+ + Checking... +
+ {:else if formState.errors[key]} + + {formState.errors[key]} + + {/if} +
+
+
+{/snippet} + + +
+ {#each patientFormFields as group} +
+ {#if group.title} +
+ {group.title} +
+ {/if} + + {#each group.rows as row} +
+ {#each row.columns as col} + {#if col.type === "group"} +
+ {#each col.columns as child} + {@render Fieldset(child)} + {/each} +
+ {:else} + {@render Fieldset(col)} + {/if} + {/each} +
+ {/each} +
+ {/each} +
+
+ + \ No newline at end of file diff --git a/src/lib/components/patient/page/edit-page.svelte b/src/lib/components/patient/page/edit-page.svelte index 1cb592d..56089e7 100644 --- a/src/lib/components/patient/page/edit-page.svelte +++ b/src/lib/components/patient/page/edit-page.svelte @@ -1,35 +1,16 @@ -{#snippet Fieldset({ key, label, required, type, optionsEndpoint, options, validateOn, dependsOn, endpointParamKey })} -
-
- - {#if required} - * - {/if} -
- -
- {#if type === "input" || type === "email" || type === "number"} - { - if (validateOn?.includes("input")) { - formState.validateField(key); - } - }} - onblur={() => { - if (validateOn?.includes("blur")) { - validateFieldAsync(key); - } - }} - /> - {:else if type === "date"} - { - formState.form[key] = dateStr; - if (validateOn?.includes("input")) { - formState.validateField(key, dateStr, false); - } - }} - /> - {:else if type === "datetime"} - - - {:else if type === "textarea"} - - {:else if type === "select"} - {@const selectedLabel = formState.selectOptions[key]?.find(opt => opt.value === formState.form[key])?.label || "Choose"} - {@const filteredOptions = getFilteredOptions(key)} - { - formState.form[key] = val; - if (validateOn?.includes("input")) { - formState.validateField(key, formState.form[key], false); - } - if (key === "Province") { - formState.form.City = ""; - formState.selectOptions.City = []; - formState.lastFetched.City = null; - } - }} - onOpenChange={(open) => { - if (open && optionsEndpoint) { - formState.fetchOptions({ key, optionsEndpoint, dependsOn, endpointParamKey}, formState.form ); - } - }} - > - - {selectedLabel} - - -
- -
- {#if formState.loadingOptions[key]} - Loading... - {:else} - {#if !required} - - None - - {/if} - {#each filteredOptions as option} - - {option.label} - - {/each} - {/if} -
-
- {:else if type === "identity"} - {@const selectedLabel = formState.selectOptions[key]?.find(opt => opt.value === formState.form.PatIdt.IdentifierType)?.label || "Choose"} -
- { - if (open && optionsEndpoint) { - formState.fetchOptions({ key, optionsEndpoint}); - } - }} - onValueChange={(val) => { - formState.form.PatIdt = { - IdentifierType: val, - Identifier:'' - }; - }} - > - - {selectedLabel} - - - {#if formState.loadingOptions[key]} - Loading... - {:else} - {#if !required} - - None - - {/if} - {#each formState.selectOptions[key] ?? [] as option} - - {option.label} - - {/each} - {/if} - - - -
- {:else if type === "custodian"} -
- - -
- {:else if type === "linkto"} -
- - -
- {:else if type === "fileupload"} -
- - {#if Object.keys(uploadErrors).length > 0} -
- {#each Object.entries(uploadErrors) as [file, msg]} - {msg} - {/each} -
- {/if} -
- {:else} - - {/if} - -
- - {#if isChecking[key]} -
- - Checking... -
- {:else if formState.errors[key]} - - {formState.errors[key]} - - {/if} -
-
-
-{/snippet} - -
- {#each patientFormFields as group} -
- {#if group.title} -
- {group.title} -
- {/if} - - {#each group.rows as row} -
- {#each row.columns as col} - {#if col.type === "group"} -
- {#each col.columns as child} - {@render Fieldset(child)} - {/each} -
- {:else} - {@render Fieldset(col)} - {/if} - {/each} -
- {/each} -
- {/each} -
-
- - \ No newline at end of file + +
\ No newline at end of file diff --git a/src/lib/components/patient/page/master-page.svelte b/src/lib/components/patient/page/master-page.svelte index 82cf151..e50b80d 100644 --- a/src/lib/components/patient/page/master-page.svelte +++ b/src/lib/components/patient/page/master-page.svelte @@ -5,7 +5,7 @@ import ReusableEmpty from "$lib/components/reusable/reusable-empty.svelte"; import { searchParam } from "$lib/components/patient/api/patient-api"; import ReusableDataTable from "$lib/components/reusable/reusable-data-table.svelte"; - import { useSearch } from "$lib/components/composable/useSearch.svelte"; + import { useSearch } from "$lib/components/composable/use-search.svelte"; import { searchFields, patientActions } from "../config/patient-config"; let props = $props(); diff --git a/src/lib/components/patient/reusable/patient-form-renderer.svelte b/src/lib/components/patient/reusable/patient-form-renderer.svelte index d150db3..db38c8c 100644 --- a/src/lib/components/patient/reusable/patient-form-renderer.svelte +++ b/src/lib/components/patient/reusable/patient-form-renderer.svelte @@ -39,7 +39,6 @@ }); async function initializeDefaultValues() { - console.log('object'); for (const group of formFields) { for (const row of group.rows) { for (const col of row.columns) { @@ -58,14 +57,22 @@ async function handleDefaultValue(field) { if (!field.defaultValue || !field.optionsEndpoint) return; - // Fetch options await formState.fetchOptions(field, formState.form); - // Set default jika form masih kosong if (!formState.form[field.key]) { formState.form[field.key] = field.defaultValue; } } + + let isDeathDateDisabled = $derived( + formState.form.DeathIndicator !== 'Y' + ); + + $effect(() => { + if (isDeathDateDisabled && formState.form.TimeOfDeath) { + formState.form.TimeOfDeath = ""; + } + }); {#snippet Fieldset({ key, label, required, type, optionsEndpoint, options, validateOn, dependsOn, endpointParamKey })} @@ -134,8 +141,9 @@ }} /> {:else if type === "datetime"} - { formState.form[key] = val; if (validateOn?.includes("input")) { diff --git a/src/lib/components/reusable/reusable-calendar-timepicker.svelte b/src/lib/components/reusable/reusable-calendar-timepicker.svelte index 18c53c2..b22f96d 100644 --- a/src/lib/components/reusable/reusable-calendar-timepicker.svelte +++ b/src/lib/components/reusable/reusable-calendar-timepicker.svelte @@ -6,16 +6,9 @@ import { Input } from "$lib/components/ui/input/index.js"; import { getLocalTimeZone, fromDate, today, parseDate } from "@internationalized/date"; import Clock2Icon from "@lucide/svelte/icons/clock-2"; - - // const id = $props.id(); - // let { title, parentFunction, initialValue } = $props(); - // let value = $state(''); - // let calendarValue = $state(null); - // let timeValue = $state("00:00:00"); - // let open = $state(false); const id = $props.id(); - let { title, parentFunction, value = $bindable("") } = $props(); + let { title, parentFunction, value = $bindable(""), disabled = false } = $props(); let open = $state(false); let calendarValue = $state(); let timeValue = $state("00:00:00"); @@ -62,39 +55,6 @@ const dt = new Date(val); return dt.toLocaleString("sv-SE"); } - - - // function updateDateTime() { - // if (!calendarValue) return; - - // const [h, m, s] = timeValue.split(":").map(Number); - // const dt = calendarValue.toDate(getLocalTimeZone()); - // dt.setHours(h, m, s); - - // value = dt.toISOString(); - // parentFunction?.(value); - // } - - // function formatDateTime(val) { - // if (!val) return "Select date"; - // const dt = new Date(val); - // return dt.toLocaleString("sv-SE"); - // } - - // $effect(() => { - // if (initialValue) { - // const dt = new Date(initialValue); - // calendarValue = fromDate(dt, getLocalTimeZone()); - // timeValue = dt.toLocaleTimeString("sv-SE", { - // hour12: false, - // hour: "2-digit", - // minute: "2-digit", - // second: "2-digit", - // }); - - // value = initialValue; - // } - // });
@@ -108,6 +68,7 @@ {...props} variant="outline" class="w-full justify-between font-normal text-muted-foreground truncate" + disabled={disabled} > {formatDateTime(value)} @@ -143,54 +104,4 @@
- - - + \ No newline at end of file diff --git a/src/lib/components/reusable/reusable-data-table.svelte b/src/lib/components/reusable/reusable-data-table.svelte index 5400507..7aefeb4 100644 --- a/src/lib/components/reusable/reusable-data-table.svelte +++ b/src/lib/components/reusable/reusable-data-table.svelte @@ -61,14 +61,14 @@ });
-
+
{ globalFilter = e.currentTarget.value; }} - class="h-8 w-64 text-xs px-2" + class="h-7 w-64 text-xs px-2" />
diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index 34acffe..30b6cfa 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -46,7 +46,7 @@
-
+
{@render children?.()}
diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index cc88df0..366dd36 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -1,2 +1,4 @@ -

Welcome to SvelteKit

-

Visit svelte.dev/docs/kit to read the documentation

+
+

Welcome to SvelteKit

+

Visit svelte.dev/docs/kit to read the documentation

+
diff --git a/src/routes/patient/+page.svelte b/src/routes/patient/+page.svelte index 27eff80..6fcfe16 100644 --- a/src/routes/patient/+page.svelte +++ b/src/routes/patient/+page.svelte @@ -1,6 +1,6 @@