@oxyhq/services 5.3.5 → 5.3.6
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/ui/navigation/OxyRouter.js +0 -5
- package/lib/commonjs/ui/navigation/OxyRouter.js.map +1 -1
- package/lib/commonjs/ui/screens/AccountSwitcherScreen.js +471 -312
- package/lib/commonjs/ui/screens/AccountSwitcherScreen.js.map +1 -1
- package/lib/module/ui/navigation/OxyRouter.js +0 -5
- package/lib/module/ui/navigation/OxyRouter.js.map +1 -1
- package/lib/module/ui/screens/AccountSwitcherScreen.js +472 -313
- package/lib/module/ui/screens/AccountSwitcherScreen.js.map +1 -1
- package/lib/typescript/ui/navigation/OxyRouter.d.ts.map +1 -1
- package/lib/typescript/ui/screens/AccountSwitcherScreen.d.ts +2 -2
- package/lib/typescript/ui/screens/AccountSwitcherScreen.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/ui/navigation/OxyRouter.tsx +0 -5
- package/src/ui/screens/AccountSwitcherScreen.tsx +493 -303
- package/lib/commonjs/ui/screens/ModernAccountSwitcherScreen.js +0 -532
- package/lib/commonjs/ui/screens/ModernAccountSwitcherScreen.js.map +0 -1
- package/lib/module/ui/screens/ModernAccountSwitcherScreen.js +0 -527
- package/lib/module/ui/screens/ModernAccountSwitcherScreen.js.map +0 -1
- package/lib/typescript/ui/screens/ModernAccountSwitcherScreen.d.ts +0 -5
- package/lib/typescript/ui/screens/ModernAccountSwitcherScreen.d.ts.map +0 -1
- package/src/ui/screens/ModernAccountSwitcherScreen.tsx +0 -552
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
ScrollView,
|
|
9
9
|
Alert,
|
|
10
10
|
Platform,
|
|
11
|
+
Image,
|
|
11
12
|
Dimensions,
|
|
12
13
|
} from 'react-native';
|
|
13
14
|
import { BaseScreenProps } from '../navigation/types';
|
|
@@ -16,6 +17,11 @@ import { SecureClientSession } from '../../models/secureSession';
|
|
|
16
17
|
import { fontFamilies } from '../styles/fonts';
|
|
17
18
|
import { User } from '../../models/interfaces';
|
|
18
19
|
|
|
20
|
+
interface SessionWithUser extends SecureClientSession {
|
|
21
|
+
userProfile?: User;
|
|
22
|
+
isLoadingProfile?: boolean;
|
|
23
|
+
}
|
|
24
|
+
|
|
19
25
|
interface DeviceSession {
|
|
20
26
|
sessionId: string;
|
|
21
27
|
deviceId: string;
|
|
@@ -26,7 +32,7 @@ interface DeviceSession {
|
|
|
26
32
|
isCurrent: boolean;
|
|
27
33
|
}
|
|
28
34
|
|
|
29
|
-
const
|
|
35
|
+
const ModernAccountSwitcherScreen: React.FC<BaseScreenProps> = ({
|
|
30
36
|
onClose,
|
|
31
37
|
theme,
|
|
32
38
|
navigate,
|
|
@@ -43,11 +49,16 @@ const AccountSwitcherScreen: React.FC<BaseScreenProps> = ({
|
|
|
43
49
|
isLoading
|
|
44
50
|
} = useOxy();
|
|
45
51
|
|
|
46
|
-
const [
|
|
47
|
-
const [loadingDeviceSessions, setLoadingDeviceSessions] = useState(false);
|
|
52
|
+
const [sessionsWithUsers, setSessionsWithUsers] = useState<SessionWithUser[]>([]);
|
|
48
53
|
const [switchingToUserId, setSwitchingToUserId] = useState<string | null>(null);
|
|
49
54
|
const [removingUserId, setRemovingUserId] = useState<string | null>(null);
|
|
50
|
-
|
|
55
|
+
|
|
56
|
+
// Device session management state
|
|
57
|
+
const [showDeviceManagement, setShowDeviceManagement] = useState(false);
|
|
58
|
+
const [deviceSessions, setDeviceSessions] = useState<DeviceSession[]>([]);
|
|
59
|
+
const [loadingDeviceSessions, setLoadingDeviceSessions] = useState(false);
|
|
60
|
+
const [remotingLogoutSessionId, setRemoteLogoutSessionId] = useState<string | null>(null);
|
|
61
|
+
const [loggingOutAllDevices, setLoggingOutAllDevices] = useState(false);
|
|
51
62
|
|
|
52
63
|
const screenWidth = Dimensions.get('window').width;
|
|
53
64
|
const isDarkTheme = theme === 'dark';
|
|
@@ -67,37 +78,46 @@ const AccountSwitcherScreen: React.FC<BaseScreenProps> = ({
|
|
|
67
78
|
shadow: isDarkTheme ? 'rgba(0,0,0,0.3)' : 'rgba(0,0,0,0.1)',
|
|
68
79
|
};
|
|
69
80
|
|
|
70
|
-
// Load
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
sessionId: session.sessionId,
|
|
79
|
-
deviceId: session.deviceId,
|
|
80
|
-
deviceName: session.deviceName || 'Unknown Device',
|
|
81
|
-
isActive: session.isActive,
|
|
82
|
-
lastActive: session.lastActive || new Date().toISOString(),
|
|
83
|
-
expiresAt: session.expiresAt || new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString(),
|
|
84
|
-
isCurrent: session.sessionId === activeSessionId
|
|
81
|
+
// Load user profiles for sessions
|
|
82
|
+
useEffect(() => {
|
|
83
|
+
const loadUserProfiles = async () => {
|
|
84
|
+
if (!sessions.length || !oxyServices) return;
|
|
85
|
+
|
|
86
|
+
const updatedSessions: SessionWithUser[] = sessions.map(session => ({
|
|
87
|
+
...session,
|
|
88
|
+
isLoadingProfile: true,
|
|
85
89
|
}));
|
|
86
|
-
|
|
87
|
-
} catch (error) {
|
|
88
|
-
console.error('Failed to load device sessions:', error);
|
|
89
|
-
Alert.alert('Error', 'Failed to load device sessions');
|
|
90
|
-
} finally {
|
|
91
|
-
setLoadingDeviceSessions(false);
|
|
92
|
-
}
|
|
93
|
-
};
|
|
90
|
+
setSessionsWithUsers(updatedSessions);
|
|
94
91
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
92
|
+
// Load profiles for each session
|
|
93
|
+
for (let i = 0; i < sessions.length; i++) {
|
|
94
|
+
const session = sessions[i];
|
|
95
|
+
try {
|
|
96
|
+
// Try to get user profile using the session
|
|
97
|
+
const userProfile = await oxyServices.getUserBySession(session.sessionId);
|
|
98
|
+
|
|
99
|
+
setSessionsWithUsers(prev =>
|
|
100
|
+
prev.map(s =>
|
|
101
|
+
s.sessionId === session.sessionId
|
|
102
|
+
? { ...s, userProfile, isLoadingProfile: false }
|
|
103
|
+
: s
|
|
104
|
+
)
|
|
105
|
+
);
|
|
106
|
+
} catch (error) {
|
|
107
|
+
console.error(`Failed to load profile for session ${session.sessionId}:`, error);
|
|
108
|
+
setSessionsWithUsers(prev =>
|
|
109
|
+
prev.map(s =>
|
|
110
|
+
s.sessionId === session.sessionId
|
|
111
|
+
? { ...s, isLoadingProfile: false }
|
|
112
|
+
: s
|
|
113
|
+
)
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
loadUserProfiles();
|
|
120
|
+
}, [sessions, oxyServices]);
|
|
101
121
|
|
|
102
122
|
const handleSwitchSession = async (sessionId: string) => {
|
|
103
123
|
if (sessionId === user?.sessionId) return; // Already active session
|
|
@@ -118,12 +138,16 @@ const AccountSwitcherScreen: React.FC<BaseScreenProps> = ({
|
|
|
118
138
|
};
|
|
119
139
|
|
|
120
140
|
const handleRemoveSession = async (sessionId: string) => {
|
|
121
|
-
const sessionToRemove =
|
|
141
|
+
const sessionToRemove = sessionsWithUsers.find(s => s.sessionId === sessionId);
|
|
122
142
|
if (!sessionToRemove) return;
|
|
123
143
|
|
|
144
|
+
const displayName = typeof sessionToRemove.userProfile?.name === 'object'
|
|
145
|
+
? sessionToRemove.userProfile.name.full || sessionToRemove.userProfile.name.first || sessionToRemove.userProfile.username
|
|
146
|
+
: sessionToRemove.userProfile?.name || sessionToRemove.userProfile?.username || 'this account';
|
|
147
|
+
|
|
124
148
|
Alert.alert(
|
|
125
149
|
'Remove Account',
|
|
126
|
-
`Are you sure you want to remove
|
|
150
|
+
`Are you sure you want to remove ${displayName} from this device? You'll need to sign in again to access this account.`,
|
|
127
151
|
[
|
|
128
152
|
{
|
|
129
153
|
text: 'Cancel',
|
|
@@ -180,27 +204,47 @@ const AccountSwitcherScreen: React.FC<BaseScreenProps> = ({
|
|
|
180
204
|
);
|
|
181
205
|
};
|
|
182
206
|
|
|
207
|
+
// Device session management functions
|
|
208
|
+
const loadAllDeviceSessions = async () => {
|
|
209
|
+
if (!oxyServices || !user?.sessionId) return;
|
|
210
|
+
|
|
211
|
+
setLoadingDeviceSessions(true);
|
|
212
|
+
try {
|
|
213
|
+
// This would call the API to get all device sessions for the current user
|
|
214
|
+
const allSessions = await oxyServices.getDeviceSessions(user.sessionId);
|
|
215
|
+
setDeviceSessions(allSessions || []);
|
|
216
|
+
} catch (error) {
|
|
217
|
+
console.error('Failed to load device sessions:', error);
|
|
218
|
+
Alert.alert('Error', 'Failed to load device sessions. Please try again.');
|
|
219
|
+
} finally {
|
|
220
|
+
setLoadingDeviceSessions(false);
|
|
221
|
+
}
|
|
222
|
+
};
|
|
223
|
+
|
|
183
224
|
const handleRemoteSessionLogout = async (sessionId: string, deviceName: string) => {
|
|
184
225
|
Alert.alert(
|
|
185
|
-
'
|
|
186
|
-
`Are you sure you want to
|
|
226
|
+
'Remove Device Session',
|
|
227
|
+
`Are you sure you want to sign out from "${deviceName}"? This will end the session on that device.`,
|
|
187
228
|
[
|
|
188
229
|
{
|
|
189
230
|
text: 'Cancel',
|
|
190
231
|
style: 'cancel',
|
|
191
232
|
},
|
|
192
233
|
{
|
|
193
|
-
text: '
|
|
234
|
+
text: 'Sign Out',
|
|
194
235
|
style: 'destructive',
|
|
195
236
|
onPress: async () => {
|
|
237
|
+
setRemoteLogoutSessionId(sessionId);
|
|
196
238
|
try {
|
|
197
|
-
await oxyServices
|
|
198
|
-
|
|
199
|
-
// Refresh the device sessions list
|
|
239
|
+
await oxyServices?.logoutSecureSession(user?.sessionId || '', sessionId);
|
|
240
|
+
// Refresh device sessions list
|
|
200
241
|
await loadAllDeviceSessions();
|
|
242
|
+
Alert.alert('Success', `Signed out from ${deviceName} successfully!`);
|
|
201
243
|
} catch (error) {
|
|
202
244
|
console.error('Remote logout failed:', error);
|
|
203
|
-
Alert.alert('Logout Failed', 'There was a problem
|
|
245
|
+
Alert.alert('Logout Failed', 'There was a problem signing out from the device. Please try again.');
|
|
246
|
+
} finally {
|
|
247
|
+
setRemoteLogoutSessionId(null);
|
|
204
248
|
}
|
|
205
249
|
},
|
|
206
250
|
},
|
|
@@ -210,26 +254,36 @@ const AccountSwitcherScreen: React.FC<BaseScreenProps> = ({
|
|
|
210
254
|
};
|
|
211
255
|
|
|
212
256
|
const handleLogoutAllDevices = async () => {
|
|
257
|
+
const otherDevicesCount = deviceSessions.filter(session => !session.isCurrent).length;
|
|
258
|
+
|
|
259
|
+
if (otherDevicesCount === 0) {
|
|
260
|
+
Alert.alert('No Other Devices', 'No other device sessions found to sign out from.');
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
|
|
213
264
|
Alert.alert(
|
|
214
|
-
'
|
|
215
|
-
|
|
265
|
+
'Sign Out All Other Devices',
|
|
266
|
+
`Are you sure you want to sign out from all ${otherDevicesCount} other device(s)? This will end sessions on all other devices except this one.`,
|
|
216
267
|
[
|
|
217
268
|
{
|
|
218
269
|
text: 'Cancel',
|
|
219
270
|
style: 'cancel',
|
|
220
271
|
},
|
|
221
272
|
{
|
|
222
|
-
text: '
|
|
273
|
+
text: 'Sign Out All',
|
|
223
274
|
style: 'destructive',
|
|
224
275
|
onPress: async () => {
|
|
276
|
+
setLoggingOutAllDevices(true);
|
|
225
277
|
try {
|
|
226
|
-
await oxyServices
|
|
227
|
-
|
|
228
|
-
// Refresh the device sessions list
|
|
278
|
+
await oxyServices?.logoutAllDeviceSessions(user?.sessionId || '', undefined, true);
|
|
279
|
+
// Refresh device sessions list
|
|
229
280
|
await loadAllDeviceSessions();
|
|
281
|
+
Alert.alert('Success', `Signed out from all other devices successfully!`);
|
|
230
282
|
} catch (error) {
|
|
231
283
|
console.error('Logout all devices failed:', error);
|
|
232
|
-
Alert.alert('Logout Failed', 'There was a problem
|
|
284
|
+
Alert.alert('Logout Failed', 'There was a problem signing out from other devices. Please try again.');
|
|
285
|
+
} finally {
|
|
286
|
+
setLoggingOutAllDevices(false);
|
|
233
287
|
}
|
|
234
288
|
},
|
|
235
289
|
},
|
|
@@ -238,108 +292,168 @@ const AccountSwitcherScreen: React.FC<BaseScreenProps> = ({
|
|
|
238
292
|
);
|
|
239
293
|
};
|
|
240
294
|
|
|
241
|
-
const
|
|
242
|
-
const
|
|
243
|
-
|
|
244
|
-
const isRemoving = removingUserId === session.sessionId;
|
|
245
|
-
|
|
295
|
+
const renderDeviceSessionItem = (deviceSession: DeviceSession) => {
|
|
296
|
+
const isLoggingOut = remotingLogoutSessionId === deviceSession.sessionId;
|
|
297
|
+
|
|
246
298
|
return (
|
|
247
299
|
<View
|
|
248
|
-
key={
|
|
300
|
+
key={deviceSession.sessionId}
|
|
249
301
|
style={[
|
|
250
|
-
styles.
|
|
302
|
+
styles.sessionCard,
|
|
251
303
|
{
|
|
252
|
-
backgroundColor:
|
|
253
|
-
borderColor:
|
|
304
|
+
backgroundColor: deviceSession.isCurrent ? colors.activeCard : colors.card,
|
|
305
|
+
borderColor: deviceSession.isCurrent ? colors.accent : colors.border,
|
|
306
|
+
borderWidth: deviceSession.isCurrent ? 2 : 1,
|
|
254
307
|
},
|
|
255
308
|
]}
|
|
256
309
|
>
|
|
257
|
-
<View style={styles.
|
|
258
|
-
<
|
|
259
|
-
{
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
310
|
+
<View style={styles.sessionHeader}>
|
|
311
|
+
<View style={styles.userInfo}>
|
|
312
|
+
<Text style={[styles.displayName, { color: colors.text }]} numberOfLines={1}>
|
|
313
|
+
{deviceSession.deviceName}
|
|
314
|
+
{deviceSession.isCurrent && (
|
|
315
|
+
<Text style={[styles.username, { color: colors.accent }]}>
|
|
316
|
+
{' (This Device)'}
|
|
317
|
+
</Text>
|
|
318
|
+
)}
|
|
319
|
+
</Text>
|
|
320
|
+
<Text style={[styles.username, { color: colors.secondaryText }]} numberOfLines={1}>
|
|
321
|
+
ID: ...{deviceSession.deviceId.slice(-8)}
|
|
322
|
+
</Text>
|
|
323
|
+
<Text style={[styles.lastActive, { color: colors.secondaryText }]} numberOfLines={1}>
|
|
324
|
+
Last active: {new Date(deviceSession.lastActive).toLocaleDateString()}
|
|
325
|
+
</Text>
|
|
326
|
+
</View>
|
|
327
|
+
|
|
328
|
+
{!deviceSession.isCurrent && (
|
|
273
329
|
<TouchableOpacity
|
|
274
|
-
style={[styles.
|
|
275
|
-
|
|
276
|
-
|
|
330
|
+
style={[styles.removeButton, {
|
|
331
|
+
borderColor: colors.destructive,
|
|
332
|
+
backgroundColor: colors.background,
|
|
333
|
+
}]}
|
|
334
|
+
onPress={() => handleRemoteSessionLogout(deviceSession.sessionId, deviceSession.deviceName)}
|
|
335
|
+
disabled={isLoggingOut}
|
|
277
336
|
>
|
|
278
|
-
{
|
|
279
|
-
<ActivityIndicator color={colors.
|
|
337
|
+
{isLoggingOut ? (
|
|
338
|
+
<ActivityIndicator color={colors.destructive} size="small" />
|
|
280
339
|
) : (
|
|
281
|
-
<Text style={[styles.
|
|
340
|
+
<Text style={[styles.removeButtonText, { color: colors.destructive }]}>
|
|
341
|
+
Sign Out
|
|
342
|
+
</Text>
|
|
282
343
|
)}
|
|
283
344
|
</TouchableOpacity>
|
|
284
345
|
)}
|
|
285
|
-
|
|
286
|
-
<TouchableOpacity
|
|
287
|
-
style={[styles.removeButton, { borderColor: colors.destructive }]}
|
|
288
|
-
onPress={() => handleRemoveSession(session.sessionId)}
|
|
289
|
-
disabled={isSwitching || isRemoving || sessions.length === 1}
|
|
290
|
-
>
|
|
291
|
-
{isRemoving ? (
|
|
292
|
-
<ActivityIndicator color={colors.destructive} size="small" />
|
|
293
|
-
) : (
|
|
294
|
-
<Text style={[styles.removeButtonText, { color: colors.destructive }]}>Remove</Text>
|
|
295
|
-
)}
|
|
296
|
-
</TouchableOpacity>
|
|
297
346
|
</View>
|
|
298
347
|
</View>
|
|
299
348
|
);
|
|
300
349
|
};
|
|
301
350
|
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
351
|
+
// Load device sessions when device management is shown
|
|
352
|
+
useEffect(() => {
|
|
353
|
+
if (showDeviceManagement && deviceSessions.length === 0) {
|
|
354
|
+
loadAllDeviceSessions();
|
|
355
|
+
}
|
|
356
|
+
}, [showDeviceManagement]);
|
|
357
|
+
|
|
358
|
+
const renderSessionItem = (sessionWithUser: SessionWithUser) => {
|
|
359
|
+
const isActive = sessionWithUser.sessionId === activeSessionId;
|
|
360
|
+
const isSwitching = switchingToUserId === sessionWithUser.sessionId;
|
|
361
|
+
const isRemoving = removingUserId === sessionWithUser.sessionId;
|
|
362
|
+
const { userProfile, isLoadingProfile } = sessionWithUser;
|
|
363
|
+
|
|
364
|
+
const displayName = typeof userProfile?.name === 'object'
|
|
365
|
+
? userProfile.name.full || userProfile.name.first || userProfile.username
|
|
366
|
+
: userProfile?.name || userProfile?.username || 'Unknown User';
|
|
367
|
+
const username = userProfile?.username || 'unknown';
|
|
368
|
+
const avatarUrl = userProfile?.avatar?.url;
|
|
369
|
+
|
|
305
370
|
return (
|
|
306
371
|
<View
|
|
307
|
-
key={
|
|
372
|
+
key={sessionWithUser.sessionId}
|
|
308
373
|
style={[
|
|
309
|
-
styles.
|
|
374
|
+
styles.sessionCard,
|
|
310
375
|
{
|
|
311
|
-
backgroundColor:
|
|
312
|
-
borderColor:
|
|
376
|
+
backgroundColor: isActive ? colors.activeCard : colors.card,
|
|
377
|
+
borderColor: isActive ? colors.accent : colors.border,
|
|
378
|
+
borderWidth: isActive ? 2 : 1,
|
|
379
|
+
shadowColor: colors.shadow,
|
|
313
380
|
},
|
|
314
381
|
]}
|
|
315
382
|
>
|
|
316
|
-
<View style={styles.
|
|
317
|
-
<
|
|
318
|
-
{
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
383
|
+
<View style={styles.sessionHeader}>
|
|
384
|
+
<View style={styles.avatarContainer}>
|
|
385
|
+
{isLoadingProfile ? (
|
|
386
|
+
<View style={[styles.avatarPlaceholder, { backgroundColor: colors.surface }]}>
|
|
387
|
+
<ActivityIndicator size="small" color={colors.accent} />
|
|
388
|
+
</View>
|
|
389
|
+
) : avatarUrl ? (
|
|
390
|
+
<Image
|
|
391
|
+
source={{ uri: avatarUrl }}
|
|
392
|
+
style={styles.avatar}
|
|
393
|
+
/>
|
|
394
|
+
) : (
|
|
395
|
+
<View style={[styles.avatarPlaceholder, { backgroundColor: colors.surface }]}>
|
|
396
|
+
<Text style={[styles.avatarText, { color: colors.accent }]}>
|
|
397
|
+
{displayName.charAt(0).toUpperCase()}
|
|
398
|
+
</Text>
|
|
399
|
+
</View>
|
|
400
|
+
)}
|
|
401
|
+
{isActive && (
|
|
402
|
+
<View style={[styles.activeBadge, { backgroundColor: colors.success }]}>
|
|
403
|
+
<Text style={styles.activeBadgeText}>✓</Text>
|
|
404
|
+
</View>
|
|
405
|
+
)}
|
|
406
|
+
</View>
|
|
407
|
+
|
|
408
|
+
<View style={styles.userInfo}>
|
|
409
|
+
<Text style={[styles.displayName, { color: colors.text }]} numberOfLines={1}>
|
|
410
|
+
{displayName}
|
|
411
|
+
</Text>
|
|
412
|
+
<Text style={[styles.username, { color: colors.secondaryText }]} numberOfLines={1}>
|
|
413
|
+
@{username}
|
|
414
|
+
</Text>
|
|
415
|
+
<Text style={[styles.lastActive, { color: colors.secondaryText }]} numberOfLines={1}>
|
|
416
|
+
Last active: {new Date(sessionWithUser.lastActive).toLocaleDateString()}
|
|
417
|
+
</Text>
|
|
418
|
+
</View>
|
|
332
419
|
</View>
|
|
333
420
|
|
|
334
|
-
<View style={styles.
|
|
335
|
-
{!
|
|
421
|
+
<View style={styles.sessionActions}>
|
|
422
|
+
{!isActive && (
|
|
336
423
|
<TouchableOpacity
|
|
337
|
-
style={[styles.
|
|
338
|
-
|
|
424
|
+
style={[styles.switchButton, {
|
|
425
|
+
borderColor: colors.accent,
|
|
426
|
+
backgroundColor: colors.background,
|
|
427
|
+
}]}
|
|
428
|
+
onPress={() => handleSwitchSession(sessionWithUser.sessionId)}
|
|
429
|
+
disabled={isSwitching || isRemoving}
|
|
339
430
|
>
|
|
340
|
-
|
|
431
|
+
{isSwitching ? (
|
|
432
|
+
<ActivityIndicator color={colors.accent} size="small" />
|
|
433
|
+
) : (
|
|
434
|
+
<Text style={[styles.switchButtonText, { color: colors.accent }]}>
|
|
435
|
+
Switch
|
|
436
|
+
</Text>
|
|
437
|
+
)}
|
|
341
438
|
</TouchableOpacity>
|
|
342
439
|
)}
|
|
440
|
+
|
|
441
|
+
<TouchableOpacity
|
|
442
|
+
style={[styles.removeButton, {
|
|
443
|
+
borderColor: colors.destructive,
|
|
444
|
+
backgroundColor: colors.background,
|
|
445
|
+
}]}
|
|
446
|
+
onPress={() => handleRemoveSession(sessionWithUser.sessionId)}
|
|
447
|
+
disabled={isSwitching || isRemoving}
|
|
448
|
+
>
|
|
449
|
+
{isRemoving ? (
|
|
450
|
+
<ActivityIndicator color={colors.destructive} size="small" />
|
|
451
|
+
) : (
|
|
452
|
+
<Text style={[styles.removeButtonText, { color: colors.destructive }]}>
|
|
453
|
+
Remove
|
|
454
|
+
</Text>
|
|
455
|
+
)}
|
|
456
|
+
</TouchableOpacity>
|
|
343
457
|
</View>
|
|
344
458
|
</View>
|
|
345
459
|
);
|
|
@@ -351,103 +465,160 @@ const AccountSwitcherScreen: React.FC<BaseScreenProps> = ({
|
|
|
351
465
|
<TouchableOpacity style={styles.backButton} onPress={goBack}>
|
|
352
466
|
<Text style={[styles.backButtonText, { color: colors.accent }]}>‹ Back</Text>
|
|
353
467
|
</TouchableOpacity>
|
|
354
|
-
<Text style={[styles.title, { color: colors.text }]}>
|
|
355
|
-
<View style={styles.
|
|
468
|
+
<Text style={[styles.title, { color: colors.text }]}>Accounts</Text>
|
|
469
|
+
<View style={styles.headerSpacer} />
|
|
356
470
|
</View>
|
|
357
471
|
|
|
358
|
-
<ScrollView
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
</Text>
|
|
369
|
-
|
|
370
|
-
{sessions.map(renderSessionItem)}
|
|
371
|
-
</View>
|
|
372
|
-
|
|
373
|
-
{/* Remote Device Management Section */}
|
|
374
|
-
<View style={styles.usersContainer}>
|
|
375
|
-
<View style={styles.sectionHeader}>
|
|
376
|
-
<Text style={[styles.sectionTitle, { color: colors.text }]}>
|
|
377
|
-
All Devices & Sessions
|
|
472
|
+
<ScrollView
|
|
473
|
+
style={styles.content}
|
|
474
|
+
showsVerticalScrollIndicator={false}
|
|
475
|
+
contentContainerStyle={styles.scrollContent}
|
|
476
|
+
>
|
|
477
|
+
{isLoading ? (
|
|
478
|
+
<View style={styles.loadingContainer}>
|
|
479
|
+
<ActivityIndicator size="large" color={colors.accent} />
|
|
480
|
+
<Text style={[styles.loadingText, { color: colors.secondaryText }]}>
|
|
481
|
+
Loading accounts...
|
|
378
482
|
</Text>
|
|
379
|
-
<TouchableOpacity
|
|
380
|
-
style={[styles.toggleButton, { borderColor: colors.accent }]}
|
|
381
|
-
onPress={() => setShowRemoteDevices(!showRemoteDevices)}
|
|
382
|
-
>
|
|
383
|
-
<Text style={[styles.toggleButtonText, { color: colors.accent }]}>
|
|
384
|
-
{showRemoteDevices ? 'Hide' : 'Show'}
|
|
385
|
-
</Text>
|
|
386
|
-
</TouchableOpacity>
|
|
387
483
|
</View>
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
484
|
+
) : (
|
|
485
|
+
<>
|
|
486
|
+
<Text style={[styles.sectionTitle, { color: colors.text }]}>
|
|
487
|
+
Saved Accounts ({sessionsWithUsers.length})
|
|
488
|
+
</Text>
|
|
489
|
+
|
|
490
|
+
{sessionsWithUsers.length === 0 ? (
|
|
491
|
+
<View style={styles.emptyState}>
|
|
492
|
+
<Text style={[styles.emptyText, { color: colors.secondaryText }]}>
|
|
493
|
+
No saved accounts found
|
|
494
|
+
</Text>
|
|
495
|
+
</View>
|
|
496
|
+
) : (
|
|
497
|
+
sessionsWithUsers.map(renderSessionItem)
|
|
498
|
+
)}
|
|
499
|
+
|
|
500
|
+
<View style={styles.actionsSection}>
|
|
501
|
+
<TouchableOpacity
|
|
502
|
+
style={[styles.actionButton, {
|
|
503
|
+
borderColor: colors.border,
|
|
504
|
+
backgroundColor: colors.card,
|
|
505
|
+
}]}
|
|
506
|
+
onPress={() => navigate?.('SignIn')}
|
|
507
|
+
>
|
|
508
|
+
<Text style={[styles.actionButtonText, { color: colors.text }]}>
|
|
509
|
+
+ Add Another Account
|
|
510
|
+
</Text>
|
|
511
|
+
</TouchableOpacity>
|
|
512
|
+
|
|
513
|
+
{sessionsWithUsers.length > 0 && (
|
|
514
|
+
<TouchableOpacity
|
|
515
|
+
style={[styles.actionButton, styles.dangerButton, {
|
|
516
|
+
borderColor: colors.destructive,
|
|
517
|
+
backgroundColor: colors.background,
|
|
518
|
+
}]}
|
|
519
|
+
onPress={handleLogoutAll}
|
|
520
|
+
>
|
|
521
|
+
<Text style={[styles.dangerButtonText, { color: colors.destructive }]}>
|
|
522
|
+
Sign Out All Accounts
|
|
396
523
|
</Text>
|
|
397
|
-
</
|
|
398
|
-
) : (
|
|
399
|
-
<>
|
|
400
|
-
{allDeviceSessions.length > 0 ? (
|
|
401
|
-
<>
|
|
402
|
-
{allDeviceSessions.map(renderDeviceSessionItem)}
|
|
403
|
-
{allDeviceSessions.filter(s => !s.isCurrent).length > 0 && (
|
|
404
|
-
<TouchableOpacity
|
|
405
|
-
style={[styles.actionButton, { borderColor: colors.destructive, marginTop: 12 }]}
|
|
406
|
-
onPress={handleLogoutAllDevices}
|
|
407
|
-
>
|
|
408
|
-
<Text style={[styles.actionButtonText, { color: colors.destructive }]}>
|
|
409
|
-
Logout All Other Devices
|
|
410
|
-
</Text>
|
|
411
|
-
</TouchableOpacity>
|
|
412
|
-
)}
|
|
413
|
-
</>
|
|
414
|
-
) : (
|
|
415
|
-
<Text style={[styles.emptyText, { color: colors.secondaryText }]}>
|
|
416
|
-
No other device sessions found
|
|
417
|
-
</Text>
|
|
418
|
-
)}
|
|
419
|
-
</>
|
|
524
|
+
</TouchableOpacity>
|
|
420
525
|
)}
|
|
421
|
-
|
|
422
|
-
)}
|
|
423
|
-
</View>
|
|
526
|
+
</View>
|
|
424
527
|
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
528
|
+
{/* Device Management Section */}
|
|
529
|
+
<View style={styles.actionsSection}>
|
|
530
|
+
<TouchableOpacity
|
|
531
|
+
style={[styles.actionButton, {
|
|
532
|
+
borderColor: colors.border,
|
|
533
|
+
backgroundColor: colors.card,
|
|
534
|
+
}]}
|
|
535
|
+
onPress={() => setShowDeviceManagement(!showDeviceManagement)}
|
|
536
|
+
>
|
|
537
|
+
<Text style={[styles.actionButtonText, { color: colors.text }]}>
|
|
538
|
+
{showDeviceManagement ? '− Hide Device Management' : '+ Manage Device Sessions'}
|
|
539
|
+
</Text>
|
|
540
|
+
</TouchableOpacity>
|
|
541
|
+
</View>
|
|
434
542
|
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
543
|
+
{showDeviceManagement && (
|
|
544
|
+
<View style={[styles.deviceManagementSection, {
|
|
545
|
+
backgroundColor: colors.card,
|
|
546
|
+
borderColor: colors.border,
|
|
547
|
+
}]}>
|
|
548
|
+
<Text style={[styles.sectionTitle, { color: colors.text }]}>
|
|
549
|
+
Device Sessions
|
|
550
|
+
</Text>
|
|
551
|
+
|
|
552
|
+
{loadingDeviceSessions ? (
|
|
553
|
+
<View style={styles.loadingContainer}>
|
|
554
|
+
<ActivityIndicator size="large" color={colors.accent} />
|
|
555
|
+
<Text style={[styles.loadingText, { color: colors.secondaryText }]}>
|
|
556
|
+
Loading device sessions...
|
|
557
|
+
</Text>
|
|
558
|
+
</View>
|
|
559
|
+
) : deviceSessions.length === 0 ? (
|
|
560
|
+
<View style={styles.emptyState}>
|
|
561
|
+
<Text style={[styles.emptyText, { color: colors.secondaryText }]}>
|
|
562
|
+
No device sessions found
|
|
563
|
+
</Text>
|
|
564
|
+
</View>
|
|
565
|
+
) : (
|
|
566
|
+
<>
|
|
567
|
+
{deviceSessions.map(renderDeviceSessionItem)}
|
|
568
|
+
|
|
569
|
+
{deviceSessions.filter(session => !session.isCurrent).length > 0 && (
|
|
570
|
+
<TouchableOpacity
|
|
571
|
+
style={[styles.actionButton, styles.dangerButton, {
|
|
572
|
+
borderColor: colors.destructive,
|
|
573
|
+
backgroundColor: colors.background,
|
|
574
|
+
marginTop: 20,
|
|
575
|
+
}]}
|
|
576
|
+
onPress={handleLogoutAllDevices}
|
|
577
|
+
disabled={loggingOutAllDevices}
|
|
578
|
+
>
|
|
579
|
+
{loggingOutAllDevices ? (
|
|
580
|
+
<ActivityIndicator color={colors.destructive} size="small" />
|
|
581
|
+
) : (
|
|
582
|
+
<Text style={[styles.dangerButtonText, { color: colors.destructive }]}>
|
|
583
|
+
Sign Out All Other Devices
|
|
584
|
+
</Text>
|
|
585
|
+
)}
|
|
586
|
+
</TouchableOpacity>
|
|
587
|
+
)}
|
|
588
|
+
</>
|
|
589
|
+
)}
|
|
590
|
+
</View>
|
|
591
|
+
)}
|
|
592
|
+
|
|
593
|
+
<View style={styles.actionsSection}>
|
|
594
|
+
<TouchableOpacity
|
|
595
|
+
style={[styles.actionButton, {
|
|
596
|
+
borderColor: colors.border,
|
|
597
|
+
backgroundColor: colors.card,
|
|
598
|
+
}]}
|
|
599
|
+
onPress={() => navigate?.('SignIn')}
|
|
600
|
+
>
|
|
601
|
+
<Text style={[styles.actionButtonText, { color: colors.text }]}>
|
|
602
|
+
+ Add Another Account
|
|
446
603
|
</Text>
|
|
604
|
+
</TouchableOpacity>
|
|
605
|
+
|
|
606
|
+
{sessionsWithUsers.length > 0 && (
|
|
607
|
+
<TouchableOpacity
|
|
608
|
+
style={[styles.actionButton, styles.dangerButton, {
|
|
609
|
+
borderColor: colors.destructive,
|
|
610
|
+
backgroundColor: colors.background,
|
|
611
|
+
}]}
|
|
612
|
+
onPress={handleLogoutAll}
|
|
613
|
+
>
|
|
614
|
+
<Text style={[styles.dangerButtonText, { color: colors.destructive }]}>
|
|
615
|
+
Sign Out All Accounts
|
|
616
|
+
</Text>
|
|
617
|
+
</TouchableOpacity>
|
|
447
618
|
)}
|
|
448
|
-
</
|
|
449
|
-
|
|
450
|
-
|
|
619
|
+
</View>
|
|
620
|
+
</>
|
|
621
|
+
)}
|
|
451
622
|
</ScrollView>
|
|
452
623
|
</View>
|
|
453
624
|
);
|
|
@@ -462,168 +633,187 @@ const styles = StyleSheet.create({
|
|
|
462
633
|
alignItems: 'center',
|
|
463
634
|
justifyContent: 'space-between',
|
|
464
635
|
paddingHorizontal: 20,
|
|
465
|
-
paddingTop:
|
|
466
|
-
paddingBottom:
|
|
467
|
-
borderBottomWidth: 1,
|
|
468
|
-
borderBottomColor: 'rgba(0, 0, 0, 0.1)',
|
|
636
|
+
paddingTop: 20,
|
|
637
|
+
paddingBottom: 10,
|
|
469
638
|
},
|
|
470
639
|
backButton: {
|
|
471
|
-
|
|
472
|
-
paddingHorizontal: 4,
|
|
640
|
+
padding: 8,
|
|
473
641
|
},
|
|
474
642
|
backButtonText: {
|
|
475
643
|
fontSize: 18,
|
|
476
|
-
fontFamily: fontFamilies.
|
|
644
|
+
fontFamily: fontFamilies.phuduMedium,
|
|
477
645
|
},
|
|
478
646
|
title: {
|
|
479
|
-
fontSize:
|
|
480
|
-
fontFamily: fontFamilies.
|
|
647
|
+
fontSize: 24,
|
|
648
|
+
fontFamily: fontFamilies.phuduBold,
|
|
481
649
|
textAlign: 'center',
|
|
482
650
|
},
|
|
483
|
-
|
|
484
|
-
width:
|
|
651
|
+
headerSpacer: {
|
|
652
|
+
width: 40,
|
|
485
653
|
},
|
|
486
|
-
|
|
654
|
+
content: {
|
|
487
655
|
flex: 1,
|
|
656
|
+
paddingHorizontal: 20,
|
|
488
657
|
},
|
|
489
|
-
|
|
490
|
-
|
|
658
|
+
scrollContent: {
|
|
659
|
+
paddingBottom: 40,
|
|
491
660
|
},
|
|
492
|
-
|
|
493
|
-
|
|
661
|
+
loadingContainer: {
|
|
662
|
+
flex: 1,
|
|
663
|
+
justifyContent: 'center',
|
|
664
|
+
alignItems: 'center',
|
|
665
|
+
paddingTop: 60,
|
|
494
666
|
},
|
|
495
|
-
|
|
496
|
-
|
|
667
|
+
loadingText: {
|
|
668
|
+
marginTop: 16,
|
|
669
|
+
fontSize: 16,
|
|
497
670
|
fontFamily: fontFamilies.phudu,
|
|
498
|
-
lineHeight: 20,
|
|
499
|
-
},
|
|
500
|
-
usersContainer: {
|
|
501
|
-
marginBottom: 32,
|
|
502
671
|
},
|
|
503
672
|
sectionTitle: {
|
|
504
|
-
fontSize:
|
|
673
|
+
fontSize: 20,
|
|
505
674
|
fontFamily: fontFamilies.phuduSemiBold,
|
|
506
|
-
marginBottom:
|
|
675
|
+
marginBottom: 20,
|
|
676
|
+
marginTop: 10,
|
|
677
|
+
},
|
|
678
|
+
emptyState: {
|
|
679
|
+
alignItems: 'center',
|
|
680
|
+
paddingVertical: 40,
|
|
507
681
|
},
|
|
508
|
-
|
|
682
|
+
emptyText: {
|
|
683
|
+
fontSize: 16,
|
|
684
|
+
fontFamily: fontFamilies.phudu,
|
|
685
|
+
textAlign: 'center',
|
|
686
|
+
},
|
|
687
|
+
sessionCard: {
|
|
688
|
+
borderRadius: 16,
|
|
689
|
+
marginBottom: 16,
|
|
690
|
+
padding: 20,
|
|
691
|
+
shadowOffset: {
|
|
692
|
+
width: 0,
|
|
693
|
+
height: 2,
|
|
694
|
+
},
|
|
695
|
+
shadowOpacity: 0.1,
|
|
696
|
+
shadowRadius: 8,
|
|
697
|
+
elevation: 3,
|
|
698
|
+
},
|
|
699
|
+
sessionHeader: {
|
|
509
700
|
flexDirection: 'row',
|
|
510
701
|
alignItems: 'center',
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
702
|
+
marginBottom: 16,
|
|
703
|
+
},
|
|
704
|
+
avatarContainer: {
|
|
705
|
+
position: 'relative',
|
|
706
|
+
marginRight: 16,
|
|
707
|
+
},
|
|
708
|
+
avatar: {
|
|
709
|
+
width: 60,
|
|
710
|
+
height: 60,
|
|
711
|
+
borderRadius: 30,
|
|
712
|
+
},
|
|
713
|
+
avatarPlaceholder: {
|
|
714
|
+
width: 60,
|
|
715
|
+
height: 60,
|
|
716
|
+
borderRadius: 30,
|
|
717
|
+
justifyContent: 'center',
|
|
718
|
+
alignItems: 'center',
|
|
719
|
+
},
|
|
720
|
+
avatarText: {
|
|
721
|
+
fontSize: 24,
|
|
722
|
+
fontFamily: fontFamilies.phuduBold,
|
|
723
|
+
},
|
|
724
|
+
activeBadge: {
|
|
725
|
+
position: 'absolute',
|
|
726
|
+
bottom: -2,
|
|
727
|
+
right: -2,
|
|
728
|
+
width: 20,
|
|
729
|
+
height: 20,
|
|
730
|
+
borderRadius: 10,
|
|
731
|
+
justifyContent: 'center',
|
|
732
|
+
alignItems: 'center',
|
|
733
|
+
},
|
|
734
|
+
activeBadgeText: {
|
|
735
|
+
color: 'white',
|
|
736
|
+
fontSize: 12,
|
|
737
|
+
fontFamily: fontFamilies.phuduBold,
|
|
516
738
|
},
|
|
517
739
|
userInfo: {
|
|
518
740
|
flex: 1,
|
|
741
|
+
justifyContent: 'center',
|
|
519
742
|
},
|
|
520
|
-
|
|
521
|
-
fontSize:
|
|
743
|
+
displayName: {
|
|
744
|
+
fontSize: 18,
|
|
522
745
|
fontFamily: fontFamilies.phuduSemiBold,
|
|
523
746
|
marginBottom: 4,
|
|
524
747
|
},
|
|
525
|
-
|
|
748
|
+
username: {
|
|
526
749
|
fontSize: 14,
|
|
527
750
|
fontFamily: fontFamilies.phudu,
|
|
528
|
-
marginBottom:
|
|
529
|
-
},
|
|
530
|
-
activeBadge: {
|
|
531
|
-
paddingHorizontal: 8,
|
|
532
|
-
paddingVertical: 4,
|
|
533
|
-
borderRadius: 6,
|
|
534
|
-
alignSelf: 'flex-start',
|
|
751
|
+
marginBottom: 4,
|
|
535
752
|
},
|
|
536
|
-
|
|
537
|
-
color: '#FFFFFF',
|
|
753
|
+
lastActive: {
|
|
538
754
|
fontSize: 12,
|
|
539
|
-
fontFamily: fontFamilies.
|
|
755
|
+
fontFamily: fontFamilies.phudu,
|
|
540
756
|
},
|
|
541
|
-
|
|
757
|
+
sessionActions: {
|
|
542
758
|
flexDirection: 'row',
|
|
543
|
-
|
|
759
|
+
justifyContent: 'space-between',
|
|
760
|
+
gap: 12,
|
|
544
761
|
},
|
|
545
762
|
switchButton: {
|
|
546
|
-
|
|
547
|
-
paddingVertical:
|
|
548
|
-
|
|
763
|
+
flex: 1,
|
|
764
|
+
paddingVertical: 12,
|
|
765
|
+
paddingHorizontal: 20,
|
|
549
766
|
borderWidth: 1,
|
|
550
|
-
|
|
767
|
+
borderRadius: 8,
|
|
551
768
|
alignItems: 'center',
|
|
769
|
+
justifyContent: 'center',
|
|
552
770
|
},
|
|
553
771
|
switchButtonText: {
|
|
554
772
|
fontSize: 14,
|
|
555
|
-
fontFamily: fontFamilies.
|
|
773
|
+
fontFamily: fontFamilies.phuduSemiBold,
|
|
556
774
|
},
|
|
557
775
|
removeButton: {
|
|
558
|
-
|
|
559
|
-
paddingVertical:
|
|
560
|
-
|
|
776
|
+
flex: 1,
|
|
777
|
+
paddingVertical: 12,
|
|
778
|
+
paddingHorizontal: 20,
|
|
561
779
|
borderWidth: 1,
|
|
562
|
-
|
|
780
|
+
borderRadius: 8,
|
|
563
781
|
alignItems: 'center',
|
|
782
|
+
justifyContent: 'center',
|
|
564
783
|
},
|
|
565
784
|
removeButtonText: {
|
|
566
785
|
fontSize: 14,
|
|
567
|
-
fontFamily: fontFamilies.
|
|
786
|
+
fontFamily: fontFamilies.phuduSemiBold,
|
|
568
787
|
},
|
|
569
|
-
|
|
788
|
+
actionsSection: {
|
|
789
|
+
marginTop: 40,
|
|
570
790
|
gap: 16,
|
|
571
791
|
},
|
|
572
792
|
actionButton: {
|
|
573
793
|
paddingVertical: 16,
|
|
574
794
|
paddingHorizontal: 20,
|
|
575
|
-
borderRadius: 12,
|
|
576
795
|
borderWidth: 1,
|
|
796
|
+
borderRadius: 12,
|
|
577
797
|
alignItems: 'center',
|
|
798
|
+
justifyContent: 'center',
|
|
578
799
|
},
|
|
579
800
|
actionButtonText: {
|
|
580
801
|
fontSize: 16,
|
|
581
|
-
fontFamily: fontFamilies.
|
|
802
|
+
fontFamily: fontFamilies.phuduSemiBold,
|
|
582
803
|
},
|
|
583
804
|
dangerButton: {
|
|
584
|
-
|
|
585
|
-
paddingHorizontal: 20,
|
|
586
|
-
borderRadius: 12,
|
|
587
|
-
alignItems: 'center',
|
|
805
|
+
// Additional styles for danger buttons if needed
|
|
588
806
|
},
|
|
589
807
|
dangerButtonText: {
|
|
590
808
|
fontSize: 16,
|
|
591
|
-
fontFamily: fontFamilies.
|
|
592
|
-
},
|
|
593
|
-
sectionHeader: {
|
|
594
|
-
flexDirection: 'row',
|
|
595
|
-
alignItems: 'center',
|
|
596
|
-
justifyContent: 'space-between',
|
|
597
|
-
marginBottom: 16,
|
|
809
|
+
fontFamily: fontFamilies.phuduSemiBold,
|
|
598
810
|
},
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
borderRadius:
|
|
811
|
+
deviceManagementSection: {
|
|
812
|
+
marginTop: 20,
|
|
813
|
+
padding: 16,
|
|
814
|
+
borderRadius: 12,
|
|
603
815
|
borderWidth: 1,
|
|
604
816
|
},
|
|
605
|
-
toggleButtonText: {
|
|
606
|
-
fontSize: 14,
|
|
607
|
-
fontFamily: fontFamilies.phuduMedium,
|
|
608
|
-
},
|
|
609
|
-
loadingContainer: {
|
|
610
|
-
flexDirection: 'row',
|
|
611
|
-
alignItems: 'center',
|
|
612
|
-
justifyContent: 'center',
|
|
613
|
-
paddingVertical: 20,
|
|
614
|
-
gap: 8,
|
|
615
|
-
},
|
|
616
|
-
loadingText: {
|
|
617
|
-
fontSize: 14,
|
|
618
|
-
fontFamily: fontFamilies.phudu,
|
|
619
|
-
},
|
|
620
|
-
emptyText: {
|
|
621
|
-
fontSize: 14,
|
|
622
|
-
fontFamily: fontFamilies.phudu,
|
|
623
|
-
textAlign: 'center',
|
|
624
|
-
paddingVertical: 20,
|
|
625
|
-
fontStyle: 'italic',
|
|
626
|
-
},
|
|
627
817
|
});
|
|
628
818
|
|
|
629
|
-
export default
|
|
819
|
+
export default ModernAccountSwitcherScreen;
|