import AsyncStorage from '@react-native-async-storage/async-storage'; import { API_CONFIG } from '../constants/api'; class AuthService { async getStoredToken() { try { return await AsyncStorage.getItem('auth_token'); } catch (error) { return null; } } async makeRequest(endpoint, data, requiresAuth = false, method = 'POST') { const fullUrl = `${API_CONFIG.BASE_URL}${endpoint}`; const requestId = Math.random().toString(36).substr(2, 9); try { const headers = { ...API_CONFIG.HEADERS }; // Determine body and adjust headers for FormData let bodyToSend; if (data instanceof FormData) { bodyToSend = data; // Let fetch set correct Content-Type with boundary if (headers['Content-Type']) delete headers['Content-Type']; } else { bodyToSend = data ? JSON.stringify(data) : undefined; } // Auto-include token for authenticated requests if (requiresAuth) { const token = await this.getStoredToken(); if (token) { headers.Authorization = `Bearer ${token}`; } } // Log request details console.log(`\nπŸš€ [${requestId}] API REQUEST`); console.log(`πŸ“ URL: ${method} ${fullUrl}`); console.log(`πŸ” Auth Required: ${requiresAuth}`); console.log(`πŸ“ Headers:`, { ...headers, Authorization: headers.Authorization ? `Bearer ${headers.Authorization.slice(-10)}...` : 'None' }); if (data) { console.log(`πŸ“¦ Body:`, data); } console.log(`⏰ Time: ${new Date().toISOString()}`); const startTime = Date.now(); const response = await fetch(fullUrl, { method, headers, body: bodyToSend, }); const endTime = Date.now(); const duration = endTime - startTime; const result = await response.json(); // Log response details console.log(`\nβœ… [${requestId}] API RESPONSE`); console.log(`πŸ“Š Status: ${response.status} ${response.statusText}`); console.log(`⏱️ Duration: ${duration}ms`); console.log(`πŸ“„ Response:`, result); if (!response.ok) { console.log(`❌ [${requestId}] API ERROR`); console.log(`πŸ”΄ Status: ${response.status}`); console.log(`πŸ’¬ Error Message:`, result.message || 'Unknown error'); // Handle token expiration if (response.status === 401 && requiresAuth) { console.log(`πŸ”“ [${requestId}] TOKEN EXPIRED - Clearing storage`); await AsyncStorage.removeItem('auth_token'); await AsyncStorage.removeItem('user_data'); throw new Error('Session expired. Please login again.'); } throw new Error(result.message || 'An error occurred'); } console.log(`✨ [${requestId}] REQUEST COMPLETED SUCCESSFULLY\n`); return result; } catch (error) { console.log(`\nπŸ’₯ [${requestId}] API REQUEST FAILED`); console.log(`πŸ“ URL: ${method} ${fullUrl}`); console.log(`πŸ”΄ Error:`, error.message); console.log(`πŸ“… Time: ${new Date().toISOString()}\n`); throw new Error(error.message || 'Network error'); } } async login(phone, password) { return this.makeRequest(API_CONFIG.ENDPOINTS.AUTH.LOGIN, { phone: parseInt(phone), password, }); } async register(phone, name, password) { return this.makeRequest(API_CONFIG.ENDPOINTS.AUTH.REGISTER, { phone: parseInt(phone), name, password, }); } async verify(phone, code) { return this.makeRequest(API_CONFIG.ENDPOINTS.AUTH.VERIFY, { phone: parseInt(phone), code: parseInt(code), }); } // Authenticated API methods async getProfile() { return this.makeRequest('/profile', null, true, 'GET'); } async updateProfile(data) { return this.makeRequest('/profile', data, true, 'POST'); } async getTransactions(page = 1, limit = 20) { return this.makeRequest(`/user/transactions?page=${page}&limit=${limit}`, null, true, 'GET'); } async getBalance() { return this.makeRequest('/user/balance', null, true, 'GET'); } // NEW: Fetch metrics for dashboard async getMetrics() { return this.makeRequest('/metrics', null, true, 'GET'); } async transferMoney(data) { return this.makeRequest('/user/transfer', data, true); } async payBill(data) { return this.makeRequest('/user/pay-bill', data, true); } async getCards() { return this.makeRequest('/user/cards', null, true, 'GET'); } async addCard(data) { return this.makeRequest('/user/cards', data, true); } async blockCard(cardId) { return this.makeRequest(`/user/cards/${cardId}/block`, null, true); } async unblockCard(cardId) { return this.makeRequest(`/user/cards/${cardId}/unblock`, null, true); } async changePassword(currentPassword, newPassword) { return this.makeRequest('/user/change-password', { current_password: currentPassword, new_password: newPassword, }, true); } async deleteAccount() { return this.makeRequest('/user/delete-account', null, true, 'DELETE'); } // ================================ // Loan Remaining Order (Karzyň galyndysy) // ================================ // Helper to read cached user data (for passport details) async getStoredUser() { try { const raw = await AsyncStorage.getItem('user_data'); return raw ? JSON.parse(raw) : null; } catch (e) { return null; } } // LIST orders async getLoanRemainingOrders() { return this.makeRequest('/loan-remaining-order', null, true, 'GET'); } // CREATE order (passport can be supplied or fetched from profile) async createLoanRemainingOrder(accountNumber, passportSerie = null, passportId = null) { let serie = passportSerie; let pid = passportId; if (!serie || !pid) { const user = await this.getStoredUser(); serie = serie || user?.passport_serie; pid = pid || user?.passport_id; } if (!serie || !pid) { throw new Error('Passport details are missing'); } const payload = { passport_serie: serie, passport_id: pid, account_number: accountNumber, }; return this.makeRequest('/loan-remaining-order', payload, true, 'POST'); } // SHOW order details async getLoanRemainingOrder(orderId) { return this.makeRequest(`/loan-remaining-order/${orderId}`, null, true, 'GET'); } // UPDATE order (only account number can change; passport details stay the same) async updateLoanRemainingOrder(orderId, accountNumber, passportSerie = null, passportId = null) { let serie = passportSerie; let pid = passportId; if (!serie || !pid) { const user = await this.getStoredUser(); serie = serie || user?.passport_serie; pid = pid || user?.passport_id; } if (!serie || !pid) { throw new Error('Passport details are missing'); } const payload = { passport_serie: serie, passport_id: pid, account_number: accountNumber, }; return this.makeRequest(`/loan-remaining-order/${orderId}`, payload, true, 'POST'); } // DELETE order async deleteLoanRemainingOrder(orderId) { return this.makeRequest(`/loan-remaining-order/${orderId}`, null, true, 'DELETE'); } // ================================ // Loan remaining quick check (returns remaining balance info) // ================================ async getLoanRemainingBalance(accountNumber, passportSerie = null, passportId = null) { let serie = passportSerie; let pid = passportId; if (!serie || !pid) { const user = await this.getStoredUser(); serie = user?.passport_serie; pid = user?.passport_id; } if (!serie || !pid) { throw new Error('Passport details are missing'); } const query = `passport_serie=${encodeURIComponent(serie)}&passport_id=${encodeURIComponent(pid)}&account_number=${encodeURIComponent(accountNumber)}`; return this.makeRequest(`/loan-remaining?${query}`, null, true, 'GET'); } // ================================ // Loan Paid-Off Letter Orders // ================================ // LIST async getLoanPaidOffLetterOrders() { return this.makeRequest('/loan-paid-off-letter-orders', null, true, 'GET'); } // CREATE async createLoanPaidOffLetterOrder(data) { return this.makeRequest('/loan-paid-off-letter-orders', data, true, 'POST'); } // SHOW async getLoanPaidOffLetterOrder(orderId) { return this.makeRequest(`/loan-paid-off-letter-orders/${orderId}`, null, true, 'GET'); } // UPDATE async updateLoanPaidOffLetterOrder(orderId, data) { return this.makeRequest(`/loan-paid-off-letter-orders/${orderId}`, data, true, 'POST'); } // DELETE async deleteLoanPaidOffLetterOrder(orderId) { return this.makeRequest(`/loan-paid-off-letter-orders/${orderId}`, null, true, 'DELETE'); } // ================================ // Loan Orders (Karz sargytlary) // ================================ // LIST async getLoanOrders() { return this.makeRequest('/loan-order', null, true, 'GET'); } // CREATE async createLoanOrder(data) { return this.makeRequest('/loan-order', data, true, 'POST'); } // SHOW async getLoanOrder(orderId) { return this.makeRequest(`/loan-order/${orderId}`, null, true, 'GET'); } // UPDATE async updateLoanOrder(orderId, data) { return this.makeRequest(`/loan-order/${orderId}`, data, true, 'POST'); } // DELETE async deleteLoanOrder(orderId) { return this.makeRequest(`/loan-order/${orderId}`, null, true, 'DELETE'); } // ================================ // Card Transactions Orders (Kart hereketleri) // ================================ // LIST async getCardTransactionOrders() { return this.makeRequest('/card-transactions', null, true, 'GET'); } // CREATE order (auto-fills passport data from stored profile) async createCardTransactionOrder(cardNumber, cardMonth, cardYear, passportSerie = null, passportId = null) { let serie = passportSerie; let pid = passportId; if (!serie || !pid) { const user = await this.getStoredUser(); serie = serie || user?.passport_serie; pid = pid || user?.passport_id; } if (!serie || !pid) { throw new Error('Passport details are missing'); } const payload = { passport_serie: serie, passport_id: pid, card_number: cardNumber, card_month: cardMonth, card_year: cardYear, }; return this.makeRequest('/card-transactions', payload, true, 'POST'); } // SHOW async getCardTransactionOrder(orderId) { return this.makeRequest(`/card-transactions/${orderId}`, null, true, 'GET'); } // UPDATE async updateCardTransactionOrder(orderId, cardNumber, cardMonth, cardYear, passportSerie = null, passportId = null) { let serie = passportSerie; let pid = passportId; if (!serie || !pid) { const user = await this.getStoredUser(); serie = serie || user?.passport_serie; pid = pid || user?.passport_id; } if (!serie || !pid) { throw new Error('Passport details are missing'); } const payload = { passport_serie: serie, passport_id: pid, card_number: cardNumber, card_month: cardMonth, card_year: cardYear, }; return this.makeRequest(`/card-transactions/${orderId}`, payload, true, 'POST'); } // DELETE async deleteCardTransactionOrder(orderId) { return this.makeRequest(`/card-transactions/${orderId}`, null, true, 'DELETE'); } // DOWNLOAD (returns object with url) async downloadCardTransactions(orderId, startDate, endDate) { const query = `start_date=${encodeURIComponent(startDate)}&end_date=${encodeURIComponent(endDate)}`; return this.makeRequest(`/card-transactions-download/${orderId}?${query}`, null, true, 'GET'); } // ================================ // Card balance quick check (Kart galyndysy) // ================================ async getCardBalanceQuickCheck(cardNumber = null, cardMonth = null, cardYear = null, passportSerie = null, passportId = null) { // Fallback to stored user profile for missing fields let serie = passportSerie; let pid = passportId; let cNumber = cardNumber; let cMonth = cardMonth; let cYear = cardYear; if (!serie || !pid || !cNumber || !cMonth || !cYear) { const user = await this.getStoredUser(); serie = serie || user?.passport_serie; pid = pid || user?.passport_id; cNumber = cNumber || user?.card_number; cMonth = cMonth || user?.card_month; cYear = cYear || user?.card_year; } if (!serie || !pid || !cNumber || !cMonth || !cYear) { throw new Error('Card or passport details are missing'); } // Ensure values are properly formatted const plainCardNumber = String(cNumber).replace(/[^0-9]/g, '').slice(0, 16); const monthStr = String(cMonth).padStart(2, '0'); const payload = { passport_serie: serie, passport_id: pid, card_number: plainCardNumber, card_month: monthStr, card_year: String(cYear), }; // POST request – authenticated (token header will be included if available) return this.makeRequest('/card-balance-quick-check', payload, true, 'POST'); } // ================================ // Card Balance Orders (Kart galyndylary) // ================================ // LIST async getCardBalanceOrders() { return this.makeRequest('/card-balances', null, true, 'GET'); } // CREATE async createCardBalanceOrder(cardNumber, cardMonth, cardYear, passportSerie = null, passportId = null) { let serie = passportSerie; let pid = passportId; if (!serie || !pid) { const user = await this.getStoredUser(); serie = serie || user?.passport_serie; pid = pid || user?.passport_id; } if (!serie || !pid) { throw new Error('Passport details are missing'); } const payload = { passport_serie: serie, passport_id: pid, card_number: cardNumber, card_month: cardMonth, card_year: cardYear, }; return this.makeRequest('/card-balances', payload, true, 'POST'); } // SHOW async getCardBalanceOrder(orderId) { return this.makeRequest(`/card-balances/${orderId}`, null, true, 'GET'); } // UPDATE async updateCardBalanceOrder(orderId, cardNumber, cardMonth, cardYear, passportSerie = null, passportId = null) { let serie = passportSerie; let pid = passportId; if (!serie || !pid) { const user = await this.getStoredUser(); serie = serie || user?.passport_serie; pid = pid || user?.passport_id; } if (!serie || !pid) { throw new Error('Passport details are missing'); } const payload = { passport_serie: serie, passport_id: pid, card_number: cardNumber, card_month: cardMonth, card_year: cardYear, }; return this.makeRequest(`/card-balances/${orderId}`, payload, true, 'POST'); } // DELETE async deleteCardBalanceOrder(orderId) { return this.makeRequest(`/card-balances/${orderId}`, null, true, 'DELETE'); } // DOWNLOAD (returns object with card details) async downloadCardBalances(orderId) { return this.makeRequest(`/card-balances-download/${orderId}`, null, true, 'GET'); } // ================================ // Card Requisites Orders (Kart rekwizitler) // ================================ // LIST async getCardRequisiteOrders() { return this.makeRequest('/card-requisites', null, true, 'GET'); } // CREATE (passport + card info) async createCardRequisiteOrder(payload) { /* payload expected keys: passport_serie, passport_id, card_number, card_month, card_year, maybe card_name */ return this.makeRequest('/card-requisites', payload, true, 'POST'); } // SHOW async getCardRequisiteOrder(orderId) { return this.makeRequest(`/card-requisites/${orderId}`, null, true, 'GET'); } // UPDATE async updateCardRequisiteOrder(orderId, payload) { return this.makeRequest(`/card-requisites/${orderId}`, payload, true, 'POST'); } // DELETE async deleteCardRequisiteOrder(orderId) { return this.makeRequest(`/card-requisites/${orderId}`, null, true, 'DELETE'); } // DOWNLOAD async downloadCardRequisites(orderId) { return this.makeRequest(`/card-requisites-download/${orderId}`, null, true, 'GET'); } } export default new AuthService();