@onairos/react-native 3.0.29 → 3.0.30
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/components/PinInput.js +1 -1
- package/lib/commonjs/components/PinInput.js.map +1 -1
- package/lib/commonjs/components/UniversalOnboarding.js +6 -2
- package/lib/commonjs/components/UniversalOnboarding.js.map +1 -1
- package/lib/commonjs/components/onboarding/OAuthWebView.js +141 -94
- package/lib/commonjs/components/onboarding/OAuthWebView.js.map +1 -1
- package/lib/module/components/PinInput.js +1 -1
- package/lib/module/components/PinInput.js.map +1 -1
- package/lib/module/components/UniversalOnboarding.js +6 -2
- package/lib/module/components/UniversalOnboarding.js.map +1 -1
- package/lib/module/components/onboarding/OAuthWebView.js +142 -95
- package/lib/module/components/onboarding/OAuthWebView.js.map +1 -1
- package/lib/typescript/components/UniversalOnboarding.d.ts.map +1 -1
- package/lib/typescript/components/onboarding/OAuthWebView.d.ts +7 -1
- package/lib/typescript/components/onboarding/OAuthWebView.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/components/PinInput.tsx +1 -1
- package/src/components/UniversalOnboarding.tsx +5 -1
- package/src/components/onboarding/OAuthWebView.tsx +181 -114
|
@@ -1,89 +1,183 @@
|
|
|
1
|
-
import React, {
|
|
2
|
-
import {
|
|
3
|
-
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
import {
|
|
3
|
+
View,
|
|
4
|
+
Text,
|
|
5
|
+
StyleSheet,
|
|
6
|
+
TouchableOpacity,
|
|
7
|
+
ActivityIndicator,
|
|
8
|
+
SafeAreaView,
|
|
9
|
+
Dimensions,
|
|
10
|
+
} from 'react-native';
|
|
11
|
+
import { WebView } from 'react-native-webview';
|
|
4
12
|
import Icon from 'react-native-vector-icons/MaterialIcons';
|
|
5
13
|
import { COLORS } from '../../constants';
|
|
6
|
-
|
|
14
|
+
|
|
15
|
+
const { width, height } = Dimensions.get('window');
|
|
16
|
+
|
|
17
|
+
export interface OAuthWebViewProps {
|
|
18
|
+
url: string;
|
|
19
|
+
onClose: () => void;
|
|
20
|
+
onSuccess: (code: string) => void;
|
|
21
|
+
platform?: string;
|
|
22
|
+
onComplete?: () => void;
|
|
23
|
+
}
|
|
7
24
|
|
|
8
25
|
export const OAuthWebView: React.FC<OAuthWebViewProps> = ({
|
|
9
26
|
url,
|
|
10
|
-
platform,
|
|
11
|
-
onComplete,
|
|
12
27
|
onClose,
|
|
13
28
|
onSuccess,
|
|
29
|
+
platform = 'platform',
|
|
30
|
+
onComplete,
|
|
14
31
|
}) => {
|
|
15
|
-
const [
|
|
32
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
33
|
+
|
|
34
|
+
console.log('Opening OAuth WebView with URL:', url); // Add logging
|
|
16
35
|
|
|
17
|
-
const handleNavigationStateChange =
|
|
18
|
-
(
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
const isYouTubeSuccess = (
|
|
34
|
-
platform === 'youtube' &&
|
|
35
|
-
navState.url.includes('accounts.google.com/o/oauth2/approval')
|
|
36
|
-
);
|
|
37
|
-
|
|
38
|
-
const isLinkedInSuccess = (
|
|
39
|
-
platform === 'linkedin' &&
|
|
40
|
-
navState.url.includes('linkedin.com/oauth/v2/authorization/success')
|
|
41
|
-
);
|
|
42
|
-
|
|
43
|
-
// Check for callback URLs with authorization codes
|
|
44
|
-
const isCallbackUrl = navState.url.includes('/callback') || navState.url.includes('code=');
|
|
45
|
-
|
|
46
|
-
// If we detect success, close the window and update connection status
|
|
47
|
-
if (isFinalRedirect || isInstagramSuccess || isYouTubeSuccess || isLinkedInSuccess) {
|
|
36
|
+
const handleNavigationStateChange = (navState: any) => {
|
|
37
|
+
console.log(`Navigation state changed for ${platform}:`, navState.url);
|
|
38
|
+
|
|
39
|
+
// Check for the final redirect to onairos.uk domain (this means backend callback completed)
|
|
40
|
+
const isFinalRedirect = (
|
|
41
|
+
navState.url.includes('onairos.uk/Home') ||
|
|
42
|
+
navState.url.includes('onairos.uk/home') ||
|
|
43
|
+
navState.url.includes('onairos.uk/success')
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
// For YouTube specifically, we need to be more careful about when to close
|
|
47
|
+
// Only close after the backend callback redirects to onairos.uk/Home
|
|
48
|
+
if (platform === 'youtube') {
|
|
49
|
+
// Only trigger success when we see the final redirect from the backend
|
|
50
|
+
if (isFinalRedirect) {
|
|
51
|
+
console.log('YouTube OAuth completed - backend callback finished and redirected to Home');
|
|
48
52
|
onSuccess('success');
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
return;
|
|
53
|
-
} else if (isCallbackUrl) {
|
|
54
|
-
// Extract the authorization code
|
|
55
|
-
const authCode = extractAuthCode(navState.url);
|
|
56
|
-
if (authCode) {
|
|
57
|
-
onSuccess(authCode);
|
|
53
|
+
|
|
54
|
+
// Close the OAuth window after a small delay to ensure redirect is processed
|
|
55
|
+
setTimeout(() => {
|
|
58
56
|
if (onComplete) {
|
|
57
|
+
console.log('Closing YouTube OAuth window after callback completion');
|
|
59
58
|
onComplete();
|
|
60
59
|
}
|
|
61
|
-
}
|
|
62
|
-
return;
|
|
60
|
+
}, 500);
|
|
63
61
|
}
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
62
|
+
return; // Exit early for YouTube to avoid other triggers
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Platform-specific success patterns (for non-YouTube platforms)
|
|
66
|
+
const platformSuccessPatterns: Record<string, RegExp[]> = {
|
|
67
|
+
reddit: [
|
|
68
|
+
/reddit\.com\/api\/v1\/authorize\?done=true/,
|
|
69
|
+
/reddit\.com\/api\/v1\/authorize\/success/
|
|
70
|
+
],
|
|
71
|
+
pinterest: [
|
|
72
|
+
/pinterest\.com\/oauth\/success/,
|
|
73
|
+
/pinterest\.com\/oauth\/complete/
|
|
74
|
+
],
|
|
75
|
+
linkedin: [
|
|
76
|
+
/linkedin\.com\/oauth\/success/,
|
|
77
|
+
/linkedin\.com\/oauth\/complete/,
|
|
78
|
+
/linkedin\.com\/uas\/oauth2\/authorization\/success/
|
|
79
|
+
],
|
|
80
|
+
email: [/success/], // Generic success pattern for email
|
|
81
|
+
instagram: [
|
|
82
|
+
/instagram\.com\/oauth\/authorize\?done=true/,
|
|
83
|
+
/instagram\.com\/oauth\/success/
|
|
84
|
+
]
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
// Check for platform-specific success patterns
|
|
88
|
+
const isPlatformSuccess = platform && platformSuccessPatterns[platform] ?
|
|
89
|
+
platformSuccessPatterns[platform].some(pattern => pattern.test(navState.url)) :
|
|
90
|
+
false;
|
|
91
|
+
|
|
92
|
+
// Check for callback URLs that might contain the authorization code
|
|
93
|
+
const isCallbackUrl = (
|
|
94
|
+
navState.url.includes('/callback') ||
|
|
95
|
+
navState.url.includes('code=') ||
|
|
96
|
+
navState.url.includes('token=') ||
|
|
97
|
+
navState.url.includes('access_token=')
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
// Extract authorization code or token if present
|
|
101
|
+
let authCode = null;
|
|
102
|
+
if (isCallbackUrl) {
|
|
103
|
+
console.log('Detected callback URL with possible code/token');
|
|
104
|
+
|
|
105
|
+
// Try to extract code or token using different patterns
|
|
106
|
+
const codeMatch = navState.url.match(/code=([^&]+)/);
|
|
107
|
+
const tokenMatch = navState.url.match(/(?:token|access_token)=([^&]+)/);
|
|
108
|
+
|
|
77
109
|
if (codeMatch && codeMatch[1]) {
|
|
78
|
-
|
|
110
|
+
authCode = codeMatch[1];
|
|
111
|
+
console.log('OAuth code extracted:', authCode);
|
|
112
|
+
} else if (tokenMatch && tokenMatch[1]) {
|
|
113
|
+
authCode = tokenMatch[1];
|
|
114
|
+
console.log('OAuth token extracted:', authCode);
|
|
79
115
|
}
|
|
80
116
|
|
|
81
|
-
//
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
117
|
+
// Call onSuccess with the extracted code/token
|
|
118
|
+
if (authCode) {
|
|
119
|
+
onSuccess(authCode);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// If we see the final redirect or platform-specific success, close the OAuth window
|
|
124
|
+
if (isFinalRedirect || isPlatformSuccess) {
|
|
125
|
+
console.log(`Detected success for ${platform}`);
|
|
126
|
+
|
|
127
|
+
// If we haven't already extracted a code/token, consider this a generic success
|
|
128
|
+
if (!authCode) {
|
|
129
|
+
onSuccess('success');
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Close the OAuth window
|
|
133
|
+
if (onComplete) {
|
|
134
|
+
console.log('Calling onComplete to close OAuth window');
|
|
135
|
+
onComplete();
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
const handleLoadEnd = () => {
|
|
141
|
+
setIsLoading(false);
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Get platform-specific icon
|
|
146
|
+
*/
|
|
147
|
+
const getPlatformIcon = (platform: string): string => {
|
|
148
|
+
switch (platform) {
|
|
149
|
+
case 'instagram':
|
|
150
|
+
return 'photo-camera';
|
|
151
|
+
case 'youtube':
|
|
152
|
+
return 'smart-display';
|
|
153
|
+
case 'pinterest':
|
|
154
|
+
return 'push-pin';
|
|
155
|
+
case 'reddit':
|
|
156
|
+
return 'forum';
|
|
157
|
+
case 'email':
|
|
158
|
+
return 'email';
|
|
159
|
+
default:
|
|
160
|
+
return 'link';
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Get platform-specific color
|
|
166
|
+
*/
|
|
167
|
+
const getPlatformColor = (platform: string): string => {
|
|
168
|
+
switch (platform) {
|
|
169
|
+
case 'instagram':
|
|
170
|
+
return '#E1306C';
|
|
171
|
+
case 'youtube':
|
|
172
|
+
return '#FF0000';
|
|
173
|
+
case 'pinterest':
|
|
174
|
+
return '#E60023';
|
|
175
|
+
case 'reddit':
|
|
176
|
+
return '#FF4500';
|
|
177
|
+
case 'email':
|
|
178
|
+
return '#4285F4';
|
|
179
|
+
default:
|
|
180
|
+
return COLORS.primary;
|
|
87
181
|
}
|
|
88
182
|
};
|
|
89
183
|
|
|
@@ -95,10 +189,11 @@ export const OAuthWebView: React.FC<OAuthWebViewProps> = ({
|
|
|
95
189
|
</TouchableOpacity>
|
|
96
190
|
<View style={styles.titleContainer}>
|
|
97
191
|
<Icon
|
|
98
|
-
name={getPlatformIcon(platform
|
|
192
|
+
name={getPlatformIcon(platform)}
|
|
99
193
|
size={20}
|
|
100
|
-
color={getPlatformColor(platform
|
|
194
|
+
color={getPlatformColor(platform)}
|
|
101
195
|
/>
|
|
196
|
+
<Text style={styles.titleText}>{platform.charAt(0).toUpperCase() + platform.slice(1)} OAuth</Text>
|
|
102
197
|
</View>
|
|
103
198
|
</View>
|
|
104
199
|
|
|
@@ -106,65 +201,24 @@ export const OAuthWebView: React.FC<OAuthWebViewProps> = ({
|
|
|
106
201
|
source={{ uri: url }}
|
|
107
202
|
onNavigationStateChange={handleNavigationStateChange}
|
|
108
203
|
onLoadEnd={handleLoadEnd}
|
|
109
|
-
startInLoadingState={true}
|
|
110
204
|
style={styles.webView}
|
|
111
205
|
javaScriptEnabled={true}
|
|
112
206
|
domStorageEnabled={true}
|
|
113
207
|
sharedCookiesEnabled={true}
|
|
114
208
|
thirdPartyCookiesEnabled={true}
|
|
115
|
-
allowsInlineMediaPlayback={true}
|
|
116
|
-
mediaPlaybackRequiresUserAction={false}
|
|
117
209
|
userAgent="Mozilla/5.0 (iPhone; CPU iPhone OS 14_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0 Mobile/15E148 Safari/604.1"
|
|
118
|
-
mixedContentMode="compatibility"
|
|
119
|
-
allowsFullscreenVideo={true}
|
|
120
|
-
allowsProtectedMedia={true}
|
|
121
210
|
/>
|
|
122
211
|
|
|
123
|
-
{
|
|
212
|
+
{isLoading && (
|
|
124
213
|
<View style={styles.loadingContainer}>
|
|
125
214
|
<ActivityIndicator size="large" color={COLORS.primary} />
|
|
215
|
+
<Text style={styles.loadingText}>Loading {platform}...</Text>
|
|
126
216
|
</View>
|
|
127
217
|
)}
|
|
128
218
|
</SafeAreaView>
|
|
129
219
|
);
|
|
130
220
|
};
|
|
131
221
|
|
|
132
|
-
/**
|
|
133
|
-
* Get platform-specific icon
|
|
134
|
-
*/
|
|
135
|
-
const getPlatformIcon = (platform: string): string => {
|
|
136
|
-
switch (platform) {
|
|
137
|
-
case 'instagram':
|
|
138
|
-
return 'photo-camera';
|
|
139
|
-
case 'youtube':
|
|
140
|
-
return 'smart-display';
|
|
141
|
-
case 'pinterest':
|
|
142
|
-
return 'push-pin';
|
|
143
|
-
case 'reddit':
|
|
144
|
-
return 'forum';
|
|
145
|
-
default:
|
|
146
|
-
return 'link';
|
|
147
|
-
}
|
|
148
|
-
};
|
|
149
|
-
|
|
150
|
-
/**
|
|
151
|
-
* Get platform-specific color
|
|
152
|
-
*/
|
|
153
|
-
const getPlatformColor = (platform: string): string => {
|
|
154
|
-
switch (platform) {
|
|
155
|
-
case 'instagram':
|
|
156
|
-
return '#E1306C';
|
|
157
|
-
case 'youtube':
|
|
158
|
-
return '#FF0000';
|
|
159
|
-
case 'pinterest':
|
|
160
|
-
return '#E60023';
|
|
161
|
-
case 'reddit':
|
|
162
|
-
return '#FF4500';
|
|
163
|
-
default:
|
|
164
|
-
return COLORS.primary;
|
|
165
|
-
}
|
|
166
|
-
};
|
|
167
|
-
|
|
168
222
|
const styles = StyleSheet.create({
|
|
169
223
|
container: {
|
|
170
224
|
flex: 1,
|
|
@@ -181,7 +235,15 @@ const styles = StyleSheet.create({
|
|
|
181
235
|
},
|
|
182
236
|
titleContainer: {
|
|
183
237
|
flex: 1,
|
|
238
|
+
flexDirection: 'row',
|
|
184
239
|
alignItems: 'center',
|
|
240
|
+
justifyContent: 'center',
|
|
241
|
+
},
|
|
242
|
+
titleText: {
|
|
243
|
+
marginLeft: 8,
|
|
244
|
+
fontSize: 16,
|
|
245
|
+
fontWeight: '500',
|
|
246
|
+
color: '#000',
|
|
185
247
|
},
|
|
186
248
|
closeButton: {
|
|
187
249
|
padding: 8,
|
|
@@ -198,4 +260,9 @@ const styles = StyleSheet.create({
|
|
|
198
260
|
alignItems: 'center',
|
|
199
261
|
justifyContent: 'center',
|
|
200
262
|
},
|
|
263
|
+
loadingText: {
|
|
264
|
+
marginTop: 10,
|
|
265
|
+
fontSize: 16,
|
|
266
|
+
color: '#666',
|
|
267
|
+
},
|
|
201
268
|
});
|