@onairos/react-native 3.1.15 → 3.1.17
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/README.md +404 -0
- package/lib/commonjs/assets/images/Checkbox.svg +3 -3
- package/lib/commonjs/assets/images/EnochE.svg +19 -19
- package/lib/commonjs/assets/images/Personalityprofile.svg +3 -3
- package/lib/commonjs/assets/images/Personalitytraits.svg +3 -3
- package/lib/commonjs/assets/images/Userpreferences.svg +3 -3
- package/lib/commonjs/assets/images/arrow.svg +20 -20
- package/lib/commonjs/assets/images/basicproficon.svg +43 -43
- package/lib/commonjs/assets/images/basicprofile.svg +3 -3
- package/lib/commonjs/assets/images/checkmark.svg +4 -4
- package/lib/commonjs/assets/images/contentanalysis.svg +3 -3
- package/lib/commonjs/assets/images/contenticon.svg +23 -23
- package/lib/commonjs/assets/images/personalityicon.svg +18 -18
- package/lib/commonjs/assets/images/x-close.svg +3 -3
- package/lib/commonjs/components/OnairosSignInButton.js +32 -74
- package/lib/commonjs/components/OnairosSignInButton.js.map +1 -1
- package/lib/commonjs/components/UniversalOnboarding.js +4 -4
- package/lib/commonjs/config/api.js +2 -2
- package/lib/commonjs/hooks/useConnections.js +6 -6
- package/lib/commonjs/hooks/useUserConnections.js +10 -10
- package/lib/commonjs/index.js +5 -12
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/services/apiClient.js +35 -35
- package/lib/commonjs/services/apiKeyService.js +99 -99
- package/lib/commonjs/services/authService.js +82 -82
- package/lib/commonjs/services/biometricPinService.js +10 -10
- package/lib/commonjs/services/connectedAccountsService.js +32 -32
- package/lib/commonjs/services/googleAuthService.js +15 -15
- package/lib/commonjs/services/imageCompressionService.js +15 -15
- package/lib/commonjs/services/jwtStorageService.js +59 -59
- package/lib/commonjs/services/mobileTrainingService.js +14 -14
- package/lib/commonjs/services/pinEncryptionService.js +10 -10
- package/lib/commonjs/services/pinStorageUtils.js +15 -15
- package/lib/commonjs/services/platformAuthService.js +47 -47
- package/lib/commonjs/services/storageService.js +31 -31
- package/lib/commonjs/services/trainingApiHelpers.js +33 -33
- package/lib/commonjs/services/userConnectionsService.js +24 -24
- package/lib/commonjs/utils/Portal.js +4 -4
- package/lib/commonjs/utils/api.js +24 -24
- package/lib/commonjs/utils/auth.js +18 -18
- package/lib/commonjs/utils/crypto.js +13 -13
- package/lib/commonjs/utils/encryption.js +12 -12
- package/lib/commonjs/utils/eventUtils.js +52 -52
- package/lib/commonjs/utils/programmaticFlow.js +16 -16
- package/lib/commonjs/utils/retryHelper.js +27 -27
- package/lib/module/assets/images/Checkbox.svg +3 -3
- package/lib/module/assets/images/EnochE.svg +19 -19
- package/lib/module/assets/images/Personalityprofile.svg +3 -3
- package/lib/module/assets/images/Personalitytraits.svg +3 -3
- package/lib/module/assets/images/Userpreferences.svg +3 -3
- package/lib/module/assets/images/arrow.svg +20 -20
- package/lib/module/assets/images/basicproficon.svg +43 -43
- package/lib/module/assets/images/basicprofile.svg +3 -3
- package/lib/module/assets/images/checkmark.svg +4 -4
- package/lib/module/assets/images/contentanalysis.svg +3 -3
- package/lib/module/assets/images/contenticon.svg +23 -23
- package/lib/module/assets/images/personalityicon.svg +18 -18
- package/lib/module/assets/images/x-close.svg +3 -3
- package/lib/module/components/OnairosSignInButton.js +32 -74
- package/lib/module/components/OnairosSignInButton.js.map +1 -1
- package/lib/module/components/UniversalOnboarding.js +4 -4
- package/lib/module/config/api.js +2 -2
- package/lib/module/hooks/useConnections.js +6 -6
- package/lib/module/hooks/useUserConnections.js +10 -10
- package/lib/module/index.js +5 -6
- package/lib/module/index.js.map +1 -1
- package/lib/module/services/apiClient.js +35 -35
- package/lib/module/services/apiKeyService.js +99 -99
- package/lib/module/services/authService.js +82 -82
- package/lib/module/services/biometricPinService.js +10 -10
- package/lib/module/services/connectedAccountsService.js +32 -32
- package/lib/module/services/googleAuthService.js +15 -15
- package/lib/module/services/imageCompressionService.js +15 -15
- package/lib/module/services/jwtStorageService.js +59 -59
- package/lib/module/services/mobileTrainingService.js +14 -14
- package/lib/module/services/pinEncryptionService.js +10 -10
- package/lib/module/services/pinStorageUtils.js +15 -15
- package/lib/module/services/platformAuthService.js +47 -47
- package/lib/module/services/storageService.js +31 -31
- package/lib/module/services/trainingApiHelpers.js +33 -33
- package/lib/module/services/userConnectionsService.js +24 -24
- package/lib/module/utils/Portal.js +4 -4
- package/lib/module/utils/api.js +24 -24
- package/lib/module/utils/auth.js +18 -18
- package/lib/module/utils/crypto.js +13 -13
- package/lib/module/utils/encryption.js +12 -12
- package/lib/module/utils/eventUtils.js +52 -52
- package/lib/module/utils/programmaticFlow.js +16 -16
- package/lib/module/utils/retryHelper.js +27 -27
- package/lib/typescript/components/OnairosSignInButton.d.ts.map +1 -1
- package/lib/typescript/index.d.ts +0 -1
- package/lib/typescript/index.d.ts.map +1 -1
- package/package.json +163 -163
- package/src/api/index.ts +151 -151
- package/src/assets/images/Checkbox.svg +3 -3
- package/src/assets/images/EnochE.svg +19 -19
- package/src/assets/images/Personalityprofile.svg +3 -3
- package/src/assets/images/Personalitytraits.svg +3 -3
- package/src/assets/images/Userpreferences.svg +3 -3
- package/src/assets/images/arrow.svg +20 -20
- package/src/assets/images/basicproficon.svg +43 -43
- package/src/assets/images/basicprofile.svg +3 -3
- package/src/assets/images/checkmark.svg +4 -4
- package/src/assets/images/contentanalysis.svg +3 -3
- package/src/assets/images/contenticon.svg +23 -23
- package/src/assets/images/personalityicon.svg +18 -18
- package/src/assets/images/x-close.svg +3 -3
- package/src/components/BodyText.tsx +33 -33
- package/src/components/BrandMark.tsx +62 -62
- package/src/components/CodeInput.tsx +32 -32
- package/src/components/DataRequestScreen.tsx +355 -355
- package/src/components/EmailInput.tsx +31 -31
- package/src/components/EmailVerificationModal.tsx +363 -363
- package/src/components/ExistingUserDataConfirmation.tsx +506 -506
- package/src/components/GoogleButton.tsx +55 -55
- package/src/components/HeadingGroup.tsx +49 -49
- package/src/components/ModalHeader.tsx +125 -125
- package/src/components/ModalSheet.tsx +57 -57
- package/src/components/Onairos.tsx +422 -422
- package/src/components/OnairosButton.tsx +339 -339
- package/src/components/OnairosSignInButton.tsx +130 -166
- package/src/components/Overlay.tsx +506 -506
- package/src/components/PersonaImage.tsx +79 -79
- package/src/components/PersonaLoadingScreen.tsx +201 -201
- package/src/components/PersonalizationConsentScreen.tsx +410 -410
- package/src/components/PinCreationScreen.tsx +492 -492
- package/src/components/PinInput.tsx +555 -555
- package/src/components/PlatformConnectorsStep.tsx +891 -891
- package/src/components/PlatformList.tsx +144 -144
- package/src/components/PlatformToggle.tsx +226 -226
- package/src/components/PrimaryButton.tsx +213 -213
- package/src/components/SignInMatchAnimation.tsx +225 -225
- package/src/components/SignInStep.tsx +217 -217
- package/src/components/TrainingModal.tsx +1047 -1047
- package/src/components/UniversalOnboarding.tsx +2887 -2887
- package/src/components/VerificationStep.tsx +198 -198
- package/src/components/WelcomeScreen.tsx +473 -473
- package/src/components/icons/Basicproficon.tsx +30 -30
- package/src/components/icons/Basicprofile.tsx +17 -17
- package/src/components/icons/Checkbox.tsx +17 -17
- package/src/components/icons/Checkmark.tsx +24 -24
- package/src/components/icons/Contentanalysis.tsx +17 -17
- package/src/components/icons/Contenticon.tsx +30 -30
- package/src/components/icons/EnochE.tsx +39 -39
- package/src/components/icons/Personalityicon.tsx +22 -22
- package/src/components/icons/Personalityprofile.tsx +17 -17
- package/src/components/icons/Personalitytraits.tsx +17 -17
- package/src/components/icons/Userpreferences.tsx +17 -17
- package/src/components/icons/index.ts +12 -12
- package/src/components/onboarding/OAuthWebView.tsx +232 -232
- package/src/config/api.ts +25 -25
- package/src/context/AuthContext.tsx +393 -393
- package/src/hooks/useConnectedAccounts.ts +138 -138
- package/src/hooks/useConnections.ts +161 -161
- package/src/hooks/useCredentials.ts +174 -174
- package/src/hooks/useUserConnections.ts +165 -165
- package/src/index.js +14 -14
- package/src/index.ts +94 -95
- package/src/services/apiClient.ts +336 -336
- package/src/services/apiKeyService.ts +919 -919
- package/src/services/authService.ts +1008 -1008
- package/src/services/biometricPinService.ts +192 -192
- package/src/services/connectedAccountsService.ts +289 -289
- package/src/services/googleAuthService.ts +279 -279
- package/src/services/imageCompressionService.ts +302 -302
- package/src/services/jwtStorageService.ts +256 -256
- package/src/services/mobileTrainingService.ts +203 -203
- package/src/services/pinEncryptionService.ts +75 -75
- package/src/services/pinStorageUtils.ts +96 -96
- package/src/services/platformAuthService.ts +1346 -1346
- package/src/services/storageService.ts +451 -451
- package/src/services/trainingApiHelpers.ts +66 -66
- package/src/services/userConnectionsService.ts +556 -556
- package/src/services/youtubeMigrationService.ts +453 -453
- package/src/theme/index.ts +239 -239
- package/src/types/ambient.d.ts +28 -28
- package/src/types/index.ts +265 -265
- package/src/types/node-fix.d.ts +18 -18
- package/src/types/node-override.d.ts +23 -23
- package/src/types/opacity.d.ts +15 -15
- package/src/types/types.d.ts +17 -17
- package/src/utils/Portal.tsx +82 -82
- package/src/utils/api.js +111 -111
- package/src/utils/auth.js +103 -103
- package/src/utils/crypto.js +59 -59
- package/src/utils/encryption.ts +68 -68
- package/src/utils/eventUtils.ts +302 -302
- package/src/utils/haptics.ts +58 -58
- package/src/utils/imagePreloader.ts +2 -2
- package/src/utils/programmaticFlow.ts +112 -112
- package/src/utils/retryHelper.ts +274 -274
|
@@ -1,423 +1,423 @@
|
|
|
1
|
-
import React, { forwardRef, useImperativeHandle, useState, useCallback, useEffect } from 'react';
|
|
2
|
-
import {
|
|
3
|
-
StyleSheet,
|
|
4
|
-
View,
|
|
5
|
-
TouchableOpacity,
|
|
6
|
-
Text,
|
|
7
|
-
ViewStyle,
|
|
8
|
-
TextStyle,
|
|
9
|
-
Platform,
|
|
10
|
-
Image,
|
|
11
|
-
Alert,
|
|
12
|
-
} from 'react-native';
|
|
13
|
-
import { UniversalOnboarding } from './UniversalOnboarding';
|
|
14
|
-
import { Overlay } from './Overlay';
|
|
15
|
-
import { COLORS } from '../constants';
|
|
16
|
-
import { hasCredentials, getCredentials, deleteCredentials } from '../utils/secureStorage';
|
|
17
|
-
import { onairosApi } from '../api';
|
|
18
|
-
import { Portal } from '../utils/Portal';
|
|
19
|
-
import { DataTier, OnairosConfig, OnairosProps } from '../types';
|
|
20
|
-
import { initializeApiKey, isApiKeyInitialized, getApiConfig } from '../services/apiKeyService';
|
|
21
|
-
|
|
22
|
-
export const Onairos = forwardRef<any, OnairosProps>((props, ref) => {
|
|
23
|
-
const {
|
|
24
|
-
returnLink,
|
|
25
|
-
prefillUrl,
|
|
26
|
-
AppName,
|
|
27
|
-
buttonType = 'normal',
|
|
28
|
-
requestData,
|
|
29
|
-
buttonWidth = 200,
|
|
30
|
-
buttonHeight = 48,
|
|
31
|
-
hasStroke = false,
|
|
32
|
-
enabled = true,
|
|
33
|
-
buttonForm = 'default',
|
|
34
|
-
onRejection,
|
|
35
|
-
onResolved,
|
|
36
|
-
preCheck,
|
|
37
|
-
color = COLORS.primary,
|
|
38
|
-
debug = false,
|
|
39
|
-
darkMode = false,
|
|
40
|
-
preferredPlatform,
|
|
41
|
-
testMode = false,
|
|
42
|
-
// API Key props
|
|
43
|
-
apiKey,
|
|
44
|
-
environment = 'production',
|
|
45
|
-
enableLogging = true,
|
|
46
|
-
timeout = 30000,
|
|
47
|
-
retryAttempts = 3,
|
|
48
|
-
} = props;
|
|
49
|
-
|
|
50
|
-
const [showOverlay, setShowOverlay] = useState(false);
|
|
51
|
-
const [isInitialized, setIsInitialized] = useState(false);
|
|
52
|
-
const [initializationError, setInitializationError] = useState<string | null>(null);
|
|
53
|
-
const [isInitializing, setIsInitializing] = useState(false);
|
|
54
|
-
|
|
55
|
-
// Initialize API key when component mounts or API key changes
|
|
56
|
-
useEffect(() => {
|
|
57
|
-
let isMounted = true;
|
|
58
|
-
|
|
59
|
-
const initializeApi = async () => {
|
|
60
|
-
// Skip if already initializing
|
|
61
|
-
if (isInitializing) return;
|
|
62
|
-
|
|
63
|
-
setIsInitializing(true);
|
|
64
|
-
setInitializationError(null);
|
|
65
|
-
|
|
66
|
-
try {
|
|
67
|
-
console.log('🚀 Onairos SDK: Starting API key initialization...');
|
|
68
|
-
|
|
69
|
-
if (!apiKey) {
|
|
70
|
-
throw new Error('API key is required. Please provide a valid API key from your Onairos dashboard.');
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
const config: OnairosConfig = {
|
|
74
|
-
apiKey,
|
|
75
|
-
environment,
|
|
76
|
-
enableLogging,
|
|
77
|
-
timeout,
|
|
78
|
-
retryAttempts,
|
|
79
|
-
};
|
|
80
|
-
|
|
81
|
-
// Initialize the API key service
|
|
82
|
-
await initializeApiKey(config);
|
|
83
|
-
|
|
84
|
-
if (isMounted) {
|
|
85
|
-
setIsInitialized(true);
|
|
86
|
-
setInitializationError(null);
|
|
87
|
-
|
|
88
|
-
if (enableLogging) {
|
|
89
|
-
console.log('✅ Onairos SDK: API key initialization completed successfully');
|
|
90
|
-
console.log('📊 Configuration:', {
|
|
91
|
-
environment,
|
|
92
|
-
enableLogging,
|
|
93
|
-
timeout,
|
|
94
|
-
retryAttempts,
|
|
95
|
-
apiKeyLength: apiKey.length,
|
|
96
|
-
});
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
} catch (error) {
|
|
100
|
-
const errorMessage = error instanceof Error ? error.message : 'Unknown initialization error';
|
|
101
|
-
|
|
102
|
-
console.error('❌ Onairos SDK: API key initialization failed:', errorMessage);
|
|
103
|
-
|
|
104
|
-
if (isMounted) {
|
|
105
|
-
setIsInitialized(false);
|
|
106
|
-
setInitializationError(errorMessage);
|
|
107
|
-
|
|
108
|
-
// Show developer-friendly error
|
|
109
|
-
if (enableLogging) {
|
|
110
|
-
console.group('🔧 API Key Troubleshooting Guide');
|
|
111
|
-
console.log('1. Check that your API key is correct and not expired');
|
|
112
|
-
console.log('2. Verify you have the right permissions for your use case');
|
|
113
|
-
console.log('3. Ensure your environment setting matches your API key');
|
|
114
|
-
console.log('4. Check your internet connection');
|
|
115
|
-
console.log('5. Visit https://dashboard.onairos.uk to manage your API keys');
|
|
116
|
-
console.groupEnd();
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
// Call rejection callback if provided
|
|
120
|
-
if (onRejection) {
|
|
121
|
-
onRejection(`SDK initialization failed: ${errorMessage}`);
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
} finally {
|
|
125
|
-
if (isMounted) {
|
|
126
|
-
setIsInitializing(false);
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
};
|
|
130
|
-
|
|
131
|
-
// Only initialize if we have an API key and aren't already initialized correctly
|
|
132
|
-
if (apiKey && (!isApiKeyInitialized() || getApiConfig()?.apiKey !== apiKey)) {
|
|
133
|
-
initializeApi();
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
return () => {
|
|
137
|
-
isMounted = false;
|
|
138
|
-
};
|
|
139
|
-
}, [apiKey, environment, enableLogging, timeout, retryAttempts, onRejection]);
|
|
140
|
-
|
|
141
|
-
// Imperative methods
|
|
142
|
-
useImperativeHandle(ref, () => ({
|
|
143
|
-
openOverlay: handleShowOverlay,
|
|
144
|
-
closeOverlay: handleCloseOverlay,
|
|
145
|
-
isInitialized: () => isInitialized,
|
|
146
|
-
getApiConfig: () => getApiConfig(),
|
|
147
|
-
}));
|
|
148
|
-
|
|
149
|
-
const handleShowOverlay = useCallback(async () => {
|
|
150
|
-
try {
|
|
151
|
-
// Check if SDK is initialized
|
|
152
|
-
if (!isInitialized) {
|
|
153
|
-
const errorMessage = initializationError || 'SDK not initialized. Please check your API key.';
|
|
154
|
-
console.error('❌ Cannot open overlay: SDK not initialized');
|
|
155
|
-
|
|
156
|
-
if (onRejection) {
|
|
157
|
-
onRejection(errorMessage);
|
|
158
|
-
} else {
|
|
159
|
-
Alert.alert(
|
|
160
|
-
'SDK Error',
|
|
161
|
-
errorMessage,
|
|
162
|
-
[{ text: 'OK' }]
|
|
163
|
-
);
|
|
164
|
-
}
|
|
165
|
-
return;
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
// Run pre-check if provided
|
|
169
|
-
if (preCheck) {
|
|
170
|
-
if (enableLogging) {
|
|
171
|
-
console.log('🔍 Running pre-check validation...');
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
try {
|
|
175
|
-
const preCheckPassed = await preCheck();
|
|
176
|
-
if (!preCheckPassed) {
|
|
177
|
-
if (enableLogging) {
|
|
178
|
-
console.log('⛔ Pre-check failed, aborting overlay');
|
|
179
|
-
}
|
|
180
|
-
return;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
if (enableLogging) {
|
|
184
|
-
console.log('✅ Pre-check passed');
|
|
185
|
-
}
|
|
186
|
-
} catch (preCheckError) {
|
|
187
|
-
console.error('❌ Pre-check error:', preCheckError);
|
|
188
|
-
if (onRejection) {
|
|
189
|
-
onRejection(`Pre-check failed: ${preCheckError.message}`);
|
|
190
|
-
}
|
|
191
|
-
return;
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
// Check for existing credentials
|
|
196
|
-
if (enableLogging) {
|
|
197
|
-
console.log('🔍 Checking for existing credentials...');
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
const hasExistingCredentials = await hasCredentials();
|
|
201
|
-
|
|
202
|
-
if (hasExistingCredentials) {
|
|
203
|
-
if (enableLogging) {
|
|
204
|
-
console.log('🔑 Existing credentials found, attempting automatic resolution...');
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
try {
|
|
208
|
-
const credentials = await getCredentials();
|
|
209
|
-
|
|
210
|
-
if (credentials && onResolved) {
|
|
211
|
-
// For existing users, we can resolve immediately with cached data
|
|
212
|
-
const mockApiUrl = 'https://api2.onairos.uk/user/data';
|
|
213
|
-
const mockToken = 'existing_user_token';
|
|
214
|
-
|
|
215
|
-
if (enableLogging) {
|
|
216
|
-
console.log('✅ Resolving with existing credentials');
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
onResolved(mockApiUrl, mockToken, credentials);
|
|
220
|
-
return;
|
|
221
|
-
}
|
|
222
|
-
} catch (credentialsError) {
|
|
223
|
-
console.warn('⚠️ Failed to retrieve existing credentials:', credentialsError);
|
|
224
|
-
// Continue with normal flow
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
if (enableLogging) {
|
|
229
|
-
console.log('🎨 Opening Onairos overlay...');
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
setShowOverlay(true);
|
|
233
|
-
} catch (error) {
|
|
234
|
-
console.error('❌ Error opening overlay:', error);
|
|
235
|
-
if (onRejection) {
|
|
236
|
-
onRejection(`Failed to open overlay: ${error.message}`);
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
}, [isInitialized, initializationError, preCheck, enableLogging, onRejection, onResolved]);
|
|
240
|
-
|
|
241
|
-
const handleCloseOverlay = useCallback((result?: any) => {
|
|
242
|
-
if (enableLogging) {
|
|
243
|
-
console.log('🔽 Closing Onairos overlay');
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
setShowOverlay(false);
|
|
247
|
-
|
|
248
|
-
if (result && onResolved) {
|
|
249
|
-
onResolved(result.apiUrl, result.token, result.userData);
|
|
250
|
-
}
|
|
251
|
-
}, [enableLogging, onResolved]);
|
|
252
|
-
|
|
253
|
-
const handleOverlayRejection = useCallback((error?: string) => {
|
|
254
|
-
if (enableLogging) {
|
|
255
|
-
console.log('❌ Overlay rejected:', error);
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
setShowOverlay(false);
|
|
259
|
-
|
|
260
|
-
if (onRejection) {
|
|
261
|
-
onRejection(error);
|
|
262
|
-
}
|
|
263
|
-
}, [enableLogging, onRejection]);
|
|
264
|
-
|
|
265
|
-
// Show error state if initialization failed
|
|
266
|
-
if (initializationError && !isInitializing) {
|
|
267
|
-
return (
|
|
268
|
-
<View style={styles.errorContainer}>
|
|
269
|
-
<TouchableOpacity
|
|
270
|
-
style={[styles.errorButton, { backgroundColor: '#FF6B6B' }]}
|
|
271
|
-
onPress={() => {
|
|
272
|
-
Alert.alert(
|
|
273
|
-
'SDK Error',
|
|
274
|
-
`Onairos SDK initialization failed:\n\n${initializationError}\n\nPlease check your API key and try again.`,
|
|
275
|
-
[{ text: 'OK' }]
|
|
276
|
-
);
|
|
277
|
-
}}
|
|
278
|
-
>
|
|
279
|
-
<Text style={styles.errorButtonText}>⚠️ SDK Error</Text>
|
|
280
|
-
</TouchableOpacity>
|
|
281
|
-
</View>
|
|
282
|
-
);
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
// Show loading state while initializing
|
|
286
|
-
if (isInitializing || !isInitialized) {
|
|
287
|
-
return (
|
|
288
|
-
<View style={styles.loadingContainer}>
|
|
289
|
-
<TouchableOpacity
|
|
290
|
-
style={[styles.loadingButton, { backgroundColor: '#999' }]}
|
|
291
|
-
disabled={true}
|
|
292
|
-
>
|
|
293
|
-
<Text style={styles.loadingButtonText}>🔄 Initializing...</Text>
|
|
294
|
-
</TouchableOpacity>
|
|
295
|
-
</View>
|
|
296
|
-
);
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
// Get button style based on type
|
|
300
|
-
const getButtonStyle = (): ViewStyle => {
|
|
301
|
-
const baseStyle: ViewStyle = {
|
|
302
|
-
width: buttonWidth,
|
|
303
|
-
height: buttonHeight,
|
|
304
|
-
backgroundColor: color,
|
|
305
|
-
borderRadius: buttonType === 'pill' ? buttonHeight / 2 : 8,
|
|
306
|
-
alignItems: 'center',
|
|
307
|
-
justifyContent: 'center',
|
|
308
|
-
flexDirection: 'row',
|
|
309
|
-
opacity: enabled ? 1 : 0.6,
|
|
310
|
-
};
|
|
311
|
-
|
|
312
|
-
if (hasStroke) {
|
|
313
|
-
baseStyle.borderWidth = 2;
|
|
314
|
-
baseStyle.borderColor = darkMode ? '#fff' : '#000';
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
return baseStyle;
|
|
318
|
-
};
|
|
319
|
-
|
|
320
|
-
const getButtonText = (): string => {
|
|
321
|
-
switch (buttonForm) {
|
|
322
|
-
case 'connect':
|
|
323
|
-
return 'Connect with Onairos';
|
|
324
|
-
default:
|
|
325
|
-
return 'Continue with Onairos';
|
|
326
|
-
}
|
|
327
|
-
};
|
|
328
|
-
|
|
329
|
-
return (
|
|
330
|
-
<>
|
|
331
|
-
<TouchableOpacity
|
|
332
|
-
style={getButtonStyle()}
|
|
333
|
-
onPress={handleShowOverlay}
|
|
334
|
-
disabled={!enabled || isInitializing || !isInitialized}
|
|
335
|
-
activeOpacity={0.8}
|
|
336
|
-
>
|
|
337
|
-
<Image
|
|
338
|
-
source={require('../assets/images/onairos_logo.png')}
|
|
339
|
-
style={styles.logo}
|
|
340
|
-
resizeMode="contain"
|
|
341
|
-
/>
|
|
342
|
-
<Text style={[styles.buttonText, { color: darkMode ? '#000' : '#fff' }]}>
|
|
343
|
-
{getButtonText()}
|
|
344
|
-
</Text>
|
|
345
|
-
</TouchableOpacity>
|
|
346
|
-
|
|
347
|
-
{showOverlay && (
|
|
348
|
-
<Portal>
|
|
349
|
-
<UniversalOnboarding
|
|
350
|
-
visible={showOverlay}
|
|
351
|
-
onClose={handleCloseOverlay}
|
|
352
|
-
AppName={AppName}
|
|
353
|
-
requestData={requestData || {}}
|
|
354
|
-
returnLink={returnLink}
|
|
355
|
-
onComplete={handleCloseOverlay}
|
|
356
|
-
embedd={false}
|
|
357
|
-
debug={debug}
|
|
358
|
-
testMode={testMode}
|
|
359
|
-
preferredPlatform={preferredPlatform}
|
|
360
|
-
/>
|
|
361
|
-
</Portal>
|
|
362
|
-
)}
|
|
363
|
-
</>
|
|
364
|
-
);
|
|
365
|
-
});
|
|
366
|
-
|
|
367
|
-
const styles = StyleSheet.create({
|
|
368
|
-
button: {
|
|
369
|
-
flexDirection: 'row',
|
|
370
|
-
alignItems: 'center',
|
|
371
|
-
justifyContent: 'center',
|
|
372
|
-
paddingVertical: 12,
|
|
373
|
-
paddingHorizontal: 16,
|
|
374
|
-
shadowColor: '#000',
|
|
375
|
-
shadowOffset: { width: 0, height: 2 },
|
|
376
|
-
shadowOpacity: 0.1,
|
|
377
|
-
shadowRadius: 4,
|
|
378
|
-
elevation: 2,
|
|
379
|
-
},
|
|
380
|
-
buttonContent: {
|
|
381
|
-
flexDirection: 'row',
|
|
382
|
-
alignItems: 'center',
|
|
383
|
-
justifyContent: 'center',
|
|
384
|
-
},
|
|
385
|
-
logo: {
|
|
386
|
-
width: 24,
|
|
387
|
-
height: 24,
|
|
388
|
-
marginRight: 8,
|
|
389
|
-
},
|
|
390
|
-
buttonText: {
|
|
391
|
-
fontSize: 16,
|
|
392
|
-
fontWeight: '600',
|
|
393
|
-
textAlign: 'center',
|
|
394
|
-
},
|
|
395
|
-
errorContainer: {
|
|
396
|
-
flex: 1,
|
|
397
|
-
justifyContent: 'center',
|
|
398
|
-
alignItems: 'center',
|
|
399
|
-
},
|
|
400
|
-
errorButton: {
|
|
401
|
-
padding: 16,
|
|
402
|
-
borderRadius: 8,
|
|
403
|
-
},
|
|
404
|
-
errorButtonText: {
|
|
405
|
-
fontSize: 16,
|
|
406
|
-
fontWeight: '600',
|
|
407
|
-
color: '#fff',
|
|
408
|
-
},
|
|
409
|
-
loadingContainer: {
|
|
410
|
-
flex: 1,
|
|
411
|
-
justifyContent: 'center',
|
|
412
|
-
alignItems: 'center',
|
|
413
|
-
},
|
|
414
|
-
loadingButton: {
|
|
415
|
-
padding: 16,
|
|
416
|
-
borderRadius: 8,
|
|
417
|
-
},
|
|
418
|
-
loadingButtonText: {
|
|
419
|
-
fontSize: 16,
|
|
420
|
-
fontWeight: '600',
|
|
421
|
-
color: '#fff',
|
|
422
|
-
},
|
|
1
|
+
import React, { forwardRef, useImperativeHandle, useState, useCallback, useEffect } from 'react';
|
|
2
|
+
import {
|
|
3
|
+
StyleSheet,
|
|
4
|
+
View,
|
|
5
|
+
TouchableOpacity,
|
|
6
|
+
Text,
|
|
7
|
+
ViewStyle,
|
|
8
|
+
TextStyle,
|
|
9
|
+
Platform,
|
|
10
|
+
Image,
|
|
11
|
+
Alert,
|
|
12
|
+
} from 'react-native';
|
|
13
|
+
import { UniversalOnboarding } from './UniversalOnboarding';
|
|
14
|
+
import { Overlay } from './Overlay';
|
|
15
|
+
import { COLORS } from '../constants';
|
|
16
|
+
import { hasCredentials, getCredentials, deleteCredentials } from '../utils/secureStorage';
|
|
17
|
+
import { onairosApi } from '../api';
|
|
18
|
+
import { Portal } from '../utils/Portal';
|
|
19
|
+
import { DataTier, OnairosConfig, OnairosProps } from '../types';
|
|
20
|
+
import { initializeApiKey, isApiKeyInitialized, getApiConfig } from '../services/apiKeyService';
|
|
21
|
+
|
|
22
|
+
export const Onairos = forwardRef<any, OnairosProps>((props, ref) => {
|
|
23
|
+
const {
|
|
24
|
+
returnLink,
|
|
25
|
+
prefillUrl,
|
|
26
|
+
AppName,
|
|
27
|
+
buttonType = 'normal',
|
|
28
|
+
requestData,
|
|
29
|
+
buttonWidth = 200,
|
|
30
|
+
buttonHeight = 48,
|
|
31
|
+
hasStroke = false,
|
|
32
|
+
enabled = true,
|
|
33
|
+
buttonForm = 'default',
|
|
34
|
+
onRejection,
|
|
35
|
+
onResolved,
|
|
36
|
+
preCheck,
|
|
37
|
+
color = COLORS.primary,
|
|
38
|
+
debug = false,
|
|
39
|
+
darkMode = false,
|
|
40
|
+
preferredPlatform,
|
|
41
|
+
testMode = false,
|
|
42
|
+
// API Key props
|
|
43
|
+
apiKey,
|
|
44
|
+
environment = 'production',
|
|
45
|
+
enableLogging = true,
|
|
46
|
+
timeout = 30000,
|
|
47
|
+
retryAttempts = 3,
|
|
48
|
+
} = props;
|
|
49
|
+
|
|
50
|
+
const [showOverlay, setShowOverlay] = useState(false);
|
|
51
|
+
const [isInitialized, setIsInitialized] = useState(false);
|
|
52
|
+
const [initializationError, setInitializationError] = useState<string | null>(null);
|
|
53
|
+
const [isInitializing, setIsInitializing] = useState(false);
|
|
54
|
+
|
|
55
|
+
// Initialize API key when component mounts or API key changes
|
|
56
|
+
useEffect(() => {
|
|
57
|
+
let isMounted = true;
|
|
58
|
+
|
|
59
|
+
const initializeApi = async () => {
|
|
60
|
+
// Skip if already initializing
|
|
61
|
+
if (isInitializing) return;
|
|
62
|
+
|
|
63
|
+
setIsInitializing(true);
|
|
64
|
+
setInitializationError(null);
|
|
65
|
+
|
|
66
|
+
try {
|
|
67
|
+
console.log('🚀 Onairos SDK: Starting API key initialization...');
|
|
68
|
+
|
|
69
|
+
if (!apiKey) {
|
|
70
|
+
throw new Error('API key is required. Please provide a valid API key from your Onairos dashboard.');
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const config: OnairosConfig = {
|
|
74
|
+
apiKey,
|
|
75
|
+
environment,
|
|
76
|
+
enableLogging,
|
|
77
|
+
timeout,
|
|
78
|
+
retryAttempts,
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
// Initialize the API key service
|
|
82
|
+
await initializeApiKey(config);
|
|
83
|
+
|
|
84
|
+
if (isMounted) {
|
|
85
|
+
setIsInitialized(true);
|
|
86
|
+
setInitializationError(null);
|
|
87
|
+
|
|
88
|
+
if (enableLogging) {
|
|
89
|
+
console.log('✅ Onairos SDK: API key initialization completed successfully');
|
|
90
|
+
console.log('📊 Configuration:', {
|
|
91
|
+
environment,
|
|
92
|
+
enableLogging,
|
|
93
|
+
timeout,
|
|
94
|
+
retryAttempts,
|
|
95
|
+
apiKeyLength: apiKey.length,
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
} catch (error) {
|
|
100
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown initialization error';
|
|
101
|
+
|
|
102
|
+
console.error('❌ Onairos SDK: API key initialization failed:', errorMessage);
|
|
103
|
+
|
|
104
|
+
if (isMounted) {
|
|
105
|
+
setIsInitialized(false);
|
|
106
|
+
setInitializationError(errorMessage);
|
|
107
|
+
|
|
108
|
+
// Show developer-friendly error
|
|
109
|
+
if (enableLogging) {
|
|
110
|
+
console.group('🔧 API Key Troubleshooting Guide');
|
|
111
|
+
console.log('1. Check that your API key is correct and not expired');
|
|
112
|
+
console.log('2. Verify you have the right permissions for your use case');
|
|
113
|
+
console.log('3. Ensure your environment setting matches your API key');
|
|
114
|
+
console.log('4. Check your internet connection');
|
|
115
|
+
console.log('5. Visit https://dashboard.onairos.uk to manage your API keys');
|
|
116
|
+
console.groupEnd();
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Call rejection callback if provided
|
|
120
|
+
if (onRejection) {
|
|
121
|
+
onRejection(`SDK initialization failed: ${errorMessage}`);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
} finally {
|
|
125
|
+
if (isMounted) {
|
|
126
|
+
setIsInitializing(false);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
// Only initialize if we have an API key and aren't already initialized correctly
|
|
132
|
+
if (apiKey && (!isApiKeyInitialized() || getApiConfig()?.apiKey !== apiKey)) {
|
|
133
|
+
initializeApi();
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
return () => {
|
|
137
|
+
isMounted = false;
|
|
138
|
+
};
|
|
139
|
+
}, [apiKey, environment, enableLogging, timeout, retryAttempts, onRejection]);
|
|
140
|
+
|
|
141
|
+
// Imperative methods
|
|
142
|
+
useImperativeHandle(ref, () => ({
|
|
143
|
+
openOverlay: handleShowOverlay,
|
|
144
|
+
closeOverlay: handleCloseOverlay,
|
|
145
|
+
isInitialized: () => isInitialized,
|
|
146
|
+
getApiConfig: () => getApiConfig(),
|
|
147
|
+
}));
|
|
148
|
+
|
|
149
|
+
const handleShowOverlay = useCallback(async () => {
|
|
150
|
+
try {
|
|
151
|
+
// Check if SDK is initialized
|
|
152
|
+
if (!isInitialized) {
|
|
153
|
+
const errorMessage = initializationError || 'SDK not initialized. Please check your API key.';
|
|
154
|
+
console.error('❌ Cannot open overlay: SDK not initialized');
|
|
155
|
+
|
|
156
|
+
if (onRejection) {
|
|
157
|
+
onRejection(errorMessage);
|
|
158
|
+
} else {
|
|
159
|
+
Alert.alert(
|
|
160
|
+
'SDK Error',
|
|
161
|
+
errorMessage,
|
|
162
|
+
[{ text: 'OK' }]
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Run pre-check if provided
|
|
169
|
+
if (preCheck) {
|
|
170
|
+
if (enableLogging) {
|
|
171
|
+
console.log('🔍 Running pre-check validation...');
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
try {
|
|
175
|
+
const preCheckPassed = await preCheck();
|
|
176
|
+
if (!preCheckPassed) {
|
|
177
|
+
if (enableLogging) {
|
|
178
|
+
console.log('⛔ Pre-check failed, aborting overlay');
|
|
179
|
+
}
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
if (enableLogging) {
|
|
184
|
+
console.log('✅ Pre-check passed');
|
|
185
|
+
}
|
|
186
|
+
} catch (preCheckError) {
|
|
187
|
+
console.error('❌ Pre-check error:', preCheckError);
|
|
188
|
+
if (onRejection) {
|
|
189
|
+
onRejection(`Pre-check failed: ${preCheckError.message}`);
|
|
190
|
+
}
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Check for existing credentials
|
|
196
|
+
if (enableLogging) {
|
|
197
|
+
console.log('🔍 Checking for existing credentials...');
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
const hasExistingCredentials = await hasCredentials();
|
|
201
|
+
|
|
202
|
+
if (hasExistingCredentials) {
|
|
203
|
+
if (enableLogging) {
|
|
204
|
+
console.log('🔑 Existing credentials found, attempting automatic resolution...');
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
try {
|
|
208
|
+
const credentials = await getCredentials();
|
|
209
|
+
|
|
210
|
+
if (credentials && onResolved) {
|
|
211
|
+
// For existing users, we can resolve immediately with cached data
|
|
212
|
+
const mockApiUrl = 'https://api2.onairos.uk/user/data';
|
|
213
|
+
const mockToken = 'existing_user_token';
|
|
214
|
+
|
|
215
|
+
if (enableLogging) {
|
|
216
|
+
console.log('✅ Resolving with existing credentials');
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
onResolved(mockApiUrl, mockToken, credentials);
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
} catch (credentialsError) {
|
|
223
|
+
console.warn('⚠️ Failed to retrieve existing credentials:', credentialsError);
|
|
224
|
+
// Continue with normal flow
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
if (enableLogging) {
|
|
229
|
+
console.log('🎨 Opening Onairos overlay...');
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
setShowOverlay(true);
|
|
233
|
+
} catch (error) {
|
|
234
|
+
console.error('❌ Error opening overlay:', error);
|
|
235
|
+
if (onRejection) {
|
|
236
|
+
onRejection(`Failed to open overlay: ${error.message}`);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}, [isInitialized, initializationError, preCheck, enableLogging, onRejection, onResolved]);
|
|
240
|
+
|
|
241
|
+
const handleCloseOverlay = useCallback((result?: any) => {
|
|
242
|
+
if (enableLogging) {
|
|
243
|
+
console.log('🔽 Closing Onairos overlay');
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
setShowOverlay(false);
|
|
247
|
+
|
|
248
|
+
if (result && onResolved) {
|
|
249
|
+
onResolved(result.apiUrl, result.token, result.userData);
|
|
250
|
+
}
|
|
251
|
+
}, [enableLogging, onResolved]);
|
|
252
|
+
|
|
253
|
+
const handleOverlayRejection = useCallback((error?: string) => {
|
|
254
|
+
if (enableLogging) {
|
|
255
|
+
console.log('❌ Overlay rejected:', error);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
setShowOverlay(false);
|
|
259
|
+
|
|
260
|
+
if (onRejection) {
|
|
261
|
+
onRejection(error);
|
|
262
|
+
}
|
|
263
|
+
}, [enableLogging, onRejection]);
|
|
264
|
+
|
|
265
|
+
// Show error state if initialization failed
|
|
266
|
+
if (initializationError && !isInitializing) {
|
|
267
|
+
return (
|
|
268
|
+
<View style={styles.errorContainer}>
|
|
269
|
+
<TouchableOpacity
|
|
270
|
+
style={[styles.errorButton, { backgroundColor: '#FF6B6B' }]}
|
|
271
|
+
onPress={() => {
|
|
272
|
+
Alert.alert(
|
|
273
|
+
'SDK Error',
|
|
274
|
+
`Onairos SDK initialization failed:\n\n${initializationError}\n\nPlease check your API key and try again.`,
|
|
275
|
+
[{ text: 'OK' }]
|
|
276
|
+
);
|
|
277
|
+
}}
|
|
278
|
+
>
|
|
279
|
+
<Text style={styles.errorButtonText}>⚠️ SDK Error</Text>
|
|
280
|
+
</TouchableOpacity>
|
|
281
|
+
</View>
|
|
282
|
+
);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// Show loading state while initializing
|
|
286
|
+
if (isInitializing || !isInitialized) {
|
|
287
|
+
return (
|
|
288
|
+
<View style={styles.loadingContainer}>
|
|
289
|
+
<TouchableOpacity
|
|
290
|
+
style={[styles.loadingButton, { backgroundColor: '#999' }]}
|
|
291
|
+
disabled={true}
|
|
292
|
+
>
|
|
293
|
+
<Text style={styles.loadingButtonText}>🔄 Initializing...</Text>
|
|
294
|
+
</TouchableOpacity>
|
|
295
|
+
</View>
|
|
296
|
+
);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// Get button style based on type
|
|
300
|
+
const getButtonStyle = (): ViewStyle => {
|
|
301
|
+
const baseStyle: ViewStyle = {
|
|
302
|
+
width: buttonWidth,
|
|
303
|
+
height: buttonHeight,
|
|
304
|
+
backgroundColor: color,
|
|
305
|
+
borderRadius: buttonType === 'pill' ? buttonHeight / 2 : 8,
|
|
306
|
+
alignItems: 'center',
|
|
307
|
+
justifyContent: 'center',
|
|
308
|
+
flexDirection: 'row',
|
|
309
|
+
opacity: enabled ? 1 : 0.6,
|
|
310
|
+
};
|
|
311
|
+
|
|
312
|
+
if (hasStroke) {
|
|
313
|
+
baseStyle.borderWidth = 2;
|
|
314
|
+
baseStyle.borderColor = darkMode ? '#fff' : '#000';
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
return baseStyle;
|
|
318
|
+
};
|
|
319
|
+
|
|
320
|
+
const getButtonText = (): string => {
|
|
321
|
+
switch (buttonForm) {
|
|
322
|
+
case 'connect':
|
|
323
|
+
return 'Connect with Onairos';
|
|
324
|
+
default:
|
|
325
|
+
return 'Continue with Onairos';
|
|
326
|
+
}
|
|
327
|
+
};
|
|
328
|
+
|
|
329
|
+
return (
|
|
330
|
+
<>
|
|
331
|
+
<TouchableOpacity
|
|
332
|
+
style={getButtonStyle()}
|
|
333
|
+
onPress={handleShowOverlay}
|
|
334
|
+
disabled={!enabled || isInitializing || !isInitialized}
|
|
335
|
+
activeOpacity={0.8}
|
|
336
|
+
>
|
|
337
|
+
<Image
|
|
338
|
+
source={require('../assets/images/onairos_logo.png')}
|
|
339
|
+
style={styles.logo}
|
|
340
|
+
resizeMode="contain"
|
|
341
|
+
/>
|
|
342
|
+
<Text style={[styles.buttonText, { color: darkMode ? '#000' : '#fff' }]}>
|
|
343
|
+
{getButtonText()}
|
|
344
|
+
</Text>
|
|
345
|
+
</TouchableOpacity>
|
|
346
|
+
|
|
347
|
+
{showOverlay && (
|
|
348
|
+
<Portal>
|
|
349
|
+
<UniversalOnboarding
|
|
350
|
+
visible={showOverlay}
|
|
351
|
+
onClose={handleCloseOverlay}
|
|
352
|
+
AppName={AppName}
|
|
353
|
+
requestData={requestData || {}}
|
|
354
|
+
returnLink={returnLink}
|
|
355
|
+
onComplete={handleCloseOverlay}
|
|
356
|
+
embedd={false}
|
|
357
|
+
debug={debug}
|
|
358
|
+
testMode={testMode}
|
|
359
|
+
preferredPlatform={preferredPlatform}
|
|
360
|
+
/>
|
|
361
|
+
</Portal>
|
|
362
|
+
)}
|
|
363
|
+
</>
|
|
364
|
+
);
|
|
365
|
+
});
|
|
366
|
+
|
|
367
|
+
const styles = StyleSheet.create({
|
|
368
|
+
button: {
|
|
369
|
+
flexDirection: 'row',
|
|
370
|
+
alignItems: 'center',
|
|
371
|
+
justifyContent: 'center',
|
|
372
|
+
paddingVertical: 12,
|
|
373
|
+
paddingHorizontal: 16,
|
|
374
|
+
shadowColor: '#000',
|
|
375
|
+
shadowOffset: { width: 0, height: 2 },
|
|
376
|
+
shadowOpacity: 0.1,
|
|
377
|
+
shadowRadius: 4,
|
|
378
|
+
elevation: 2,
|
|
379
|
+
},
|
|
380
|
+
buttonContent: {
|
|
381
|
+
flexDirection: 'row',
|
|
382
|
+
alignItems: 'center',
|
|
383
|
+
justifyContent: 'center',
|
|
384
|
+
},
|
|
385
|
+
logo: {
|
|
386
|
+
width: 24,
|
|
387
|
+
height: 24,
|
|
388
|
+
marginRight: 8,
|
|
389
|
+
},
|
|
390
|
+
buttonText: {
|
|
391
|
+
fontSize: 16,
|
|
392
|
+
fontWeight: '600',
|
|
393
|
+
textAlign: 'center',
|
|
394
|
+
},
|
|
395
|
+
errorContainer: {
|
|
396
|
+
flex: 1,
|
|
397
|
+
justifyContent: 'center',
|
|
398
|
+
alignItems: 'center',
|
|
399
|
+
},
|
|
400
|
+
errorButton: {
|
|
401
|
+
padding: 16,
|
|
402
|
+
borderRadius: 8,
|
|
403
|
+
},
|
|
404
|
+
errorButtonText: {
|
|
405
|
+
fontSize: 16,
|
|
406
|
+
fontWeight: '600',
|
|
407
|
+
color: '#fff',
|
|
408
|
+
},
|
|
409
|
+
loadingContainer: {
|
|
410
|
+
flex: 1,
|
|
411
|
+
justifyContent: 'center',
|
|
412
|
+
alignItems: 'center',
|
|
413
|
+
},
|
|
414
|
+
loadingButton: {
|
|
415
|
+
padding: 16,
|
|
416
|
+
borderRadius: 8,
|
|
417
|
+
},
|
|
418
|
+
loadingButtonText: {
|
|
419
|
+
fontSize: 16,
|
|
420
|
+
fontWeight: '600',
|
|
421
|
+
color: '#fff',
|
|
422
|
+
},
|
|
423
423
|
});
|