diff --git a/services/api.ts b/services/api.ts index 4e62e51..1afc6ab 100644 --- a/services/api.ts +++ b/services/api.ts @@ -27,6 +27,23 @@ const ELDERLY_AVATARS = [ 'https://images.unsplash.com/photo-1548142813-c348350df52b?w=200&h=200&fit=crop&crop=face', // grandmother portrait ]; +// Room locations for sensor placement +// Used in device settings to select where sensor is installed +export const ROOM_LOCATIONS = [ + { id: 'bedroom', label: 'Bedroom', icon: '🛏️' }, + { id: 'living_room', label: 'Living Room', icon: '🛋️' }, + { id: 'kitchen', label: 'Kitchen', icon: '🍳' }, + { id: 'bathroom', label: 'Bathroom', icon: '🚿' }, + { id: 'hallway', label: 'Hallway', icon: '🚪' }, + { id: 'entrance', label: 'Entrance', icon: '🏠' }, + { id: 'garage', label: 'Garage', icon: '🚗' }, + { id: 'basement', label: 'Basement', icon: '🪜' }, + { id: 'office', label: 'Office', icon: '💼' }, + { id: 'other', label: 'Other', icon: '📍' }, +] as const; + +export type RoomLocationId = typeof ROOM_LOCATIONS[number]['id']; + // Get consistent avatar based on deployment_id function getAvatarForBeneficiary(deploymentId: number): string { const index = deploymentId % ELDERLY_AVATARS.length; @@ -272,7 +289,6 @@ class ApiService { async verifyOTP(email: string, code: string): Promise> { try { const payload = { email: email.trim().toLowerCase(), code }; - console.log('[API] verifyOTP request:', JSON.stringify(payload)); const response = await fetch(`${WELLNUO_API_URL}/auth/verify-otp`, { method: 'POST', @@ -283,7 +299,6 @@ class ApiService { }); const data = await response.json(); - console.log('[API] verifyOTP response:', JSON.stringify(data)); if (response.ok && data.token) { // Save ONLY technical auth data (token, userId, email) @@ -300,7 +315,6 @@ class ApiService { error: { message: data.error || data.message || 'Invalid or expired code' }, }; } catch (error) { - console.error('[API] verifyOTP network error:', error); return { ok: false, error: { message: 'Network error. Please check your connection.' }, @@ -319,30 +333,23 @@ class ApiService { const token = await this.getToken(); const userId = await SecureStore.getItemAsync('userId'); - console.log('[API] getStoredUser: token exists =', !!token, ', userId =', userId); - if (!token || !userId) { - console.log('[API] getStoredUser: No token or userId, returning null'); return null; } // Fetch profile from server - console.log('[API] getStoredUser: Fetching profile from server...'); const profile = await this.getProfile(); - console.log('[API] getStoredUser: Profile response ok =', profile.ok, ', error =', profile.error); if (!profile.ok || !profile.data) { // If token is invalid (401), clear all tokens and return null // This will trigger re-authentication if (profile.error?.code === 'UNAUTHORIZED') { - console.log('[API] getStoredUser: Token invalid (401), clearing auth data'); await this.logout(); return null; } // For network errors OR other API errors, fall back to minimal info // We don't want to log out the user just because the server is temporarily unavailable - console.log('[API] getStoredUser: API error, falling back to local data'); const email = await SecureStore.getItemAsync('userEmail'); return { user_id: parseInt(userId, 10), @@ -355,7 +362,6 @@ class ApiService { // /auth/me returns { user: {...}, beneficiaries: [...] } // Extract user data from nested 'user' object const userData = profile.data.user || profile.data; - console.log('[API] getStoredUser: userData =', JSON.stringify(userData)); return { user_id: userData.id, @@ -368,7 +374,6 @@ class ApiService { }; } catch (error) { // On any unexpected error, fall back to local data instead of logging out - console.log('[API] getStoredUser: Unexpected error, falling back to local data', error); const userId = await SecureStore.getItemAsync('userId'); const email = await SecureStore.getItemAsync('userEmail'); if (userId) { @@ -384,6 +389,7 @@ class ApiService { } // Get user profile from WellNuo API + // Note: /auth/me can return { user: {...}, beneficiaries: [...] } or just { id, email, ... } async getProfile(): Promise> { const token = await this.getToken(); @@ -451,8 +464,6 @@ class ApiService { } try { - console.log('[API] updateProfile: sending', JSON.stringify(updates)); - const response = await fetch(`${WELLNUO_API_URL}/auth/profile`, { method: 'PATCH', headers: { @@ -463,17 +474,13 @@ class ApiService { }); const data = await response.json(); - console.log('[API] updateProfile: response status', response.status, 'data:', JSON.stringify(data)); if (!response.ok) { - console.error('[API] updateProfile: failed', data.error); return { ok: false, error: { message: data.error || 'Failed to update profile' } }; } - console.log('[API] updateProfile: success'); return { data, ok: true }; } catch (error) { - console.error('[API] updateProfile: network error', error); return { ok: false, error: { message: 'Network error', code: 'NETWORK_ERROR' } }; } } @@ -518,7 +525,6 @@ class ApiService { return { data: data.user, ok: true }; } catch (error) { - console.error('[API] updateProfileAvatar error:', error); return { ok: false, error: { message: 'Network error', code: 'NETWORK_ERROR' } }; } } @@ -644,15 +650,12 @@ class ApiService { // Get all beneficiaries from WellNuo API async getAllBeneficiaries(): Promise> { const token = await this.getToken(); - console.log('[API] getAllBeneficiaries - token exists:', !!token, 'length:', token?.length); if (!token) { - console.log('[API] getAllBeneficiaries - No token found!'); return { ok: false, error: { message: 'Not authenticated', code: 'UNAUTHORIZED' } }; } try { - console.log('[API] getAllBeneficiaries - Fetching from:', `${WELLNUO_API_URL}/me/beneficiaries`); const response = await fetch(`${WELLNUO_API_URL}/me/beneficiaries`, { method: 'GET', headers: { @@ -660,9 +663,7 @@ class ApiService { }, }); - console.log('[API] getAllBeneficiaries - Response status:', response.status); const data = await response.json(); - console.log('[API] getAllBeneficiaries - Data:', JSON.stringify(data).substring(0, 200)); if (!response.ok) { if (response.status === 401) { @@ -693,7 +694,6 @@ class ApiService { return { data: beneficiaries, ok: true }; } catch (error) { - console.log('[API] getAllBeneficiaries - Catch error:', error); return { ok: false, error: { message: 'Network error', code: 'NETWORK_ERROR' } }; } } @@ -716,14 +716,6 @@ class ApiService { const data = await response.json(); - console.log('[API] getWellNuoBeneficiary - Raw response:', JSON.stringify({ - id: data.id, - name: data.name, - hasDevices: data.hasDevices, - equipmentStatus: data.equipmentStatus, - subscription: data.subscription - })); - if (!response.ok) { return { ok: false, error: { message: data.error || 'Failed to get beneficiary' } }; } @@ -740,7 +732,7 @@ class ApiService { address: typeof data.address === 'string' ? data.address : (data.address?.street ? `${data.address.street}, ${data.address.city}` : undefined), subscription: data.subscription ? { status: data.subscription.status, - plan: data.subscription.plan, + planType: data.subscription.planType || data.subscription.plan, endDate: data.subscription.endDate, cancelAtPeriodEnd: data.subscription.cancelAtPeriodEnd, } : undefined, @@ -789,6 +781,7 @@ class ApiService { const beneficiary: Beneficiary = { id: data.beneficiary.id, name: data.beneficiary.name || data.beneficiary.email, + displayName: data.beneficiary.displayName || data.beneficiary.name || data.beneficiary.email, email: data.beneficiary.email, status: 'offline' as const, }; @@ -863,11 +856,8 @@ class ApiService { // Create data URI base64Image = `data:${mimeType};base64,${base64Data}`; - console.log('[API] Avatar converted to base64, length:', base64Image.length); } - console.log('[API] Uploading avatar for beneficiary:', id); - const apiResponse = await fetch(`${WELLNUO_API_URL}/me/beneficiaries/${id}/avatar`, { method: 'PATCH', headers: { @@ -879,15 +869,12 @@ class ApiService { const data = await apiResponse.json(); - console.log('[API] Avatar upload response:', apiResponse.status, data); - if (!apiResponse.ok) { return { ok: false, error: { message: data.error || 'Failed to update avatar' } }; } return { data: { avatarUrl: data.beneficiary?.avatarUrl || null }, ok: true }; } catch (error) { - console.error('[API] updateBeneficiaryAvatar error:', error); return { ok: false, error: { message: 'Network error', code: 'NETWORK_ERROR' } }; } } @@ -1472,7 +1459,6 @@ class ApiService { }); const data = await response.json(); - console.log('[API] Legacy login response:', data.status, 'token type:', typeof data.access_token); // Check that access_token is a valid JWT string (not 0 or empty) if (data.status === '200 OK' && data.access_token && typeof data.access_token === 'string' && data.access_token.includes('.')) { @@ -1480,18 +1466,14 @@ class ApiService { await SecureStore.setItemAsync('legacyAccessToken', data.access_token); await SecureStore.setItemAsync('legacyUserId', String(data.user_id)); await SecureStore.setItemAsync('legacyUserName', this.DEMO_LEGACY_USER); - console.log('[API] Legacy credentials saved successfully'); return { data: data as AuthResponse, ok: true }; } - - console.log('[API] Legacy login failed - invalid token:', data.access_token); return { ok: false, error: { message: data.message || 'Legacy login failed - invalid credentials' }, }; } catch (error) { - console.error('[API] Legacy login error:', error); return { ok: false, error: { message: 'Failed to connect to dashboard API' }, @@ -1501,7 +1483,6 @@ class ApiService { // Refresh legacy token async refreshLegacyToken(): Promise> { - console.log('[API] Refreshing legacy token...'); return this.loginToLegacyDashboard(); } @@ -1523,10 +1504,8 @@ class ApiService { const oneHour = 60 * 60; const isExpiring = (exp - now) < oneHour; - console.log('[API] Legacy token expiring soon:', isExpiring, 'expires in:', Math.round((exp - now) / 60), 'min'); return isExpiring; } catch (e) { - console.log('[API] Error checking legacy token:', e); return true; } } @@ -1546,12 +1525,8 @@ class ApiService { const isValidToken = token && typeof token === 'string' && token.includes('.'); if (!isValidToken || !userName || !userId) { - console.log('[API] Legacy credentials missing or invalid token, logging in...'); - console.log('[API] Token valid:', isValidToken, 'userName:', !!userName, 'userId:', !!userId); - // Clear any invalid cached credentials if (token && !isValidToken) { - console.log('[API] Clearing invalid cached token:', token); await SecureStore.deleteItemAsync('legacyAccessToken'); await SecureStore.deleteItemAsync('legacyUserName'); await SecureStore.deleteItemAsync('legacyUserId'); @@ -1569,10 +1544,8 @@ class ApiService { return { token: newToken, userName: newUserName, userId: newUserId }; } - console.log('[API] Legacy credentials found:', userName, 'token length:', token.length); return { token, userName, userId }; } catch (e) { - console.error('[API] Error getting legacy credentials:', e); return null; } } @@ -1690,7 +1663,6 @@ class ApiService { return { ok: true, data: sensors }; } catch (error: any) { - console.error('[API] getDevicesForBeneficiary error:', error); return { ok: false, error: error.message }; } } @@ -1730,7 +1702,6 @@ class ApiService { const deviceIds = data.result_list.map((device: any) => device[0]); return new Set(deviceIds); } catch (error) { - console.error('[API] getOnlineDevices error:', error); return new Set(); } } @@ -1797,7 +1768,6 @@ class ApiService { return { ok: true }; } catch (error: any) { - console.error('[API] attachDeviceToBeneficiary error:', error); return { ok: false, error: error.message }; } } @@ -1852,7 +1822,6 @@ class ApiService { return { ok: true, data: { success: true } }; } catch (error: any) { - console.error('[API] updateDeviceMetadata error:', error); return { ok: false, error: { message: error.message || 'Network error', code: 'NETWORK_ERROR' } }; } } @@ -1889,8 +1858,6 @@ class ApiService { reuse_existing_devices: '1', }); - console.log('[API] attachDeviceToDeployment: deployment=', deploymentId, 'wellId=', wellId, 'ssid=', ssid); - const response = await fetch(API_BASE_URL, { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, @@ -1904,14 +1871,11 @@ class ApiService { const data = await response.json(); if (data.status !== '200 OK') { - console.error('[API] attachDeviceToDeployment failed:', data); return { ok: false, error: { message: data.message || 'Failed to attach device' } }; } - console.log('[API] attachDeviceToDeployment success'); return { ok: true, data: { success: true } }; } catch (error: any) { - console.error('[API] attachDeviceToDeployment error:', error); return { ok: false, error: { message: error.message || 'Network error', code: 'NETWORK_ERROR' } }; } } @@ -1943,7 +1907,6 @@ class ApiService { return { ok: true }; } catch (error: any) { - console.error('[API] detachDeviceFromBeneficiary error:', error); return { ok: false, error: error.message }; } }