@onairos/react-native 3.7.1 → 3.7.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/commonjs/api/index.js +219 -9
- package/lib/commonjs/assets/icons/spotify.png +0 -0
- package/lib/commonjs/assets/images/spotify.png +0 -0
- package/lib/commonjs/components/BodyText.js +27 -9
- package/lib/commonjs/components/BrandMark.js +111 -10
- package/lib/commonjs/components/CodeInput.js +116 -9
- package/lib/commonjs/components/EmailInput.js +30 -8
- package/lib/commonjs/components/GoogleButton.js +56 -9
- package/lib/commonjs/components/HeadingGroup.js +43 -9
- package/lib/commonjs/components/LLMDataInputModal.js +664 -14
- package/lib/commonjs/components/ModalHeader.js +99 -9
- package/lib/commonjs/components/ModalSheet.js +47 -9
- package/lib/commonjs/components/Onairos.js +380 -14
- package/lib/commonjs/components/OnairosButton.js +313 -13
- package/lib/commonjs/components/OnairosSignInButton.js +130 -12
- package/lib/commonjs/components/Overlay.js +465 -13
- package/lib/commonjs/components/PersonaImage.js +137 -10
- package/lib/commonjs/components/PersonaLoadingScreen.js +318 -12
- package/lib/commonjs/components/PersonalizationConsentScreen.js +467 -13
- package/lib/commonjs/components/PinCreationScreen.js +403 -12
- package/lib/commonjs/components/PinInput.js +464 -9
- package/lib/commonjs/components/PlatformConnectorsStep.js +1311 -23
- package/lib/commonjs/components/PlatformList.js +137 -10
- package/lib/commonjs/components/PlatformToggle.js +180 -9
- package/lib/commonjs/components/PrimaryButton.js +180 -10
- package/lib/commonjs/components/SignInMatchAnimation.js +197 -9
- package/lib/commonjs/components/SignInStep.js +345 -12
- package/lib/commonjs/components/UniversalOnboarding.js +2780 -30
- package/lib/commonjs/components/VerificationStep.js +176 -11
- package/lib/commonjs/components/WelcomeScreen.js +461 -22
- package/lib/commonjs/components/icons/Basicproficon.js +37 -8
- package/lib/commonjs/components/icons/Basicprofile.js +21 -8
- package/lib/commonjs/components/icons/Checkbox.js +21 -8
- package/lib/commonjs/components/icons/Checkmark.js +27 -8
- package/lib/commonjs/components/icons/Contentanalysis.js +21 -8
- package/lib/commonjs/components/icons/Contenticon.js +39 -8
- package/lib/commonjs/components/icons/EnochE.js +41 -8
- package/lib/commonjs/components/icons/Personalityicon.js +30 -8
- package/lib/commonjs/components/icons/Personalityprofile.js +21 -8
- package/lib/commonjs/components/icons/Personalitytraits.js +21 -8
- package/lib/commonjs/components/icons/Userpreferences.js +21 -8
- package/lib/commonjs/components/icons/index.js +84 -17
- package/lib/commonjs/components/onboarding/OAuthWebView.js +1754 -18
- package/lib/commonjs/components/onboarding/OnboardingHeader.js +74 -10
- package/lib/commonjs/components/onboarding/PinInput.js +283 -10
- package/lib/commonjs/components/onboarding/PlatformConnector.js +249 -11
- package/lib/commonjs/config/PLATFORM_APIS.md +849 -0
- package/lib/commonjs/config/api.js +56 -7
- package/lib/commonjs/constants/index.js +120 -7
- package/lib/commonjs/context/AuthContext.js +345 -10
- package/lib/commonjs/hooks/useConnectedAccounts.js +111 -9
- package/lib/commonjs/hooks/useConnections.js +102 -8
- package/lib/commonjs/hooks/useCredentials.js +178 -10
- package/lib/commonjs/hooks/useUserConnections.js +148 -10
- package/lib/commonjs/index.js +439 -34
- package/lib/commonjs/services/apiClient.js +298 -8
- package/lib/commonjs/services/biometricPinService.js +180 -8
- package/lib/commonjs/services/chatGPTConversationExtractor.js +155 -8
- package/lib/commonjs/services/chatGPTConversationService.js +275 -9
- package/lib/commonjs/services/claudeConversationExtractor.js +103 -8
- package/lib/commonjs/services/claudeConversationService.js +158 -9
- package/lib/commonjs/services/connectedAccountsService.js +310 -10
- package/lib/commonjs/services/googleAuthService.js +252 -11
- package/lib/commonjs/services/hingeDataExtractor.js +105 -8
- package/lib/commonjs/services/hingeDataService.js +150 -9
- package/lib/commonjs/services/imageCompressionService.js +260 -7
- package/lib/commonjs/services/instagramDataExtractor.js +126 -8
- package/lib/commonjs/services/instagramDataService.js +163 -9
- package/lib/commonjs/services/jwtStorageService.js +276 -7
- package/lib/commonjs/services/linkedinDOMExtractor.js +245 -7
- package/lib/commonjs/services/linkedinProfileService.js +222 -9
- package/lib/commonjs/services/linkedinScrapingService.js +230 -8
- package/lib/commonjs/services/llmDataStorage.js +294 -8
- package/lib/commonjs/services/mobileTrainingService.js +186 -8
- package/lib/commonjs/services/netflixDataExtractor.js +120 -8
- package/lib/commonjs/services/netflixDataService.js +198 -9
- package/lib/commonjs/services/pinEncryptionService.js +84 -8
- package/lib/commonjs/services/pinStorageUtils.js +105 -7
- package/lib/commonjs/services/platformAuthService.js +1484 -12
- package/lib/commonjs/services/sephoraDataExtractor.js +140 -8
- package/lib/commonjs/services/sephoraDataService.js +200 -9
- package/lib/commonjs/services/spotifyDataExtractor.js +148 -8
- package/lib/commonjs/services/spotifyDataService.js +241 -9
- package/lib/commonjs/services/storageService.js +404 -8
- package/lib/commonjs/services/telegramDataExtractor.js +115 -8
- package/lib/commonjs/services/telegramDataService.js +499 -9
- package/lib/commonjs/services/trainingApiHelpers.js +73 -7
- package/lib/commonjs/services/userConnectionsService.js +340 -10
- package/lib/commonjs/services/youtubeMigrationService.js +416 -10
- package/lib/commonjs/theme/index.js +250 -7
- package/lib/commonjs/types/ambient.d.js +2 -1
- package/lib/commonjs/types/declarations.d.js +2 -1
- package/lib/commonjs/types/index.js +6 -1
- package/lib/commonjs/types/node-fix.d.js +2 -1
- package/lib/commonjs/types/node-override.d.js +2 -1
- package/lib/commonjs/types/opacity.d.js +2 -1
- package/lib/commonjs/types.js +14 -1
- package/lib/commonjs/utils/Portal.js +98 -8
- package/lib/commonjs/utils/api.js +130 -9
- package/lib/commonjs/utils/assetRegistry.js +210 -35
- package/lib/commonjs/utils/auth.js +112 -9
- package/lib/commonjs/utils/connectorTests.js +613 -29
- package/lib/commonjs/utils/crypto.js +62 -8
- package/lib/commonjs/utils/debugHelper.js +64 -1
- package/lib/commonjs/utils/encryption.js +76 -7
- package/lib/commonjs/utils/eventUtils.js +288 -1
- package/lib/commonjs/utils/haptics.js +66 -9
- package/lib/commonjs/utils/imagePreloader.js +6 -1
- package/lib/commonjs/utils/networkDiagnostics.js +226 -8
- package/lib/commonjs/utils/onairosApi.js +350 -9
- package/lib/commonjs/utils/programmaticFlow.js +117 -9
- package/lib/commonjs/utils/retryHelper.js +220 -1
- package/lib/commonjs/utils/secureStorage.js +349 -10
- package/lib/commonjs/utils/webviewScripts/chatgpt.js +551 -1
- package/lib/commonjs/utils/webviewScripts/claude.js +376 -1
- package/lib/commonjs/utils/webviewScripts/hinge.js +411 -1
- package/lib/commonjs/utils/webviewScripts/index.js +698 -15
- package/lib/commonjs/utils/webviewScripts/instagram.js +454 -1
- package/lib/commonjs/utils/webviewScripts/linkedin.js +880 -1
- package/lib/commonjs/utils/webviewScripts/netflix.js +382 -1
- package/lib/commonjs/utils/webviewScripts/sephora.js +516 -1
- package/lib/commonjs/utils/webviewScripts/spotify.js +419 -1
- package/lib/commonjs/utils/webviewScripts/telegram.js +678 -1
- package/lib/module/api/index.js +211 -1
- package/lib/module/assets/icons/spotify.png +0 -0
- package/lib/module/assets/images/spotify.png +0 -0
- package/lib/module/components/BodyText.js +20 -1
- package/lib/module/components/BrandMark.js +104 -1
- package/lib/module/components/CodeInput.js +109 -1
- package/lib/module/components/EmailInput.js +23 -1
- package/lib/module/components/GoogleButton.js +49 -1
- package/lib/module/components/HeadingGroup.js +36 -1
- package/lib/module/components/LLMDataInputModal.js +656 -7
- package/lib/module/components/ModalHeader.js +92 -1
- package/lib/module/components/ModalSheet.js +39 -1
- package/lib/module/components/Onairos.js +373 -1
- package/lib/module/components/OnairosButton.js +305 -1
- package/lib/module/components/OnairosSignInButton.js +121 -1
- package/lib/module/components/Overlay.js +456 -1
- package/lib/module/components/PersonaImage.js +129 -1
- package/lib/module/components/PersonaLoadingScreen.js +310 -1
- package/lib/module/components/PersonalizationConsentScreen.js +460 -1
- package/lib/module/components/PinCreationScreen.js +396 -1
- package/lib/module/components/PinInput.js +456 -1
- package/lib/module/components/PlatformConnectorsStep.js +1302 -6
- package/lib/module/components/PlatformList.js +129 -1
- package/lib/module/components/PlatformToggle.js +173 -1
- package/lib/module/components/PrimaryButton.js +172 -1
- package/lib/module/components/SignInMatchAnimation.js +189 -1
- package/lib/module/components/SignInStep.js +338 -1
- package/lib/module/components/UniversalOnboarding.js +2770 -1
- package/lib/module/components/VerificationStep.js +168 -1
- package/lib/module/components/WelcomeScreen.js +453 -1
- package/lib/module/components/icons/Basicproficon.js +30 -1
- package/lib/module/components/icons/Basicprofile.js +14 -1
- package/lib/module/components/icons/Checkbox.js +14 -1
- package/lib/module/components/icons/Checkmark.js +20 -1
- package/lib/module/components/icons/Contentanalysis.js +14 -1
- package/lib/module/components/icons/Contenticon.js +32 -1
- package/lib/module/components/icons/EnochE.js +34 -1
- package/lib/module/components/icons/Personalityicon.js +23 -1
- package/lib/module/components/icons/Personalityprofile.js +14 -1
- package/lib/module/components/icons/Personalitytraits.js +14 -1
- package/lib/module/components/icons/Userpreferences.js +14 -1
- package/lib/module/components/icons/index.js +13 -1
- package/lib/module/components/onboarding/OAuthWebView.js +1746 -1
- package/lib/module/components/onboarding/OnboardingHeader.js +66 -1
- package/lib/module/components/onboarding/PinInput.js +274 -1
- package/lib/module/components/onboarding/PlatformConnector.js +240 -1
- package/lib/module/config/PLATFORM_APIS.md +849 -0
- package/lib/module/config/api.js +47 -1
- package/lib/module/constants/index.js +114 -1
- package/lib/module/context/AuthContext.js +335 -1
- package/lib/module/hooks/useConnectedAccounts.js +106 -1
- package/lib/module/hooks/useConnections.js +95 -1
- package/lib/module/hooks/useCredentials.js +171 -6
- package/lib/module/hooks/useUserConnections.js +140 -1
- package/lib/module/index.js +172 -1
- package/lib/module/services/apiClient.js +295 -1
- package/lib/module/services/biometricPinService.js +169 -1
- package/lib/module/services/chatGPTConversationExtractor.js +149 -1
- package/lib/module/services/chatGPTConversationService.js +268 -1
- package/lib/module/services/claudeConversationExtractor.js +97 -1
- package/lib/module/services/claudeConversationService.js +151 -1
- package/lib/module/services/connectedAccountsService.js +293 -1
- package/lib/module/services/googleAuthService.js +241 -1
- package/lib/module/services/hingeDataExtractor.js +99 -1
- package/lib/module/services/hingeDataService.js +143 -1
- package/lib/module/services/imageCompressionService.js +250 -1
- package/lib/module/services/instagramDataExtractor.js +120 -1
- package/lib/module/services/instagramDataService.js +156 -1
- package/lib/module/services/jwtStorageService.js +257 -1
- package/lib/module/services/linkedinDOMExtractor.js +234 -1
- package/lib/module/services/linkedinProfileService.js +210 -1
- package/lib/module/services/linkedinScrapingService.js +219 -1
- package/lib/module/services/llmDataStorage.js +277 -1
- package/lib/module/services/mobileTrainingService.js +173 -1
- package/lib/module/services/netflixDataExtractor.js +114 -1
- package/lib/module/services/netflixDataService.js +191 -1
- package/lib/module/services/pinEncryptionService.js +74 -6
- package/lib/module/services/pinStorageUtils.js +93 -1
- package/lib/module/services/platformAuthService.js +1461 -1
- package/lib/module/services/sephoraDataExtractor.js +134 -1
- package/lib/module/services/sephoraDataService.js +193 -1
- package/lib/module/services/spotifyDataExtractor.js +142 -1
- package/lib/module/services/spotifyDataService.js +234 -1
- package/lib/module/services/storageService.js +383 -1
- package/lib/module/services/telegramDataExtractor.js +109 -1
- package/lib/module/services/telegramDataService.js +493 -1
- package/lib/module/services/trainingApiHelpers.js +67 -1
- package/lib/module/services/userConnectionsService.js +329 -1
- package/lib/module/services/youtubeMigrationService.js +405 -1
- package/lib/module/theme/index.js +245 -1
- package/lib/module/types.js +10 -1
- package/lib/module/utils/Portal.js +90 -1
- package/lib/module/utils/api.js +118 -1
- package/lib/module/utils/assetRegistry.js +200 -34
- package/lib/module/utils/auth.js +100 -1
- package/lib/module/utils/connectorTests.js +600 -27
- package/lib/module/utils/crypto.js +54 -1
- package/lib/module/utils/debugHelper.js +54 -1
- package/lib/module/utils/encryption.js +67 -1
- package/lib/module/utils/eventUtils.js +270 -1
- package/lib/module/utils/haptics.js +59 -8
- package/lib/module/utils/imagePreloader.js +3 -1
- package/lib/module/utils/networkDiagnostics.js +217 -1
- package/lib/module/utils/onairosApi.js +333 -1
- package/lib/module/utils/programmaticFlow.js +111 -1
- package/lib/module/utils/retryHelper.js +211 -1
- package/lib/module/utils/secureStorage.js +330 -6
- package/lib/module/utils/webviewScripts/chatgpt.js +545 -1
- package/lib/module/utils/webviewScripts/claude.js +370 -1
- package/lib/module/utils/webviewScripts/hinge.js +405 -1
- package/lib/module/utils/webviewScripts/index.js +434 -1
- package/lib/module/utils/webviewScripts/instagram.js +448 -1
- package/lib/module/utils/webviewScripts/linkedin.js +874 -1
- package/lib/module/utils/webviewScripts/netflix.js +376 -1
- package/lib/module/utils/webviewScripts/sephora.js +510 -1
- package/lib/module/utils/webviewScripts/spotify.js +413 -1
- package/lib/module/utils/webviewScripts/telegram.js +672 -1
- package/package.json +2 -2
|
@@ -1 +1,99 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Hinge Data Extractor
|
|
3
|
+
*
|
|
4
|
+
* Orchestrates the Hinge data export flow:
|
|
5
|
+
* 1. Receives extracted matches/chats from WebView
|
|
6
|
+
* 2. Validates and formats data
|
|
7
|
+
* 3. Sends to backend via hingeDataService
|
|
8
|
+
*
|
|
9
|
+
* This acts as the bridge between OAuthWebView and the backend API.
|
|
10
|
+
*
|
|
11
|
+
* @reference ChatGPT implementation: src/services/chatGPTConversationExtractor.ts
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { storeHingeData } from './hingeDataService';
|
|
15
|
+
import { Alert } from 'react-native';
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Combined Hinge export data from WebView
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Hook for Hinge data extraction operations
|
|
23
|
+
*/
|
|
24
|
+
export const useHingeDataExtractor = () => {
|
|
25
|
+
/**
|
|
26
|
+
* Initiate data export to backend
|
|
27
|
+
*
|
|
28
|
+
* @param username - User identifier
|
|
29
|
+
* @param data - Extracted Hinge data (matches and chats)
|
|
30
|
+
* @returns true if successful, false otherwise
|
|
31
|
+
*/
|
|
32
|
+
const initiateDataExport = async (username, data) => {
|
|
33
|
+
var _data$chats;
|
|
34
|
+
console.log('🚀 [HINGE_EXTRACTOR] Initiating data export');
|
|
35
|
+
console.log('👤 [HINGE_EXTRACTOR] Username:', username);
|
|
36
|
+
console.log('📊 [HINGE_EXTRACTOR] Matches:', data.total_matches);
|
|
37
|
+
console.log('📊 [HINGE_EXTRACTOR] Chats:', data.total_chats);
|
|
38
|
+
console.log('📊 [HINGE_EXTRACTOR] Messages:', data.total_messages);
|
|
39
|
+
|
|
40
|
+
// Validation
|
|
41
|
+
if (!username) {
|
|
42
|
+
console.error('❌ [HINGE_EXTRACTOR] Username is required');
|
|
43
|
+
Alert.alert('Error', 'Username is required to export Hinge data.', [{
|
|
44
|
+
text: 'OK',
|
|
45
|
+
style: 'default'
|
|
46
|
+
}]);
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Handle empty data as success - user might be new
|
|
51
|
+
if ((!data.matches || data.matches.length === 0) && (!data.chats || data.chats.length === 0)) {
|
|
52
|
+
console.log('ℹ️ [HINGE_EXTRACTOR] No data to export - treating as success (connected)');
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Validate chat structure
|
|
57
|
+
const validChats = (data.chats || []).filter(chat => {
|
|
58
|
+
const isValid = chat.match_id && Array.isArray(chat.user_messages) && chat.user_messages.length > 0;
|
|
59
|
+
if (!isValid) {
|
|
60
|
+
console.warn('⚠️ [HINGE_EXTRACTOR] Invalid chat:', chat);
|
|
61
|
+
}
|
|
62
|
+
return isValid;
|
|
63
|
+
});
|
|
64
|
+
if (validChats.length < (((_data$chats = data.chats) === null || _data$chats === void 0 ? void 0 : _data$chats.length) || 0)) {
|
|
65
|
+
var _data$chats2;
|
|
66
|
+
console.warn(`⚠️ [HINGE_EXTRACTOR] Filtered out ${(((_data$chats2 = data.chats) === null || _data$chats2 === void 0 ? void 0 : _data$chats2.length) || 0) - validChats.length} invalid chats`);
|
|
67
|
+
}
|
|
68
|
+
try {
|
|
69
|
+
console.log('📡 [HINGE_EXTRACTOR] Sending to backend...');
|
|
70
|
+
const result = await storeHingeData(username, {
|
|
71
|
+
matches: data.matches || [],
|
|
72
|
+
chats: validChats
|
|
73
|
+
});
|
|
74
|
+
if (result.success) {
|
|
75
|
+
console.log('✅ [HINGE_EXTRACTOR] Export completed successfully');
|
|
76
|
+
console.log('📊 [HINGE_EXTRACTOR] Backend response:', result.data);
|
|
77
|
+
return true;
|
|
78
|
+
} else {
|
|
79
|
+
console.error('❌ [HINGE_EXTRACTOR] Backend storage failed:', result.error);
|
|
80
|
+
Alert.alert('Export Failed', result.error || 'An unknown error occurred during data storage.', [{
|
|
81
|
+
text: 'OK',
|
|
82
|
+
style: 'default'
|
|
83
|
+
}]);
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
} catch (error) {
|
|
87
|
+
console.error('❌ [HINGE_EXTRACTOR] Unexpected error during export:', error);
|
|
88
|
+
Alert.alert('Export Error', 'Failed to connect to the data storage service. Please check your network connection.', [{
|
|
89
|
+
text: 'OK',
|
|
90
|
+
style: 'default'
|
|
91
|
+
}]);
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
return {
|
|
96
|
+
initiateDataExport
|
|
97
|
+
};
|
|
98
|
+
};
|
|
99
|
+
//# sourceMappingURL=hingeDataExtractor.js.map
|
|
@@ -1 +1,143 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Hinge Data Service
|
|
3
|
+
*
|
|
4
|
+
* API layer for storing Hinge data on backend.
|
|
5
|
+
* Sends extracted matches and chats to /platform-data/store endpoint.
|
|
6
|
+
*
|
|
7
|
+
* MATCHES ChatGPT implementation pattern
|
|
8
|
+
* - Sends data in batches
|
|
9
|
+
* - Uses format: { platform, data, metadata }
|
|
10
|
+
* - Platform: "mobile-hinge"
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { API_CONFIG } from '../config/api';
|
|
14
|
+
import AsyncStorage from '@react-native-async-storage/async-storage';
|
|
15
|
+
import { Platform } from 'react-native';
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Structure of a single message in a chat
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Structure of chat data extracted from Hinge
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Structure of match data extracted from Hinge
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Combined Hinge data to store
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Response from backend endpoint
|
|
35
|
+
*/
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Store Hinge data on backend
|
|
39
|
+
*
|
|
40
|
+
* @param userId - Username or identifier
|
|
41
|
+
* @param data - Hinge matches and chat data
|
|
42
|
+
* @returns Response indicating success/failure with metadata
|
|
43
|
+
*/
|
|
44
|
+
export const storeHingeData = async (userId, data) => {
|
|
45
|
+
console.log('🚀 [HINGE_SERVICE] Storing Hinge data for:', userId);
|
|
46
|
+
console.log('📊 [HINGE_SERVICE] Matches:', data.matches.length);
|
|
47
|
+
console.log('📊 [HINGE_SERVICE] Chats:', data.chats.length);
|
|
48
|
+
console.log('📊 [HINGE_SERVICE] Total user messages:', data.chats.reduce((sum, c) => sum + c.user_messages.length, 0));
|
|
49
|
+
|
|
50
|
+
// Input validation
|
|
51
|
+
if (!userId) {
|
|
52
|
+
console.error('❌ [HINGE_SERVICE] Invalid input: userId missing');
|
|
53
|
+
return {
|
|
54
|
+
success: false,
|
|
55
|
+
error: 'Invalid input: userId missing.'
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
try {
|
|
59
|
+
// Get auth token - check all possible storage keys
|
|
60
|
+
const authToken = (await AsyncStorage.getItem('onairos_jwt_token')) || (await AsyncStorage.getItem('enoch_token')) || (await AsyncStorage.getItem('auth_token'));
|
|
61
|
+
if (!authToken) {
|
|
62
|
+
console.error('❌ [HINGE_SERVICE] No auth token found');
|
|
63
|
+
return {
|
|
64
|
+
success: false,
|
|
65
|
+
error: 'Authentication token not found. Please log in again.'
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
console.log('🔑 [HINGE_SERVICE] Auth token found');
|
|
69
|
+
|
|
70
|
+
// Mobile metadata
|
|
71
|
+
const mobileMetadata = {
|
|
72
|
+
platform: Platform.OS,
|
|
73
|
+
appVersion: '1.0.0',
|
|
74
|
+
osVersion: Platform.OS === 'ios' ? '17.0' : Platform.OS,
|
|
75
|
+
deviceModel: Platform.OS === 'ios' ? 'iPhone' : 'Android',
|
|
76
|
+
isOfflineSync: false,
|
|
77
|
+
extractedAt: new Date().toISOString()
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
// Build request body
|
|
81
|
+
const requestBody = {
|
|
82
|
+
platform: 'mobile-hinge',
|
|
83
|
+
dataType: 'dating',
|
|
84
|
+
data: {
|
|
85
|
+
matches: data.matches,
|
|
86
|
+
chats: data.chats.map(chat => ({
|
|
87
|
+
matchId: chat.match_id,
|
|
88
|
+
matchName: chat.match_name,
|
|
89
|
+
messages: chat.user_messages.map((msg, idx) => ({
|
|
90
|
+
id: `${chat.match_id}-msg-${idx}`,
|
|
91
|
+
content: msg.content,
|
|
92
|
+
timestamp: msg.timestamp || new Date().toISOString(),
|
|
93
|
+
role: 'user'
|
|
94
|
+
})),
|
|
95
|
+
totalMessages: chat.total_messages
|
|
96
|
+
}))
|
|
97
|
+
},
|
|
98
|
+
summary: {
|
|
99
|
+
matchCount: data.matches.length,
|
|
100
|
+
chatCount: data.chats.length,
|
|
101
|
+
totalUserMessages: data.chats.reduce((sum, c) => sum + c.user_messages.length, 0)
|
|
102
|
+
},
|
|
103
|
+
mobileMetadata: mobileMetadata
|
|
104
|
+
};
|
|
105
|
+
console.log('📡 [HINGE_SERVICE] Sending to backend...');
|
|
106
|
+
console.log('📍 [HINGE_SERVICE] URL:', `${API_CONFIG.BASE_URL}/platform-data/store`);
|
|
107
|
+
const response = await fetch(`${API_CONFIG.BASE_URL}/platform-data/store`, {
|
|
108
|
+
method: 'POST',
|
|
109
|
+
headers: {
|
|
110
|
+
'Content-Type': 'application/json',
|
|
111
|
+
'Authorization': `Bearer ${authToken}`,
|
|
112
|
+
'User-Agent': `OnairosSDK/1.0.0 (${Platform.OS})`
|
|
113
|
+
},
|
|
114
|
+
body: JSON.stringify(requestBody)
|
|
115
|
+
});
|
|
116
|
+
const responseData = await response.json();
|
|
117
|
+
if (response.ok) {
|
|
118
|
+
console.log('✅ [HINGE_SERVICE] Successfully stored Hinge data');
|
|
119
|
+
if (responseData.message) {
|
|
120
|
+
console.log(`📝 [HINGE_SERVICE] Backend response: ${responseData.message}`);
|
|
121
|
+
}
|
|
122
|
+
return {
|
|
123
|
+
success: true,
|
|
124
|
+
message: responseData.message || 'Hinge data stored successfully',
|
|
125
|
+
data: responseData.data
|
|
126
|
+
};
|
|
127
|
+
} else {
|
|
128
|
+
console.warn(`⚠️ [HINGE_SERVICE] Backend returned status: ${response.status}`);
|
|
129
|
+
console.warn(`⚠️ [HINGE_SERVICE] Error: ${responseData.error || 'Unknown error'}`);
|
|
130
|
+
return {
|
|
131
|
+
success: false,
|
|
132
|
+
error: responseData.error || `HTTP ${response.status}`
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
} catch (error) {
|
|
136
|
+
console.error('❌ [HINGE_SERVICE] Network error:', error);
|
|
137
|
+
return {
|
|
138
|
+
success: false,
|
|
139
|
+
error: error.message || 'Network error. Please check your connection.'
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
//# sourceMappingURL=hingeDataService.js.map
|
|
@@ -1 +1,250 @@
|
|
|
1
|
-
import _0x1eb3e1 from'@bam.tech/react-native-image-resizer';function _0x4787(_0x1de9c0,_0x4787f5){_0x1de9c0=_0x1de9c0-0x0;const _0x1abcba=_0x1de9();let _0x3d1b11=_0x1abcba[_0x1de9c0];return _0x3d1b11;}const getFileSizeFromUri=async _0x426d95=>{const _0x48461c={'tAlZu':function(_0x93eafc,_0xb14eb9){return _0x93eafc(_0xb14eb9);},'KfwFW':_0x4787(0x0)};try{const _0x1eb208=await _0x48461c[_0x4787(0x1)](fetch,_0x426d95),_0x97efe=await _0x1eb208[_0x4787(0x2)]();return _0x97efe[_0x4787(0x3)];}catch(_0x133420){return console[_0x4787(0x4)](_0x48461c['KfwFW'],_0x133420),0x0;}},imageToBase64=async _0x4adea1=>{const _0x3baf75={'WPYDS':_0x4787(0x5),'GMBBD':function(_0x4c4594,_0xbc3ca){return _0x4c4594(_0xbc3ca);},'CQFyB':function(_0x12b325,_0x40e04b){return _0x12b325===_0x40e04b;}};try{const _0x464365=await _0x3baf75[_0x4787(0x6)](fetch,_0x4adea1),_0x538616=await _0x464365['blob']();return new Promise((_0x1204fb,_0x25863e)=>{const _0xadc5a5=new FileReader();_0xadc5a5[_0x4787(0x7)]=()=>{const _0x450b03={'RRGut':_0x3baf75[_0x4787(0x8)]};try{const _0x4178cb=_0xadc5a5[_0x4787(0x9)],_0x807ea3=_0x4178cb[_0x4787(0xa)](',')[0x1];_0x3baf75[_0x4787(0x6)](_0x1204fb,_0x807ea3);}catch(_0x4e771d){if(_0x3baf75[_0x4787(0xb)](_0x4787(0xc),_0x4787(0xc)))_0x3baf75[_0x4787(0x6)](_0x25863e,_0x4e771d);else return _0x24dfbe[_0x4787(0x4)](_0x450b03['RRGut'],_0x157ff3),null;}},_0xadc5a5[_0x4787(0xd)]=_0x25863e,_0xadc5a5[_0x4787(0xe)](_0x538616);});}catch(_0x3bc0e6){return console['error'](_0x3baf75[_0x4787(0x8)],_0x3bc0e6),null;}};export const compressImageToTarget=async(_0x2d8020,_0x3de6b5={})=>{const _0x148f42={'rTWJw':_0x4787(0xf),'IpwdV':function(_0x5e57c8,_0xc8e686){return _0x5e57c8/_0xc8e686;},'wEAPY':function(_0x44d81f,_0x54ae69){return _0x44d81f*_0x54ae69;},'DWHOV':function(_0x5813cb,_0x4e5315){return _0x5813cb*_0x4e5315;},'nujRc':function(_0x3d9231,_0x34b7cd){return _0x3d9231(_0x34b7cd);},'VYOlf':function(_0x39f9ec,_0x1b1523){return _0x39f9ec*_0x1b1523;},'rYfDT':_0x4787(0x10),'jhvmH':function(_0x524cb7,_0x2b93fe){return _0x524cb7!==_0x2b93fe;},'svCnY':_0x4787(0x11),'vNPEp':_0x4787(0x12),'ARMAJ':function(_0x55f280,_0x41bf5c){return _0x55f280<=_0x41bf5c;},'GuKmi':_0x4787(0x13),'ZrPIu':function(_0x33c7fc,_0x42f58f){return _0x33c7fc(_0x42f58f);},'mxtWR':function(_0x4150eb,_0x9e8582){return _0x4150eb<_0x9e8582;},'Bwbrs':'avAur','LSdeo':function(_0x431d1c,_0x5e3e6b){return _0x431d1c!==_0x5e3e6b;},'tXdIE':'rkFty','adqDb':'htZOM','KhGKX':_0x4787(0x14),'BPbot':_0x4787(0x15),'pRGsb':function(_0x723fb6,_0x4ac03e){return _0x723fb6+_0x4ac03e;},'HMPJM':function(_0x31a5b2,_0x2d0469){return _0x31a5b2>_0x2d0469;},'IeYuS':function(_0x6b7a3f,_0x3bcddd){return _0x6b7a3f*_0x3bcddd;},'oTzLU':function(_0x19a82c,_0x2b2ca9){return _0x19a82c>_0x2b2ca9;},'knDmp':function(_0x4992b3,_0x14684c){return _0x4992b3*_0x14684c;},'wIQwZ':function(_0x221234,_0xe2fa53){return _0x221234!==_0xe2fa53;},'lzjmR':_0x4787(0x16),'sdvRw':function(_0x50d12c,_0x1bb1d3){return _0x50d12c*_0x1bb1d3;},'NoWSS':function(_0x189d6d,_0x305010){return _0x189d6d<_0x305010;},'SnZGh':_0x4787(0x17),'RFZjs':_0x4787(0x18),'dgKMy':function(_0x27c3ac,_0x464127){return _0x27c3ac(_0x464127);},'xezpD':function(_0x3f4c7a,_0x3df1a7){return _0x3f4c7a/_0x3df1a7;},'NkMJj':function(_0x18d8b0,_0x95458e){return _0x18d8b0(_0x95458e);},'zEmni':function(_0x237b7f,_0x386dab){return _0x237b7f/_0x386dab;},'mvHgz':_0x4787(0x19),'DkkHl':'VWEez','KlYLl':_0x4787(0x1a),'AtyPC':function(_0x6cb2b9,_0x4fec2d){return _0x6cb2b9 instanceof _0x4fec2d;},'WnDjy':_0x4787(0x1b)},{maxSizeKB:maxSizeKB=0x12c,maxWidth:maxWidth=0x4b0,maxHeight:maxHeight=0x4b0,quality:quality=0.8,format:format=_0x148f42[_0x4787(0x1c)]}=_0x3de6b5;try{if(_0x148f42[_0x4787(0x1d)](_0x4787(0x11),_0x148f42[_0x4787(0x1e)]))return _0x36a4b3[_0x4787(0x1f)](_0x148f42[_0x4787(0x20)],_0x196b74,'KB'),{'success':!![],'base64':_0x489a39,'sizeKB':_0x2b46f3,'originalSizeKB':_0x4da4bd,'compressionRatio':_0x148f42[_0x4787(0x21)](_0x5919ff,_0x4aba68)};else{console[_0x4787(0x1f)]('🖼️\x20[COMPRESSION]\x20Starting\x20compression\x20for:',_0x2d8020);const _0xe9d29e=await getFileSizeFromUri(_0x2d8020),_0x53c917=Math[_0x4787(0x22)](_0xe9d29e/0x400);console[_0x4787(0x1f)](_0x148f42[_0x4787(0x23)],_0x53c917,'KB');if(_0x148f42[_0x4787(0x24)](_0x53c917,maxSizeKB)){console[_0x4787(0x1f)](_0x148f42[_0x4787(0x25)]);const _0x8e20f2=await _0x148f42[_0x4787(0x26)](imageToBase64,_0x2d8020);if(_0x8e20f2)return{'success':!![],'base64':_0x8e20f2,'sizeKB':_0x53c917,'originalSizeKB':_0x53c917,'compressionRatio':0x1};}let _0x4fec05=quality,_0x2f4177=maxWidth,_0x1af441=maxHeight,_0x271ddf=0x0;const _0x311b34=0x8;while(_0x148f42['mxtWR'](_0x271ddf,_0x311b34)){_0x271ddf++,console[_0x4787(0x1f)]('🔄\x20[COMPRESSION]\x20Attempt\x20'+_0x271ddf+_0x4787(0x27)+_0x4fec05+',\x20size='+_0x2f4177+'x'+_0x1af441);try{if(_0x148f42[_0x4787(0x28)]!==_0x4787(0x29)){const _0x7e62eb=await _0x1eb3e1['createResizedImage'](_0x2d8020,_0x2f4177,_0x1af441,format,Math['round'](_0x148f42['DWHOV'](_0x4fec05,0x64)),0x0,undefined,![],{'mode':_0x4787(0x18),'onlyScaleDown':!![]}),_0x3a4654=await _0x148f42[_0x4787(0x26)](getFileSizeFromUri,_0x7e62eb[_0x4787(0x2a)]),_0x5e5320=Math[_0x4787(0x22)](_0x3a4654/0x400);console[_0x4787(0x1f)](_0x4787(0x2b)+_0x271ddf+'\x20result:\x20'+_0x5e5320+_0x4787(0x2c));if(_0x5e5320<=maxSizeKB){if(_0x148f42[_0x4787(0x2d)](_0x148f42[_0x4787(0x2e)],_0x148f42['adqDb'])){console[_0x4787(0x1f)](_0x148f42[_0x4787(0x2f)]);const _0x3b4f47=await _0x148f42[_0x4787(0x30)](imageToBase64,_0x7e62eb[_0x4787(0x2a)]);if(_0x3b4f47){const _0x2cc3de=_0x148f42[_0x4787(0x21)](_0x53c917,_0x5e5320);return console['log'](_0x148f42[_0x4787(0x31)],{'originalSizeKB':_0x53c917,'finalSizeKB':_0x5e5320,'compressionRatio':_0x148f42['pRGsb'](_0x2cc3de[_0x4787(0x32)](0x2),'x'),'attempts':_0x271ddf}),{'success':!![],'base64':_0x3b4f47,'sizeKB':_0x5e5320,'originalSizeKB':_0x53c917,'compressionRatio':_0x2cc3de};}}else _0x104266*=0.75,_0x303bb8=_0x30dd81[_0x4787(0x22)](_0x148f42[_0x4787(0x33)](_0x36f6fe,0.9)),_0x4592c5=_0x3a22cf[_0x4787(0x22)](_0x148f42['DWHOV'](_0x16e28f,0.9));}if(_0x148f42[_0x4787(0x34)](_0x5e5320,maxSizeKB)){const _0x2390d7=_0x148f42[_0x4787(0x21)](_0x5e5320,maxSizeKB);if(_0x148f42[_0x4787(0x34)](_0x2390d7,0x2))_0x4fec05*=0.6,_0x2f4177=Math[_0x4787(0x22)](_0x2f4177*0.8),_0x1af441=Math['round'](_0x148f42[_0x4787(0x35)](_0x1af441,0.8));else _0x148f42[_0x4787(0x36)](_0x2390d7,1.5)?(_0x4fec05*=0.75,_0x2f4177=Math['round'](_0x148f42[_0x4787(0x35)](_0x2f4177,0.9)),_0x1af441=Math[_0x4787(0x22)](_0x148f42[_0x4787(0x37)](_0x1af441,0.9))):_0x148f42[_0x4787(0x38)](_0x4787(0x16),_0x148f42['lzjmR'])?_0x4303cb*=0.85:_0x4fec05*=0.85;_0x4fec05=Math[_0x4787(0x39)](0.1,_0x4fec05),_0x2f4177=Math[_0x4787(0x39)](0x190,_0x2f4177),_0x1af441=Math[_0x4787(0x39)](0x190,_0x1af441);}}else return{'success':!![],'base64':_0x2fbc49,'sizeKB':_0x5b4a96,'originalSizeKB':_0x21b1ff,'compressionRatio':0x1};}catch(_0xf58784){console['error'](_0x4787(0x3a)+_0x271ddf+_0x4787(0x3b),_0xf58784),_0x4fec05*=0.7,_0x2f4177=Math[_0x4787(0x22)](_0x148f42['DWHOV'](_0x2f4177,0.8)),_0x1af441=Math[_0x4787(0x22)](_0x148f42[_0x4787(0x3c)](_0x1af441,0.8));if(_0x148f42[_0x4787(0x3d)](_0x4fec05,0.1)||_0x2f4177<0xc8||_0x148f42[_0x4787(0x3e)](_0x1af441,0xc8))break;}}console[_0x4787(0x1f)](_0x148f42['SnZGh']);try{if(_0x4787(0x3f)===_0x4787(0x40)){const _0x18a7b3=_0xed4c7['result'],_0x2c8bda=_0x18a7b3[_0x4787(0xa)](',')[0x1];_0x148f42[_0x4787(0x30)](_0x15d841,_0x2c8bda);}else{const _0x1783e7=await _0x1eb3e1[_0x4787(0x41)](_0x2d8020,Math[_0x4787(0x39)](0x190,_0x2f4177),Math[_0x4787(0x39)](0x190,_0x1af441),format,0x1e,0x0,undefined,![],{'mode':_0x148f42['RFZjs'],'onlyScaleDown':!![]}),_0x261c5f=await _0x148f42[_0x4787(0x42)](getFileSizeFromUri,_0x1783e7[_0x4787(0x2a)]),_0x43b04f=Math[_0x4787(0x22)](_0x148f42[_0x4787(0x43)](_0x261c5f,0x400)),_0x1ff2c2=await _0x148f42[_0x4787(0x44)](imageToBase64,_0x1783e7[_0x4787(0x2a)]);if(_0x1ff2c2)return console[_0x4787(0x1f)](_0x148f42[_0x4787(0x20)],_0x43b04f,'KB'),{'success':!![],'base64':_0x1ff2c2,'sizeKB':_0x43b04f,'originalSizeKB':_0x53c917,'compressionRatio':_0x148f42['zEmni'](_0x53c917,_0x43b04f)};}}catch(_0x4b3992){if(_0x148f42[_0x4787(0x45)]==='tBoOz')console['error'](_0x4787(0x46),_0x4b3992);else return _0x474e8c(_0x476f63,{'maxSizeKB':_0x5b5e5e,'maxWidth':0x4b0,'maxHeight':0x4b0,'quality':0.8,'format':_0x4787(0x10)});}return{'success':![],'error':_0x4787(0x47)+maxSizeKB+_0x4787(0x48)+_0x311b34+_0x4787(0x49),'originalSizeKB':_0x53c917};}}catch(_0x2cf29d){if(_0x148f42[_0x4787(0x1d)](_0x148f42[_0x4787(0x4a)],_0x4787(0x4b)))return console[_0x4787(0x4)](_0x148f42[_0x4787(0x4c)],_0x2cf29d),{'success':![],'error':_0x148f42[_0x4787(0x4d)](_0x2cf29d,Error)?_0x2cf29d['message']:_0x148f42[_0x4787(0x4e)],'originalSizeKB':0x0};else _0x1068b8*=0.6,_0x3f6f5b=_0x1b0124[_0x4787(0x22)](_0x3f789d*0.8),_0xade4ee=_0x281750[_0x4787(0x22)](_0x148f42[_0x4787(0x4f)](_0x52e00c,0.8));}};export const compressProfilePicture=async _0x35d901=>{const _0x1d65ab={'AYdiF':function(_0x466662,_0x2fb5fa,_0x3f4246){return _0x466662(_0x2fb5fa,_0x3f4246);}};return _0x1d65ab[_0x4787(0x50)](compressImageToTarget,_0x35d901,{'maxSizeKB':0x12c,'maxWidth':0x4b0,'maxHeight':0x4b0,'quality':0.8,'format':_0x4787(0x10)});};export const compressForUpload=async(_0x4c5538,_0x513a40=0x12c)=>{const _0xcda5a6={'qMsci':function(_0x568ac6,_0x29183d,_0xaeec4a){return _0x568ac6(_0x29183d,_0xaeec4a);},'TqXRM':_0x4787(0x10)};return _0xcda5a6[_0x4787(0x51)](compressImageToTarget,_0x4c5538,{'maxSizeKB':_0x513a40,'maxWidth':0x4b0,'maxHeight':0x4b0,'quality':0.8,'format':_0xcda5a6['TqXRM']});};function _0x1de9(){const _0x3e5cd0=['Error\x20getting\x20file\x20size:','tAlZu','blob','size','error','Error\x20converting\x20image\x20to\x20base64:','GMBBD','onloadend','WPYDS','result','split','CQFyB','UqdsL','onerror','readAsDataURL','📤\x20[COMPRESSION]\x20Final\x20result\x20(best\x20effort):','JPEG','kHmbi','📊\x20[COMPRESSION]\x20Original\x20size:','✅\x20[COMPRESSION]\x20Image\x20already\x20under\x20target\x20size','✅\x20[COMPRESSION]\x20Target\x20size\x20achieved!','🎯\x20[COMPRESSION]\x20Success:','foGgm','⚠️\x20[COMPRESSION]\x20Max\x20attempts\x20reached,\x20using\x20best\x20effort','contain','tBoOz','❌\x20[COMPRESSION]\x20Compression\x20service\x20error:','Unknown\x20compression\x20error','rYfDT','jhvmH','svCnY','log','rTWJw','IpwdV','round','vNPEp','ARMAJ','GuKmi','ZrPIu',':\x20quality=','Bwbrs','SMpWb','uri','📊\x20[COMPRESSION]\x20Attempt\x20','\x20KB','LSdeo','tXdIE','KhGKX','nujRc','BPbot','toFixed','wEAPY','HMPJM','IeYuS','oTzLU','knDmp','wIQwZ','max','❌\x20[COMPRESSION]\x20Resize\x20attempt\x20','\x20failed:','sdvRw','mxtWR','NoWSS','DnZaB','LvEsB','createResizedImage','dgKMy','xezpD','NkMJj','mvHgz','❌\x20[COMPRESSION]\x20Final\x20compression\x20attempt\x20failed:','Failed\x20to\x20compress\x20image\x20to\x20','KB\x20after\x20','\x20attempts','DkkHl','kIhdk','KlYLl','AtyPC','WnDjy','VYOlf','AYdiF','qMsci','cmRgi','pJaXN','success','base64'];_0x1de9=function(){return _0x3e5cd0;};return _0x1de9();}export const convertImageToOptimizedBase64=async(_0x5afd7e,_0x3c66cd=0.8)=>{const _0x887c18={'cmRgi':function(_0x95e981,_0x514213,_0x33037e){return _0x95e981(_0x514213,_0x33037e);},'pJaXN':_0x4787(0x10)},_0x548280=await _0x887c18[_0x4787(0x52)](compressImageToTarget,_0x5afd7e,{'maxSizeKB':0x12c,'quality':_0x3c66cd,'format':_0x887c18[_0x4787(0x53)]});return _0x548280[_0x4787(0x54)]?_0x548280[_0x4787(0x55)]||null:null;};
|
|
1
|
+
import ImageResizer from '@bam.tech/react-native-image-resizer';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Comprehensive image compression service for React Native
|
|
5
|
+
* Supports iterative compression to meet specific size targets
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Get file size from URI (React Native compatible)
|
|
10
|
+
*/
|
|
11
|
+
const getFileSizeFromUri = async uri => {
|
|
12
|
+
try {
|
|
13
|
+
const response = await fetch(uri);
|
|
14
|
+
const blob = await response.blob();
|
|
15
|
+
return blob.size;
|
|
16
|
+
} catch (error) {
|
|
17
|
+
console.error('Error getting file size:', error);
|
|
18
|
+
return 0;
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Convert image to base64 string
|
|
24
|
+
*/
|
|
25
|
+
const imageToBase64 = async uri => {
|
|
26
|
+
try {
|
|
27
|
+
const response = await fetch(uri);
|
|
28
|
+
const blob = await response.blob();
|
|
29
|
+
return new Promise((resolve, reject) => {
|
|
30
|
+
const reader = new FileReader();
|
|
31
|
+
reader.onloadend = () => {
|
|
32
|
+
try {
|
|
33
|
+
const base64data = reader.result;
|
|
34
|
+
// Remove the data:image/jpeg;base64, prefix
|
|
35
|
+
const base64 = base64data.split(',')[1];
|
|
36
|
+
resolve(base64);
|
|
37
|
+
} catch (error) {
|
|
38
|
+
reject(error);
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
reader.onerror = reject;
|
|
42
|
+
reader.readAsDataURL(blob);
|
|
43
|
+
});
|
|
44
|
+
} catch (error) {
|
|
45
|
+
console.error('Error converting image to base64:', error);
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Compress image with iterative quality reduction to meet size target
|
|
52
|
+
*/
|
|
53
|
+
export const compressImageToTarget = async (imageUri, options = {}) => {
|
|
54
|
+
const {
|
|
55
|
+
maxSizeKB = 300,
|
|
56
|
+
maxWidth = 1200,
|
|
57
|
+
maxHeight = 1200,
|
|
58
|
+
quality = 0.8,
|
|
59
|
+
format = 'JPEG'
|
|
60
|
+
} = options;
|
|
61
|
+
try {
|
|
62
|
+
console.log('🖼️ [COMPRESSION] Starting compression for:', imageUri);
|
|
63
|
+
|
|
64
|
+
// Get original file size
|
|
65
|
+
const originalSize = await getFileSizeFromUri(imageUri);
|
|
66
|
+
const originalSizeKB = Math.round(originalSize / 1024);
|
|
67
|
+
console.log('📊 [COMPRESSION] Original size:', originalSizeKB, 'KB');
|
|
68
|
+
|
|
69
|
+
// If already under target, just convert to base64
|
|
70
|
+
if (originalSizeKB <= maxSizeKB) {
|
|
71
|
+
console.log('✅ [COMPRESSION] Image already under target size');
|
|
72
|
+
const base64 = await imageToBase64(imageUri);
|
|
73
|
+
if (base64) {
|
|
74
|
+
return {
|
|
75
|
+
success: true,
|
|
76
|
+
base64,
|
|
77
|
+
sizeKB: originalSizeKB,
|
|
78
|
+
originalSizeKB,
|
|
79
|
+
compressionRatio: 1.0
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Start with initial compression parameters
|
|
85
|
+
let currentQuality = quality;
|
|
86
|
+
let currentWidth = maxWidth;
|
|
87
|
+
let currentHeight = maxHeight;
|
|
88
|
+
let attempts = 0;
|
|
89
|
+
const maxAttempts = 8;
|
|
90
|
+
while (attempts < maxAttempts) {
|
|
91
|
+
attempts++;
|
|
92
|
+
console.log(`🔄 [COMPRESSION] Attempt ${attempts}: quality=${currentQuality}, size=${currentWidth}x${currentHeight}`);
|
|
93
|
+
try {
|
|
94
|
+
// Resize and compress the image
|
|
95
|
+
const resizedImage = await ImageResizer.createResizedImage(imageUri, currentWidth, currentHeight, format, Math.round(currentQuality * 100),
|
|
96
|
+
// Convert to percentage
|
|
97
|
+
0,
|
|
98
|
+
// rotation
|
|
99
|
+
undefined,
|
|
100
|
+
// outputPath
|
|
101
|
+
false,
|
|
102
|
+
// keepMeta
|
|
103
|
+
{
|
|
104
|
+
mode: 'contain',
|
|
105
|
+
// Maintain aspect ratio
|
|
106
|
+
onlyScaleDown: true // Don't upscale
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
// Check the size of the compressed image
|
|
110
|
+
const compressedSize = await getFileSizeFromUri(resizedImage.uri);
|
|
111
|
+
const compressedSizeKB = Math.round(compressedSize / 1024);
|
|
112
|
+
console.log(`📊 [COMPRESSION] Attempt ${attempts} result: ${compressedSizeKB} KB`);
|
|
113
|
+
|
|
114
|
+
// If we've hit our target, convert to base64 and return
|
|
115
|
+
if (compressedSizeKB <= maxSizeKB) {
|
|
116
|
+
console.log('✅ [COMPRESSION] Target size achieved!');
|
|
117
|
+
const base64 = await imageToBase64(resizedImage.uri);
|
|
118
|
+
if (base64) {
|
|
119
|
+
const compressionRatio = originalSizeKB / compressedSizeKB;
|
|
120
|
+
console.log('🎯 [COMPRESSION] Success:', {
|
|
121
|
+
originalSizeKB,
|
|
122
|
+
finalSizeKB: compressedSizeKB,
|
|
123
|
+
compressionRatio: compressionRatio.toFixed(2) + 'x',
|
|
124
|
+
attempts
|
|
125
|
+
});
|
|
126
|
+
return {
|
|
127
|
+
success: true,
|
|
128
|
+
base64,
|
|
129
|
+
sizeKB: compressedSizeKB,
|
|
130
|
+
originalSizeKB,
|
|
131
|
+
compressionRatio
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// If still too large, adjust parameters for next attempt
|
|
137
|
+
if (compressedSizeKB > maxSizeKB) {
|
|
138
|
+
// Reduce quality more aggressively if we're way over
|
|
139
|
+
const sizeRatio = compressedSizeKB / maxSizeKB;
|
|
140
|
+
if (sizeRatio > 2.0) {
|
|
141
|
+
// Way too big - reduce quality and dimensions significantly
|
|
142
|
+
currentQuality *= 0.6;
|
|
143
|
+
currentWidth = Math.round(currentWidth * 0.8);
|
|
144
|
+
currentHeight = Math.round(currentHeight * 0.8);
|
|
145
|
+
} else if (sizeRatio > 1.5) {
|
|
146
|
+
// Moderately too big - reduce quality more
|
|
147
|
+
currentQuality *= 0.75;
|
|
148
|
+
currentWidth = Math.round(currentWidth * 0.9);
|
|
149
|
+
currentHeight = Math.round(currentHeight * 0.9);
|
|
150
|
+
} else {
|
|
151
|
+
// Close to target - fine-tune quality
|
|
152
|
+
currentQuality *= 0.85;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Ensure we don't go below minimum thresholds
|
|
156
|
+
currentQuality = Math.max(0.1, currentQuality);
|
|
157
|
+
currentWidth = Math.max(400, currentWidth);
|
|
158
|
+
currentHeight = Math.max(400, currentHeight);
|
|
159
|
+
}
|
|
160
|
+
} catch (resizeError) {
|
|
161
|
+
console.error(`❌ [COMPRESSION] Resize attempt ${attempts} failed:`, resizeError);
|
|
162
|
+
|
|
163
|
+
// Try with more aggressive settings
|
|
164
|
+
currentQuality *= 0.7;
|
|
165
|
+
currentWidth = Math.round(currentWidth * 0.8);
|
|
166
|
+
currentHeight = Math.round(currentHeight * 0.8);
|
|
167
|
+
if (currentQuality < 0.1 || currentWidth < 200 || currentHeight < 200) {
|
|
168
|
+
break;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// If we've exhausted all attempts, return the best effort
|
|
174
|
+
console.log('⚠️ [COMPRESSION] Max attempts reached, using best effort');
|
|
175
|
+
try {
|
|
176
|
+
const finalImage = await ImageResizer.createResizedImage(imageUri, Math.max(400, currentWidth), Math.max(400, currentHeight), format, 30,
|
|
177
|
+
// Very low quality as last resort
|
|
178
|
+
0, undefined, false, {
|
|
179
|
+
mode: 'contain',
|
|
180
|
+
onlyScaleDown: true
|
|
181
|
+
});
|
|
182
|
+
const finalSize = await getFileSizeFromUri(finalImage.uri);
|
|
183
|
+
const finalSizeKB = Math.round(finalSize / 1024);
|
|
184
|
+
const base64 = await imageToBase64(finalImage.uri);
|
|
185
|
+
if (base64) {
|
|
186
|
+
console.log('📤 [COMPRESSION] Final result (best effort):', finalSizeKB, 'KB');
|
|
187
|
+
return {
|
|
188
|
+
success: true,
|
|
189
|
+
base64,
|
|
190
|
+
sizeKB: finalSizeKB,
|
|
191
|
+
originalSizeKB,
|
|
192
|
+
compressionRatio: originalSizeKB / finalSizeKB
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
} catch (finalError) {
|
|
196
|
+
console.error('❌ [COMPRESSION] Final compression attempt failed:', finalError);
|
|
197
|
+
}
|
|
198
|
+
return {
|
|
199
|
+
success: false,
|
|
200
|
+
error: `Failed to compress image to ${maxSizeKB}KB after ${maxAttempts} attempts`,
|
|
201
|
+
originalSizeKB
|
|
202
|
+
};
|
|
203
|
+
} catch (error) {
|
|
204
|
+
console.error('❌ [COMPRESSION] Compression service error:', error);
|
|
205
|
+
return {
|
|
206
|
+
success: false,
|
|
207
|
+
error: error instanceof Error ? error.message : 'Unknown compression error',
|
|
208
|
+
originalSizeKB: 0
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Quick compression for profile pictures (300KB target)
|
|
215
|
+
*/
|
|
216
|
+
export const compressProfilePicture = async imageUri => {
|
|
217
|
+
return compressImageToTarget(imageUri, {
|
|
218
|
+
maxSizeKB: 300,
|
|
219
|
+
maxWidth: 1200,
|
|
220
|
+
maxHeight: 1200,
|
|
221
|
+
quality: 0.8,
|
|
222
|
+
format: 'JPEG'
|
|
223
|
+
});
|
|
224
|
+
};
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Compress image for upload with custom settings
|
|
228
|
+
*/
|
|
229
|
+
export const compressForUpload = async (imageUri, maxSizeKB = 300) => {
|
|
230
|
+
return compressImageToTarget(imageUri, {
|
|
231
|
+
maxSizeKB,
|
|
232
|
+
maxWidth: 1200,
|
|
233
|
+
maxHeight: 1200,
|
|
234
|
+
quality: 0.8,
|
|
235
|
+
format: 'JPEG'
|
|
236
|
+
});
|
|
237
|
+
};
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Legacy function for backward compatibility
|
|
241
|
+
*/
|
|
242
|
+
export const convertImageToOptimizedBase64 = async (imageUri, quality = 0.8) => {
|
|
243
|
+
const result = await compressImageToTarget(imageUri, {
|
|
244
|
+
maxSizeKB: 300,
|
|
245
|
+
quality,
|
|
246
|
+
format: 'JPEG'
|
|
247
|
+
});
|
|
248
|
+
return result.success ? result.base64 || null : null;
|
|
249
|
+
};
|
|
250
|
+
//# sourceMappingURL=imageCompressionService.js.map
|