204 lines
6.3 KiB
TypeScript
204 lines
6.3 KiB
TypeScript
import { ref, readonly } from 'vue'
|
|
import type { CheckInResult } from '~/types/checkin'
|
|
|
|
export interface UseCheckInOptions {
|
|
showSnackbar: (title: string, message: string, color: string, icon: string) => void
|
|
saveToHistory: (item: {
|
|
patientId: string
|
|
queueNumber?: string
|
|
status: string
|
|
checkInTime: string
|
|
checkInDate: string
|
|
method: string
|
|
}) => void
|
|
saveSuccessfulScan: (qrData: string) => void
|
|
onCheckInSuccess: (result: {
|
|
success: boolean
|
|
patientId: string
|
|
status: string
|
|
message: string
|
|
action: 'checkin' | 'kembali'
|
|
}) => void
|
|
autoCloseDialog: () => void
|
|
}
|
|
|
|
export const useCheckIn = (options: UseCheckInOptions) => {
|
|
const { showSnackbar, saveToHistory, saveSuccessfulScan, onCheckInSuccess, autoCloseDialog } = options
|
|
|
|
// State
|
|
const lastCheckInResult = ref<CheckInResult | null>(null)
|
|
|
|
// Perform check-in
|
|
const performCheckIn = async (data: string, method: string = 'QR Scan'): Promise<boolean> => {
|
|
await new Promise(resolve => setTimeout(resolve, 1000))
|
|
const success = Math.random() < 0.8
|
|
|
|
// History akan disimpan di processQRCode setelah performCheckIn selesai
|
|
// Jadi kita hanya perlu return hasil check-in
|
|
return success
|
|
}
|
|
|
|
// Process QR code (rename dari onDetect)
|
|
const processQRCode = async (decodedText: string) => {
|
|
const [patientId, status] = decodedText.split('|')
|
|
|
|
// Validasi format QR code
|
|
if (!patientId || !status) {
|
|
showSnackbar('Error', 'QR Code tidak valid. Format harus: ID_PASIEN|STATUS', 'error', 'mdi-close-circle')
|
|
return
|
|
}
|
|
|
|
// Cek apakah pasien diperbolehkan check-in
|
|
const isAllowed = status === 'ALLOWED'
|
|
|
|
if (isAllowed) {
|
|
// Jika diperbolehkan, langsung proses check-in
|
|
const checkinSuccess = await performCheckIn(decodedText, 'QR Scan')
|
|
|
|
// Simpan hasil check-in
|
|
lastCheckInResult.value = {
|
|
success: checkinSuccess,
|
|
patientId: patientId,
|
|
status: status
|
|
}
|
|
|
|
// Simpan ke history check-in dengan status hasil check-in
|
|
saveToHistory({
|
|
patientId: patientId || 'Unknown',
|
|
status: checkinSuccess ? 'success' : 'failed',
|
|
checkInTime: new Date().toISOString(),
|
|
checkInDate: new Date().toISOString(),
|
|
method: 'QR Scan'
|
|
})
|
|
|
|
// Tampilkan dialog dengan hasil check-in
|
|
if (checkinSuccess) {
|
|
// Simpan QR code yang berhasil di-scan untuk mencegah scan ulang
|
|
saveSuccessfulScan(decodedText)
|
|
onCheckInSuccess({
|
|
success: true,
|
|
patientId: patientId,
|
|
status: status,
|
|
message: `✅ Check-in Berhasil!\n\nPasien ${patientId} berhasil melakukan check-in.`,
|
|
action: 'checkin'
|
|
})
|
|
} else {
|
|
onCheckInSuccess({
|
|
success: false,
|
|
patientId: patientId,
|
|
status: status,
|
|
message: `❌ Check-in Gagal!\n\nPasien ${patientId} diperbolehkan check-in, namun proses check-in gagal. Silakan coba lagi.`,
|
|
action: 'checkin'
|
|
})
|
|
}
|
|
|
|
autoCloseDialog()
|
|
} else {
|
|
// Jika belum diperbolehkan, tampilkan pesan
|
|
lastCheckInResult.value = {
|
|
success: false,
|
|
patientId: patientId,
|
|
status: status
|
|
}
|
|
|
|
// Simpan ke history check-in untuk NOT_ALLOWED
|
|
saveToHistory({
|
|
patientId: patientId || 'Unknown',
|
|
status: 'NOT_ALLOWED',
|
|
checkInTime: new Date().toISOString(),
|
|
checkInDate: new Date().toISOString(),
|
|
method: 'QR Scan'
|
|
})
|
|
|
|
onCheckInSuccess({
|
|
success: false,
|
|
patientId: patientId,
|
|
status: status,
|
|
message: `⏳ Belum Diizinkan Check-in\n\nAntrean Pasien ${patientId} belum diperbolehkan check-in. Mohon menunggu hingga antrean Anda dipanggil.`,
|
|
action: 'kembali'
|
|
})
|
|
|
|
autoCloseDialog()
|
|
}
|
|
}
|
|
|
|
// Check-in manual
|
|
const checkInManual = async (
|
|
patientId: string,
|
|
onSuccess: () => void,
|
|
onError: () => void
|
|
) => {
|
|
try {
|
|
if (!patientId || !patientId.trim()) {
|
|
showSnackbar('Error', 'Mohon isi nomor antrean atau ID pasien', 'error', 'mdi-alert')
|
|
onError()
|
|
return
|
|
}
|
|
|
|
const trimmedPatientId = patientId.trim()
|
|
|
|
// Simulasi check-in manual
|
|
const success = await performCheckIn(`${trimmedPatientId}|ALLOWED`, 'Manual')
|
|
|
|
// Simpan hasil check-in
|
|
lastCheckInResult.value = {
|
|
success: success,
|
|
patientId: trimmedPatientId,
|
|
status: 'ALLOWED',
|
|
}
|
|
|
|
// Simpan ke history check-in
|
|
saveToHistory({
|
|
patientId: trimmedPatientId,
|
|
status: success ? 'success' : 'failed',
|
|
checkInTime: new Date().toISOString(),
|
|
checkInDate: new Date().toISOString(),
|
|
method: 'Manual'
|
|
})
|
|
|
|
if (success) {
|
|
// Simpan QR code yang berhasil untuk mencegah double antrian (jika menggunakan format yang sama)
|
|
saveSuccessfulScan(`${trimmedPatientId}|ALLOWED`)
|
|
showSnackbar('Berhasil!', 'Check-in manual berhasil dilakukan.', 'success', 'mdi-check-circle')
|
|
|
|
// Update info dialog
|
|
onCheckInSuccess({
|
|
success: true,
|
|
patientId: trimmedPatientId,
|
|
status: 'ALLOWED',
|
|
message: `✅ Check-in Berhasil!\n\nPasien ${trimmedPatientId} berhasil melakukan check-in secara manual.`,
|
|
action: 'checkin'
|
|
})
|
|
|
|
autoCloseDialog()
|
|
onSuccess()
|
|
} else {
|
|
showSnackbar('Gagal!', 'Check-in manual gagal dilakukan. Silakan coba lagi!', 'error', 'mdi-close-circle')
|
|
|
|
// Update info dialog untuk gagal
|
|
onCheckInSuccess({
|
|
success: false,
|
|
patientId: trimmedPatientId,
|
|
status: 'ALLOWED',
|
|
message: `❌ Check-in Gagal!\n\nPasien ${trimmedPatientId} gagal melakukan check-in secara manual. Silakan coba lagi.`,
|
|
action: 'checkin'
|
|
})
|
|
|
|
autoCloseDialog()
|
|
onError()
|
|
}
|
|
} catch (error) {
|
|
console.error('Error in checkInManual:', error)
|
|
showSnackbar('Error', 'Terjadi kesalahan saat melakukan check-in. Silakan coba lagi.', 'error', 'mdi-alert')
|
|
onError()
|
|
}
|
|
}
|
|
|
|
return {
|
|
lastCheckInResult: readonly(lastCheckInResult),
|
|
performCheckIn,
|
|
processQRCode,
|
|
checkInManual,
|
|
}
|
|
}
|