wip: data masih dead pixel upload sukses
This commit is contained in:
@@ -3,7 +3,7 @@ import type { FormErrors } from '~/types/error'
|
||||
import { toTypedSchema } from '@vee-validate/zod'
|
||||
import { Form } from '~/components/pub/ui/form'
|
||||
import InputBase from '~/components/pub/my-ui/form/input-base.vue'
|
||||
import FileUpload from '~/components/pub/my-ui/form/file-upload.vue'
|
||||
import FileUpload from '~/components/pub/my-ui/form/file-field.vue'
|
||||
import InputName from './_common/input-name.vue'
|
||||
import RadioCommunicationBarrier from './_common/radio-communication-barrier.vue'
|
||||
import RadioDisability from './_common/radio-disability.vue'
|
||||
@@ -144,20 +144,22 @@ defineExpose({
|
||||
</div>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2">
|
||||
<FileUpload
|
||||
field-name="identityCardFile"
|
||||
field-name="residentIdentityFile"
|
||||
label="Dokumen KTP"
|
||||
placeholder="Unggah scan dokumen KTP"
|
||||
:errors="errors"
|
||||
:accept="['pdf', 'jpg', 'png']"
|
||||
:max-size-mb="1"
|
||||
@update:model-value="values.residentIdentityFile = $event"
|
||||
/>
|
||||
<FileUpload
|
||||
field-name="familyCardFile"
|
||||
field-name="familyIdentityFile"
|
||||
label="Dokumen KK"
|
||||
placeholder="Unggah scan dokumen KK"
|
||||
:errors="errors"
|
||||
:accept="['pdf', 'jpg', 'png']"
|
||||
:max-size-mb="1"
|
||||
@update:model-value="values.familyIdentityFile = $event"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -184,19 +184,6 @@ function onClick(type: string) {
|
||||
<DetailRow label="Hubungan">
|
||||
{{ relationshipOptions.find((item) => item.code === relative.relationship_code)?.label || '-' }}
|
||||
</DetailRow>
|
||||
<DetailRow label="Jenis Kelamin">
|
||||
{{ genderOptions.find((item) => item.code === relative.gender_code)?.label || '-' }}
|
||||
</DetailRow>
|
||||
<DetailRow label="Pendidikan">
|
||||
{{ educationOptions.find((item) => item.code === relative.education_code)?.label || '-' }}
|
||||
</DetailRow>
|
||||
<DetailRow label="Pekerjaan">
|
||||
{{
|
||||
occupationOptions.find((item) => item.code === relative.occupation_code)?.label ||
|
||||
relative.occupation_name ||
|
||||
'-'
|
||||
}}
|
||||
</DetailRow>
|
||||
<DetailRow label="Alamat">{{ relative.address || '-' }}</DetailRow>
|
||||
<DetailRow label="Nomor HP">{{ relative.phoneNumber || '-' }}</DetailRow>
|
||||
</template>
|
||||
|
||||
@@ -10,7 +10,8 @@ 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 } from '~/services/patient.service'
|
||||
import { postPatient, uploadAttachment } from '~/services/patient.service'
|
||||
import { uploadCode } from '~/lib/constants'
|
||||
|
||||
// #region Props & Emits
|
||||
const props = defineProps<{
|
||||
@@ -97,13 +98,26 @@ async function sendRequest() {
|
||||
|
||||
try {
|
||||
const result = await postPatient(formData)
|
||||
const patientData: PatientBase = result.body
|
||||
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.person_id)
|
||||
await navigateTo(props.callbackUrl + '?patient-id=' + patientData.id)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -115,7 +129,6 @@ async function sendRequest() {
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error creating patient:', error)
|
||||
// Handle error - show error message to user
|
||||
}
|
||||
}
|
||||
// #endregion region
|
||||
|
||||
+12
-4
@@ -28,6 +28,13 @@ const hintMsg = computed(() => {
|
||||
}
|
||||
return 'Gunakan file yang sesuai'
|
||||
})
|
||||
|
||||
async function onFileChange(event: Event, handleChange: (value: any) => void) {
|
||||
const target = event.target as HTMLInputElement
|
||||
const file = target.files?.[0]
|
||||
|
||||
handleChange(file)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -44,20 +51,21 @@ const hintMsg = computed(() => {
|
||||
:errors="errors"
|
||||
>
|
||||
<FormField
|
||||
v-slot="{ componentField }"
|
||||
v-slot="{ componentField, handleChange }"
|
||||
:name="fieldName"
|
||||
>
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Input
|
||||
<FormControl class="flex flex-col">
|
||||
<input
|
||||
@change="onFileChange($event, handleChange)"
|
||||
type="file"
|
||||
:disabled="isDisabled"
|
||||
v-bind="componentField"
|
||||
:placeholder="placeholder"
|
||||
:class="cn('focus:border-primary focus:ring-2 focus:ring-primary focus:ring-offset-0')"
|
||||
/>
|
||||
<span class="my-2 text-xs">{{ hintMsg }}</span>
|
||||
</FormControl>
|
||||
<span class="my-2 text-xs">{{ hintMsg }}</span>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
@@ -327,7 +327,10 @@ export const uploadCode: Record<string, string> = {
|
||||
kk: 'person-family-card',
|
||||
paspor: 'person-passport',
|
||||
'mcu-report': 'mcu-item-result',
|
||||
}
|
||||
} as const
|
||||
|
||||
export type UploadCodeKey = keyof typeof uploadCode
|
||||
export type UploadCodeValue = (typeof uploadCode)[UploadCodeKey]
|
||||
|
||||
export const infraGroupCodes: Record<string, string> = {
|
||||
building: 'Bangunan',
|
||||
|
||||
@@ -12,6 +12,8 @@ const IsNewBornSchema = z
|
||||
})
|
||||
.transform((val) => val === 'YA')
|
||||
|
||||
const ACCEPTED_UPLOAD_TYPES = ['image/jpeg', 'image/png', 'application/pdf']
|
||||
|
||||
const PatientSchema = z
|
||||
.object({
|
||||
// Data Diri Pasien
|
||||
@@ -21,8 +23,24 @@ const PatientSchema = z
|
||||
// })
|
||||
// .min(16, 'NIK harus berupa angka 16 digit')
|
||||
// .regex(/^\d+$/, 'NIK harus berupa angka 16 digit'),
|
||||
// identityCardFile: z.instanceof(File, { message: 'File KTP harus dipilih' }),
|
||||
// familyCardFile: z.instanceof(File, { message: 'File KK harus dipilih' }),
|
||||
residentIdentityFile: z
|
||||
.any()
|
||||
.optional()
|
||||
.refine((f) => !f || f instanceof File, { message: 'Harus berupa file yang valid' })
|
||||
.refine((f) => !f || ACCEPTED_UPLOAD_TYPES.includes(f.type), {
|
||||
message: 'Format file harus JPG, PNG, atau PDF',
|
||||
})
|
||||
.refine((f) => !f || f.size <= 1 * 1024 * 1024, { message: 'Maksimal 1MB' }),
|
||||
|
||||
familyIdentityFile: z
|
||||
.any()
|
||||
.optional()
|
||||
.refine((f) => !f || f instanceof File, { message: 'Harus berupa file yang valid' })
|
||||
.refine((f) => !f || ACCEPTED_UPLOAD_TYPES.includes(f.type), {
|
||||
message: 'Format file harus JPG, PNG, atau PDF',
|
||||
})
|
||||
.refine((f) => !f || f.size <= 1 * 1024 * 1024, { message: 'Maksimal 1MB' }),
|
||||
// .refine(f => ['image/jpeg', 'image/png'].includes(f.type), 'Hanya JPG/PNG')
|
||||
|
||||
// Informasi Dasar
|
||||
// alias: z.string({
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { xfetch } from '~/composables/useXfetch'
|
||||
import { uploadCode, type UploadCodeKey } from '~/lib/constants'
|
||||
|
||||
const mainUrl = '/api/v1/patient'
|
||||
|
||||
@@ -77,3 +78,30 @@ export async function removePatient(id: number) {
|
||||
throw new Error('Failed to delete patient')
|
||||
}
|
||||
}
|
||||
|
||||
export async function uploadAttachment(file: File, userId: number, key: UploadCodeKey) {
|
||||
try {
|
||||
const resolvedKey = uploadCode[key]
|
||||
if (!resolvedKey) {
|
||||
throw new Error(`Invalid upload code key: ${key}`)
|
||||
}
|
||||
|
||||
// siapkan form-data body
|
||||
const formData = new FormData()
|
||||
formData.append('code', resolvedKey)
|
||||
formData.append('content', file)
|
||||
|
||||
// kirim via xfetch
|
||||
const resp = await xfetch(`${mainUrl}/${userId}/upload`, 'POST', formData)
|
||||
|
||||
// struktur hasil sama seperti patchPatient
|
||||
const result: any = {}
|
||||
result.success = resp.success
|
||||
result.body = (resp.body as Record<string, any>) || {}
|
||||
|
||||
return result
|
||||
} catch (error) {
|
||||
console.error('Error uploading attachment:', error)
|
||||
throw new Error('Failed to upload attachment')
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user