import AsyncStorage from '@react-native-async-storage/async-storage'; import NetInfo from '@react-native-community/netinfo'; import Constants from 'expo-constants'; import * as Device from 'expo-device'; import { Platform } from 'react-native'; import { ConstEnv } from '@/constants/ConstEnv'; const QUEUE_KEY = 'error_log_queue'; const APP_NAME = 'desa-plus'; type ErrorPayload = { affectedVersion: string; device: string; os: string; description: string; app: string; source: 'SYSTEM'; stackTrace: string; }; function buildPayload(description: string, stackTrace?: string): ErrorPayload { const platformName = Platform.OS === 'ios' ? 'iOS' : 'Android'; return { affectedVersion: Constants.expoConfig?.version ?? 'unknown', device: Device.modelName ?? 'unknown', os: `${platformName} ${Device.osVersion ?? ''}`.trim(), description, app: APP_NAME, source: 'SYSTEM', stackTrace: stackTrace ?? '', }; } async function sendToMonitoring(payload: ErrorPayload): Promise { try { const res = await fetch(`${ConstEnv.url_monitoring}/api/bugs`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-API-Key': ConstEnv.key_api_monitoring ?? '', }, body: JSON.stringify(payload), }); return res.ok; } catch (error) { console.log(error); return false; } } async function enqueue(payload: ErrorPayload): Promise { try { const raw = await AsyncStorage.getItem(QUEUE_KEY); const queue: ErrorPayload[] = raw ? JSON.parse(raw) : []; queue.push(payload); await AsyncStorage.setItem(QUEUE_KEY, JSON.stringify(queue)); } catch {} } export async function flushErrorQueue(): Promise { try { const state = await NetInfo.fetch(); if (!state.isConnected) return; const raw = await AsyncStorage.getItem(QUEUE_KEY); if (!raw) return; const queue: ErrorPayload[] = JSON.parse(raw); if (queue.length === 0) return; const failed: ErrorPayload[] = []; for (const payload of queue) { const ok = await sendToMonitoring(payload); if (!ok) failed.push(payload); } if (failed.length > 0) { await AsyncStorage.setItem(QUEUE_KEY, JSON.stringify(failed)); } else { await AsyncStorage.removeItem(QUEUE_KEY); } } catch {} } export async function logError(description: string, error?: Error | unknown): Promise { const stackTrace = error instanceof Error ? (error.stack ?? error.message) : String(error ?? ''); const payload = buildPayload(description, stackTrace); try { const state = await NetInfo.fetch(); if (state.isConnected) { const ok = await sendToMonitoring(payload); if (!ok) await enqueue(payload); } else { await enqueue(payload); } } catch { await enqueue(payload); } }