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