feat(patient): add patient handler and refactor form submission

- Introduce new patient handler using genCrudHandler for CRUD operations
- Refactor patient entry form to use handler for save operations
- Separate form data composition from submission logic
- Handle file uploads and navigation after successful submission
This commit is contained in:
Khafid Prayoga
2025-10-16 14:04:00 +07:00
parent 20b96ab7e4
commit 070239270e
3 changed files with 100 additions and 44 deletions
+63 -42
View File
@@ -10,14 +10,28 @@ 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'
import { postPatient, uploadAttachment } from '~/services/patient.service'
import { uploadCode } from '~/lib/constants'
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 payload = ref<Patient>()
const residentIdentityFile = ref<File>()
const familyCardFile = ref<File>()
// form related state
const personAddressForm = ref<ExposedForm<any> | null>(null)
@@ -65,7 +79,7 @@ onMounted(() => {
// #endregion
// #region Functions
async function sendRequest() {
async function composeFormData(): Promise<Patient> {
const [patient, address, addressRelative, families, contacts, emergencyContact] = await Promise.all([
personPatientForm.value?.validate(),
personAddressForm.value?.validate(),
@@ -81,7 +95,7 @@ async function sendRequest() {
// exit, if form errors happend during validation
// for example: dropdown not selected
if (!allValid) return
if (!allValid) return Promise.reject('Form validation failed')
const formDataRequest: genPatientProps = {
patient: patient?.values,
@@ -93,57 +107,64 @@ async function sendRequest() {
}
const formData = genPatient(formDataRequest)
console.log(formData)
payload.value = formData
try {
const result = await postPatient(formData)
const patientData: PatientBase = result.body.data
if (result.success) {
console.log('Patient created successfully:', patientData)
const createdPatientId = patientData.id
// void run uploadAttachment in background so this try-catch non blocking
// behavior: fire-and-forget
if (patient?.values.residentIdentityFile) {
void uploadAttachment(patient?.values.residentIdentityFile, createdPatientId, 'ktp')
}
if (patient?.values.familyIdentityFile) {
void uploadAttachment(patient?.values.familyIdentityFile, createdPatientId, 'kk')
}
// 30s
await new Promise((r) => setTimeout(r, 30_000))
// If has callback provided redirect to callback with patientData
if (props.callbackUrl) {
await navigateTo(props.callbackUrl + '?patient-id=' + patientData.id)
return
}
// Navigate to patient list or show success message
await navigateTo('/client/patient')
} else {
console.error('Failed to create patient:', result)
// Handle error - show error message to user
}
} catch (error) {
console.error('Error creating patient:', error)
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') {
await sendRequest()
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') {
navigateTo({
if (props.callbackUrl) {
await navigateTo(props.callbackUrl)
return
}
await navigateTo({
name: 'client-patient',
})
// handleCancelForm()
}
}
// #endregion