diff --git a/apps/web/src/api/health/appointments.ts b/apps/web/src/api/health/appointments.ts new file mode 100644 index 0000000..b2832b2 --- /dev/null +++ b/apps/web/src/api/health/appointments.ts @@ -0,0 +1,160 @@ +import client from '../client'; +import type { PaginatedResponse } from '../types'; + +// --- Types --- +export interface Appointment { + id: string; + patient_id: string; + doctor_id?: string; + appointment_type: string; + appointment_date: string; + start_time: string; + end_time: string; + status: string; + cancel_reason?: string; + notes?: string; + created_at: string; + updated_at: string; + version: number; +} + +export interface CreateAppointmentReq { + patient_id: string; + doctor_id?: string; + appointment_type?: string; + appointment_date: string; + start_time: string; + end_time: string; + notes?: string; +} + +export interface UpdateAppointmentStatusReq { + status: string; + cancel_reason?: string; +} + +export interface Schedule { + id: string; + doctor_id: string; + schedule_date: string; + period_type: string; + start_time: string; + end_time: string; + max_appointments: number; + current_appointments: number; + status: string; + created_at: string; + updated_at: string; + version: number; +} + +export interface CreateScheduleReq { + doctor_id: string; + schedule_date: string; + period_type?: string; + start_time: string; + end_time: string; + max_appointments: number; +} + +export interface UpdateScheduleReq { + start_time?: string; + end_time?: string; + max_appointments?: number; + status?: string; +} + +export interface CalendarDay { + date: string; + schedules: Schedule[]; +} + +// --- API --- +export const appointmentApi = { + list: async (params: { + page?: number; + page_size?: number; + status?: string; + patient_id?: string; + doctor_id?: string; + date?: string; + }) => { + const { data } = await client.get<{ + success: boolean; + data: PaginatedResponse; + }>('/health/appointments', { params }); + return data.data; + }, + + get: async (id: string) => { + const { data } = await client.get<{ + success: boolean; + data: Appointment; + }>(`/health/appointments/${id}`); + return data.data; + }, + + create: async (req: CreateAppointmentReq) => { + const { data } = await client.post<{ + success: boolean; + data: Appointment; + }>('/health/appointments', req); + return data.data; + }, + + updateStatus: async ( + id: string, + req: UpdateAppointmentStatusReq & { version: number }, + ) => { + const { data } = await client.put<{ + success: boolean; + data: Appointment; + }>(`/health/appointments/${id}/status`, req); + return data.data; + }, + + // Schedules + listSchedules: async (params: { + page?: number; + page_size?: number; + doctor_id?: string; + date?: string; + }) => { + const { data } = await client.get<{ + success: boolean; + data: PaginatedResponse; + }>('/health/doctor-schedules', { params }); + return data.data; + }, + + createSchedule: async (req: CreateScheduleReq) => { + const { data } = await client.post<{ + success: boolean; + data: Schedule; + }>('/health/doctor-schedules', req); + return data.data; + }, + + updateSchedule: async ( + id: string, + req: UpdateScheduleReq & { version: number }, + ) => { + const { data } = await client.put<{ + success: boolean; + data: Schedule; + }>(`/health/doctor-schedules/${id}`, req); + return data.data; + }, + + calendar: async (params: { + start_date: string; + end_date: string; + doctor_id?: string; + }) => { + const { data } = await client.get<{ + success: boolean; + data: CalendarDay[]; + }>('/health/doctor-schedules/calendar', { params }); + return data.data; + }, +}; diff --git a/apps/web/src/api/health/consultations.ts b/apps/web/src/api/health/consultations.ts new file mode 100644 index 0000000..8ebc2dc --- /dev/null +++ b/apps/web/src/api/health/consultations.ts @@ -0,0 +1,107 @@ +import client from '../client'; +import type { PaginatedResponse } from '../types'; + +// --- Types --- +export interface Session { + id: string; + patient_id: string; + doctor_id?: string; + consultation_type: string; + status: string; + last_message_at?: string; + unread_count_patient: number; + unread_count_doctor: number; + created_at: string; +} + +export interface CreateSessionReq { + patient_id: string; + doctor_id?: string; + consultation_type?: string; +} + +export interface Message { + id: string; + session_id: string; + sender_id: string; + sender_role: string; + content_type: string; + content: string; + is_read: boolean; + created_at: string; +} + +export interface CreateMessageReq { + session_id: string; + sender_id: string; + sender_role: string; + content_type?: string; + content: string; +} + +// --- API --- +export const consultationApi = { + listSessions: async (params: { + page?: number; + page_size?: number; + status?: string; + patient_id?: string; + doctor_id?: string; + }) => { + const { data } = await client.get<{ + success: boolean; + data: PaginatedResponse; + }>('/health/consultation-sessions', { params }); + return data.data; + }, + + createSession: async (req: CreateSessionReq) => { + const { data } = await client.post<{ + success: boolean; + data: Session; + }>('/health/consultation-sessions', req); + return data.data; + }, + + closeSession: async ( + id: string, + req: { version: number }, + ) => { + const { data } = await client.put<{ + success: boolean; + data: Session; + }>(`/health/consultation-sessions/${id}/close`, req); + return data.data; + }, + + listMessages: async ( + sessionId: string, + params: { page?: number; page_size?: number }, + ) => { + const { data } = await client.get<{ + success: boolean; + data: PaginatedResponse; + }>(`/health/consultation-sessions/${sessionId}/messages`, { params }); + return data.data; + }, + + createMessage: async (req: CreateMessageReq) => { + const { data } = await client.post<{ + success: boolean; + data: Message; + }>('/health/consultation-messages', req); + return data.data; + }, + + exportSessions: async (params: { + status?: string; + patient_id?: string; + doctor_id?: string; + }) => { + const { data } = await client.get<{ + success: boolean; + data: Session[]; + }>('/health/consultation-sessions/export', { params }); + return data.data; + }, +}; diff --git a/apps/web/src/api/health/doctors.ts b/apps/web/src/api/health/doctors.ts new file mode 100644 index 0000000..582e9d2 --- /dev/null +++ b/apps/web/src/api/health/doctors.ts @@ -0,0 +1,83 @@ +import client from '../client'; +import type { PaginatedResponse } from '../types'; + +// --- Types --- +export interface Doctor { + id: string; + user_id?: string; + name: string; + department?: string; + title?: string; + specialty?: string; + license_number?: string; + bio?: string; + online_status: string; + created_at: string; + updated_at: string; + version: number; +} + +export interface CreateDoctorReq { + user_id?: string; + name: string; + department?: string; + title?: string; + specialty?: string; + license_number?: string; + bio?: string; +} + +export interface UpdateDoctorReq { + name?: string; + department?: string; + title?: string; + specialty?: string; + license_number?: string; + bio?: string; + online_status?: string; +} + +// --- API --- +export const doctorApi = { + list: async (params: { + page?: number; + page_size?: number; + search?: string; + department?: string; + title?: string; + }) => { + const { data } = await client.get<{ + success: boolean; + data: PaginatedResponse; + }>('/health/doctors', { params }); + return data.data; + }, + + get: async (id: string) => { + const { data } = await client.get<{ + success: boolean; + data: Doctor; + }>(`/health/doctors/${id}`); + return data.data; + }, + + create: async (req: CreateDoctorReq) => { + const { data } = await client.post<{ + success: boolean; + data: Doctor; + }>('/health/doctors', req); + return data.data; + }, + + update: async (id: string, req: UpdateDoctorReq & { version: number }) => { + const { data } = await client.put<{ + success: boolean; + data: Doctor; + }>(`/health/doctors/${id}`, req); + return data.data; + }, + + delete: async (id: string) => { + await client.delete(`/health/doctors/${id}`); + }, +}; diff --git a/apps/web/src/api/health/followUp.ts b/apps/web/src/api/health/followUp.ts new file mode 100644 index 0000000..eee6215 --- /dev/null +++ b/apps/web/src/api/health/followUp.ts @@ -0,0 +1,131 @@ +import client from '../client'; +import type { PaginatedResponse } from '../types'; + +// --- Types --- +export interface FollowUpTask { + id: string; + patient_id: string; + assigned_to?: string; + follow_up_type: string; + planned_date: string; + status: string; + content_template?: string; + related_appointment_id?: string; + created_at: string; + updated_at: string; + version: number; +} + +export interface CreateFollowUpTaskReq { + patient_id: string; + assigned_to?: string; + follow_up_type: string; + planned_date: string; + content_template?: string; + related_appointment_id?: string; +} + +export interface UpdateFollowUpTaskReq { + assigned_to?: string; + follow_up_type?: string; + planned_date?: string; + content_template?: string; + status?: string; +} + +export interface FollowUpRecord { + id: string; + task_id: string; + executed_by?: string; + executed_date: string; + result?: string; + patient_condition?: string; + medical_advice?: string; + next_follow_up_date?: string; + created_at: string; + updated_at: string; + version: number; +} + +export interface CreateFollowUpRecordReq { + task_id: string; + executed_by?: string; + executed_date: string; + result?: string; + patient_condition?: string; + medical_advice?: string; + next_follow_up_date?: string; +} + +// --- API --- +export const followUpApi = { + // Tasks + listTasks: async (params: { + page?: number; + page_size?: number; + patient_id?: string; + assigned_to?: string; + status?: string; + }) => { + const { data } = await client.get<{ + success: boolean; + data: PaginatedResponse; + }>('/health/follow-up-tasks', { params }); + return data.data; + }, + + getTask: async (id: string) => { + const { data } = await client.get<{ + success: boolean; + data: FollowUpTask; + }>(`/health/follow-up-tasks/${id}`); + return data.data; + }, + + createTask: async (req: CreateFollowUpTaskReq) => { + const { data } = await client.post<{ + success: boolean; + data: FollowUpTask; + }>('/health/follow-up-tasks', req); + return data.data; + }, + + updateTask: async ( + id: string, + req: UpdateFollowUpTaskReq & { version: number }, + ) => { + const { data } = await client.put<{ + success: boolean; + data: FollowUpTask; + }>(`/health/follow-up-tasks/${id}`, req); + return data.data; + }, + + deleteTask: async (id: string, version: number) => { + await client.delete(`/health/follow-up-tasks/${id}`, { + data: { version }, + }); + }, + + // Records + listRecords: async (params: { + page?: number; + page_size?: number; + task_id?: string; + patient_id?: string; + }) => { + const { data } = await client.get<{ + success: boolean; + data: PaginatedResponse; + }>('/health/follow-up-records', { params }); + return data.data; + }, + + createRecord: async (taskId: string, req: Omit) => { + const { data } = await client.post<{ + success: boolean; + data: FollowUpRecord; + }>(`/health/follow-up-tasks/${taskId}/records`, { ...req, task_id: taskId }); + return data.data; + }, +}; diff --git a/apps/web/src/api/health/healthData.ts b/apps/web/src/api/health/healthData.ts new file mode 100644 index 0000000..4e820fc --- /dev/null +++ b/apps/web/src/api/health/healthData.ts @@ -0,0 +1,240 @@ +import client from '../client'; +import type { PaginatedResponse } from '../types'; + +// --- Types --- +export interface VitalSigns { + id: string; + patient_id: string; + record_date: string; + systolic_bp_morning?: number; + diastolic_bp_morning?: number; + systolic_bp_evening?: number; + diastolic_bp_evening?: number; + heart_rate?: number; + weight?: number; + blood_sugar?: number; + water_intake_ml?: number; + urine_output_ml?: number; + notes?: string; + created_at: string; + updated_at: string; + version: number; +} + +export interface CreateVitalSignsReq { + record_date: string; + systolic_bp_morning?: number; + diastolic_bp_morning?: number; + systolic_bp_evening?: number; + diastolic_bp_evening?: number; + heart_rate?: number; + weight?: number; + blood_sugar?: number; + water_intake_ml?: number; + urine_output_ml?: number; + notes?: string; +} + +export interface LabReport { + id: string; + patient_id: string; + report_date: string; + report_type: string; + indicators?: Record; + image_urls?: string[]; + doctor_interpretation?: string; + created_at: string; + updated_at: string; + version: number; +} + +export interface CreateLabReportReq { + report_date: string; + report_type: string; + indicators?: Record; + image_urls?: string[]; + doctor_interpretation?: string; +} + +export interface HealthRecord { + id: string; + patient_id: string; + record_type: string; + record_date: string; + content?: string; + attachment_urls?: string[]; + created_at: string; + updated_at: string; + version: number; +} + +export interface CreateHealthRecordReq { + record_type: string; + record_date: string; + content?: string; + attachment_urls?: string[]; +} + +export interface TrendData { + id: string; + patient_id: string; + indicator: string; + trend_data: { date: string; value: number }[]; + generated_at: string; +} + +// --- API --- +export const healthDataApi = { + // Vital Signs + listVitalSigns: async ( + patientId: string, + params: { page?: number; page_size?: number }, + ) => { + const { data } = await client.get<{ + success: boolean; + data: PaginatedResponse; + }>(`/health/patients/${patientId}/vital-signs`, { params }); + return data.data; + }, + + createVitalSigns: async (patientId: string, req: CreateVitalSignsReq) => { + const { data } = await client.post<{ + success: boolean; + data: VitalSigns; + }>(`/health/patients/${patientId}/vital-signs`, req); + return data.data; + }, + + updateVitalSigns: async ( + patientId: string, + id: string, + req: Partial & { version: number }, + ) => { + const { data } = await client.put<{ + success: boolean; + data: VitalSigns; + }>(`/health/patients/${patientId}/vital-signs/${id}`, req); + return data.data; + }, + + deleteVitalSigns: async (patientId: string, id: string) => { + await client.delete(`/health/patients/${patientId}/vital-signs/${id}`); + }, + + // Lab Reports + listLabReports: async ( + patientId: string, + params: { page?: number; page_size?: number }, + ) => { + const { data } = await client.get<{ + success: boolean; + data: PaginatedResponse; + }>(`/health/patients/${patientId}/lab-reports`, { params }); + return data.data; + }, + + createLabReport: async (patientId: string, req: CreateLabReportReq) => { + const { data } = await client.post<{ + success: boolean; + data: LabReport; + }>(`/health/patients/${patientId}/lab-reports`, req); + return data.data; + }, + + updateLabReport: async ( + patientId: string, + id: string, + req: Partial & { version: number }, + ) => { + const { data } = await client.put<{ + success: boolean; + data: LabReport; + }>(`/health/patients/${patientId}/lab-reports/${id}`, req); + return data.data; + }, + + deleteLabReport: async (patientId: string, id: string) => { + await client.delete(`/health/patients/${patientId}/lab-reports/${id}`); + }, + + // Health Records + listHealthRecords: async ( + patientId: string, + params: { page?: number; page_size?: number }, + ) => { + const { data } = await client.get<{ + success: boolean; + data: PaginatedResponse; + }>(`/health/patients/${patientId}/health-records`, { params }); + return data.data; + }, + + createHealthRecord: async ( + patientId: string, + req: CreateHealthRecordReq, + ) => { + const { data } = await client.post<{ + success: boolean; + data: HealthRecord; + }>(`/health/patients/${patientId}/health-records`, req); + return data.data; + }, + + updateHealthRecord: async ( + patientId: string, + id: string, + req: Partial & { version: number }, + ) => { + const { data } = await client.put<{ + success: boolean; + data: HealthRecord; + }>(`/health/patients/${patientId}/health-records/${id}`, req); + return data.data; + }, + + deleteHealthRecord: async (patientId: string, id: string) => { + await client.delete(`/health/patients/${patientId}/health-records/${id}`); + }, + + // Trends + listTrends: async (patientId: string) => { + const { data } = await client.get<{ + success: boolean; + data: TrendData[]; + }>(`/health/patients/${patientId}/trends`); + return data.data; + }, + + generateTrend: async (patientId: string) => { + const { data } = await client.post<{ + success: boolean; + data: TrendData[]; + }>(`/health/patients/${patientId}/trends/generate`); + return data.data; + }, + + getIndicatorTimeseries: async (patientId: string, indicator: string) => { + const { data } = await client.get<{ + success: boolean; + data: { date: string; value: number }[]; + }>(`/health/patients/${patientId}/trends/${encodeURIComponent(indicator)}`); + return data.data; + }, + + // Mini program endpoints + getMiniTrend: async (params: { indicator?: string; days?: number }) => { + const { data } = await client.get<{ + success: boolean; + data: { date: string; value: number }[]; + }>('/health/vital-signs/trend', { params }); + return data.data; + }, + + getMiniToday: async () => { + const { data } = await client.get<{ + success: boolean; + data: VitalSigns | null; + }>('/health/vital-signs/today'); + return data.data; + }, +}; diff --git a/apps/web/src/api/health/patients.ts b/apps/web/src/api/health/patients.ts new file mode 100644 index 0000000..857aca2 --- /dev/null +++ b/apps/web/src/api/health/patients.ts @@ -0,0 +1,182 @@ +import client from '../client'; +import type { PaginatedResponse } from '../types'; + +// --- Types --- +export interface PatientListItem { + id: string; + name: string; + gender?: string; + birth_date?: string; + blood_type?: string; + status: string; + verification_status: string; + source?: string; + created_at: string; + updated_at: string; +} + +export interface PatientDetail { + id: string; + user_id?: string; + name: string; + gender?: string; + birth_date?: string; + blood_type?: string; + id_number?: string; + allergy_history?: string; + medical_history_summary?: string; + emergency_contact_name?: string; + emergency_contact_phone?: string; + status: string; + verification_status: string; + source?: string; + notes?: string; + created_at: string; + updated_at: string; + version: number; +} + +export interface CreatePatientReq { + name: string; + gender?: string; + birth_date?: string; + blood_type?: string; + id_number?: string; + allergy_history?: string; + medical_history_summary?: string; + emergency_contact_name?: string; + emergency_contact_phone?: string; + source?: string; + notes?: string; +} + +export interface UpdatePatientReq extends Partial { + status?: string; + verification_status?: string; +} + +export interface FamilyMember { + id: string; + name: string; + relationship: string; + phone?: string; + id_number?: string; + notes?: string; + created_at: string; + updated_at: string; + version: number; +} + +export interface CreateFamilyMemberReq { + name: string; + relationship: string; + phone?: string; + id_number?: string; + notes?: string; +} + +// --- API --- +export const patientApi = { + list: async (params: { + page?: number; + page_size?: number; + search?: string; + status?: string; + tag_id?: string; + }) => { + const { data } = await client.get<{ + success: boolean; + data: PaginatedResponse; + }>('/health/patients', { params }); + return data.data; + }, + + get: async (id: string) => { + const { data } = await client.get<{ + success: boolean; + data: PatientDetail; + }>(`/health/patients/${id}`); + return data.data; + }, + + create: async (req: CreatePatientReq) => { + const { data } = await client.post<{ + success: boolean; + data: PatientDetail; + }>('/health/patients', req); + return data.data; + }, + + update: async (id: string, req: UpdatePatientReq & { version: number }) => { + const { data } = await client.put<{ + success: boolean; + data: PatientDetail; + }>(`/health/patients/${id}`, req); + return data.data; + }, + + delete: async (id: string, version: number) => { + await client.delete(`/health/patients/${id}`, { data: { version } }); + }, + + manageTags: async (id: string, tagIds: string[]) => { + await client.post(`/health/patients/${id}/tags`, { tag_ids: tagIds }); + }, + + getHealthSummary: async (id: string) => { + const { data } = await client.get<{ + success: boolean; + data: Record; + }>(`/health/patients/${id}/health-summary`); + return data.data; + }, + + listFamilyMembers: async (id: string) => { + const { data } = await client.get<{ + success: boolean; + data: FamilyMember[]; + }>(`/health/patients/${id}/family-members`); + return data.data; + }, + + createFamilyMember: async (id: string, req: CreateFamilyMemberReq) => { + const { data } = await client.post<{ + success: boolean; + data: FamilyMember; + }>(`/health/patients/${id}/family-members`, req); + return data.data; + }, + + updateFamilyMember: async ( + patientId: string, + memberId: string, + req: Partial & { version: number }, + ) => { + const { data } = await client.put<{ + success: boolean; + data: FamilyMember; + }>(`/health/patients/${patientId}/family-members/${memberId}`, req); + return data.data; + }, + + deleteFamilyMember: async (patientId: string, memberId: string) => { + await client.delete( + `/health/patients/${patientId}/family-members/${memberId}`, + ); + }, + + assignDoctor: async ( + id: string, + doctorId: string, + relationshipType: string, + ) => { + await client.post(`/health/patients/${id}/doctors`, { + doctor_id: doctorId, + relationship_type: relationshipType, + }); + }, + + removeDoctor: async (id: string, doctorId: string) => { + await client.delete(`/health/patients/${id}/doctors/${doctorId}`); + }, +};