@oxyhq/services 5.7.5 → 5.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +76 -76
- package/lib/commonjs/core/index.js +177 -102
- package/lib/commonjs/core/index.js.map +1 -1
- package/lib/commonjs/index.js +88 -29
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/node/createAuth.js +585 -7
- package/lib/commonjs/node/createAuth.js.map +1 -1
- package/lib/commonjs/node/index.js +38 -1
- package/lib/commonjs/node/index.js.map +1 -1
- package/lib/commonjs/ui/components/Avatar.js +15 -6
- package/lib/commonjs/ui/components/Avatar.js.map +1 -1
- package/lib/commonjs/ui/components/GroupedItem.js +58 -13
- package/lib/commonjs/ui/components/GroupedItem.js.map +1 -1
- package/lib/commonjs/ui/components/GroupedSection.js +7 -1
- package/lib/commonjs/ui/components/GroupedSection.js.map +1 -1
- package/lib/commonjs/ui/components/Header.js +322 -0
- package/lib/commonjs/ui/components/Header.js.map +1 -0
- package/lib/commonjs/ui/components/OxyProvider.js +23 -7
- package/lib/commonjs/ui/components/OxyProvider.js.map +1 -1
- package/lib/commonjs/ui/components/index.js +7 -0
- package/lib/commonjs/ui/components/index.js.map +1 -1
- package/lib/commonjs/ui/components/internal/GroupedPillButtons.js +1 -1
- package/lib/commonjs/ui/components/internal/GroupedPillButtons.js.map +1 -1
- package/lib/commonjs/ui/components/internal/TextField.js +606 -546
- package/lib/commonjs/ui/components/internal/TextField.js.map +1 -1
- package/lib/commonjs/ui/components/internal/TextField.md +436 -0
- package/lib/commonjs/ui/context/OxyContext.js +122 -78
- package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
- package/lib/commonjs/ui/hooks/useSessionSocket.js +5 -2
- package/lib/commonjs/ui/hooks/useSessionSocket.js.map +1 -1
- package/lib/commonjs/ui/navigation/OxyRouter.js +1 -1
- package/lib/commonjs/ui/navigation/OxyRouter.js.map +1 -1
- package/lib/commonjs/ui/screens/AccountCenterScreen.js +6 -6
- package/lib/commonjs/ui/screens/AccountCenterScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/AccountManagementDemo.js +3 -3
- package/lib/commonjs/ui/screens/AccountManagementDemo.js.map +1 -1
- package/lib/commonjs/ui/screens/AccountOverviewScreen.js +241 -598
- package/lib/commonjs/ui/screens/AccountOverviewScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/AccountSettingsScreen.js +1151 -406
- package/lib/commonjs/ui/screens/AccountSettingsScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/AccountSwitcherScreen.js +135 -237
- package/lib/commonjs/ui/screens/AccountSwitcherScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/AppInfoScreen.js +246 -463
- package/lib/commonjs/ui/screens/AppInfoScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/FeedbackScreen.js +3 -3
- package/lib/commonjs/ui/screens/FeedbackScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/PaymentGatewayScreen.js +808 -650
- package/lib/commonjs/ui/screens/PaymentGatewayScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/RecoverAccountScreen.js +51 -72
- package/lib/commonjs/ui/screens/RecoverAccountScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/SessionManagementScreen.js +11 -29
- package/lib/commonjs/ui/screens/SessionManagementScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/SignInScreen.js +30 -303
- package/lib/commonjs/ui/screens/SignInScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/SignUpScreen.js +4 -4
- package/lib/commonjs/ui/screens/SignUpScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/internal/SignInPasswordStep.js +19 -31
- package/lib/commonjs/ui/screens/internal/SignInPasswordStep.js.map +1 -1
- package/lib/commonjs/ui/screens/internal/SignInUsernameStep.js +7 -10
- package/lib/commonjs/ui/screens/internal/SignInUsernameStep.js.map +1 -1
- package/lib/commonjs/ui/screens/internal/SignUpIdentityStep.js +11 -5
- package/lib/commonjs/ui/screens/internal/SignUpIdentityStep.js.map +1 -1
- package/lib/commonjs/ui/screens/internal/SignUpSecurityStep.js +11 -4
- package/lib/commonjs/ui/screens/internal/SignUpSecurityStep.js.map +1 -1
- package/lib/commonjs/ui/stores/authStore.js +12 -0
- package/lib/commonjs/ui/stores/authStore.js.map +1 -1
- package/lib/commonjs/ui/styles/authStyles.js +337 -0
- package/lib/commonjs/ui/styles/authStyles.js.map +1 -0
- package/lib/commonjs/ui/styles/index.js +11 -0
- package/lib/commonjs/ui/styles/index.js.map +1 -1
- package/lib/module/core/index.js +177 -41
- package/lib/module/core/index.js.map +1 -1
- package/lib/module/index.js +26 -4
- package/lib/module/index.js.map +1 -1
- package/lib/module/node/createAuth.js +584 -7
- package/lib/module/node/createAuth.js.map +1 -1
- package/lib/module/node/index.js +7 -1
- package/lib/module/node/index.js.map +1 -1
- package/lib/module/ui/components/Avatar.js +15 -6
- package/lib/module/ui/components/Avatar.js.map +1 -1
- package/lib/module/ui/components/GroupedItem.js +59 -14
- package/lib/module/ui/components/GroupedItem.js.map +1 -1
- package/lib/module/ui/components/GroupedSection.js +7 -1
- package/lib/module/ui/components/GroupedSection.js.map +1 -1
- package/lib/module/ui/components/Header.js +317 -0
- package/lib/module/ui/components/Header.js.map +1 -0
- package/lib/module/ui/components/OxyProvider.js +25 -9
- package/lib/module/ui/components/OxyProvider.js.map +1 -1
- package/lib/module/ui/components/index.js +1 -0
- package/lib/module/ui/components/index.js.map +1 -1
- package/lib/module/ui/components/internal/GroupedPillButtons.js +1 -1
- package/lib/module/ui/components/internal/GroupedPillButtons.js.map +1 -1
- package/lib/module/ui/components/internal/TextField.js +607 -547
- package/lib/module/ui/components/internal/TextField.js.map +1 -1
- package/lib/module/ui/components/internal/TextField.md +436 -0
- package/lib/module/ui/context/OxyContext.js +121 -77
- package/lib/module/ui/context/OxyContext.js.map +1 -1
- package/lib/module/ui/hooks/useSessionSocket.js +5 -2
- package/lib/module/ui/hooks/useSessionSocket.js.map +1 -1
- package/lib/module/ui/navigation/OxyRouter.js +1 -1
- package/lib/module/ui/navigation/OxyRouter.js.map +1 -1
- package/lib/module/ui/screens/AccountCenterScreen.js +6 -6
- package/lib/module/ui/screens/AccountCenterScreen.js.map +1 -1
- package/lib/module/ui/screens/AccountManagementDemo.js +3 -3
- package/lib/module/ui/screens/AccountManagementDemo.js.map +1 -1
- package/lib/module/ui/screens/AccountOverviewScreen.js +242 -597
- package/lib/module/ui/screens/AccountOverviewScreen.js.map +1 -1
- package/lib/module/ui/screens/AccountSettingsScreen.js +1152 -407
- package/lib/module/ui/screens/AccountSettingsScreen.js.map +1 -1
- package/lib/module/ui/screens/AccountSwitcherScreen.js +135 -237
- package/lib/module/ui/screens/AccountSwitcherScreen.js.map +1 -1
- package/lib/module/ui/screens/AppInfoScreen.js +248 -465
- package/lib/module/ui/screens/AppInfoScreen.js.map +1 -1
- package/lib/module/ui/screens/FeedbackScreen.js +3 -3
- package/lib/module/ui/screens/FeedbackScreen.js.map +1 -1
- package/lib/module/ui/screens/PaymentGatewayScreen.js +809 -651
- package/lib/module/ui/screens/PaymentGatewayScreen.js.map +1 -1
- package/lib/module/ui/screens/RecoverAccountScreen.js +53 -74
- package/lib/module/ui/screens/RecoverAccountScreen.js.map +1 -1
- package/lib/module/ui/screens/SessionManagementScreen.js +11 -29
- package/lib/module/ui/screens/SessionManagementScreen.js.map +1 -1
- package/lib/module/ui/screens/SignInScreen.js +32 -305
- package/lib/module/ui/screens/SignInScreen.js.map +1 -1
- package/lib/module/ui/screens/SignUpScreen.js +5 -5
- package/lib/module/ui/screens/SignUpScreen.js.map +1 -1
- package/lib/module/ui/screens/internal/SignInPasswordStep.js +19 -31
- package/lib/module/ui/screens/internal/SignInPasswordStep.js.map +1 -1
- package/lib/module/ui/screens/internal/SignInUsernameStep.js +7 -10
- package/lib/module/ui/screens/internal/SignInUsernameStep.js.map +1 -1
- package/lib/module/ui/screens/internal/SignUpIdentityStep.js +11 -5
- package/lib/module/ui/screens/internal/SignUpIdentityStep.js.map +1 -1
- package/lib/module/ui/screens/internal/SignUpSecurityStep.js +11 -4
- package/lib/module/ui/screens/internal/SignUpSecurityStep.js.map +1 -1
- package/lib/module/ui/stores/authStore.js +12 -0
- package/lib/module/ui/stores/authStore.js.map +1 -1
- package/lib/module/ui/styles/authStyles.js +332 -0
- package/lib/module/ui/styles/authStyles.js.map +1 -0
- package/lib/module/ui/styles/index.js +1 -0
- package/lib/module/ui/styles/index.js.map +1 -1
- package/lib/typescript/core/index.d.ts +68 -24
- package/lib/typescript/core/index.d.ts.map +1 -1
- package/lib/typescript/index.d.ts +13 -3
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/node/createAuth.d.ts +112 -0
- package/lib/typescript/node/createAuth.d.ts.map +1 -1
- package/lib/typescript/node/index.d.ts +2 -0
- package/lib/typescript/node/index.d.ts.map +1 -1
- package/lib/typescript/ui/components/Avatar.d.ts.map +1 -1
- package/lib/typescript/ui/components/GroupedItem.d.ts +6 -0
- package/lib/typescript/ui/components/GroupedItem.d.ts.map +1 -1
- package/lib/typescript/ui/components/GroupedSection.d.ts +6 -0
- package/lib/typescript/ui/components/GroupedSection.d.ts.map +1 -1
- package/lib/typescript/ui/components/Header.d.ts +22 -0
- package/lib/typescript/ui/components/Header.d.ts.map +1 -0
- package/lib/typescript/ui/components/OxyProvider.d.ts.map +1 -1
- package/lib/typescript/ui/components/index.d.ts +1 -0
- package/lib/typescript/ui/components/index.d.ts.map +1 -1
- package/lib/typescript/ui/components/internal/TextField.d.ts +31 -16
- package/lib/typescript/ui/components/internal/TextField.d.ts.map +1 -1
- package/lib/typescript/ui/context/OxyContext.d.ts +5 -2
- package/lib/typescript/ui/context/OxyContext.d.ts.map +1 -1
- package/lib/typescript/ui/hooks/useSessionSocket.d.ts.map +1 -1
- package/lib/typescript/ui/navigation/types.d.ts +9 -2
- package/lib/typescript/ui/navigation/types.d.ts.map +1 -1
- package/lib/typescript/ui/screens/AccountOverviewScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/AccountSettingsScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/AccountSwitcherScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/AppInfoScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/PaymentGatewayScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/RecoverAccountScreen.d.ts +5 -1
- package/lib/typescript/ui/screens/RecoverAccountScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/SessionManagementScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/SignInScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/internal/SignInPasswordStep.d.ts +1 -1
- package/lib/typescript/ui/screens/internal/SignInPasswordStep.d.ts.map +1 -1
- package/lib/typescript/ui/screens/internal/SignInUsernameStep.d.ts +0 -1
- package/lib/typescript/ui/screens/internal/SignInUsernameStep.d.ts.map +1 -1
- package/lib/typescript/ui/screens/internal/SignUpIdentityStep.d.ts.map +1 -1
- package/lib/typescript/ui/screens/internal/SignUpSecurityStep.d.ts.map +1 -1
- package/lib/typescript/ui/stores/authStore.d.ts.map +1 -1
- package/lib/typescript/ui/styles/authStyles.d.ts +326 -0
- package/lib/typescript/ui/styles/authStyles.d.ts.map +1 -0
- package/lib/typescript/ui/styles/index.d.ts +1 -0
- package/lib/typescript/ui/styles/index.d.ts.map +1 -1
- package/package.json +1 -4
- package/src/core/index.ts +195 -41
- package/src/index.ts +72 -4
- package/src/node/createAuth.ts +623 -7
- package/src/node/index.ts +19 -1
- package/src/ui/components/Avatar.tsx +11 -5
- package/src/ui/components/GroupedItem.tsx +57 -9
- package/src/ui/components/GroupedSection.tsx +12 -0
- package/src/ui/components/Header.tsx +364 -0
- package/src/ui/components/OxyProvider.tsx +31 -15
- package/src/ui/components/index.ts +1 -0
- package/src/ui/components/internal/GroupedPillButtons.tsx +1 -1
- package/src/ui/components/internal/TextField.md +436 -0
- package/src/ui/components/internal/TextField.tsx +720 -620
- package/src/ui/context/OxyContext.tsx +150 -63
- package/src/ui/hooks/useSessionSocket.ts +5 -2
- package/src/ui/navigation/OxyRouter.tsx +1 -1
- package/src/ui/navigation/types.ts +10 -2
- package/src/ui/screens/AccountCenterScreen.tsx +5 -5
- package/src/ui/screens/AccountManagementDemo.tsx +9 -9
- package/src/ui/screens/AccountOverviewScreen.tsx +265 -414
- package/src/ui/screens/AccountSettingsScreen.tsx +1165 -403
- package/src/ui/screens/AccountSwitcherScreen.tsx +158 -202
- package/src/ui/screens/AppInfoScreen.tsx +270 -497
- package/src/ui/screens/FeedbackScreen.tsx +3 -3
- package/src/ui/screens/PaymentGatewayScreen.tsx +668 -365
- package/src/ui/screens/ProfileScreen.tsx +5 -5
- package/src/ui/screens/RecoverAccountScreen.tsx +46 -74
- package/src/ui/screens/SessionManagementScreen.tsx +14 -22
- package/src/ui/screens/SignInScreen.tsx +27 -294
- package/src/ui/screens/SignUpScreen.tsx +5 -5
- package/src/ui/screens/internal/SignInPasswordStep.tsx +11 -22
- package/src/ui/screens/internal/SignInUsernameStep.tsx +3 -10
- package/src/ui/screens/internal/SignUpIdentityStep.tsx +2 -5
- package/src/ui/screens/internal/SignUpSecurityStep.tsx +3 -4
- package/src/ui/stores/authStore.ts +12 -0
- package/src/ui/styles/authStyles.ts +352 -0
- package/src/ui/styles/index.ts +1 -0
- package/lib/commonjs/core/auth-manager.js +0 -440
- package/lib/commonjs/core/auth-manager.js.map +0 -1
- package/lib/commonjs/core/use-auth.js +0 -244
- package/lib/commonjs/core/use-auth.js.map +0 -1
- package/lib/module/core/auth-manager.js +0 -432
- package/lib/module/core/auth-manager.js.map +0 -1
- package/lib/module/core/use-auth.js +0 -235
- package/lib/module/core/use-auth.js.map +0 -1
- package/lib/typescript/core/auth-manager.d.ts +0 -136
- package/lib/typescript/core/auth-manager.d.ts.map +0 -1
- package/lib/typescript/core/use-auth.d.ts +0 -79
- package/lib/typescript/core/use-auth.d.ts.map +0 -1
- package/src/__tests__/middleware.test.ts +0 -105
- package/src/__tests__/setup.ts +0 -10
- package/src/__tests__/zero-config-auth.test.ts +0 -607
- package/src/core/auth-manager.ts +0 -500
- package/src/core/use-auth.tsx +0 -245
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import React, { createContext, useContext, useEffect, useCallback, ReactNode, useMemo } from 'react';
|
|
1
|
+
import React, { createContext, useContext, useEffect, useCallback, ReactNode, useMemo, useRef, useState } from 'react';
|
|
2
2
|
import { OxyServices } from '../../core';
|
|
3
|
-
import { User } from '../../models/interfaces';
|
|
3
|
+
import { User, ApiError } from '../../models/interfaces';
|
|
4
4
|
import { SecureLoginResponse, SecureClientSession, MinimalUserData } from '../../models/secureSession';
|
|
5
5
|
import { DeviceManager } from '../../utils/deviceManager';
|
|
6
6
|
import { useSessionSocket } from '../hooks/useSessionSocket';
|
|
@@ -49,9 +49,11 @@ const OxyContext = createContext<OxyContextState | null>(null);
|
|
|
49
49
|
// Props for the OxyContextProvider
|
|
50
50
|
export interface OxyContextProviderProps {
|
|
51
51
|
children: ReactNode;
|
|
52
|
-
oxyServices
|
|
52
|
+
oxyServices?: OxyServices; // Now optional - will be created automatically if not provided
|
|
53
|
+
baseURL?: string; // New: API base URL for automatic service creation
|
|
53
54
|
storageKeyPrefix?: string;
|
|
54
55
|
onAuthStateChange?: (user: User | null) => void;
|
|
56
|
+
onError?: (error: ApiError) => void; // New: Error callback
|
|
55
57
|
bottomSheetRef?: React.RefObject<any>;
|
|
56
58
|
}
|
|
57
59
|
|
|
@@ -114,13 +116,30 @@ const getSecureStorageKeys = (prefix = 'oxy_secure') => ({
|
|
|
114
116
|
activeSessionId: `${prefix}_active_session_id`, // ID of currently active session
|
|
115
117
|
});
|
|
116
118
|
|
|
117
|
-
export const
|
|
119
|
+
export const OxyProvider: React.FC<OxyContextProviderProps> = ({
|
|
118
120
|
children,
|
|
119
|
-
oxyServices,
|
|
121
|
+
oxyServices: providedOxyServices,
|
|
122
|
+
baseURL,
|
|
120
123
|
storageKeyPrefix = 'oxy_secure',
|
|
121
124
|
onAuthStateChange,
|
|
125
|
+
onError,
|
|
122
126
|
bottomSheetRef,
|
|
123
127
|
}) => {
|
|
128
|
+
// Create oxyServices automatically if not provided
|
|
129
|
+
const oxyServicesRef = useRef<OxyServices | null>(null);
|
|
130
|
+
|
|
131
|
+
if (!oxyServicesRef.current) {
|
|
132
|
+
if (providedOxyServices) {
|
|
133
|
+
oxyServicesRef.current = providedOxyServices;
|
|
134
|
+
} else if (baseURL) {
|
|
135
|
+
oxyServicesRef.current = new OxyServices({ baseURL });
|
|
136
|
+
} else {
|
|
137
|
+
throw new Error('Either oxyServices or baseURL must be provided to OxyContextProvider');
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const oxyServices = oxyServicesRef.current;
|
|
142
|
+
|
|
124
143
|
// Zustand state
|
|
125
144
|
const user = useAuthStore((state) => state.user);
|
|
126
145
|
const isAuthenticated = useAuthStore((state) => state.isAuthenticated);
|
|
@@ -259,25 +278,7 @@ export const OxyContextProvider: React.FC<OxyContextProviderProps> = ({
|
|
|
259
278
|
}
|
|
260
279
|
}, [storage, oxyServices, keys, onAuthStateChange]);
|
|
261
280
|
|
|
262
|
-
|
|
263
|
-
useEffect(() => {
|
|
264
|
-
const restoreToken = async () => {
|
|
265
|
-
if (activeSessionId && oxyServices) {
|
|
266
|
-
try {
|
|
267
|
-
await oxyServices.getTokenBySession(activeSessionId);
|
|
268
|
-
setTokenReady(true);
|
|
269
|
-
} catch (err) {
|
|
270
|
-
// If token restoration fails, force logout
|
|
271
|
-
await logout();
|
|
272
|
-
setTokenReady(false);
|
|
273
|
-
}
|
|
274
|
-
} else {
|
|
275
|
-
setTokenReady(true); // No session, so token is not needed
|
|
276
|
-
}
|
|
277
|
-
};
|
|
278
|
-
restoreToken();
|
|
279
|
-
// Only run when activeSessionId or oxyServices changes
|
|
280
|
-
}, [activeSessionId, oxyServices]);
|
|
281
|
+
|
|
281
282
|
|
|
282
283
|
// Remove invalid session
|
|
283
284
|
const removeInvalidSession = useCallback(async (sessionId: string): Promise<void> => {
|
|
@@ -357,7 +358,7 @@ export const OxyContextProvider: React.FC<OxyContextProviderProps> = ({
|
|
|
357
358
|
}, [oxyServices, onAuthStateChange, loginSuccess, saveActiveSessionId]);
|
|
358
359
|
|
|
359
360
|
// Secure login method
|
|
360
|
-
const login = async (username: string, password: string, deviceName?: string): Promise<User> => {
|
|
361
|
+
const login = useCallback(async (username: string, password: string, deviceName?: string): Promise<User> => {
|
|
361
362
|
if (!storage) throw new Error('Storage not initialized');
|
|
362
363
|
useAuthStore.setState({ isLoading: true, error: null });
|
|
363
364
|
|
|
@@ -439,10 +440,10 @@ export const OxyContextProvider: React.FC<OxyContextProviderProps> = ({
|
|
|
439
440
|
} finally {
|
|
440
441
|
useAuthStore.setState({ isLoading: false });
|
|
441
442
|
}
|
|
442
|
-
};
|
|
443
|
+
}, [storage, oxyServices, sessions, activeSessionId, saveSessionsToStorage, saveActiveSessionId, loginSuccess, setMinimalUser, onAuthStateChange, loginFailure]);
|
|
443
444
|
|
|
444
445
|
// Logout method
|
|
445
|
-
const logout = async (targetSessionId?: string): Promise<void> => {
|
|
446
|
+
const logout = useCallback(async (targetSessionId?: string): Promise<void> => {
|
|
446
447
|
if (!activeSessionId) return;
|
|
447
448
|
|
|
448
449
|
try {
|
|
@@ -475,10 +476,10 @@ export const OxyContextProvider: React.FC<OxyContextProviderProps> = ({
|
|
|
475
476
|
console.error('Logout error:', error);
|
|
476
477
|
useAuthStore.setState({ error: 'Logout failed' });
|
|
477
478
|
}
|
|
478
|
-
};
|
|
479
|
+
}, [activeSessionId, oxyServices, sessions, saveSessionsToStorage, switchToSession, logoutStore, setMinimalUser, storage, keys.activeSessionId, onAuthStateChange]);
|
|
479
480
|
|
|
480
481
|
// Logout all sessions
|
|
481
|
-
const logoutAll = async (): Promise<void> => {
|
|
482
|
+
const logoutAll = useCallback(async (): Promise<void> => {
|
|
482
483
|
console.log('logoutAll called with activeSessionId:', activeSessionId);
|
|
483
484
|
|
|
484
485
|
if (!activeSessionId) {
|
|
@@ -515,10 +516,30 @@ export const OxyContextProvider: React.FC<OxyContextProviderProps> = ({
|
|
|
515
516
|
useAuthStore.setState({ error: `Logout all failed: ${error instanceof Error ? error.message : 'Unknown error'}` });
|
|
516
517
|
throw error;
|
|
517
518
|
}
|
|
518
|
-
};
|
|
519
|
+
}, [activeSessionId, oxyServices, logoutStore, setMinimalUser, clearAllStorage, onAuthStateChange]);
|
|
520
|
+
|
|
521
|
+
// Effect to restore token on app load or session switch
|
|
522
|
+
useEffect(() => {
|
|
523
|
+
const restoreToken = async () => {
|
|
524
|
+
if (activeSessionId && oxyServices) {
|
|
525
|
+
try {
|
|
526
|
+
await oxyServices.getTokenBySession(activeSessionId);
|
|
527
|
+
setTokenReady(true);
|
|
528
|
+
} catch (err) {
|
|
529
|
+
// If token restoration fails, force logout
|
|
530
|
+
await logout();
|
|
531
|
+
setTokenReady(false);
|
|
532
|
+
}
|
|
533
|
+
} else {
|
|
534
|
+
setTokenReady(true); // No session, so token is not needed
|
|
535
|
+
}
|
|
536
|
+
};
|
|
537
|
+
restoreToken();
|
|
538
|
+
// Only run when activeSessionId or oxyServices changes
|
|
539
|
+
}, [activeSessionId, oxyServices, logout]);
|
|
519
540
|
|
|
520
541
|
// Sign up method
|
|
521
|
-
const signUp = async (username: string, email: string, password: string): Promise<User> => {
|
|
542
|
+
const signUp = useCallback(async (username: string, email: string, password: string): Promise<User> => {
|
|
522
543
|
if (!storage) throw new Error('Storage not initialized');
|
|
523
544
|
|
|
524
545
|
useAuthStore.setState({ isLoading: true, error: null });
|
|
@@ -540,42 +561,83 @@ export const OxyContextProvider: React.FC<OxyContextProviderProps> = ({
|
|
|
540
561
|
} finally {
|
|
541
562
|
useAuthStore.setState({ isLoading: false });
|
|
542
563
|
}
|
|
543
|
-
};
|
|
564
|
+
}, [storage, oxyServices, login, loginFailure]);
|
|
544
565
|
|
|
545
566
|
// Switch session method
|
|
546
|
-
const switchSession = async (sessionId: string): Promise<void> => {
|
|
567
|
+
const switchSession = useCallback(async (sessionId: string): Promise<void> => {
|
|
547
568
|
await switchToSession(sessionId);
|
|
548
|
-
};
|
|
569
|
+
}, [switchToSession]);
|
|
549
570
|
|
|
550
571
|
// Remove session method
|
|
551
|
-
const removeSession = async (sessionId: string): Promise<void> => {
|
|
572
|
+
const removeSession = useCallback(async (sessionId: string): Promise<void> => {
|
|
552
573
|
await logout(sessionId);
|
|
553
|
-
};
|
|
574
|
+
}, [logout]);
|
|
554
575
|
|
|
555
576
|
// Refresh sessions method
|
|
556
|
-
const refreshSessions = async (): Promise<void> => {
|
|
557
|
-
|
|
577
|
+
const refreshSessions = useCallback(async (): Promise<void> => {
|
|
578
|
+
console.log('refreshSessions called with activeSessionId:', activeSessionId);
|
|
579
|
+
|
|
580
|
+
if (!activeSessionId) {
|
|
581
|
+
console.log('refreshSessions: No activeSessionId, returning');
|
|
582
|
+
return;
|
|
583
|
+
}
|
|
558
584
|
|
|
559
585
|
try {
|
|
586
|
+
console.log('refreshSessions: Calling getSessionsBySessionId...');
|
|
560
587
|
const serverSessions = await oxyServices.getSessionsBySessionId(activeSessionId);
|
|
588
|
+
console.log('refreshSessions: Server sessions received:', serverSessions);
|
|
561
589
|
|
|
562
590
|
// Update local sessions with server data
|
|
563
591
|
const updatedSessions: SecureClientSession[] = serverSessions.map(serverSession => ({
|
|
564
592
|
sessionId: serverSession.sessionId,
|
|
565
593
|
deviceId: serverSession.deviceId,
|
|
566
|
-
expiresAt: new Date().toISOString(),
|
|
567
|
-
lastActive: new Date().toISOString()
|
|
594
|
+
expiresAt: serverSession.expiresAt || new Date().toISOString(),
|
|
595
|
+
lastActive: serverSession.lastActive || new Date().toISOString(),
|
|
596
|
+
userId: serverSession.userId || user?.id
|
|
568
597
|
}));
|
|
569
598
|
|
|
599
|
+
console.log('refreshSessions: Updated sessions:', updatedSessions);
|
|
570
600
|
setSessions(updatedSessions);
|
|
571
601
|
await saveSessionsToStorage(updatedSessions);
|
|
602
|
+
console.log('refreshSessions: Sessions saved to storage');
|
|
572
603
|
} catch (error) {
|
|
573
604
|
console.error('Refresh sessions error:', error);
|
|
605
|
+
|
|
606
|
+
// If the current session is invalid, try to find another valid session
|
|
607
|
+
if (sessions.length > 1) {
|
|
608
|
+
console.log('Current session invalid, trying to switch to another session...');
|
|
609
|
+
const otherSessions = sessions.filter(s => s.sessionId !== activeSessionId);
|
|
610
|
+
|
|
611
|
+
for (const session of otherSessions) {
|
|
612
|
+
try {
|
|
613
|
+
// Try to validate this session
|
|
614
|
+
await oxyServices.validateSession(session.sessionId);
|
|
615
|
+
console.log('Found valid session, switching to:', session.sessionId);
|
|
616
|
+
await switchToSession(session.sessionId);
|
|
617
|
+
return; // Successfully switched to another session
|
|
618
|
+
} catch (sessionError) {
|
|
619
|
+
console.log('Session validation failed for:', session.sessionId, sessionError);
|
|
620
|
+
continue; // Try next session
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
// If no valid sessions found, clear all sessions
|
|
626
|
+
console.log('No valid sessions found, clearing all sessions');
|
|
627
|
+
setSessions([]);
|
|
628
|
+
setActiveSessionId(null);
|
|
629
|
+
logoutStore();
|
|
630
|
+
setMinimalUser(null);
|
|
631
|
+
await clearAllStorage();
|
|
632
|
+
|
|
633
|
+
if (onAuthStateChange) {
|
|
634
|
+
onAuthStateChange(null);
|
|
635
|
+
}
|
|
574
636
|
}
|
|
575
|
-
};
|
|
637
|
+
}, [activeSessionId, oxyServices, user?.id, sessions, saveSessionsToStorage, switchToSession, logoutStore, setMinimalUser, clearAllStorage, onAuthStateChange]);
|
|
576
638
|
|
|
577
639
|
// Device management methods
|
|
578
|
-
const getDeviceSessions = async (): Promise<any[]> => {
|
|
640
|
+
const getDeviceSessions = useCallback(async (): Promise<any[]> => {
|
|
579
641
|
if (!activeSessionId) throw new Error('No active session');
|
|
580
642
|
|
|
581
643
|
try {
|
|
@@ -584,9 +646,9 @@ export const OxyContextProvider: React.FC<OxyContextProviderProps> = ({
|
|
|
584
646
|
console.error('Get device sessions error:', error);
|
|
585
647
|
throw error;
|
|
586
648
|
}
|
|
587
|
-
};
|
|
649
|
+
}, [activeSessionId, oxyServices]);
|
|
588
650
|
|
|
589
|
-
const logoutAllDeviceSessions = async (): Promise<void> => {
|
|
651
|
+
const logoutAllDeviceSessions = useCallback(async (): Promise<void> => {
|
|
590
652
|
if (!activeSessionId) throw new Error('No active session');
|
|
591
653
|
|
|
592
654
|
try {
|
|
@@ -606,9 +668,9 @@ export const OxyContextProvider: React.FC<OxyContextProviderProps> = ({
|
|
|
606
668
|
console.error('Logout all device sessions error:', error);
|
|
607
669
|
throw error;
|
|
608
670
|
}
|
|
609
|
-
};
|
|
671
|
+
}, [activeSessionId, oxyServices, logoutStore, setMinimalUser, clearAllStorage, onAuthStateChange]);
|
|
610
672
|
|
|
611
|
-
const updateDeviceName = async (deviceName: string): Promise<void> => {
|
|
673
|
+
const updateDeviceName = useCallback(async (deviceName: string): Promise<void> => {
|
|
612
674
|
if (!activeSessionId) throw new Error('No active session');
|
|
613
675
|
|
|
614
676
|
try {
|
|
@@ -620,7 +682,7 @@ export const OxyContextProvider: React.FC<OxyContextProviderProps> = ({
|
|
|
620
682
|
console.error('Update device name error:', error);
|
|
621
683
|
throw error;
|
|
622
684
|
}
|
|
623
|
-
};
|
|
685
|
+
}, [activeSessionId, oxyServices]);
|
|
624
686
|
|
|
625
687
|
// Bottom sheet control methods
|
|
626
688
|
const showBottomSheet = useCallback((screenOrConfig?: string | { screen: string; props?: Record<string, any> }) => {
|
|
@@ -638,6 +700,7 @@ export const OxyContextProvider: React.FC<OxyContextProviderProps> = ({
|
|
|
638
700
|
bottomSheetRef.current.present();
|
|
639
701
|
} else {
|
|
640
702
|
console.warn('No expand or present method available on bottomSheetRef');
|
|
703
|
+
console.log('Available methods on bottomSheetRef.current:', Object.keys(bottomSheetRef.current));
|
|
641
704
|
}
|
|
642
705
|
|
|
643
706
|
// Then navigate to the specified screen if provided
|
|
@@ -657,6 +720,8 @@ export const OxyContextProvider: React.FC<OxyContextProviderProps> = ({
|
|
|
657
720
|
}
|
|
658
721
|
} else {
|
|
659
722
|
console.warn('bottomSheetRef is not available');
|
|
723
|
+
console.warn('To fix this, ensure you pass a bottomSheetRef to OxyProvider:');
|
|
724
|
+
console.warn('<OxyProvider baseURL="..." bottomSheetRef={yourBottomSheetRef}>');
|
|
660
725
|
}
|
|
661
726
|
}, [bottomSheetRef]);
|
|
662
727
|
|
|
@@ -672,16 +737,38 @@ export const OxyContextProvider: React.FC<OxyContextProviderProps> = ({
|
|
|
672
737
|
userId: user?.id,
|
|
673
738
|
activeSessionId,
|
|
674
739
|
refreshSessions,
|
|
675
|
-
logout
|
|
740
|
+
logout,
|
|
676
741
|
baseURL: oxyServices.getBaseURL(),
|
|
677
|
-
onRemoteSignOut: () => {
|
|
742
|
+
onRemoteSignOut: useCallback(() => {
|
|
678
743
|
toast.info('You have been signed out remotely.');
|
|
679
744
|
logout();
|
|
680
|
-
},
|
|
745
|
+
}, [logout]),
|
|
681
746
|
});
|
|
682
747
|
|
|
683
748
|
// Context value
|
|
684
|
-
const contextValue: OxyContextState = {
|
|
749
|
+
const contextValue: OxyContextState = useMemo(() => ({
|
|
750
|
+
user,
|
|
751
|
+
minimalUser,
|
|
752
|
+
sessions,
|
|
753
|
+
activeSessionId,
|
|
754
|
+
isAuthenticated,
|
|
755
|
+
isLoading,
|
|
756
|
+
error,
|
|
757
|
+
login,
|
|
758
|
+
logout,
|
|
759
|
+
logoutAll,
|
|
760
|
+
signUp,
|
|
761
|
+
switchSession,
|
|
762
|
+
removeSession,
|
|
763
|
+
refreshSessions,
|
|
764
|
+
getDeviceSessions,
|
|
765
|
+
logoutAllDeviceSessions,
|
|
766
|
+
updateDeviceName,
|
|
767
|
+
oxyServices,
|
|
768
|
+
bottomSheetRef,
|
|
769
|
+
showBottomSheet,
|
|
770
|
+
hideBottomSheet,
|
|
771
|
+
}), [
|
|
685
772
|
user,
|
|
686
773
|
minimalUser,
|
|
687
774
|
sessions,
|
|
@@ -691,22 +778,19 @@ export const OxyContextProvider: React.FC<OxyContextProviderProps> = ({
|
|
|
691
778
|
error,
|
|
692
779
|
login,
|
|
693
780
|
logout,
|
|
694
|
-
logoutAll
|
|
695
|
-
signUp
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
getDeviceSessions: async () => { return await getDeviceSessions(); },
|
|
703
|
-
logoutAllDeviceSessions: async () => { await logoutAllDeviceSessions(); },
|
|
704
|
-
updateDeviceName: async (deviceName) => { await updateDeviceName(deviceName); },
|
|
781
|
+
logoutAll,
|
|
782
|
+
signUp,
|
|
783
|
+
switchSession,
|
|
784
|
+
removeSession,
|
|
785
|
+
refreshSessions,
|
|
786
|
+
getDeviceSessions,
|
|
787
|
+
logoutAllDeviceSessions,
|
|
788
|
+
updateDeviceName,
|
|
705
789
|
oxyServices,
|
|
706
790
|
bottomSheetRef,
|
|
707
791
|
showBottomSheet,
|
|
708
792
|
hideBottomSheet,
|
|
709
|
-
|
|
793
|
+
]);
|
|
710
794
|
|
|
711
795
|
// Wrap children rendering to block until token is ready
|
|
712
796
|
if (!tokenReady) {
|
|
@@ -720,6 +804,9 @@ export const OxyContextProvider: React.FC<OxyContextProviderProps> = ({
|
|
|
720
804
|
);
|
|
721
805
|
};
|
|
722
806
|
|
|
807
|
+
// Alias for backward compatibility
|
|
808
|
+
export const OxyContextProvider = OxyProvider;
|
|
809
|
+
|
|
723
810
|
// Hook to use the context
|
|
724
811
|
export const useOxy = (): OxyContextState => {
|
|
725
812
|
const context = useContext(OxyContext);
|
|
@@ -33,12 +33,15 @@ export function useSessionSocket({ userId, activeSessionId, refreshSessions, log
|
|
|
33
33
|
|
|
34
34
|
socket.on('session_update', (data: { type: string; sessionId: string }) => {
|
|
35
35
|
console.log('Received session_update:', data);
|
|
36
|
+
|
|
37
|
+
// Always refresh sessions to get the latest state
|
|
38
|
+
refreshSessions();
|
|
39
|
+
|
|
40
|
+
// If the current session was logged out, handle it specially
|
|
36
41
|
if (data.sessionId === activeSessionId) {
|
|
37
42
|
if (onRemoteSignOut) onRemoteSignOut();
|
|
38
43
|
else toast.info('You have been signed out remotely.');
|
|
39
44
|
logout();
|
|
40
|
-
} else {
|
|
41
|
-
refreshSessions();
|
|
42
45
|
}
|
|
43
46
|
});
|
|
44
47
|
|
|
@@ -13,6 +13,9 @@ export interface BaseScreenProps {
|
|
|
13
13
|
onAuthenticated?: (user: User) => void;
|
|
14
14
|
theme: 'light' | 'dark';
|
|
15
15
|
containerWidth?: number;
|
|
16
|
+
initialStep?: number;
|
|
17
|
+
username?: string;
|
|
18
|
+
userProfile?: any;
|
|
16
19
|
}
|
|
17
20
|
|
|
18
21
|
/**
|
|
@@ -42,9 +45,14 @@ export interface OxyRouterProps {
|
|
|
42
45
|
*/
|
|
43
46
|
export interface OxyProviderProps {
|
|
44
47
|
/**
|
|
45
|
-
* Instance of OxyServices
|
|
48
|
+
* Instance of OxyServices (optional if baseURL is provided)
|
|
46
49
|
*/
|
|
47
|
-
oxyServices
|
|
50
|
+
oxyServices?: OxyServices;
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* API base URL for automatic service creation (optional if oxyServices is provided)
|
|
54
|
+
*/
|
|
55
|
+
baseURL?: string;
|
|
48
56
|
|
|
49
57
|
/**
|
|
50
58
|
* Initial screen to display
|
|
@@ -81,7 +81,7 @@ const AccountCenterScreen: React.FC<BaseScreenProps> = ({
|
|
|
81
81
|
<ProfileCard
|
|
82
82
|
user={user}
|
|
83
83
|
theme={theme}
|
|
84
|
-
onEditPress={() => navigate('
|
|
84
|
+
onEditPress={() => navigate('EditProfile', { activeTab: 'profile' })}
|
|
85
85
|
onClosePress={onClose}
|
|
86
86
|
showCloseButton={!!onClose}
|
|
87
87
|
/>
|
|
@@ -93,7 +93,7 @@ const AccountCenterScreen: React.FC<BaseScreenProps> = ({
|
|
|
93
93
|
<QuickActions
|
|
94
94
|
actions={[
|
|
95
95
|
{ id: 'overview', icon: 'person-circle', iconColor: '#007AFF', title: 'Overview', onPress: () => navigate('AccountOverview') },
|
|
96
|
-
{ id: 'settings', icon: 'settings', iconColor: '#5856D6', title: '
|
|
96
|
+
{ id: 'settings', icon: 'settings', iconColor: '#5856D6', title: 'Edit Profile', onPress: () => navigate('EditProfile') },
|
|
97
97
|
{ id: 'sessions', icon: 'shield-checkmark', iconColor: '#30D158', title: 'Sessions', onPress: () => navigate('SessionManagement') },
|
|
98
98
|
{ id: 'premium', icon: 'star', iconColor: '#FFD700', title: 'Premium', onPress: () => navigate('PremiumSubscription') },
|
|
99
99
|
...(user?.isPremium ? [{ id: 'billing', icon: 'card', iconColor: '#34C759', title: 'Billing', onPress: () => navigate('') }] : []),
|
|
@@ -119,9 +119,9 @@ const AccountCenterScreen: React.FC<BaseScreenProps> = ({
|
|
|
119
119
|
id: 'settings',
|
|
120
120
|
icon: 'settings',
|
|
121
121
|
iconColor: '#5856D6',
|
|
122
|
-
title: '
|
|
123
|
-
subtitle: 'Manage your preferences',
|
|
124
|
-
onPress: () => navigate('
|
|
122
|
+
title: 'Edit Profile',
|
|
123
|
+
subtitle: 'Manage your profile and preferences',
|
|
124
|
+
onPress: () => navigate('EditProfile'),
|
|
125
125
|
},
|
|
126
126
|
{
|
|
127
127
|
id: 'sessions',
|
|
@@ -30,7 +30,7 @@ const AccountManagementDemo: React.FC = () => {
|
|
|
30
30
|
'Multi-account switching',
|
|
31
31
|
'Session management access'
|
|
32
32
|
]}
|
|
33
|
-
navigatesTo={['AccountOverview', 'AccountSwitcher', '
|
|
33
|
+
navigatesTo={['AccountOverview', 'AccountSwitcher', 'EditProfile', 'SessionManagement']}
|
|
34
34
|
/>
|
|
35
35
|
|
|
36
36
|
<ScreenCard
|
|
@@ -42,11 +42,11 @@ const AccountManagementDemo: React.FC = () => {
|
|
|
42
42
|
'Subscription management',
|
|
43
43
|
'Privacy and security overview'
|
|
44
44
|
]}
|
|
45
|
-
navigatesTo={['
|
|
45
|
+
navigatesTo={['EditProfile', 'SessionManagement']}
|
|
46
46
|
/>
|
|
47
47
|
|
|
48
48
|
<ScreenCard
|
|
49
|
-
title="
|
|
49
|
+
title="EditProfileScreen"
|
|
50
50
|
description="Complete account configuration and preferences"
|
|
51
51
|
features={[
|
|
52
52
|
'Profile editing (username, email, name)',
|
|
@@ -90,22 +90,22 @@ const AccountManagementDemo: React.FC = () => {
|
|
|
90
90
|
<Text style={styles.flowDescription}>
|
|
91
91
|
The screens are designed with intuitive navigation patterns:
|
|
92
92
|
</Text>
|
|
93
|
-
|
|
93
|
+
|
|
94
94
|
<View style={styles.flowItem}>
|
|
95
95
|
<Text style={styles.flowStep}>1. Entry Point</Text>
|
|
96
96
|
<Text style={styles.flowText}>Users typically start at AccountCenterScreen</Text>
|
|
97
97
|
</View>
|
|
98
|
-
|
|
98
|
+
|
|
99
99
|
<View style={styles.flowItem}>
|
|
100
100
|
<Text style={styles.flowStep}>2. Explore</Text>
|
|
101
101
|
<Text style={styles.flowText}>Navigate to specific screens based on needs</Text>
|
|
102
102
|
</View>
|
|
103
|
-
|
|
103
|
+
|
|
104
104
|
<View style={styles.flowItem}>
|
|
105
105
|
<Text style={styles.flowStep}>3. Manage</Text>
|
|
106
106
|
<Text style={styles.flowText}>Perform account actions in specialized screens</Text>
|
|
107
107
|
</View>
|
|
108
|
-
|
|
108
|
+
|
|
109
109
|
<View style={styles.flowItem}>
|
|
110
110
|
<Text style={styles.flowStep}>4. Return</Text>
|
|
111
111
|
<Text style={styles.flowText}>Navigate back or to related screens seamlessly</Text>
|
|
@@ -142,12 +142,12 @@ const ScreenCard: React.FC<{
|
|
|
142
142
|
<View style={styles.screenCard}>
|
|
143
143
|
<Text style={styles.screenTitle}>{title}</Text>
|
|
144
144
|
<Text style={styles.screenDescription}>{description}</Text>
|
|
145
|
-
|
|
145
|
+
|
|
146
146
|
<Text style={styles.featuresTitle}>Features:</Text>
|
|
147
147
|
{features.map((feature, index) => (
|
|
148
148
|
<Text key={index} style={styles.feature}>• {feature}</Text>
|
|
149
149
|
))}
|
|
150
|
-
|
|
150
|
+
|
|
151
151
|
<Text style={styles.navigationTitle}>Navigates to:</Text>
|
|
152
152
|
{navigatesTo.map((nav, index) => (
|
|
153
153
|
<Text key={index} style={styles.navigationItem}>→ {nav}</Text>
|