194 lines
5.1 KiB
TypeScript
194 lines
5.1 KiB
TypeScript
// composables/useQueueAPI.ts
|
|
// Composable untuk API calls terkait antrian pasien
|
|
|
|
export interface Patient {
|
|
no: number;
|
|
jamPanggil: string;
|
|
barcode: string;
|
|
noAntrian: string;
|
|
shift: string;
|
|
klinik: string;
|
|
fastTrack: string;
|
|
pembayaran: string;
|
|
status: 'waiting' | 'pending' | 'di-loket' | 'di-klinik' | 'selesai' | 'terlambat';
|
|
processStage: 'loket' | 'klinik' | 'penunjang';
|
|
createdAt: string;
|
|
registrationType?: 'online' | 'onsite';
|
|
visitType?: string;
|
|
visitDate?: string;
|
|
}
|
|
|
|
export interface QueueAPIResponse<T = any> {
|
|
success: boolean;
|
|
data?: T;
|
|
message?: string;
|
|
error?: string;
|
|
}
|
|
|
|
export const useQueueAPI = () => {
|
|
const config = useRuntimeConfig();
|
|
const baseURL = config.public.apiBaseUrl || '/api/queue';
|
|
|
|
/**
|
|
* Fetch all patients from database
|
|
*/
|
|
const fetchAllPatients = async (): Promise<Patient[]> => {
|
|
try {
|
|
const response = await $fetch<QueueAPIResponse<Patient[]>>(`${baseURL}/patients`, {
|
|
method: 'GET',
|
|
});
|
|
|
|
if (response.success && response.data) {
|
|
return response.data;
|
|
}
|
|
throw new Error(response.message || 'Failed to fetch patients');
|
|
} catch (error: any) {
|
|
console.error('❌ Error fetching patients:', error);
|
|
throw error;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Fetch single patient by ID or barcode
|
|
*/
|
|
const fetchPatient = async (idOrBarcode: string): Promise<Patient | null> => {
|
|
try {
|
|
const response = await $fetch<QueueAPIResponse<Patient>>(`${baseURL}/patients/${idOrBarcode}`, {
|
|
method: 'GET',
|
|
});
|
|
|
|
if (response.success && response.data) {
|
|
return response.data;
|
|
}
|
|
return null;
|
|
} catch (error: any) {
|
|
console.error('❌ Error fetching patient:', error);
|
|
return null;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Create new patient (register from Anjungan)
|
|
*/
|
|
const createPatient = async (patientData: Partial<Patient>): Promise<Patient> => {
|
|
try {
|
|
const response = await $fetch<QueueAPIResponse<Patient>>(`${baseURL}/patients`, {
|
|
method: 'POST',
|
|
body: patientData,
|
|
});
|
|
|
|
if (response.success && response.data) {
|
|
return response.data;
|
|
}
|
|
throw new Error(response.message || 'Failed to create patient');
|
|
} catch (error: any) {
|
|
console.error('❌ Error creating patient:', error);
|
|
throw error;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Update patient status (check-in, process, etc)
|
|
*/
|
|
const updatePatient = async (
|
|
idOrBarcode: string,
|
|
updates: Partial<Patient>
|
|
): Promise<Patient> => {
|
|
try {
|
|
const response = await $fetch<QueueAPIResponse<Patient>>(
|
|
`${baseURL}/patients/${idOrBarcode}`,
|
|
{
|
|
method: 'PATCH',
|
|
body: updates,
|
|
}
|
|
);
|
|
|
|
if (response.success && response.data) {
|
|
return response.data;
|
|
}
|
|
throw new Error(response.message || 'Failed to update patient');
|
|
} catch (error: any) {
|
|
console.error('❌ Error updating patient:', error);
|
|
throw error;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Check-in patient (update status to di-loket)
|
|
*/
|
|
const checkInPatient = async (idOrBarcode: string): Promise<Patient> => {
|
|
return updatePatient(idOrBarcode, { status: 'di-loket' });
|
|
};
|
|
|
|
/**
|
|
* Process patient at loket (update status and processStage)
|
|
*/
|
|
const processPatientAtLoket = async (
|
|
idOrBarcode: string,
|
|
updates: { status?: string; processStage?: string }
|
|
): Promise<Patient> => {
|
|
return updatePatient(idOrBarcode, updates);
|
|
};
|
|
|
|
/**
|
|
* Sync local state with database
|
|
*/
|
|
const syncWithDatabase = async (localPatients: Patient[]): Promise<Patient[]> => {
|
|
try {
|
|
// Fetch latest from database
|
|
const dbPatients = await fetchAllPatients();
|
|
|
|
// Merge strategy: prefer database data, but keep local if newer
|
|
const merged = new Map<string, Patient>();
|
|
|
|
// Add database patients
|
|
dbPatients.forEach(patient => {
|
|
merged.set(patient.barcode, patient);
|
|
});
|
|
|
|
// Add local patients that don't exist in DB or are newer
|
|
localPatients.forEach(localPatient => {
|
|
const existing = merged.get(localPatient.barcode);
|
|
if (!existing || new Date(localPatient.createdAt) > new Date(existing.createdAt)) {
|
|
merged.set(localPatient.barcode, localPatient);
|
|
}
|
|
});
|
|
|
|
return Array.from(merged.values());
|
|
} catch (error: any) {
|
|
console.error('❌ Error syncing with database:', error);
|
|
// Return local patients as fallback
|
|
return localPatients;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Batch sync: save multiple patients to database
|
|
*/
|
|
const batchSyncPatients = async (patients: Patient[]): Promise<boolean> => {
|
|
try {
|
|
const response = await $fetch<QueueAPIResponse>(`${baseURL}/patients/batch`, {
|
|
method: 'POST',
|
|
body: { patients },
|
|
});
|
|
|
|
return response.success || false;
|
|
} catch (error: any) {
|
|
console.error('❌ Error batch syncing patients:', error);
|
|
return false;
|
|
}
|
|
};
|
|
|
|
return {
|
|
fetchAllPatients,
|
|
fetchPatient,
|
|
createPatient,
|
|
updatePatient,
|
|
checkInPatient,
|
|
processPatientAtLoket,
|
|
syncWithDatabase,
|
|
batchSyncPatients,
|
|
};
|
|
};
|
|
|