refactor(patient): rename entry component to add and clean up form error props

Remove FormErrors type imports and error props from all form components
Move content from entry.vue to add.vue with updated title styling
This commit is contained in:
Khafid Prayoga
2025-11-24 12:03:53 +07:00
parent 5c60e4e570
commit cd57dc6243
9 changed files with 320 additions and 365 deletions
-23
View File
@@ -1,5 +1,4 @@
<script setup lang="ts">
import type { FormErrors } from '~/types/error'
import { toTypedSchema } from '@vee-validate/zod'
import { Form } from '~/components/pub/ui/form'
@@ -28,7 +27,6 @@ import {
const props = defineProps<{
schema: any
initialValues?: any
errors?: FormErrors
}>()
const formSchema = toTypedSchema(props.schema)
@@ -62,7 +60,6 @@ defineExpose({
field-name="identityNumber"
label="No. KTP"
placeholder="Masukkan NIK"
:errors="errors"
numeric-only
/>
<InputBase
@@ -71,68 +68,58 @@ defineExpose({
placeholder="Masukkan nomor SIM"
numeric-only
:max-length="20"
:errors="errors"
/>
<InputBase
field-name="passportNumber"
label="No. Paspor"
placeholder="Masukkan nomor paspor"
:max-length="20"
:errors="errors"
/>
<InputName
field-name-alias="alias"
field-name-input="fullName"
label-for-input="Nama Lengkap"
placeholder="Masukkan nama lengkap pasien"
:errors="errors"
is-required
/>
<RadioNewborn
field-name="isNewBorn"
label="Pasien Bayi"
placeholder="Pilih status pasien"
:errors="errors"
is-required
/>
<SelectGender
field-name="gender"
label="Jenis Kelamin"
placeholder="Pilih jenis kelamin"
:errors="errors"
is-required
/>
<SelectBirthPlace
field-name="birthPlace"
label="Tempat Lahir"
placeholder="Pilih tempat lahir"
:errors="errors"
is-required
/>
<SelectDob
label="Tanggal Lahir"
:errors="errors"
is-required
/>
<SelectEducation
field-name="education"
label="Pendidikan"
placeholder="Pilih pendidikan"
:errors="errors"
is-required
/>
<SelectJob
field-name="job"
label="Pekerjaan"
placeholder="Pilih pekerjaan"
:errors="errors"
is-required
/>
<SelectMaritalStatus
field-name="maritalStatus"
label="Status Perkawinan"
placeholder="Pilih status Perkawinan"
:errors="errors"
is-required
/>
<DE.Cell />
@@ -140,46 +127,39 @@ defineExpose({
field-name="nationality"
label="Kebangsaan"
placeholder="Pilih kebangsaan"
:errors="errors"
is-required
/>
<SelectEthnicity
field-name="ethnicity"
label="Suku"
placeholder="Pilih suku bangsa"
:errors="errors"
:is-disabled="values.nationality !== 'WNI'"
/>
<SelectLanguage
field-name="language"
label="Bahasa"
placeholder="Pilih preferensi bahasa"
:errors="errors"
is-required
/>
<SelectReligion
field-name="religion"
label="Agama"
placeholder="Pilih agama"
:errors="errors"
is-required
/>
<RadioCommunicationBarrier
field-name="communicationBarrier"
label="Hambatan Berkomunikasi"
:errors="errors"
is-required
/>
<RadioDisability
field-name="disability"
label="Disabilitas"
:errors="errors"
is-required
/>
<SelectDisability
label="Jenis Disabilitas"
field-name="disabilityType"
:errors="errors"
:is-disabled="values.disability !== 'YA'"
:is-required="values.disability === 'YA'"
/>
@@ -187,7 +167,6 @@ defineExpose({
field-name="note"
label="Kepercayaan"
placeholder="Contoh: tidak ingin diperiksa oleh dokter laki-laki"
:errors="errors"
/>
</DE.Block>
@@ -202,7 +181,6 @@ defineExpose({
field-name="identityCardFile"
label="Dokumen KTP"
placeholder="Unggah scan dokumen KTP"
:errors="errors"
:accept="['pdf', 'jpg', 'png']"
:max-size-mb="1"
/>
@@ -210,7 +188,6 @@ defineExpose({
field-name="familyCardFile"
label="Dokumen KK"
placeholder="Unggah scan dokumen KK"
:errors="errors"
:accept="['pdf', 'jpg', 'png']"
:max-size-mb="1"
/>
@@ -1,5 +1,4 @@
<script setup lang="ts">
import type { FormErrors } from '~/types/error'
import { toTypedSchema } from '@vee-validate/zod'
// components
@@ -17,7 +16,6 @@ const props = defineProps<{
}
schema: any
initialValues?: any
errors?: FormErrors
}>()
const formSchema = toTypedSchema(props.schema)
@@ -283,10 +281,7 @@ watch(
>
Apakah alamat KTP sama dengan alamat sekarang?
</DE.Label>
<DE.Field
id="isSameAddress"
:errors="errors"
>
<DE.Field id="isSameAddress">
<FormField
v-slot="{ componentField }"
name="isSameAddress"
@@ -354,7 +349,6 @@ watch(
label="Alamat"
:placeholder="getFieldState('address').placeholder"
:is-disabled="getFieldState('address').disabled"
:errors="errors"
:is-required="values.isSameAddress !== true && values.isSameAddress !== '1'"
:col-span="2"
/>
@@ -362,7 +356,6 @@ watch(
<InputBase
field-name="rt"
label="RT"
:errors="errors"
numeric-only
:max-length="2"
:placeholder="getFieldState('rt').placeholder"
@@ -373,7 +366,6 @@ watch(
label="RW"
:placeholder="getFieldState('rw').placeholder"
:is-disabled="getFieldState('rw').disabled"
:errors="errors"
:max-length="2"
numeric-only
/>
@@ -1,5 +1,4 @@
<script setup lang="ts">
import type { FormErrors } from '~/types/error'
import { toTypedSchema } from '@vee-validate/zod'
// components
@@ -15,7 +14,6 @@ const props = defineProps<{
}
schema: any
initialValues?: any
errors?: FormErrors
}>()
const formSchema = toTypedSchema(props.schema)
@@ -207,7 +205,6 @@ watch(
field-name="address"
label="Alamat"
placeholder="Masukkan alamat"
:errors="errors"
is-required
:col-span="2"
/>
@@ -217,7 +214,6 @@ watch(
field-name="rt"
label="RT"
placeholder="01"
:errors="errors"
numeric-only
:max-length="2"
/>
@@ -225,7 +221,6 @@ watch(
field-name="rw"
label="RW"
placeholder="02"
:errors="errors"
:max-length="2"
numeric-only
/>
@@ -1,5 +1,4 @@
<script setup lang="ts">
import type { FormErrors } from '~/types/error'
import { toTypedSchema } from '@vee-validate/zod'
// components
@@ -13,7 +12,6 @@ const props = defineProps<{
schema: any
contactLimit: number
initialValues?: any
errors?: FormErrors
}>()
const { contactLimit = 5 } = props
@@ -1,5 +1,4 @@
<script setup lang="ts">
import type { FormErrors } from '~/types/error'
import { toTypedSchema } from '@vee-validate/zod'
import { FieldArray } from 'vee-validate'
import InputBase from '~/components/pub/my-ui/form/input-base.vue'
@@ -11,7 +10,6 @@ const props = defineProps<{
title: string
schema: any
initialValues?: any
errors?: FormErrors
}>()
const formSchema = toTypedSchema(props.schema)
@@ -82,7 +80,6 @@ defineExpose({
<SelectContactRelation
:field-name="`contacts[${idx}].relation`"
placeholder="Pilih"
:errors="errors"
field-group-class="mb-0"
/>
</div>
@@ -98,7 +95,6 @@ defineExpose({
label=""
:field-name="`contacts[${idx}].name`"
placeholder="Masukkan Nama"
:errors="errors"
/>
</div>
@@ -113,7 +109,6 @@ defineExpose({
:field-name="`contacts[${idx}].address`"
label=""
placeholder="Masukkan Alamat"
:errors="errors"
/>
</div>
@@ -130,7 +125,6 @@ defineExpose({
placeholder="081234567890"
:max-length="15"
numeric-only
:errors="errors"
/>
</div>
</div>
@@ -1,6 +1,5 @@
<script setup lang="ts">
import type { PersonFamilyFormData as FamilyData } from '~/schemas/person-family.schema'
import type { FormErrors } from '~/types/error'
import { toTypedSchema } from '@vee-validate/zod'
import { FieldArray } from 'vee-validate'
@@ -14,7 +13,6 @@ const props = defineProps<{
title: string
schema: any
initialValues?: any
errors?: FormErrors
}>()
const formSchema = toTypedSchema(props.schema)
@@ -118,7 +116,6 @@ defineExpose({
? 'Masukkan nama ayah pasien'
: 'Masukkan nama'
"
:errors="errors"
is-required
/>
</div>
@@ -134,7 +131,6 @@ defineExpose({
: 'Pendidikan'
"
placeholder="Pilih"
:errors="errors"
/>
</div>
</div>
@@ -156,7 +152,6 @@ defineExpose({
? 'Masukkan pekerjaan ayah'
: 'Masukkan pekerjaan'
"
:errors="errors"
/>
</div>
</div>
+318 -5
View File
@@ -1,9 +1,322 @@
<script setup lang="ts"></script>
<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 xl:text-xl">
<Icon name="i-lucide-user" class="me-2" />
<span class="font-semibold">Tambah</span> Pasien
<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>
<AppPatientEntryForm />
</template>
<style scoped>
/* component style */
</style>
-309
View File
@@ -1,309 +0,0 @@
<script setup lang="ts">
import type { Patient, genPatientProps } from '~/models/patient'
import type { ExposedForm } from '~/types/form'
import type { PatientBase } from '~/models/patient'
import Action from '~/components/pub/my-ui/nav-footer/ba-dr-su.vue'
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'
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(formDataRequest)
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>
+1 -1
View File
@@ -34,7 +34,7 @@ const callbackUrl = route.query['return-path'] as string | undefined
<template>
<div>
<div v-if="canRead">
<ContentPatientEntry :callback-url="callbackUrl" />
<ContentPatientAdd :callback-url="callbackUrl" />
</div>
<Error
v-else