mirror of
https://github.com/faiztyanirh/clqms-shadcn-v1.git
synced 2026-04-22 09:35:34 +07:00
continue patient list & admission
This commit is contained in:
parent
cc22abb033
commit
a3b8582e57
@ -95,7 +95,6 @@ export async function searchWithPath(endpoint, searchQuery) {
|
||||
}
|
||||
|
||||
export async function create(endpoint, formData) {
|
||||
console.log(cleanEmptyStrings(formData));
|
||||
try {
|
||||
const res = await fetch(`${API.BASE_URL}${endpoint}`, {
|
||||
method: 'POST',
|
||||
@ -115,19 +114,19 @@ export async function create(endpoint, formData) {
|
||||
|
||||
export async function update(endpoint, formData) {
|
||||
console.log(cleanEmptyStrings(formData));
|
||||
try {
|
||||
const res = await fetch(`${API.BASE_URL}${endpoint}`, {
|
||||
method: 'PATCH',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(cleanEmptyStrings(formData))
|
||||
});
|
||||
// try {
|
||||
// const res = await fetch(`${API.BASE_URL}${endpoint}`, {
|
||||
// method: 'PATCH',
|
||||
// headers: {
|
||||
// 'Content-Type': 'application/json',
|
||||
// },
|
||||
// body: JSON.stringify(cleanEmptyStrings(formData))
|
||||
// });
|
||||
|
||||
const data = await res.json();
|
||||
return data;
|
||||
} catch (err) {
|
||||
console.error('Update Error:', err.message);
|
||||
return { success: false, message: err.message || 'Network error' };
|
||||
}
|
||||
// const data = await res.json();
|
||||
// return data;
|
||||
// } catch (err) {
|
||||
// console.error('Update Error:', err.message);
|
||||
// return { success: false, message: err.message || 'Network error' };
|
||||
// }
|
||||
}
|
||||
@ -2,6 +2,10 @@
|
||||
import ChartPieIcon from "@lucide/svelte/icons/chart-pie";
|
||||
import FrameIcon from "@lucide/svelte/icons/frame";
|
||||
import LifeBuoyIcon from "@lucide/svelte/icons/life-buoy";
|
||||
import ChartColumnIcon from "@lucide/svelte/icons/chart-column";
|
||||
import UserIcon from "@lucide/svelte/icons/user";
|
||||
import ReceiptTextIcon from "@lucide/svelte/icons/receipt-text";
|
||||
import BookOpenIcon from "@lucide/svelte/icons/book-open";
|
||||
import MapIcon from "@lucide/svelte/icons/map";
|
||||
import SendIcon from "@lucide/svelte/icons/send";
|
||||
import Settings2Icon from "@lucide/svelte/icons/settings-2";
|
||||
@ -17,12 +21,12 @@
|
||||
{
|
||||
title: "Dashboard",
|
||||
url: "/",
|
||||
icon: LifeBuoyIcon,
|
||||
icon: ChartColumnIcon,
|
||||
},
|
||||
{
|
||||
title: "Patient",
|
||||
url: "/patient",
|
||||
icon: LifeBuoyIcon,
|
||||
icon: UserIcon,
|
||||
submenus: [
|
||||
{
|
||||
title: "Patient List",
|
||||
@ -37,7 +41,7 @@
|
||||
{
|
||||
title: "Order",
|
||||
url: "/order",
|
||||
icon: LifeBuoyIcon,
|
||||
icon: ReceiptTextIcon,
|
||||
submenus: [
|
||||
{
|
||||
title: "Test Order",
|
||||
@ -50,7 +54,7 @@
|
||||
{
|
||||
title: "Admission",
|
||||
url: "/admission",
|
||||
icon: LifeBuoyIcon,
|
||||
icon: BookOpenIcon,
|
||||
submenus: [
|
||||
{
|
||||
title: "Contact",
|
||||
@ -69,7 +73,7 @@
|
||||
{
|
||||
title: "Value",
|
||||
url: "#",
|
||||
icon: LifeBuoyIcon,
|
||||
icon: BookOpenIcon,
|
||||
submenus: [
|
||||
{
|
||||
title: "Value Set Def",
|
||||
@ -84,7 +88,7 @@
|
||||
{
|
||||
title: "Sample",
|
||||
url: "#",
|
||||
icon: LifeBuoyIcon,
|
||||
icon: BookOpenIcon,
|
||||
submenus: [
|
||||
{
|
||||
title: "Container",
|
||||
@ -95,7 +99,7 @@
|
||||
{
|
||||
title: "Organization",
|
||||
url: "#",
|
||||
icon: LifeBuoyIcon,
|
||||
icon: BookOpenIcon,
|
||||
submenus: [
|
||||
{
|
||||
title: "Account",
|
||||
@ -122,7 +126,7 @@
|
||||
{
|
||||
title: "Test",
|
||||
url: "#",
|
||||
icon: LifeBuoyIcon,
|
||||
icon: BookOpenIcon,
|
||||
submenus: [
|
||||
{
|
||||
title: "Test Site",
|
||||
|
||||
@ -7,12 +7,13 @@ export function useForm({schema, initialForm, defaultErrors, mode, modeOpt, save
|
||||
const val = useFormValidation(schema, state.form, defaultErrors, mode);
|
||||
const options = useFormOptions(modeOpt);
|
||||
|
||||
async function save() {
|
||||
async function save(currentMode, customPayload = null) {
|
||||
state.isSaving.current = true
|
||||
|
||||
try {
|
||||
const payload = { ...state.form };
|
||||
const result = mode === 'edit' ? await editEndpoint(payload) : await saveEndpoint(payload)
|
||||
// const payload = { ...state.form };
|
||||
const payload = customPayload || { ...state.form };
|
||||
const result = currentMode === 'edit' ? await editEndpoint(payload) : await saveEndpoint(payload);
|
||||
return result;
|
||||
} catch (error) {
|
||||
console.error('Save failed', error);
|
||||
|
||||
@ -42,21 +42,20 @@ export function useMasterDetail(options = {}) {
|
||||
}
|
||||
}
|
||||
|
||||
function enterCreate(initialData = null) {
|
||||
mode = "create";
|
||||
selectedItem = null;
|
||||
function enterCreate(initialData = null) {
|
||||
mode = "create";
|
||||
selectedItem = null;
|
||||
|
||||
formState.reset();
|
||||
formState.reset();
|
||||
|
||||
if (initialData) {
|
||||
formState.setForm({
|
||||
...formState.form,
|
||||
...initialData
|
||||
});
|
||||
if (initialData) {
|
||||
formState.setForm({
|
||||
...formState.form,
|
||||
...initialData
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function enterEdit(mapToForm = null) {
|
||||
if (!selectedItem) return;
|
||||
mode = "edit";
|
||||
@ -74,9 +73,6 @@ function enterCreate(initialData = null) {
|
||||
}
|
||||
|
||||
function exitForm() {
|
||||
// const confirmed = confirm('You have unsaved changes. Are you sure you want to exit?');
|
||||
// if (!confirmed) return;
|
||||
|
||||
mode = "view";
|
||||
selectedItem = null;
|
||||
}
|
||||
@ -87,12 +83,10 @@ function enterCreate(initialData = null) {
|
||||
}
|
||||
|
||||
function saveForm() {
|
||||
// Commit changes (mark as saved)
|
||||
formSnapshot = { ...form };
|
||||
}
|
||||
|
||||
return {
|
||||
// State
|
||||
get selectedItem() {
|
||||
return selectedItem;
|
||||
},
|
||||
@ -127,7 +121,6 @@ function enterCreate(initialData = null) {
|
||||
return formState;
|
||||
},
|
||||
|
||||
// Actions
|
||||
select,
|
||||
enterCreate,
|
||||
enterEdit,
|
||||
|
||||
@ -41,7 +41,7 @@ export const searchFields = [
|
||||
|
||||
export const detailSections = [
|
||||
{
|
||||
title: "", // No title for top row
|
||||
title: "",
|
||||
class: "grid grid-cols-1 md:grid-cols-2 gap-4",
|
||||
groups: [
|
||||
{
|
||||
@ -84,10 +84,6 @@ export function admissionActions(masterDetail, selectedPatient) {
|
||||
{
|
||||
Icon: PlusIcon,
|
||||
label: 'Add Visit',
|
||||
// onClick: masterDetail.enterCreate({
|
||||
// PatientID: selectedPatient?.PatientID,
|
||||
// InternalPID: selectedPatient?.InternalPID
|
||||
// }),
|
||||
onClick: () => masterDetail.enterCreate({
|
||||
PatientID: selectedPatient?.PatientID,
|
||||
InternalPID: selectedPatient?.InternalPID
|
||||
@ -108,7 +104,6 @@ export function viewActions(handlers){
|
||||
Icon: PencilIcon,
|
||||
label: 'Edit Patient',
|
||||
onClick: handlers.editPatient,
|
||||
|
||||
},
|
||||
]
|
||||
}
|
||||
@ -18,6 +18,7 @@ export const admissionInitialForm = {
|
||||
RefDoc: "",
|
||||
AdmDoc: "",
|
||||
CnsDoc: "",
|
||||
isDischarge: false
|
||||
};
|
||||
|
||||
export const admissionDefaultErrors = {};
|
||||
@ -131,7 +132,7 @@ export const admissionFormFields = [
|
||||
optionsEndpoint: `${API.BASE_URL}${API.VALUESET}/service_classes`,
|
||||
},
|
||||
{
|
||||
key: "Discharge",
|
||||
key: "isDischarge",
|
||||
label: "Discharge Status",
|
||||
required: false,
|
||||
type: "toggle",
|
||||
|
||||
105
src/lib/components/patient/admission/config/admission-payload.js
Normal file
105
src/lib/components/patient/admission/config/admission-payload.js
Normal file
@ -0,0 +1,105 @@
|
||||
import { cleanEmptyStrings } from "$lib/utils/cleanEmptyStrings";
|
||||
|
||||
const ADT_CODE_MAP = {
|
||||
LocationID: "A02",
|
||||
AttDoc: "A54",
|
||||
RefDoc: "A08",
|
||||
AdmDoc: "A08",
|
||||
CnsDoc: "A61",
|
||||
isDischarge: "A03",
|
||||
};
|
||||
|
||||
export function compareAdmissionData(oldData, newData) {
|
||||
let diffs = [];
|
||||
let current = { ...oldData };
|
||||
let sequence = 1;
|
||||
|
||||
for (const key in ADT_CODE_MAP) {
|
||||
// Skip if field tidak ada atau tidak berubah
|
||||
if (!Object.hasOwn(oldData, key) || oldData[key] === newData[key]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Track discharge status
|
||||
const originalisDischarge = !!oldData.isDischarge;
|
||||
const newisDischarge = !!newData.isDischarge;
|
||||
|
||||
// Update current state
|
||||
current[key] = newData[key];
|
||||
|
||||
// Build diff entry
|
||||
const filtered = Object.fromEntries(
|
||||
Object.keys(ADT_CODE_MAP).map((k) => [k, current[k]])
|
||||
);
|
||||
|
||||
diffs.push({
|
||||
sequence: sequence++,
|
||||
code: ADT_CODE_MAP[key],
|
||||
originalisDischarge,
|
||||
isDischarge: newisDischarge,
|
||||
...filtered,
|
||||
});
|
||||
}
|
||||
return diffs;
|
||||
}
|
||||
|
||||
export function buildEditAdmissionPayload(form, diffs = []) {
|
||||
const base = {
|
||||
InternalPVID: form.InternalPVID,
|
||||
PVID: form.PVID,
|
||||
EpisodeID: form.EpisodeID,
|
||||
InternalPID: form.InternalPID,
|
||||
PatDiag: {
|
||||
DiagCode: form.DiagCode || null,
|
||||
Diagnosis: form.Diagnosis || null,
|
||||
},
|
||||
};
|
||||
|
||||
// No changes, return empty PatVisitADT
|
||||
if (!diffs.length) {
|
||||
return {
|
||||
...base,
|
||||
PatVisitADT: [],
|
||||
};
|
||||
}
|
||||
|
||||
// Map diffs ke PatVisitADT entries
|
||||
const PatVisitADT = diffs.map(diff => {
|
||||
// Determine ADTCode based on discharge status
|
||||
let ADTCode;
|
||||
if (diff.isDischarge) {
|
||||
ADTCode = "A03"; // Discharge
|
||||
} else if (diff.originalisDischarge) {
|
||||
ADTCode = "A13"; // Cancel discharge
|
||||
} else {
|
||||
ADTCode = diff.code; // Normal update
|
||||
}
|
||||
|
||||
return {
|
||||
sequence: diff.sequence,
|
||||
ADTCode,
|
||||
LocationID: diff.LocationID || null,
|
||||
AttDoc: diff.AttDoc || null,
|
||||
RefDoc: diff.RefDoc || null,
|
||||
AdmDoc: diff.AdmDoc || null,
|
||||
CnsDoc: diff.CnsDoc || null,
|
||||
};
|
||||
});
|
||||
|
||||
return { ...base, PatVisitADT };
|
||||
}
|
||||
|
||||
export function buildEditPayloadWithDiff(originalData, formData) {
|
||||
// Clean data
|
||||
const cleanedForm = cleanEmptyStrings(formData);
|
||||
const cleanedOriginal = cleanEmptyStrings(originalData);
|
||||
|
||||
// Compare & get diffs
|
||||
const diffs = compareAdmissionData(cleanedOriginal, cleanedForm);
|
||||
console.log(formData);
|
||||
|
||||
// Build payload
|
||||
const payload = buildEditAdmissionPayload(cleanedForm, diffs);
|
||||
|
||||
return cleanEmptyStrings(payload);
|
||||
}
|
||||
@ -0,0 +1,62 @@
|
||||
<script>
|
||||
import { useForm } from "$lib/components/composable/use-form.svelte";
|
||||
import { admissionSchema, admissionInitialForm, admissionDefaultErrors, admissionFormFields, getAdmissionFormActions, buildPayload } from "$lib/components/patient/admission/config/admission-form-config";
|
||||
import { createAdmission } from "$lib/components/patient/admission/api/patient-admission-api";
|
||||
import { usePatientForm } from "$lib/components/composable/use-patient-form.svelte";
|
||||
import FormPageContainer from "$lib/components/patient/reusable/form-page-container.svelte";
|
||||
import PatientFormRenderer from "$lib/components/patient/reusable/patient-form-renderer.svelte";
|
||||
|
||||
let props = $props();
|
||||
|
||||
let formState = useForm({
|
||||
schema: admissionSchema,
|
||||
initialForm: admissionInitialForm,
|
||||
defaultErrors: admissionDefaultErrors,
|
||||
mode: 'create',
|
||||
modeOpt: 'default',
|
||||
saveEndpoint: createAdmission,
|
||||
editEndpoint: null,
|
||||
});
|
||||
|
||||
const helpers = usePatientForm(formState, admissionSchema);
|
||||
|
||||
const handlers = {
|
||||
clearForm: () => {
|
||||
formState.reset();
|
||||
}
|
||||
};
|
||||
|
||||
const actions = getAdmissionFormActions(handlers);
|
||||
|
||||
async function handleSave() {
|
||||
const payload = buildPayload(formState.form);
|
||||
|
||||
console.log(payload);
|
||||
}
|
||||
|
||||
const primaryAction = $derived({
|
||||
label: 'Save',
|
||||
onClick: handleSave,
|
||||
disabled: helpers.hasErrors || formState.isSaving.current,
|
||||
loading: formState.isSaving.current
|
||||
});
|
||||
|
||||
const secondaryActions = [];
|
||||
|
||||
$effect(() => {
|
||||
if (props.masterDetail.form?.PatientID) {
|
||||
formState.setForm({
|
||||
...formState.form,
|
||||
...props.masterDetail.form
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<FormPageContainer title="Create Admission" {primaryAction} {secondaryActions} {actions}>
|
||||
<PatientFormRenderer
|
||||
{formState}
|
||||
formFields={admissionFormFields}
|
||||
mode="create"
|
||||
/>
|
||||
</FormPageContainer>
|
||||
@ -1,24 +1,17 @@
|
||||
<script>
|
||||
import { useForm } from "$lib/components/composable/use-form.svelte";
|
||||
import { admissionSchema, admissionInitialForm, admissionDefaultErrors, admissionFormFields, getAdmissionFormActions, buildPayload } from "$lib/components/patient/admission/config/admission-form-config";
|
||||
import { createAdmission } from "$lib/components/patient/admission/api/patient-admission-api";
|
||||
import { usePatientForm } from "$lib/components/composable/use-patient-form.svelte";
|
||||
import FormPageContainer from "$lib/components/patient/reusable/form-page-container.svelte";
|
||||
import PatientFormRenderer from "$lib/components/patient/reusable/patient-form-renderer.svelte";
|
||||
import { buildPayload } from "$lib/components/patient/admission/config/admission-form-config";
|
||||
import { toast } from "svelte-sonner";
|
||||
|
||||
let props = $props();
|
||||
|
||||
let formState = useForm({
|
||||
schema: admissionSchema,
|
||||
initialForm: admissionInitialForm,
|
||||
defaultErrors: admissionDefaultErrors,
|
||||
mode: 'create',
|
||||
modeOpt: 'default',
|
||||
saveEndpoint: createAdmission,
|
||||
editEndpoint: null,
|
||||
});
|
||||
const { masterDetail, formFields, formActions, schema } = props.context;
|
||||
|
||||
const helpers = usePatientForm(formState, admissionSchema);
|
||||
const { formState } = masterDetail;
|
||||
|
||||
const helpers = usePatientForm(formState, schema);
|
||||
|
||||
const handlers = {
|
||||
clearForm: () => {
|
||||
@ -26,12 +19,16 @@
|
||||
}
|
||||
};
|
||||
|
||||
const actions = getAdmissionFormActions(handlers);
|
||||
const actions = formActions(handlers);
|
||||
|
||||
async function handleSave() {
|
||||
const payload = buildPayload(formState.form);
|
||||
|
||||
// const result = await formState.save(masterDetail.mode, payload);
|
||||
|
||||
console.log(payload);
|
||||
toast('Visit Created!');
|
||||
masterDetail?.exitForm();
|
||||
}
|
||||
|
||||
const primaryAction = $derived({
|
||||
@ -44,10 +41,10 @@
|
||||
const secondaryActions = [];
|
||||
|
||||
$effect(() => {
|
||||
if (props.masterDetail.form?.PatientID) {
|
||||
if (masterDetail.form?.PatientID) {
|
||||
formState.setForm({
|
||||
...formState.form,
|
||||
...props.masterDetail.form
|
||||
...masterDetail.form
|
||||
});
|
||||
}
|
||||
});
|
||||
@ -56,7 +53,7 @@
|
||||
<FormPageContainer title="Create Admission" {primaryAction} {secondaryActions} {actions}>
|
||||
<PatientFormRenderer
|
||||
{formState}
|
||||
formFields={admissionFormFields}
|
||||
formFields={formFields}
|
||||
mode="create"
|
||||
/>
|
||||
</FormPageContainer>
|
||||
@ -1,39 +1,51 @@
|
||||
<script>
|
||||
import { useForm } from "$lib/components/composable/use-form.svelte";
|
||||
import { admissionSchema, admissionInitialForm, admissionDefaultErrors, admissionFormFields, getAdmissionFormActions } from "$lib/components/patient/admission/config/admission-form-config";
|
||||
import { editAdmission } from "$lib/components/patient/admission/api/patient-admission-api";
|
||||
import { usePatientForm } from "$lib/components/composable/use-patient-form.svelte";
|
||||
import FormPageContainer from "$lib/components/patient/reusable/form-page-container.svelte";
|
||||
import PatientFormRenderer from "$lib/components/patient/reusable/patient-form-renderer.svelte";
|
||||
import { untrack } from "svelte";
|
||||
import { buildPayload } from "$lib/components/patient/admission/config/admission-form-config";
|
||||
import { toast } from "svelte-sonner";
|
||||
import { buildEditPayloadWithDiff } from "$lib/components/patient/admission/config/admission-payload";
|
||||
|
||||
let props = $props();
|
||||
|
||||
const { masterDetail, formFields, formActions, schema, initialForm, defaultError } = props.context;
|
||||
|
||||
let formState = useForm({
|
||||
schema: admissionSchema,
|
||||
initialForm: admissionInitialForm,
|
||||
defaultErrors: {},
|
||||
mode: 'edit',
|
||||
modeOpt: 'default',
|
||||
saveEndpoint: null,
|
||||
editEndpoint: editAdmission,
|
||||
});
|
||||
const { formState } = masterDetail;
|
||||
|
||||
$effect(() => {
|
||||
const backendData = props.masterDetail?.selectedItem.data;
|
||||
const backendData = masterDetail?.selectedItem.data;
|
||||
if (!backendData) return;
|
||||
console.log(backendData);
|
||||
|
||||
untrack(() => {
|
||||
const formData = {
|
||||
...backendData,
|
||||
};
|
||||
|
||||
formState.setForm(formData);
|
||||
|
||||
formFields.forEach(group => {
|
||||
group.rows.forEach(row => {
|
||||
row.columns.forEach(col => {
|
||||
if (col.type === "select" && col.optionsEndpoint) {
|
||||
formState.fetchOptions(col, formData);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
})
|
||||
})
|
||||
|
||||
$inspect(formState.form)
|
||||
async function handleEdit() {
|
||||
console.log('object');
|
||||
// const payload = buildPayload(formState.form);
|
||||
const payload = buildEditPayloadWithDiff(
|
||||
masterDetail.selectedItem?.data,
|
||||
formState.form
|
||||
);
|
||||
|
||||
console.log(payload);
|
||||
// toast('Visit Updated!');
|
||||
// masterDetail?.exitForm();
|
||||
// const result = await formState.save();
|
||||
|
||||
// if (result.status === 'success') {
|
||||
@ -55,7 +67,7 @@
|
||||
<FormPageContainer title="Edit Admission" {primaryAction} {secondaryActions}>
|
||||
<PatientFormRenderer
|
||||
{formState}
|
||||
formFields={admissionFormFields}
|
||||
formFields={formFields}
|
||||
mode="edit"
|
||||
/>
|
||||
</FormPageContainer>
|
||||
@ -5,11 +5,12 @@
|
||||
import { searchFields, admissionActions } from "$lib/components/patient/admission/config/admission-config";
|
||||
import TopbarWrapper from "$lib/components/topbar/topbar-wrapper.svelte";
|
||||
import ReusableSearchParam from "$lib/components/reusable/reusable-search-param.svelte";
|
||||
import SearchParamModal from "../modal/search-param-modal.svelte";
|
||||
import ReusableEmpty from "$lib/components/reusable/reusable-empty.svelte";
|
||||
import ReusableDataTable from "$lib/components/reusable/reusable-data-table.svelte";
|
||||
import SearchParamModal from "../modal/search-param-modal.svelte";
|
||||
|
||||
let props = $props();
|
||||
|
||||
let selectedPID = $state(null);
|
||||
let selectedPatient = $state(null);
|
||||
let tableData = $state([]);
|
||||
|
||||
@ -6,10 +6,12 @@
|
||||
|
||||
let props = $props();
|
||||
|
||||
let visit = $derived(props.masterDetail?.selectedItem?.data);
|
||||
const { masterDetail, formFields, formActions, schema } = props.context;
|
||||
|
||||
let visit = $derived(masterDetail?.selectedItem?.data);
|
||||
|
||||
const handlers = {
|
||||
editPatient: () => props.masterDetail.enterEdit(),
|
||||
editPatient: () => masterDetail.enterEdit(),
|
||||
};
|
||||
|
||||
const actions = viewActions(handlers);
|
||||
@ -44,10 +46,10 @@
|
||||
</div>
|
||||
{/snippet}
|
||||
|
||||
{#if props.masterDetail.selectedItem}
|
||||
{#if masterDetail.selectedItem}
|
||||
<div class="flex flex-col px-2 py-1 gap-2 h-full w-full">
|
||||
<TopbarWrapper
|
||||
title={props.masterDetail.selectedItem.data.PVID}
|
||||
title={masterDetail.selectedItem.data.PVID}
|
||||
{actions}
|
||||
/>
|
||||
<div class="flex-1 min-h-0 overflow-y-auto space-y-4">
|
||||
@ -86,27 +88,4 @@
|
||||
</div>
|
||||
{:else}
|
||||
<ReusableEmpty desc="Select a visit to see details"/>
|
||||
{/if}
|
||||
|
||||
<!-- {#if props.masterDetail.selectedItem}
|
||||
<div class="flex flex-col px-2 py-1 gap-2 h-full w-full">
|
||||
<TopbarWrapper title={props.masterDetail.selectedItem.data.PVID} {actions} />
|
||||
<div class="flex-1 min-h-0 overflow-y-auto space-y-4">
|
||||
{#each detailSections as section}
|
||||
<div class="p-4">
|
||||
<div class={section.class}>
|
||||
{#each section.fields as field}
|
||||
{@render Fieldset({
|
||||
label: field.label,
|
||||
value: getFieldValue(field),
|
||||
isUTCDate: field.isUTCDate,
|
||||
})}
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
{:else}
|
||||
<ReusableEmpty desc="Select a visit to see details"/>
|
||||
{/if} -->
|
||||
{/if}
|
||||
@ -5,6 +5,7 @@
|
||||
import { toast } from "svelte-sonner";
|
||||
|
||||
let props = $props();
|
||||
|
||||
const { masterDetail, formFields, formActions, schema } = props.context;
|
||||
|
||||
const { formState } = masterDetail;
|
||||
@ -20,7 +21,7 @@
|
||||
const actions = formActions(handlers);
|
||||
|
||||
async function handleSave() {
|
||||
const result = await formState.save();
|
||||
const result = await formState.save(masterDetail.mode);
|
||||
|
||||
if (result.status === 'success') {
|
||||
toast('Patient Created!');
|
||||
|
||||
@ -7,12 +7,11 @@
|
||||
import { API } from "$lib/config/api";
|
||||
|
||||
let props = $props();
|
||||
const { masterDetail, formFields, formActions, schema, initialForm } = props.context;
|
||||
|
||||
const { masterDetail, formFields, formActions, schema, initialForm, defaultError } = props.context;
|
||||
|
||||
const { formState } = masterDetail;
|
||||
|
||||
console.log(formState);
|
||||
|
||||
const helpers = usePatientForm(formState, schema);
|
||||
|
||||
$effect(() => {
|
||||
@ -69,12 +68,13 @@
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$inspect(formState.form)
|
||||
async function handleEdit() {
|
||||
const result = await formState.save();
|
||||
const result = await formState.save(masterDetail.mode);
|
||||
|
||||
if (result.status === 'success') {
|
||||
console.log('Patient updated successfully');
|
||||
toast('Patient Updated!');
|
||||
masterDetail.exitForm();
|
||||
} else {
|
||||
console.error('Failed to update patient:', result.message);
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
import ReusableEmpty from "$lib/components/reusable/reusable-empty.svelte";
|
||||
|
||||
let props = $props();
|
||||
|
||||
const { masterDetail, formFields, formActions, schema } = props.context;
|
||||
|
||||
let patient = $derived(masterDetail?.selectedItem?.patient);
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<script>
|
||||
import * as DropdownMenu from "$lib/components/ui/dropdown-menu/index.js";
|
||||
import * as Select from "$lib/components/ui/select/index.js";
|
||||
import * as ToggleGroup from "$lib/components/ui/toggle-group/index.js";
|
||||
import { Toggle } from "$lib/components/ui/toggle/index.js";
|
||||
import { Button } from "$lib/components/ui/button/index.js";
|
||||
import { Input } from "$lib/components/ui/input/index.js";
|
||||
import { Label } from "$lib/components/ui/label/index.js";
|
||||
@ -230,8 +230,8 @@
|
||||
}}
|
||||
onValueChange={(val) => {
|
||||
formState.form.PatIdt = {
|
||||
IdentifierType: val,
|
||||
Identifier:''
|
||||
IdentifierType: val,
|
||||
Identifier:''
|
||||
};
|
||||
}}
|
||||
>
|
||||
@ -284,23 +284,23 @@
|
||||
</div>
|
||||
{:else if type === "toggle"}
|
||||
<div class="flex items-center w-full">
|
||||
<ToggleGroup.Root variant="outline" type="single" class="w-full" bind:value={formState.form[key]} >
|
||||
<ToggleGroup.Item
|
||||
value="yes"
|
||||
aria-label="Toggle Yes"
|
||||
class="flex gap-2 px-4 w-1/2 transition-all data-[state=on]:bg-primary/10 data-[state=on]:text-primary data-[state=on]:border-primary/30 data-[state=on]:*:[svg]:stroke-[6px]"
|
||||
>
|
||||
<CheckIcon class="h-4 w-4" />
|
||||
</ToggleGroup.Item>
|
||||
|
||||
<ToggleGroup.Item
|
||||
value="no"
|
||||
aria-label="Toggle No"
|
||||
class="flex gap-2 px-4 w-1/2 transition-all data-[state=on]:bg-primary/10 data-[state=on]:text-primary data-[state=on]:border-primary/30 data-[state=on]:*:[svg]:stroke-[6px]"
|
||||
>
|
||||
<XIcon class="h-4 w-4" />
|
||||
</ToggleGroup.Item>
|
||||
</ToggleGroup.Root>
|
||||
<Toggle
|
||||
aria-label="Toggle discharge"
|
||||
variant="outline"
|
||||
class="w-full transition-all data-[state=on]:text-primary"
|
||||
bind:pressed={formState.form.isDischarge}
|
||||
onPressedChange={(pressed) => {
|
||||
formState.form.ADTCode = pressed ? "A03" : "";
|
||||
}}
|
||||
>
|
||||
|
||||
{#if formState.form.isDischarge}
|
||||
<XIcon class="mr-2 h-4 w-4" />
|
||||
{:else}
|
||||
<CheckIcon class="mr-2 h-4 w-4" />
|
||||
{/if}
|
||||
{formState.form.isDischarge ? "Discharged" : "Active"}
|
||||
</Toggle>
|
||||
</div>
|
||||
{:else}
|
||||
<Input
|
||||
|
||||
@ -1,17 +1,39 @@
|
||||
<script>
|
||||
import { Separator } from "$lib/components/ui/separator/index.js";
|
||||
import { useMasterDetail } from "$lib/components/composable/use-master-detail.svelte";
|
||||
import { getVisit } from "$lib/components/patient/admission/api/patient-admission-api";
|
||||
import { getVisit, createAdmission, editAdmission } from "$lib/components/patient/admission/api/patient-admission-api";
|
||||
import MasterPage from "$lib/components/patient/admission/page/master-page.svelte";
|
||||
import ViewPage from "$lib/components/patient/admission/page/view-page.svelte";
|
||||
import CreatePage from "$lib/components/patient/admission/page/create-page.svelte";
|
||||
import EditPage from "$lib/components/patient/admission/page/edit-page.svelte";
|
||||
import { admissionSchema, admissionInitialForm, admissionDefaultErrors, admissionFormFields, getAdmissionFormActions, buildPayload } from "$lib/components/patient/admission/config/admission-form-config";
|
||||
|
||||
const masterDetail = useMasterDetail({
|
||||
onSelect: async (row) => {
|
||||
return await getVisit(row.PVID);
|
||||
},
|
||||
formConfig: {
|
||||
schema: admissionSchema,
|
||||
initialForm: admissionInitialForm,
|
||||
defaultErrors: admissionDefaultErrors,
|
||||
mode: 'create',
|
||||
modeOpt: 'default',
|
||||
saveEndpoint: createAdmission,
|
||||
editEndpoint: editAdmission,
|
||||
}
|
||||
});
|
||||
|
||||
const pageContext = {
|
||||
masterDetail,
|
||||
formFields: admissionFormFields,
|
||||
formActions: getAdmissionFormActions,
|
||||
schema: admissionSchema,
|
||||
initialForm: admissionInitialForm,
|
||||
defaultErrors: {
|
||||
create: admissionDefaultErrors,
|
||||
edit: {}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="flex w-full h-full overflow-hidden">
|
||||
@ -22,11 +44,11 @@
|
||||
{#if masterDetail.showDetail}
|
||||
<main class={`${masterDetail.isMobile ? 'w-full' : masterDetail.isFormMode ? 'w-[97%] flex flex-col items-start' : 'w-[65%]'} h-full overflow-y-auto flex flex-col items-center transition-all duration-300`}>
|
||||
{#if masterDetail.mode === "view"}
|
||||
<ViewPage {masterDetail}/>
|
||||
<ViewPage context={pageContext}/>
|
||||
{:else if masterDetail.mode === "create"}
|
||||
<CreatePage {masterDetail}/>
|
||||
<CreatePage context={pageContext}/>
|
||||
{:else if masterDetail.mode === "edit"}
|
||||
<EditPage {masterDetail}/>
|
||||
<EditPage context={pageContext}/>
|
||||
{/if}
|
||||
</main>
|
||||
{/if}
|
||||
|
||||
@ -30,7 +30,7 @@
|
||||
schema: patientSchema,
|
||||
initialForm: patientInitialForm,
|
||||
defaultErrors: {
|
||||
create: patientDefaultErrors,
|
||||
create: patientDefaultErrors,
|
||||
edit: {}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user