cd57dc6243
Remove FormErrors type imports and error props from all form components Move content from entry.vue to add.vue with updated title styling
323 lines
11 KiB
Vue
323 lines
11 KiB
Vue
<script setup lang="ts">
|
|
// type
|
|
import type { Patient, genPatientProps } from '~/models/patient'
|
|
import type { ExposedForm } from '~/types/form'
|
|
import type { PatientBase } from '~/models/patient'
|
|
|
|
// schema and models
|
|
import { genPatient } from '~/models/patient'
|
|
import { PatientSchema } from '~/schemas/patient.schema'
|
|
import { PersonAddressRelativeSchema } from '~/schemas/person-address-relative.schema'
|
|
import { PersonAddressSchema } from '~/schemas/person-address.schema'
|
|
import { PersonContactListSchema } from '~/schemas/person-contact.schema'
|
|
import { PersonFamiliesSchema } from '~/schemas/person-family.schema'
|
|
import { ResponsiblePersonSchema } from '~/schemas/person-relative.schema'
|
|
|
|
// components
|
|
import Action from '~/components/pub/my-ui/nav-footer/ba-dr-su.vue'
|
|
import AppPatientEntryForm from '~/components/app/patient/entry-form.vue'
|
|
import AppPersonAddressEntryForm from '~/components/app/person-address/entry-form.vue'
|
|
import AppPersonAddressEntryFormRelative from '~/components/app/person-address/entry-form-relative.vue'
|
|
import AppPersonFamilyParentsForm from '~/components/app/person/family-parents-form.vue'
|
|
import AppPersonContactEntryForm from '~/components/app/person-contact/entry-form.vue'
|
|
import AppPersonRelativeEntryForm from '~/components/app/person-relative/entry-form.vue'
|
|
|
|
// services
|
|
import { uploadAttachment } from '~/services/patient.service'
|
|
|
|
import {
|
|
// for form entry
|
|
isReadonly,
|
|
isProcessing,
|
|
isFormEntryDialogOpen,
|
|
isRecordConfirmationOpen,
|
|
onResetState,
|
|
handleActionSave,
|
|
handleCancelForm,
|
|
} from '~/handlers/patient.handler'
|
|
|
|
import { toast } from '~/components/pub/ui/toast'
|
|
|
|
// #region Props & Emits
|
|
const props = defineProps<{
|
|
callbackUrl?: string
|
|
}>()
|
|
|
|
const residentIdentityFile = ref<File>()
|
|
const familyCardFile = ref<File>()
|
|
|
|
// form related state
|
|
const personAddressForm = ref<ExposedForm<any> | null>(null)
|
|
const personAddressRelativeForm = ref<ExposedForm<any> | null>(null)
|
|
const personContactForm = ref<ExposedForm<any> | null>(null)
|
|
const personEmergencyContactRelative = ref<ExposedForm<any> | null>(null)
|
|
const personFamilyForm = ref<ExposedForm<any> | null>(null)
|
|
const personPatientForm = ref<ExposedForm<any> | null>(null)
|
|
|
|
// #endregion
|
|
|
|
// #region State & Computed
|
|
// #endregion
|
|
|
|
// #region Lifecycle Hooks
|
|
onMounted(() => {
|
|
// Initial synchronization when forms are mounted and isSameAddress is true by default
|
|
nextTick(() => {
|
|
const isSameAddress = personAddressRelativeForm.value?.values?.isSameAddress
|
|
if (
|
|
(isSameAddress === true || isSameAddress === '1') &&
|
|
personAddressForm.value?.values &&
|
|
personAddressRelativeForm.value
|
|
) {
|
|
const currentAddressValues = personAddressForm.value.values
|
|
if (Object.keys(currentAddressValues).length > 0) {
|
|
personAddressRelativeForm.value.setValues(
|
|
{
|
|
...personAddressRelativeForm.value.values,
|
|
province_code: currentAddressValues.province_code || undefined,
|
|
regency_code: currentAddressValues.regency_code || undefined,
|
|
district_code: currentAddressValues.district_code || undefined,
|
|
village_code: currentAddressValues.village_code || undefined,
|
|
postalRegion_code: currentAddressValues.postalRegion_code || undefined,
|
|
address: currentAddressValues.address || undefined,
|
|
rt: currentAddressValues.rt || undefined,
|
|
rw: currentAddressValues.rw || undefined,
|
|
},
|
|
false,
|
|
)
|
|
}
|
|
}
|
|
})
|
|
})
|
|
// #endregion
|
|
|
|
// #region Functions
|
|
async function composeFormData(): Promise<Patient> {
|
|
const [patient, address, addressRelative, families, contacts, emergencyContact] = await Promise.all([
|
|
personPatientForm.value?.validate(),
|
|
personAddressForm.value?.validate(),
|
|
personAddressRelativeForm.value?.validate(),
|
|
personFamilyForm.value?.validate(),
|
|
personContactForm.value?.validate(),
|
|
personEmergencyContactRelative.value?.validate(),
|
|
])
|
|
|
|
const results = [patient, address, addressRelative, families, contacts, emergencyContact]
|
|
console.log(results)
|
|
const allValid = results.every((r) => r?.valid)
|
|
|
|
// exit, if form errors happend during validation
|
|
// for example: dropdown not selected
|
|
if (!allValid) return Promise.reject('Form validation failed')
|
|
|
|
const formDataRequest: genPatientProps = {
|
|
patient: patient?.values,
|
|
residentAddress: address?.values,
|
|
cardAddress: addressRelative?.values,
|
|
familyData: families?.values,
|
|
contacts: contacts?.values,
|
|
responsible: emergencyContact?.values,
|
|
}
|
|
|
|
const formData = genPatient()
|
|
|
|
if (patient?.values.residentIdentityFile) {
|
|
residentIdentityFile.value = patient?.values.residentIdentityFile
|
|
}
|
|
|
|
if (patient?.values.familyIdentityFile) {
|
|
familyCardFile.value = patient?.values.familyIdentityFile
|
|
}
|
|
|
|
return new Promise((resolve) => resolve(formData))
|
|
}
|
|
// #endregion region
|
|
|
|
// #region Utilities & event handlers
|
|
async function handleActionClick(eventType: string) {
|
|
if (eventType === 'submit') {
|
|
const patient: Patient = await composeFormData()
|
|
let createdPatientId = 0
|
|
|
|
const response = await handleActionSave(
|
|
patient,
|
|
() => {},
|
|
() => {},
|
|
toast,
|
|
)
|
|
|
|
const data = (response?.body?.data ?? null) as PatientBase | null
|
|
if (!data) return
|
|
createdPatientId = data.id
|
|
|
|
if (residentIdentityFile.value) {
|
|
void uploadAttachment(residentIdentityFile.value, createdPatientId, 'ktp')
|
|
}
|
|
if (familyCardFile.value) {
|
|
void uploadAttachment(familyCardFile.value, createdPatientId, 'kk')
|
|
}
|
|
|
|
// If has callback provided redirect to callback with patientData
|
|
if (props.callbackUrl) {
|
|
await navigateTo(props.callbackUrl + '?patient-id=' + patient.id)
|
|
return
|
|
}
|
|
|
|
// Navigate to patient list or show success message
|
|
await navigateTo('/client/patient')
|
|
return
|
|
}
|
|
|
|
if (eventType === 'cancel') {
|
|
if (props.callbackUrl) {
|
|
await navigateTo(props.callbackUrl)
|
|
return
|
|
}
|
|
|
|
await navigateTo({
|
|
name: 'client-patient',
|
|
})
|
|
// handleCancelForm()
|
|
}
|
|
}
|
|
// #endregion
|
|
|
|
// #region Watchers
|
|
// Watcher untuk sinkronisasi initial ketika kedua form sudah ready
|
|
watch(
|
|
[() => personAddressForm.value, () => personAddressRelativeForm.value],
|
|
([addressForm, relativeForm]) => {
|
|
if (addressForm && relativeForm) {
|
|
// Trigger initial sync jika isSameAddress adalah true
|
|
nextTick(() => {
|
|
const isSameAddress = relativeForm.values?.isSameAddress
|
|
if ((isSameAddress === true || isSameAddress === '1') && addressForm.values) {
|
|
const currentAddressValues = addressForm.values
|
|
if (Object.keys(currentAddressValues).length > 0) {
|
|
relativeForm.setValues(
|
|
{
|
|
...relativeForm.values,
|
|
province_code: currentAddressValues.province_code || undefined,
|
|
regency_code: currentAddressValues.regency_code || undefined,
|
|
district_code: currentAddressValues.district_code || undefined,
|
|
village_code: currentAddressValues.village_code || undefined,
|
|
postalRegion_code: currentAddressValues.postalRegion_code || undefined,
|
|
address: currentAddressValues.address || undefined,
|
|
rt: currentAddressValues.rt || undefined,
|
|
rw: currentAddressValues.rw || undefined,
|
|
},
|
|
false,
|
|
)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
},
|
|
{ immediate: true },
|
|
)
|
|
|
|
// Watcher untuk sinkronisasi alamat ketika isSameAddress = true
|
|
watch(
|
|
() => personAddressForm.value?.values,
|
|
(newAddressValues) => {
|
|
// Cek apakah alamat KTP harus sama dengan alamat sekarang
|
|
const isSameAddress = personAddressRelativeForm.value?.values?.isSameAddress
|
|
|
|
if ((isSameAddress === true || isSameAddress === '1') && newAddressValues && personAddressRelativeForm.value) {
|
|
// Sinkronkan semua field alamat dari alamat sekarang ke alamat KTP
|
|
personAddressRelativeForm.value.setValues(
|
|
{
|
|
...personAddressRelativeForm.value.values,
|
|
province_code: newAddressValues.province_code || undefined,
|
|
regency_code: newAddressValues.regency_code || undefined,
|
|
district_code: newAddressValues.district_code || undefined,
|
|
village_code: newAddressValues.village_code || undefined,
|
|
postalRegion_code: newAddressValues.postalRegion_code || undefined,
|
|
address: newAddressValues.address || undefined,
|
|
rt: newAddressValues.rt || undefined,
|
|
rw: newAddressValues.rw || undefined,
|
|
},
|
|
false,
|
|
)
|
|
}
|
|
},
|
|
{ deep: true },
|
|
)
|
|
|
|
// Watcher untuk memantau perubahan isSameAddress
|
|
watch(
|
|
() => personAddressRelativeForm.value?.values?.isSameAddress,
|
|
(isSameAddress) => {
|
|
if (
|
|
(isSameAddress === true || isSameAddress === '1') &&
|
|
personAddressForm.value?.values &&
|
|
personAddressRelativeForm.value?.values
|
|
) {
|
|
// Ketika isSameAddress diubah menjadi true, copy alamat sekarang ke alamat KTP
|
|
const currentAddressValues = personAddressForm.value.values
|
|
personAddressRelativeForm.value.setValues(
|
|
{
|
|
...personAddressRelativeForm.value.values,
|
|
province_code: currentAddressValues.province_code || undefined,
|
|
regency_code: currentAddressValues.regency_code || undefined,
|
|
district_code: currentAddressValues.district_code || undefined,
|
|
village_code: currentAddressValues.village_code || undefined,
|
|
postalRegion_code: currentAddressValues.postalRegion_code || undefined,
|
|
address: currentAddressValues.address || undefined,
|
|
rt: currentAddressValues.rt || undefined,
|
|
rw: currentAddressValues.rw || undefined,
|
|
},
|
|
false,
|
|
)
|
|
}
|
|
},
|
|
)
|
|
// #endregion
|
|
</script>
|
|
|
|
<template>
|
|
<div class="mb-5 border-b border-b-slate-300 pb-3 text-lg font-semibold xl:text-xl">Tambah Pasien</div>
|
|
<AppPatientEntryForm
|
|
ref="personPatientForm"
|
|
:schema="PatientSchema"
|
|
/>
|
|
<div class="h-6"></div>
|
|
<AppPersonAddressEntryForm
|
|
ref="personAddressForm"
|
|
title="Alamat Sekarang"
|
|
:schema="PersonAddressSchema"
|
|
/>
|
|
<div class="h-6"></div>
|
|
<AppPersonAddressEntryFormRelative
|
|
ref="personAddressRelativeForm"
|
|
title="Alamat KTP"
|
|
:schema="PersonAddressRelativeSchema"
|
|
/>
|
|
<div class="h-6"></div>
|
|
<AppPersonFamilyParentsForm
|
|
ref="personFamilyForm"
|
|
title="Identitas Orang Tua"
|
|
:schema="PersonFamiliesSchema"
|
|
/>
|
|
<div class="h-6"></div>
|
|
<AppPersonContactEntryForm
|
|
ref="personContactForm"
|
|
title="Kontak Pasien"
|
|
:contact-limit="10"
|
|
:schema="PersonContactListSchema"
|
|
/>
|
|
<AppPersonRelativeEntryForm
|
|
ref="personEmergencyContactRelative"
|
|
title="Penanggung Jawab"
|
|
:schema="ResponsiblePersonSchema"
|
|
/>
|
|
|
|
<div class="my-2 flex justify-end py-2">
|
|
<Action @click="handleActionClick" />
|
|
</div>
|
|
</template>
|
|
|
|
<style scoped>
|
|
/* component style */
|
|
</style>
|