@oxyhq/services 5.3.1 → 5.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/lib/commonjs/ui/components/OxyProvider.js +18 -6
  2. package/lib/commonjs/ui/components/OxyProvider.js.map +1 -1
  3. package/lib/commonjs/ui/context/OxyContext.js +24 -11
  4. package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
  5. package/lib/commonjs/ui/navigation/OxyRouter.js +41 -3
  6. package/lib/commonjs/ui/navigation/OxyRouter.js.map +1 -1
  7. package/lib/commonjs/ui/screens/AccountSwitcherScreen.js +70 -26
  8. package/lib/commonjs/ui/screens/AccountSwitcherScreen.js.map +1 -1
  9. package/lib/commonjs/ui/screens/ModernAccountSwitcherScreen.js +532 -0
  10. package/lib/commonjs/ui/screens/ModernAccountSwitcherScreen.js.map +1 -0
  11. package/lib/module/ui/components/OxyProvider.js +18 -6
  12. package/lib/module/ui/components/OxyProvider.js.map +1 -1
  13. package/lib/module/ui/context/OxyContext.js +24 -11
  14. package/lib/module/ui/context/OxyContext.js.map +1 -1
  15. package/lib/module/ui/navigation/OxyRouter.js +41 -3
  16. package/lib/module/ui/navigation/OxyRouter.js.map +1 -1
  17. package/lib/module/ui/screens/AccountSwitcherScreen.js +72 -28
  18. package/lib/module/ui/screens/AccountSwitcherScreen.js.map +1 -1
  19. package/lib/module/ui/screens/ModernAccountSwitcherScreen.js +527 -0
  20. package/lib/module/ui/screens/ModernAccountSwitcherScreen.js.map +1 -0
  21. package/lib/typescript/ui/components/OxyProvider.d.ts.map +1 -1
  22. package/lib/typescript/ui/context/OxyContext.d.ts.map +1 -1
  23. package/lib/typescript/ui/navigation/OxyRouter.d.ts.map +1 -1
  24. package/lib/typescript/ui/navigation/types.d.ts +1 -0
  25. package/lib/typescript/ui/navigation/types.d.ts.map +1 -1
  26. package/lib/typescript/ui/screens/AccountSwitcherScreen.d.ts.map +1 -1
  27. package/lib/typescript/ui/screens/ModernAccountSwitcherScreen.d.ts +5 -0
  28. package/lib/typescript/ui/screens/ModernAccountSwitcherScreen.d.ts.map +1 -0
  29. package/package.json +1 -1
  30. package/src/ui/components/OxyProvider.tsx +17 -5
  31. package/src/ui/context/OxyContext.tsx +25 -11
  32. package/src/ui/navigation/OxyRouter.tsx +42 -2
  33. package/src/ui/navigation/types.ts +1 -0
  34. package/src/ui/screens/AccountSwitcherScreen.tsx +85 -25
  35. package/src/ui/screens/ModernAccountSwitcherScreen.tsx +552 -0
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/ui/navigation/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EAAE,IAAI,EAAE,MAAM,yBAAyB,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAGjD;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,WAAW,EAAE,WAAW,CAAC;IACzB,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,GAAG,KAAK,IAAI,CAAC;IAChD,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,eAAe,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IACvC,KAAK,EAAE,OAAO,GAAG,MAAM,CAAC;CACzB;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,aAAa,CAAC,GAAG,CAAC,CAAC;IAC9B,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,WAAW,EAAE,WAAW,CAAC;IACzB,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,eAAe,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IACvC,KAAK,EAAE,OAAO,GAAG,MAAM,CAAC;IACxB,gBAAgB,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;CAClD;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;OAEG;IACH,WAAW,EAAE,WAAW,CAAC;IAEzB;;;OAGG;IACH,aAAa,CAAC,EAAE,QAAQ,GAAG,QAAQ,GAAG,eAAe,CAAC;IAEtD;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IAErB;;OAEG;IACH,eAAe,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IAEvC;;;OAGG;IACH,KAAK,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IAEzB;;;;;OAKG;IACH,cAAc,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;IAEtC;;;OAGG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IAEtB;;OAEG;IACH,YAAY,CAAC,EAAE;QACb;;WAEG;QACH,eAAe,CAAC,EAAE,MAAM,CAAC;QAEzB;;WAEG;QACH,WAAW,CAAC,EAAE,MAAM,CAAC;QAErB;;WAEG;QACH,cAAc,CAAC,EAAE,MAAM,CAAC;KACzB,CAAC;IAEF;;OAEG;IACH,QAAQ,CAAC,EAAE,SAAS,CAAC;IAErB;;;OAGG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IAEtB;;OAEG;IACH,iBAAiB,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,KAAK,IAAI,CAAC;IAEhD;;;OAGG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/ui/navigation/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EAAE,IAAI,EAAE,MAAM,yBAAyB,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAGjD;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,WAAW,EAAE,WAAW,CAAC;IACzB,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,GAAG,KAAK,IAAI,CAAC;IAChD,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,eAAe,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IACvC,KAAK,EAAE,OAAO,GAAG,MAAM,CAAC;CACzB;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,aAAa,CAAC,GAAG,CAAC,CAAC;IAC9B,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,WAAW,EAAE,WAAW,CAAC;IACzB,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,eAAe,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IACvC,KAAK,EAAE,OAAO,GAAG,MAAM,CAAC;IACxB,gBAAgB,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACjD,aAAa,CAAC,EAAE,KAAK,CAAC,gBAAgB,CAAC,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAAK,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC;CACxG;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;OAEG;IACH,WAAW,EAAE,WAAW,CAAC;IAEzB;;;OAGG;IACH,aAAa,CAAC,EAAE,QAAQ,GAAG,QAAQ,GAAG,eAAe,CAAC;IAEtD;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IAErB;;OAEG;IACH,eAAe,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IAEvC;;;OAGG;IACH,KAAK,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IAEzB;;;;;OAKG;IACH,cAAc,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;IAEtC;;;OAGG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IAEtB;;OAEG;IACH,YAAY,CAAC,EAAE;QACb;;WAEG;QACH,eAAe,CAAC,EAAE,MAAM,CAAC;QAEzB;;WAEG;QACH,WAAW,CAAC,EAAE,MAAM,CAAC;QAErB;;WAEG;QACH,cAAc,CAAC,EAAE,MAAM,CAAC;KACzB,CAAC;IAEF;;OAEG;IACH,QAAQ,CAAC,EAAE,SAAS,CAAC;IAErB;;;OAGG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IAEtB;;OAEG;IACH,iBAAiB,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,KAAK,IAAI,CAAC;IAEhD;;;OAGG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B"}
@@ -1 +1 @@
1
- {"version":3,"file":"AccountSwitcherScreen.d.ts","sourceRoot":"","sources":["../../../../src/ui/screens/AccountSwitcherScreen.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA8B,MAAM,OAAO,CAAC;AAWnD,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAKtD,QAAA,MAAM,qBAAqB,EAAE,KAAK,CAAC,EAAE,CAAC,eAAe,CAgOpD,CAAC;AA6IF,eAAe,qBAAqB,CAAC"}
1
+ {"version":3,"file":"AccountSwitcherScreen.d.ts","sourceRoot":"","sources":["../../../../src/ui/screens/AccountSwitcherScreen.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA8B,MAAM,OAAO,CAAC;AAanD,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAWtD,QAAA,MAAM,qBAAqB,EAAE,KAAK,CAAC,EAAE,CAAC,eAAe,CAoRpD,CAAC;AA6IF,eAAe,qBAAqB,CAAC"}
@@ -0,0 +1,5 @@
1
+ import React from 'react';
2
+ import { BaseScreenProps } from '../navigation/types';
3
+ declare const ModernAccountSwitcherScreen: React.FC<BaseScreenProps>;
4
+ export default ModernAccountSwitcherScreen;
5
+ //# sourceMappingURL=ModernAccountSwitcherScreen.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ModernAccountSwitcherScreen.d.ts","sourceRoot":"","sources":["../../../../src/ui/screens/ModernAccountSwitcherScreen.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA8B,MAAM,OAAO,CAAC;AAanD,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAWtD,QAAA,MAAM,2BAA2B,EAAE,KAAK,CAAC,EAAE,CAAC,eAAe,CAmV1D,CAAC;AA4LF,eAAe,2BAA2B,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oxyhq/services",
3
- "version": "5.3.1",
3
+ "version": "5.3.3",
4
4
  "description": "Reusable OxyHQ module to handle authentication, user management, karma system, device-based session management and more 🚀",
5
5
  "main": "lib/commonjs/node/index.js",
6
6
  "module": "lib/module/node/index.js",
@@ -95,6 +95,9 @@ const OxyBottomSheet: React.FC<OxyProviderProps> = ({
95
95
  }) => {
96
96
  // Use the internal ref (which is passed as a prop from OxyProvider)
97
97
  const modalRef = useRef<BottomSheetModal>(null);
98
+
99
+ // Create a ref to store the navigation function from OxyRouter
100
+ const navigationRef = useRef<((screen: string, props?: Record<string, any>) => void) | null>(null);
98
101
 
99
102
  // Track content height for dynamic sizing
100
103
  const [contentHeight, setContentHeight] = useState<number>(0);
@@ -122,16 +125,24 @@ const OxyBottomSheet: React.FC<OxyProviderProps> = ({
122
125
  // Add a method to navigate between screens
123
126
  // @ts-ignore - Adding custom method
124
127
  bottomSheetRef.current._navigateToScreen = (screenName: string, props?: Record<string, any>) => {
125
- // Access the navigation function exposed by OxyRouter
126
- // Use internal mechanism to notify router about navigation
127
- // We'll use a simple event-based approach
128
+ console.log(`Navigation requested: ${screenName}`, props);
129
+
130
+ // Try direct navigation function first (most reliable)
131
+ if (navigationRef.current) {
132
+ console.log('Using direct navigation function');
133
+ navigationRef.current(screenName, props);
134
+ return;
135
+ }
136
+
137
+ // Fallback to event-based navigation
128
138
  if (typeof document !== 'undefined') {
129
139
  // For web - use a custom event
140
+ console.log('Using web event navigation');
130
141
  const event = new CustomEvent('oxy:navigate', { detail: { screen: screenName, props } });
131
142
  document.dispatchEvent(event);
132
143
  } else {
133
- // For React Native - use the navigation prop directly if available
134
- // We'll implement a mechanism in OxyRouter to listen for this
144
+ // For React Native - use the global variable approach
145
+ console.log('Using React Native global navigation');
135
146
  (global as any).oxyNavigateEvent = { screen: screenName, props };
136
147
  }
137
148
  };
@@ -481,6 +492,7 @@ const OxyBottomSheet: React.FC<OxyProviderProps> = ({
481
492
  onAuthenticated={handleAuthenticated}
482
493
  theme={theme}
483
494
  adjustSnapPoints={adjustSnapPoints}
495
+ navigationRef={navigationRef}
484
496
  />
485
497
  </Animated.View>
486
498
  </BottomSheetScrollView>
@@ -502,25 +502,39 @@ export const OxyContextProvider: React.FC<OxyContextProviderProps> = ({
502
502
 
503
503
  // Bottom sheet control methods
504
504
  const showBottomSheet = useCallback((screenOrConfig?: string | { screen: string; props?: Record<string, any> }) => {
505
+ console.log('showBottomSheet called with:', screenOrConfig);
506
+
505
507
  if (bottomSheetRef?.current) {
506
- // Use expand() instead of present() to trigger animations
508
+ console.log('bottomSheetRef is available');
509
+
510
+ // First, show the bottom sheet
507
511
  if (bottomSheetRef.current.expand) {
512
+ console.log('Expanding bottom sheet');
508
513
  bottomSheetRef.current.expand();
514
+ } else if (bottomSheetRef.current.present) {
515
+ console.log('Presenting bottom sheet');
516
+ bottomSheetRef.current.present();
509
517
  } else {
510
- // Fallback to present if expand is not available
511
- bottomSheetRef.current.present?.();
518
+ console.warn('No expand or present method available on bottomSheetRef');
512
519
  }
513
520
 
514
- // Navigate to the specified screen if provided
521
+ // Then navigate to the specified screen if provided
515
522
  if (screenOrConfig) {
516
- if (typeof screenOrConfig === 'string') {
517
- // Simple screen name
518
- bottomSheetRef.current._navigateToScreen?.(screenOrConfig);
519
- } else {
520
- // Screen with props
521
- bottomSheetRef.current._navigateToScreen?.(screenOrConfig.screen, screenOrConfig.props);
522
- }
523
+ // Add a small delay to ensure the bottom sheet is opened first
524
+ setTimeout(() => {
525
+ if (typeof screenOrConfig === 'string') {
526
+ // Simple screen name
527
+ console.log('Navigating to screen:', screenOrConfig);
528
+ bottomSheetRef.current?._navigateToScreen?.(screenOrConfig);
529
+ } else {
530
+ // Screen with props
531
+ console.log('Navigating to screen with props:', screenOrConfig.screen, screenOrConfig.props);
532
+ bottomSheetRef.current?._navigateToScreen?.(screenOrConfig.screen, screenOrConfig.props);
533
+ }
534
+ }, 100);
523
535
  }
536
+ } else {
537
+ console.warn('bottomSheetRef is not available');
524
538
  }
525
539
  }, [bottomSheetRef]);
526
540
 
@@ -7,6 +7,7 @@ import SignInScreen from '../screens/SignInScreen';
7
7
  import SignUpScreen from '../screens/SignUpScreen';
8
8
  import AccountCenterScreen from '../screens/AccountCenterScreen';
9
9
  import AccountSwitcherScreen from '../screens/AccountSwitcherScreen';
10
+ import ModernAccountSwitcherScreen from '../screens/ModernAccountSwitcherScreen';
10
11
  import SessionManagementScreen from '../screens/SessionManagementScreen';
11
12
  import AccountOverviewScreen from '../screens/AccountOverviewScreen';
12
13
  import AccountSettingsScreen from '../screens/AccountSettingsScreen';
@@ -40,6 +41,10 @@ const routes: Record<string, RouteConfig> = {
40
41
  component: AccountSwitcherScreen,
41
42
  snapPoints: ['70%', '100%'],
42
43
  },
44
+ ModernAccountSwitcher: {
45
+ component: ModernAccountSwitcherScreen,
46
+ snapPoints: ['70%', '100%'],
47
+ },
43
48
  SessionManagement: {
44
49
  component: SessionManagementScreen,
45
50
  snapPoints: ['70%', '100%'],
@@ -93,6 +98,7 @@ const OxyRouter: React.FC<OxyRouterProps> = ({
93
98
  onAuthenticated,
94
99
  theme,
95
100
  adjustSnapPoints,
101
+ navigationRef,
96
102
  }) => {
97
103
  const [currentScreen, setCurrentScreen] = useState<string>(initialScreen);
98
104
  const [screenHistory, setScreenHistory] = useState<string[]>([initialScreen]);
@@ -114,7 +120,22 @@ const OxyRouter: React.FC<OxyRouterProps> = ({
114
120
  } else {
115
121
  console.error(`Screen "${screen}" not found`);
116
122
  }
117
- }; // Expose the navigate method to the parent component (OxyProvider)
123
+ };
124
+
125
+ // Expose the navigate function to the parent component
126
+ useEffect(() => {
127
+ if (navigationRef) {
128
+ navigationRef.current = navigate;
129
+ }
130
+
131
+ return () => {
132
+ if (navigationRef) {
133
+ navigationRef.current = null;
134
+ }
135
+ };
136
+ }, [navigate, navigationRef]);
137
+
138
+ // Expose the navigate method to the parent component (OxyProvider)
118
139
  useEffect(() => {
119
140
  // Set up event listener for navigation events
120
141
  const handleNavigationEvent = (event: any) => {
@@ -132,9 +153,25 @@ const OxyRouter: React.FC<OxyRouterProps> = ({
132
153
  }
133
154
  };
134
155
 
135
- // Add event listener (web only)
156
+ // For React Native - check for global navigation events
157
+ let intervalId: NodeJS.Timeout | null = null;
158
+
136
159
  if (typeof document !== 'undefined') {
160
+ // Web - use custom event listener
137
161
  document.addEventListener('oxy:navigate', handleNavigationEvent);
162
+ } else {
163
+ // React Native - poll for global navigation events
164
+ intervalId = setInterval(() => {
165
+ const globalNav = (global as any).oxyNavigateEvent;
166
+ if (globalNav) {
167
+ console.log(`RN Navigation event received:`, globalNav);
168
+ if (globalNav.screen) {
169
+ navigate(globalNav.screen, globalNav.props || {});
170
+ }
171
+ // Clear the event after processing
172
+ (global as any).oxyNavigateEvent = null;
173
+ }
174
+ }, 100); // Check every 100ms
138
175
  }
139
176
 
140
177
  // Cleanup
@@ -142,6 +179,9 @@ const OxyRouter: React.FC<OxyRouterProps> = ({
142
179
  if (typeof document !== 'undefined') {
143
180
  document.removeEventListener('oxy:navigate', handleNavigationEvent);
144
181
  }
182
+ if (intervalId) {
183
+ clearInterval(intervalId);
184
+ }
145
185
  };
146
186
  }, []);
147
187
 
@@ -33,6 +33,7 @@ export interface OxyRouterProps {
33
33
  onAuthenticated?: (user: User) => void;
34
34
  theme: 'light' | 'dark';
35
35
  adjustSnapPoints: (snapPoints: string[]) => void;
36
+ navigationRef?: React.MutableRefObject<((screen: string, props?: Record<string, any>) => void) | null>;
36
37
  }
37
38
 
38
39
  /**
@@ -8,17 +8,26 @@ import {
8
8
  ScrollView,
9
9
  Alert,
10
10
  Platform,
11
+ Image,
12
+ Dimensions,
11
13
  } from 'react-native';
12
14
  import { BaseScreenProps } from '../navigation/types';
13
15
  import { useOxy } from '../context/OxyContext';
14
16
  import { SecureClientSession } from '../../models/secureSession';
15
17
  import { fontFamilies } from '../styles/fonts';
18
+ import { User } from '../../models/interfaces';
19
+
20
+ interface SessionWithUser extends SecureClientSession {
21
+ userProfile?: User;
22
+ isLoadingProfile?: boolean;
23
+ }
16
24
 
17
25
  const AccountSwitcherScreen: React.FC<BaseScreenProps> = ({
18
26
  onClose,
19
27
  theme,
20
28
  navigate,
21
29
  goBack,
30
+ oxyServices,
22
31
  }) => {
23
32
  const {
24
33
  user,
@@ -30,17 +39,68 @@ const AccountSwitcherScreen: React.FC<BaseScreenProps> = ({
30
39
  isLoading
31
40
  } = useOxy();
32
41
 
42
+ const [sessionsWithUsers, setSessionsWithUsers] = useState<SessionWithUser[]>([]);
33
43
  const [switchingToUserId, setSwitchingToUserId] = useState<string | null>(null);
34
44
  const [removingUserId, setRemovingUserId] = useState<string | null>(null);
35
45
 
46
+ const screenWidth = Dimensions.get('window').width;
36
47
  const isDarkTheme = theme === 'dark';
37
- const textColor = isDarkTheme ? '#FFFFFF' : '#000000';
38
- const backgroundColor = isDarkTheme ? '#121212' : '#FFFFFF';
39
- const secondaryBackgroundColor = isDarkTheme ? '#222222' : '#F5F5F5';
40
- const borderColor = isDarkTheme ? '#444444' : '#E0E0E0';
41
- const primaryColor = '#0066CC';
42
- const dangerColor = '#D32F2F';
43
- const successColor = '#2E7D32';
48
+
49
+ // Modern color scheme
50
+ const colors = {
51
+ background: isDarkTheme ? '#000000' : '#FFFFFF',
52
+ surface: isDarkTheme ? '#1C1C1E' : '#F2F2F7',
53
+ card: isDarkTheme ? '#2C2C2E' : '#FFFFFF',
54
+ text: isDarkTheme ? '#FFFFFF' : '#000000',
55
+ secondaryText: isDarkTheme ? '#8E8E93' : '#6D6D70',
56
+ accent: '#007AFF',
57
+ destructive: '#FF3B30',
58
+ success: '#34C759',
59
+ border: isDarkTheme ? '#38383A' : '#C6C6C8',
60
+ activeCard: isDarkTheme ? '#0A84FF20' : '#007AFF15',
61
+ shadow: isDarkTheme ? 'rgba(0,0,0,0.3)' : 'rgba(0,0,0,0.1)',
62
+ };
63
+
64
+ // Load user profiles for sessions
65
+ useEffect(() => {
66
+ const loadUserProfiles = async () => {
67
+ if (!sessions.length || !oxyServices) return;
68
+
69
+ const updatedSessions: SessionWithUser[] = sessions.map(session => ({
70
+ ...session,
71
+ isLoadingProfile: true,
72
+ }));
73
+ setSessionsWithUsers(updatedSessions);
74
+
75
+ // Load profiles for each session
76
+ for (let i = 0; i < sessions.length; i++) {
77
+ const session = sessions[i];
78
+ try {
79
+ // Try to get user profile using the session
80
+ const userProfile = await oxyServices.getUserBySession(session.sessionId);
81
+
82
+ setSessionsWithUsers(prev =>
83
+ prev.map(s =>
84
+ s.sessionId === session.sessionId
85
+ ? { ...s, userProfile, isLoadingProfile: false }
86
+ : s
87
+ )
88
+ );
89
+ } catch (error) {
90
+ console.error(`Failed to load profile for session ${session.sessionId}:`, error);
91
+ setSessionsWithUsers(prev =>
92
+ prev.map(s =>
93
+ s.sessionId === session.sessionId
94
+ ? { ...s, isLoadingProfile: false }
95
+ : s
96
+ )
97
+ );
98
+ }
99
+ }
100
+ };
101
+
102
+ loadUserProfiles();
103
+ }, [sessions, oxyServices]);
44
104
 
45
105
  const handleSwitchSession = async (sessionId: string) => {
46
106
  if (sessionId === user?.sessionId) return; // Already active session
@@ -134,20 +194,20 @@ const AccountSwitcherScreen: React.FC<BaseScreenProps> = ({
134
194
  style={[
135
195
  styles.userItem,
136
196
  {
137
- backgroundColor: isActive ? primaryColor + '20' : secondaryBackgroundColor,
138
- borderColor: isActive ? primaryColor : borderColor,
197
+ backgroundColor: isActive ? colors.activeCard : colors.surface,
198
+ borderColor: isActive ? colors.accent : colors.border,
139
199
  },
140
200
  ]}
141
201
  >
142
202
  <View style={styles.userInfo}>
143
- <Text style={[styles.username, { color: textColor }]}>
203
+ <Text style={[styles.username, { color: colors.text }]}>
144
204
  {isActive ? user?.username || 'Current Account' : 'Account Session'}
145
205
  </Text>
146
206
  <Text style={[styles.email, { color: isDarkTheme ? '#BBBBBB' : '#666666' }]}>
147
207
  Last active: {new Date(session.lastActive).toLocaleDateString()}
148
208
  </Text>
149
209
  {isActive && (
150
- <View style={[styles.activeBadge, { backgroundColor: successColor }]}>
210
+ <View style={[styles.activeBadge, { backgroundColor: colors.success }]}>
151
211
  <Text style={styles.activeBadgeText}>Active</Text>
152
212
  </View>
153
213
  )}
@@ -156,27 +216,27 @@ const AccountSwitcherScreen: React.FC<BaseScreenProps> = ({
156
216
  <View style={styles.userActions}>
157
217
  {!isActive && (
158
218
  <TouchableOpacity
159
- style={[styles.switchButton, { borderColor: primaryColor }]}
219
+ style={[styles.switchButton, { borderColor: colors.accent }]}
160
220
  onPress={() => handleSwitchSession(session.sessionId)}
161
221
  disabled={isSwitching || isRemoving}
162
222
  >
163
223
  {isSwitching ? (
164
- <ActivityIndicator color={primaryColor} size="small" />
224
+ <ActivityIndicator color={colors.accent} size="small" />
165
225
  ) : (
166
- <Text style={[styles.switchButtonText, { color: primaryColor }]}>Switch</Text>
226
+ <Text style={[styles.switchButtonText, { color: colors.accent }]}>Switch</Text>
167
227
  )}
168
228
  </TouchableOpacity>
169
229
  )}
170
230
 
171
231
  <TouchableOpacity
172
- style={[styles.removeButton, { borderColor: dangerColor }]}
232
+ style={[styles.removeButton, { borderColor: colors.destructive }]}
173
233
  onPress={() => handleRemoveSession(session.sessionId)}
174
234
  disabled={isSwitching || isRemoving || sessions.length === 1}
175
235
  >
176
236
  {isRemoving ? (
177
- <ActivityIndicator color={dangerColor} size="small" />
237
+ <ActivityIndicator color={colors.destructive} size="small" />
178
238
  ) : (
179
- <Text style={[styles.removeButtonText, { color: dangerColor }]}>Remove</Text>
239
+ <Text style={[styles.removeButtonText, { color: colors.destructive }]}>Remove</Text>
180
240
  )}
181
241
  </TouchableOpacity>
182
242
  </View>
@@ -185,12 +245,12 @@ const AccountSwitcherScreen: React.FC<BaseScreenProps> = ({
185
245
  };
186
246
 
187
247
  return (
188
- <View style={[styles.container, { backgroundColor }]}>
248
+ <View style={[styles.container, { backgroundColor: colors.background }]}>
189
249
  <View style={styles.header}>
190
250
  <TouchableOpacity style={styles.backButton} onPress={goBack}>
191
- <Text style={[styles.backButtonText, { color: primaryColor }]}>‹ Back</Text>
251
+ <Text style={[styles.backButtonText, { color: colors.accent }]}>‹ Back</Text>
192
252
  </TouchableOpacity>
193
- <Text style={[styles.title, { color: textColor }]}>Account Switcher</Text>
253
+ <Text style={[styles.title, { color: colors.text }]}>Account Switcher</Text>
194
254
  <View style={styles.placeholder} />
195
255
  </View>
196
256
 
@@ -202,7 +262,7 @@ const AccountSwitcherScreen: React.FC<BaseScreenProps> = ({
202
262
  </View>
203
263
 
204
264
  <View style={styles.usersContainer}>
205
- <Text style={[styles.sectionTitle, { color: textColor }]}>
265
+ <Text style={[styles.sectionTitle, { color: colors.text }]}>
206
266
  Sessions ({sessions.length})
207
267
  </Text>
208
268
 
@@ -211,10 +271,10 @@ const AccountSwitcherScreen: React.FC<BaseScreenProps> = ({
211
271
 
212
272
  <View style={styles.actionsContainer}>
213
273
  <TouchableOpacity
214
- style={[styles.actionButton, { borderColor }]}
274
+ style={[styles.actionButton, { borderColor: colors.border }]}
215
275
  onPress={() => navigate('SignIn')}
216
276
  >
217
- <Text style={[styles.actionButtonText, { color: textColor }]}>
277
+ <Text style={[styles.actionButtonText, { color: colors.text }]}>
218
278
  Add Another Account
219
279
  </Text>
220
280
  </TouchableOpacity>
@@ -226,9 +286,9 @@ const AccountSwitcherScreen: React.FC<BaseScreenProps> = ({
226
286
  disabled={isLoading}
227
287
  >
228
288
  {isLoading ? (
229
- <ActivityIndicator color={dangerColor} size="small" />
289
+ <ActivityIndicator color={colors.destructive} size="small" />
230
290
  ) : (
231
- <Text style={[styles.dangerButtonText, { color: dangerColor }]}>
291
+ <Text style={[styles.dangerButtonText, { color: colors.destructive }]}>
232
292
  Sign Out All Sessions
233
293
  </Text>
234
294
  )}