import client from '../client'; import type { PaginatedResponse } from '../types'; // --- Types --- export interface PointsRule { id: string; event_type: string; name: string; description: string | null; points_value: number; daily_cap: number; streak_7d_bonus: number; streak_14d_bonus: number; streak_30d_bonus: number; is_active: boolean; created_at: string; updated_at: string; version: number; } export interface CreatePointsRuleReq { event_type: string; name: string; description?: string; points_value: number; daily_cap?: number; streak_7d_bonus?: number; streak_14d_bonus?: number; streak_30d_bonus?: number; } export interface PointsProduct { id: string; name: string; product_type: string; // physical / service / privilege points_cost: number; stock: number; image_url: string | null; description: string | null; is_active: boolean; sort_order: number; created_at: string; updated_at: string; version: number; } export interface CreatePointsProductReq { name: string; product_type: string; points_cost: number; stock: number; description?: string; image_url?: string; sort_order?: number; } export interface PointsOrder { id: string; patient_id: string; product_id: string; points_cost: number; status: string; // pending / verified / cancelled / expired qr_code: string; verified_by: string | null; verified_at: string | null; expires_at: string | null; notes: string | null; created_at: string; updated_at: string; version: number; } export interface VerifyOrderReq { qr_code: string; } export interface OfflineEvent { id: string; title: string; description: string | null; event_date: string; start_time: string | null; end_time: string | null; location: string | null; points_reward: number; max_participants: number; current_participants: number; status: string; // draft / published / ongoing / completed / cancelled image_url: string | null; created_at: string; updated_at: string; version: number; } export interface CreateOfflineEventReq { title: string; description?: string; event_date: string; start_time?: string; end_time?: string; location?: string; points_reward?: number; max_participants?: number; status?: string; image_url?: string; } export interface PointsStatistics { total_issued: number; total_spent: number; total_expired: number; active_accounts: number; top_earners: Array<{ account_id: string; patient_id: string; total_earned: number; }>; } export interface PatientStatistics { total_patients: number; new_this_month: number; new_this_week: number; active_this_month: number; } export interface ConsultationStatistics { total_sessions: number; pending_reply: number; avg_response_time_minutes: number | null; this_month: number; } export interface FollowUpStatistics { total_tasks: number; completed: number; pending: number; overdue: number; completion_rate: number; } export interface OverviewStatistics { patients: PatientStatistics; consultations: ConsultationStatistics; follow_ups: FollowUpStatistics; points: PointsStatistics; } // --- API --- export const pointsApi = { // Rules listRules: async () => { const { data } = await client.get<{ success: boolean; data: PointsRule[]; }>('/health/admin/points/rules'); return data.data; }, createRule: async (req: CreatePointsRuleReq) => { const { data } = await client.post<{ success: boolean; data: PointsRule; }>('/health/admin/points/rules', req); return data.data; }, // Products listProducts: async (params?: Record) => { const { data } = await client.get<{ success: boolean; data: PaginatedResponse; }>('/health/points/products', { params }); return data.data; }, createProduct: async (req: CreatePointsProductReq) => { const { data } = await client.post<{ success: boolean; data: PointsProduct; }>('/health/admin/points/products', req); return data.data; }, // Orders listOrders: async (params?: Record) => { const { data } = await client.get<{ success: boolean; data: PaginatedResponse; }>('/health/admin/points/orders', { params }); return data.data; }, verifyOrder: async (req: VerifyOrderReq) => { const { data } = await client.post<{ success: boolean; data: PointsOrder; }>('/health/points/verify', req); return data.data; }, // Offline Events listOfflineEvents: async (params?: Record) => { const { data } = await client.get<{ success: boolean; data: PaginatedResponse; }>('/health/admin/offline-events', { params }); return data.data; }, createOfflineEvent: async (req: CreateOfflineEventReq) => { const { data } = await client.post<{ success: boolean; data: OfflineEvent; }>('/health/admin/offline-events', req); return data.data; }, updateOfflineEvent: async (id: string, req: Partial & { version: number }) => { const { data } = await client.put<{ success: boolean; data: OfflineEvent; }>(`/health/admin/offline-events/${id}`, req); return data.data; }, deleteOfflineEvent: async (id: string, version: number) => { await client.delete(`/health/admin/offline-events/${id}`, { data: { version }, }); }, // Points Statistics getStatistics: async () => { const { data } = await client.get<{ success: boolean; data: PointsStatistics; }>('/health/admin/points/statistics'); return data.data; }, // --- Dashboard Statistics (hybrid: aggregate from list endpoints) --- getPatientStats: async (): Promise => { const { data } = await client.get<{ success: boolean; data: PaginatedResponse<{ id: string }>; }>('/health/patients', { params: { page: 1, page_size: 1 } }); const total = data.data?.total || 0; return { total_patients: total, new_this_month: 0, new_this_week: 0, active_this_month: 0 }; }, getConsultationStats: async (): Promise => { const { data } = await client.get<{ success: boolean; data: PaginatedResponse<{ id: string }>; }>('/health/consultation-sessions', { params: { page: 1, page_size: 1 } }); const total = data.data?.total || 0; return { total_sessions: total, pending_reply: 0, avg_response_time_minutes: null, this_month: 0 }; }, getFollowUpStats: async (): Promise => { const { data } = await client.get<{ success: boolean; data: PaginatedResponse<{ id: string }>; }>('/health/follow-up-tasks', { params: { page: 1, page_size: 1 } }); const total = data.data?.total || 0; return { total_tasks: total, completed: 0, pending: 0, overdue: 0, completion_rate: 0 }; }, };