@oxyhq/services 5.13.1 → 5.13.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.
- package/README.md +71 -0
- package/lib/commonjs/core/HttpClient.js +238 -0
- package/lib/commonjs/core/HttpClient.js.map +1 -0
- package/lib/commonjs/core/OxyServices.js +538 -332
- package/lib/commonjs/core/OxyServices.js.map +1 -1
- package/lib/commonjs/core/RequestManager.js +199 -0
- package/lib/commonjs/core/RequestManager.js.map +1 -0
- package/lib/commonjs/core/index.js +38 -1
- package/lib/commonjs/core/index.js.map +1 -1
- package/lib/commonjs/index.js +36 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/ui/components/Avatar.js +94 -27
- package/lib/commonjs/ui/components/Avatar.js.map +1 -1
- package/lib/commonjs/ui/components/FollowButton.js +1 -0
- package/lib/commonjs/ui/components/FollowButton.js.map +1 -1
- package/lib/commonjs/ui/components/internal/TextField.js +13 -8
- package/lib/commonjs/ui/components/internal/TextField.js.map +1 -1
- package/lib/commonjs/ui/context/OxyContext.js +183 -224
- package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
- package/lib/commonjs/ui/hooks/useSessionSocket.js +80 -22
- package/lib/commonjs/ui/hooks/useSessionSocket.js.map +1 -1
- package/lib/commonjs/ui/index.js +4 -1
- package/lib/commonjs/ui/index.js.map +1 -1
- package/lib/commonjs/ui/screens/AccountSettingsScreen.js +32 -2
- package/lib/commonjs/ui/screens/AccountSettingsScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/AccountSwitcherScreen.js +101 -59
- package/lib/commonjs/ui/screens/AccountSwitcherScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/FileManagementScreen.js +3 -2
- package/lib/commonjs/ui/screens/FileManagementScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/LanguageSelectorScreen.js +75 -117
- package/lib/commonjs/ui/screens/LanguageSelectorScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/SignInScreen.js +0 -11
- package/lib/commonjs/ui/screens/SignInScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/SignUpScreen.js +14 -16
- package/lib/commonjs/ui/screens/SignUpScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/WelcomeNewUserScreen.js +50 -18
- package/lib/commonjs/ui/screens/WelcomeNewUserScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/internal/SignInPasswordStep.js +10 -10
- package/lib/commonjs/ui/screens/internal/SignInPasswordStep.js.map +1 -1
- package/lib/commonjs/ui/screens/steps/SignInPasswordStep.js +16 -26
- package/lib/commonjs/ui/screens/steps/SignInPasswordStep.js.map +1 -1
- package/lib/commonjs/ui/screens/steps/SignInUsernameStep.js +104 -212
- package/lib/commonjs/ui/screens/steps/SignInUsernameStep.js.map +1 -1
- package/lib/commonjs/ui/stores/accountStore.js +237 -0
- package/lib/commonjs/ui/stores/accountStore.js.map +1 -0
- package/lib/commonjs/ui/stores/authStore.js +2 -1
- package/lib/commonjs/ui/stores/authStore.js.map +1 -1
- package/lib/commonjs/ui/styles/authStyles.js +14 -7
- package/lib/commonjs/ui/styles/authStyles.js.map +1 -1
- package/lib/commonjs/utils/asyncUtils.js +9 -22
- package/lib/commonjs/utils/asyncUtils.js.map +1 -1
- package/lib/commonjs/utils/cache.js +259 -0
- package/lib/commonjs/utils/cache.js.map +1 -0
- package/lib/commonjs/utils/index.js +99 -0
- package/lib/commonjs/utils/index.js.map +1 -1
- package/lib/commonjs/utils/languageUtils.js +159 -0
- package/lib/commonjs/utils/languageUtils.js.map +1 -0
- package/lib/commonjs/utils/requestUtils.js +217 -0
- package/lib/commonjs/utils/requestUtils.js.map +1 -0
- package/lib/commonjs/utils/sessionUtils.js +191 -0
- package/lib/commonjs/utils/sessionUtils.js.map +1 -0
- package/lib/module/core/HttpClient.js +232 -0
- package/lib/module/core/HttpClient.js.map +1 -0
- package/lib/module/core/OxyServices.js +536 -326
- package/lib/module/core/OxyServices.js.map +1 -1
- package/lib/module/core/RequestManager.js +194 -0
- package/lib/module/core/RequestManager.js.map +1 -0
- package/lib/module/core/index.js +2 -0
- package/lib/module/core/index.js.map +1 -1
- package/lib/module/index.js +2 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/ui/components/Avatar.js +94 -27
- package/lib/module/ui/components/Avatar.js.map +1 -1
- package/lib/module/ui/components/FollowButton.js +1 -0
- package/lib/module/ui/components/FollowButton.js.map +1 -1
- package/lib/module/ui/components/internal/TextField.js +13 -8
- package/lib/module/ui/components/internal/TextField.js.map +1 -1
- package/lib/module/ui/context/OxyContext.js +182 -223
- package/lib/module/ui/context/OxyContext.js.map +1 -1
- package/lib/module/ui/hooks/useSessionSocket.js +80 -22
- package/lib/module/ui/hooks/useSessionSocket.js.map +1 -1
- package/lib/module/ui/index.js +4 -2
- package/lib/module/ui/index.js.map +1 -1
- package/lib/module/ui/screens/AccountSettingsScreen.js +33 -2
- package/lib/module/ui/screens/AccountSettingsScreen.js.map +1 -1
- package/lib/module/ui/screens/AccountSwitcherScreen.js +102 -60
- package/lib/module/ui/screens/AccountSwitcherScreen.js.map +1 -1
- package/lib/module/ui/screens/FileManagementScreen.js +3 -2
- package/lib/module/ui/screens/FileManagementScreen.js.map +1 -1
- package/lib/module/ui/screens/LanguageSelectorScreen.js +73 -117
- package/lib/module/ui/screens/LanguageSelectorScreen.js.map +1 -1
- package/lib/module/ui/screens/SignInScreen.js +0 -11
- package/lib/module/ui/screens/SignInScreen.js.map +1 -1
- package/lib/module/ui/screens/SignUpScreen.js +14 -16
- package/lib/module/ui/screens/SignUpScreen.js.map +1 -1
- package/lib/module/ui/screens/WelcomeNewUserScreen.js +50 -18
- package/lib/module/ui/screens/WelcomeNewUserScreen.js.map +1 -1
- package/lib/module/ui/screens/internal/SignInPasswordStep.js +10 -10
- package/lib/module/ui/screens/internal/SignInPasswordStep.js.map +1 -1
- package/lib/module/ui/screens/steps/SignInPasswordStep.js +16 -26
- package/lib/module/ui/screens/steps/SignInPasswordStep.js.map +1 -1
- package/lib/module/ui/screens/steps/SignInUsernameStep.js +105 -214
- package/lib/module/ui/screens/steps/SignInUsernameStep.js.map +1 -1
- package/lib/module/ui/stores/accountStore.js +229 -0
- package/lib/module/ui/stores/accountStore.js.map +1 -0
- package/lib/module/ui/stores/authStore.js +2 -1
- package/lib/module/ui/stores/authStore.js.map +1 -1
- package/lib/module/ui/styles/authStyles.js +14 -7
- package/lib/module/ui/styles/authStyles.js.map +1 -1
- package/lib/module/utils/asyncUtils.js +10 -22
- package/lib/module/utils/asyncUtils.js.map +1 -1
- package/lib/module/utils/cache.js +250 -0
- package/lib/module/utils/cache.js.map +1 -0
- package/lib/module/utils/index.js +7 -0
- package/lib/module/utils/index.js.map +1 -1
- package/lib/module/utils/languageUtils.js +151 -0
- package/lib/module/utils/languageUtils.js.map +1 -0
- package/lib/module/utils/requestUtils.js +210 -0
- package/lib/module/utils/requestUtils.js.map +1 -0
- package/lib/module/utils/sessionUtils.js +180 -0
- package/lib/module/utils/sessionUtils.js.map +1 -0
- package/lib/typescript/core/HttpClient.d.ts +64 -0
- package/lib/typescript/core/HttpClient.d.ts.map +1 -0
- package/lib/typescript/core/OxyServices.d.ts +88 -71
- package/lib/typescript/core/OxyServices.d.ts.map +1 -1
- package/lib/typescript/core/RequestManager.d.ts +67 -0
- package/lib/typescript/core/RequestManager.d.ts.map +1 -0
- package/lib/typescript/core/index.d.ts +2 -0
- package/lib/typescript/core/index.d.ts.map +1 -1
- package/lib/typescript/index.d.ts +2 -0
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/models/interfaces.d.ts +15 -0
- package/lib/typescript/models/interfaces.d.ts.map +1 -1
- package/lib/typescript/models/session.d.ts +1 -0
- package/lib/typescript/models/session.d.ts.map +1 -1
- package/lib/typescript/ui/components/Avatar.d.ts +6 -7
- package/lib/typescript/ui/components/Avatar.d.ts.map +1 -1
- package/lib/typescript/ui/components/FollowButton.d.ts.map +1 -1
- package/lib/typescript/ui/components/internal/TextField.d.ts.map +1 -1
- package/lib/typescript/ui/context/OxyContext.d.ts +4 -0
- 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/index.d.ts +2 -2
- package/lib/typescript/ui/index.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/LanguageSelectorScreen.d.ts +3 -3
- package/lib/typescript/ui/screens/LanguageSelectorScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/SignInScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/SignUpScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/WelcomeNewUserScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/internal/SignInPasswordStep.d.ts.map +1 -1
- package/lib/typescript/ui/screens/steps/SignInPasswordStep.d.ts.map +1 -1
- package/lib/typescript/ui/screens/steps/SignInUsernameStep.d.ts.map +1 -1
- package/lib/typescript/ui/stores/accountStore.d.ts +34 -0
- package/lib/typescript/ui/stores/accountStore.d.ts.map +1 -0
- package/lib/typescript/ui/stores/authStore.d.ts.map +1 -1
- package/lib/typescript/ui/styles/authStyles.d.ts +18 -2
- package/lib/typescript/ui/styles/authStyles.d.ts.map +1 -1
- package/lib/typescript/utils/asyncUtils.d.ts +2 -0
- package/lib/typescript/utils/asyncUtils.d.ts.map +1 -1
- package/lib/typescript/utils/cache.d.ts +128 -0
- package/lib/typescript/utils/cache.d.ts.map +1 -0
- package/lib/typescript/utils/index.d.ts +4 -0
- package/lib/typescript/utils/index.d.ts.map +1 -1
- package/lib/typescript/utils/languageUtils.d.ts +38 -0
- package/lib/typescript/utils/languageUtils.d.ts.map +1 -0
- package/lib/typescript/utils/requestUtils.d.ts +122 -0
- package/lib/typescript/utils/requestUtils.d.ts.map +1 -0
- package/lib/typescript/utils/sessionUtils.d.ts +55 -0
- package/lib/typescript/utils/sessionUtils.d.ts.map +1 -0
- package/package.json +1 -1
- package/src/core/HttpClient.ts +277 -0
- package/src/core/OxyServices.ts +466 -351
- package/src/core/RequestManager.ts +240 -0
- package/src/core/index.ts +10 -0
- package/src/index.ts +10 -0
- package/src/models/interfaces.ts +19 -0
- package/src/models/session.ts +1 -1
- package/src/ui/components/Avatar.tsx +151 -35
- package/src/ui/components/FollowButton.tsx +1 -0
- package/src/ui/components/internal/TextField.tsx +7 -6
- package/src/ui/context/OxyContext.tsx +213 -217
- package/src/ui/hooks/useSessionSocket.ts +72 -18
- package/src/ui/index.ts +4 -1
- package/src/ui/screens/AccountSettingsScreen.tsx +34 -2
- package/src/ui/screens/AccountSwitcherScreen.tsx +102 -68
- package/src/ui/screens/FileManagementScreen.tsx +1 -1
- package/src/ui/screens/LanguageSelectorScreen.tsx +86 -143
- package/src/ui/screens/SignInScreen.tsx +0 -7
- package/src/ui/screens/SignUpScreen.tsx +14 -15
- package/src/ui/screens/WelcomeNewUserScreen.tsx +52 -15
- package/src/ui/screens/internal/SignInPasswordStep.tsx +4 -6
- package/src/ui/screens/steps/SignInPasswordStep.tsx +4 -8
- package/src/ui/screens/steps/SignInUsernameStep.tsx +110 -256
- package/src/ui/stores/accountStore.ts +285 -0
- package/src/ui/stores/authStore.ts +2 -1
- package/src/ui/styles/authStyles.ts +14 -7
- package/src/utils/asyncUtils.ts +10 -24
- package/src/utils/cache.ts +264 -0
- package/src/utils/index.ts +19 -0
- package/src/utils/languageUtils.ts +174 -0
- package/src/utils/requestUtils.ts +234 -0
- package/src/utils/sessionUtils.ts +206 -0
|
@@ -4,22 +4,21 @@ import { useRef, useEffect, useMemo, useState, useCallback } from 'react';
|
|
|
4
4
|
import {
|
|
5
5
|
View,
|
|
6
6
|
Text,
|
|
7
|
-
Platform,
|
|
8
7
|
StyleSheet,
|
|
9
|
-
type ViewStyle,
|
|
10
|
-
type TextStyle,
|
|
11
8
|
ActivityIndicator,
|
|
9
|
+
TouchableOpacity,
|
|
12
10
|
} from 'react-native';
|
|
13
11
|
import { Ionicons } from '@expo/vector-icons';
|
|
14
12
|
import HighFive from '../../../assets/illustrations/HighFive';
|
|
15
13
|
import GroupedPillButtons from '../../components/internal/GroupedPillButtons';
|
|
16
14
|
import TextField from '../../components/internal/TextField';
|
|
17
15
|
import { useI18n } from '../../hooks/useI18n';
|
|
18
|
-
import {
|
|
16
|
+
import { stepStyles } from '../../styles/spacing';
|
|
19
17
|
import Avatar from '../../components/Avatar';
|
|
20
|
-
import { TouchableOpacity } from 'react-native';
|
|
21
18
|
import { useOxy } from '../../context/OxyContext';
|
|
22
19
|
import { toast } from '../../../lib/sonner';
|
|
20
|
+
import { useAccountStore, useAccounts, useAccountLoading, useAccountLoadingSession, type QuickAccount } from '../../stores/accountStore';
|
|
21
|
+
import { fontFamilies } from '../../styles/fonts';
|
|
23
22
|
|
|
24
23
|
interface SignInUsernameStepProps {
|
|
25
24
|
// Common props from StepBasedScreen
|
|
@@ -56,13 +55,6 @@ interface SignInUsernameStepProps {
|
|
|
56
55
|
validateUsername: (username: string) => Promise<boolean>;
|
|
57
56
|
}
|
|
58
57
|
|
|
59
|
-
interface QuickAccount {
|
|
60
|
-
sessionId: string;
|
|
61
|
-
username: string;
|
|
62
|
-
displayName: string;
|
|
63
|
-
avatar?: string;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
58
|
const MAX_QUICK_ACCOUNTS = 3;
|
|
67
59
|
|
|
68
60
|
const getThemeMode = (theme: string | undefined): 'light' | 'dark' =>
|
|
@@ -89,190 +81,103 @@ const SignInUsernameStep: React.FC<SignInUsernameStepProps> = ({
|
|
|
89
81
|
const { t } = useI18n();
|
|
90
82
|
const { sessions, activeSessionId, switchSession, oxyServices } = useOxy();
|
|
91
83
|
const baseStyles = stepStyles;
|
|
92
|
-
const webShadowReset = Platform.OS === 'web' ? ({ boxShadow: 'none' } as any) : null;
|
|
93
84
|
const themeMode = getThemeMode(theme);
|
|
94
|
-
const [quickAccounts, setQuickAccounts] = useState<QuickAccount[]>([]);
|
|
95
|
-
const [loadingAccounts, setLoadingAccounts] = useState(false);
|
|
96
85
|
const [switchingSessionId, setSwitchingSessionId] = useState<string | null>(null);
|
|
97
86
|
const [showAccounts, setShowAccounts] = useState(false);
|
|
87
|
+
const previousSessionIdsRef = useRef<string>('');
|
|
98
88
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
);
|
|
89
|
+
// Zustand store - use stable selectors
|
|
90
|
+
const quickAccounts = useAccounts();
|
|
91
|
+
const loadingAccounts = useAccountLoading();
|
|
92
|
+
const isLoading = useAccountStore(state => state.loading);
|
|
103
93
|
|
|
104
|
-
//
|
|
105
|
-
const
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
const sessionsToShow = isAddAccountMode ? otherSessions : (sessions ?? []);
|
|
109
|
-
|
|
110
|
-
// Debug logging
|
|
111
|
-
if (__DEV__) {
|
|
112
|
-
console.log('SignInUsernameStep - Debug:', {
|
|
113
|
-
isAddAccountMode,
|
|
114
|
-
hasSessions,
|
|
115
|
-
sessionsCount: sessions?.length ?? 0,
|
|
116
|
-
otherSessionsCount: otherSessions.length,
|
|
117
|
-
sessionsToShowCount: sessionsToShow.length,
|
|
118
|
-
activeSessionId,
|
|
119
|
-
quickAccountsCount: quickAccounts.length,
|
|
120
|
-
loadingAccounts,
|
|
121
|
-
});
|
|
122
|
-
}
|
|
94
|
+
// Store actions are stable - get them once
|
|
95
|
+
const loadAccountsRef = useRef(useAccountStore.getState().loadAccounts);
|
|
96
|
+
const setAccountsRef = useRef(useAccountStore.getState().setAccounts);
|
|
97
|
+
const moveAccountToTopRef = useRef(useAccountStore.getState().moveAccountToTop);
|
|
123
98
|
|
|
99
|
+
// Update refs if store changes (shouldn't happen, but safe)
|
|
124
100
|
useEffect(() => {
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
101
|
+
loadAccountsRef.current = useAccountStore.getState().loadAccounts;
|
|
102
|
+
setAccountsRef.current = useAccountStore.getState().setAccounts;
|
|
103
|
+
moveAccountToTopRef.current = useAccountStore.getState().moveAccountToTop;
|
|
104
|
+
}, []);
|
|
105
|
+
|
|
106
|
+
const sessionsToLoad = useMemo(() => {
|
|
107
|
+
const allSessions = sessions || [];
|
|
108
|
+
return allSessions.slice(0, MAX_QUICK_ACCOUNTS);
|
|
109
|
+
}, [sessions]);
|
|
110
|
+
|
|
111
|
+
const sessionsToLoadIds = useMemo(
|
|
112
|
+
() => sessionsToLoad.map(s => s.sessionId).sort().join(','),
|
|
113
|
+
[sessionsToLoad]
|
|
114
|
+
);
|
|
137
115
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
}
|
|
116
|
+
useEffect(() => {
|
|
117
|
+
if (previousSessionIdsRef.current === sessionsToLoadIds || isLoading) return;
|
|
118
|
+
if (!sessionsToLoad.length || !oxyServices) {
|
|
119
|
+
setAccountsRef.current([]);
|
|
120
|
+
previousSessionIdsRef.current = sessionsToLoadIds;
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
146
123
|
|
|
147
|
-
|
|
148
|
-
if (!isAddAccountMode && sessionsToShow.length === 0) {
|
|
149
|
-
if (!cancelled) {
|
|
150
|
-
setQuickAccounts([]);
|
|
151
|
-
setLoadingAccounts(false);
|
|
152
|
-
}
|
|
153
|
-
return;
|
|
154
|
-
}
|
|
124
|
+
previousSessionIdsRef.current = sessionsToLoadIds;
|
|
155
125
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
targetSessions.map(async (session): Promise<QuickAccount | null> => {
|
|
162
|
-
try {
|
|
163
|
-
const profile = await oxyServices.getUserBySession(session.sessionId);
|
|
164
|
-
const displayName =
|
|
165
|
-
profile?.name?.full ||
|
|
166
|
-
profile?.name?.first ||
|
|
167
|
-
profile?.username ||
|
|
168
|
-
'Account';
|
|
169
|
-
|
|
170
|
-
return {
|
|
171
|
-
sessionId: session.sessionId,
|
|
172
|
-
username: profile?.username ?? 'account',
|
|
173
|
-
displayName,
|
|
174
|
-
avatar: profile?.avatar,
|
|
175
|
-
};
|
|
176
|
-
} catch (error) {
|
|
177
|
-
if (__DEV__) {
|
|
178
|
-
console.error(
|
|
179
|
-
`Failed to load profile for session ${session.sessionId}`,
|
|
180
|
-
error
|
|
181
|
-
);
|
|
182
|
-
}
|
|
183
|
-
return null;
|
|
184
|
-
}
|
|
185
|
-
})
|
|
186
|
-
);
|
|
187
|
-
|
|
188
|
-
if (!cancelled) {
|
|
189
|
-
setQuickAccounts(results.filter((item): item is QuickAccount => Boolean(item)));
|
|
190
|
-
}
|
|
191
|
-
} finally {
|
|
192
|
-
if (!cancelled) {
|
|
193
|
-
setLoadingAccounts(false);
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
};
|
|
126
|
+
const uniqueSessionIds = Array.from(new Set(sessionsToLoad.map(s => s.sessionId)));
|
|
127
|
+
if (uniqueSessionIds.length === 0) {
|
|
128
|
+
setAccountsRef.current([]);
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
197
131
|
|
|
198
|
-
|
|
132
|
+
const currentAccounts = useAccountStore.getState().accounts;
|
|
133
|
+
const accountsArray = Object.values(currentAccounts);
|
|
199
134
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
};
|
|
203
|
-
}, [hasSessions, sessionsToShow, oxyServices, isAddAccountMode]);
|
|
135
|
+
void loadAccountsRef.current(uniqueSessionIds, oxyServices, accountsArray);
|
|
136
|
+
}, [sessionsToLoadIds, oxyServices, isLoading]);
|
|
204
137
|
|
|
205
138
|
const handleSwitchAccount = useCallback(
|
|
206
139
|
async (sessionId: string) => {
|
|
140
|
+
if (switchingSessionId || sessionId === activeSessionId) return;
|
|
141
|
+
|
|
207
142
|
setSwitchingSessionId(sessionId);
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
const
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
} catch (error) {
|
|
218
|
-
if (__DEV__) {
|
|
219
|
-
console.error('Failed to switch account:', error);
|
|
143
|
+
moveAccountToTopRef.current(sessionId);
|
|
144
|
+
|
|
145
|
+
switchSession(sessionId).catch((error) => {
|
|
146
|
+
if (__DEV__) console.error('Failed to switch account:', error);
|
|
147
|
+
const state = useAccountStore.getState();
|
|
148
|
+
const account = state.accounts[sessionId];
|
|
149
|
+
if (account) {
|
|
150
|
+
const filtered = Object.values(state.accounts).filter(a => a.sessionId !== sessionId);
|
|
151
|
+
setAccountsRef.current([...filtered, account]);
|
|
220
152
|
}
|
|
221
|
-
toast.error(
|
|
222
|
-
|
|
223
|
-
);
|
|
224
|
-
} finally {
|
|
153
|
+
toast.error(t('signin.actions.switchAccountFailed') || 'Unable to switch accounts. Please try again.');
|
|
154
|
+
}).finally(() => {
|
|
225
155
|
setSwitchingSessionId(null);
|
|
226
|
-
}
|
|
156
|
+
});
|
|
227
157
|
},
|
|
228
|
-
[
|
|
158
|
+
[switchSession, switchingSessionId, activeSessionId, t]
|
|
229
159
|
);
|
|
230
160
|
|
|
231
|
-
const otherAccountsCount = sessionsToShow.length;
|
|
232
|
-
|
|
233
|
-
// Get all accounts for avatar display (current user + quick accounts)
|
|
234
|
-
const allAccountsForAvatars = useMemo(() => {
|
|
235
|
-
const accounts: Array<{
|
|
236
|
-
sessionId: string;
|
|
237
|
-
displayName: string;
|
|
238
|
-
username?: string;
|
|
239
|
-
avatar?: string;
|
|
240
|
-
isCurrent?: boolean;
|
|
241
|
-
}> = [];
|
|
242
|
-
|
|
243
|
-
// Add current user if in add account mode
|
|
244
|
-
if (isAddAccountMode && user) {
|
|
245
|
-
accounts.push({
|
|
246
|
-
sessionId: activeSessionId || '',
|
|
247
|
-
displayName: user.name?.full || user.username || 'Account',
|
|
248
|
-
username: user.username,
|
|
249
|
-
avatar: user.avatar,
|
|
250
|
-
isCurrent: true,
|
|
251
|
-
});
|
|
252
|
-
}
|
|
253
161
|
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
isCurrent
|
|
262
|
-
}
|
|
162
|
+
const accountsForDisplay = useMemo(() => {
|
|
163
|
+
const sessionMap = new Map(sessions?.map(s => [s.sessionId, s]) || []);
|
|
164
|
+
return quickAccounts.map(account => {
|
|
165
|
+
const session = sessionMap.get(account.sessionId);
|
|
166
|
+
const isCurrent = session?.isCurrent === true || account.sessionId === activeSessionId;
|
|
167
|
+
return {
|
|
168
|
+
...account,
|
|
169
|
+
isCurrent,
|
|
170
|
+
};
|
|
263
171
|
});
|
|
172
|
+
}, [quickAccounts, sessions, activeSessionId]);
|
|
264
173
|
|
|
265
|
-
|
|
266
|
-
}, [isAddAccountMode, user, quickAccounts, activeSessionId]);
|
|
267
|
-
|
|
268
|
-
const handleUsernameChange = (text: string) => {
|
|
269
|
-
// Text is already filtered by formatValue prop, but ensure it's clean
|
|
174
|
+
const handleUsernameChange = useCallback((text: string) => {
|
|
270
175
|
const filteredText = text.replace(/[^a-zA-Z0-9]/g, '');
|
|
271
176
|
setUsername(filteredText);
|
|
272
177
|
if (errorMessage) setErrorMessage('');
|
|
273
|
-
};
|
|
178
|
+
}, [setUsername, setErrorMessage, errorMessage]);
|
|
274
179
|
|
|
275
|
-
const handleContinue = async () => {
|
|
180
|
+
const handleContinue = useCallback(async () => {
|
|
276
181
|
const trimmedUsername = username?.trim() || '';
|
|
277
182
|
|
|
278
183
|
if (!trimmedUsername) {
|
|
@@ -287,9 +192,7 @@ const SignInUsernameStep: React.FC<SignInUsernameStepProps> = ({
|
|
|
287
192
|
}
|
|
288
193
|
|
|
289
194
|
try {
|
|
290
|
-
// Validate the username before proceeding
|
|
291
195
|
const isValid = await validateUsername(trimmedUsername);
|
|
292
|
-
|
|
293
196
|
if (isValid) {
|
|
294
197
|
nextStep();
|
|
295
198
|
}
|
|
@@ -297,7 +200,7 @@ const SignInUsernameStep: React.FC<SignInUsernameStepProps> = ({
|
|
|
297
200
|
if (__DEV__) console.error('Error during username validation:', error);
|
|
298
201
|
setErrorMessage('Unable to validate username. Please try again.');
|
|
299
202
|
}
|
|
300
|
-
};
|
|
203
|
+
}, [username, validateUsername, nextStep, setErrorMessage, t]);
|
|
301
204
|
|
|
302
205
|
return (
|
|
303
206
|
<>
|
|
@@ -345,8 +248,7 @@ const SignInUsernameStep: React.FC<SignInUsernameStepProps> = ({
|
|
|
345
248
|
/>
|
|
346
249
|
</View>
|
|
347
250
|
|
|
348
|
-
{
|
|
349
|
-
{((isAddAccountMode && user) || (hasSessions && sessionsToShow.length > 0)) && (
|
|
251
|
+
{accountsForDisplay.length > 0 && (
|
|
350
252
|
<View style={[baseStyles.container, baseStyles.sectionSpacing, stylesheet.dividerContainer]}>
|
|
351
253
|
<View style={[stylesheet.dividerLine, { backgroundColor: colors.border }]} />
|
|
352
254
|
<Text style={[stylesheet.dividerText, { color: colors.secondaryText }]}>
|
|
@@ -356,7 +258,7 @@ const SignInUsernameStep: React.FC<SignInUsernameStepProps> = ({
|
|
|
356
258
|
</View>
|
|
357
259
|
)}
|
|
358
260
|
|
|
359
|
-
{
|
|
261
|
+
{accountsForDisplay.length > 0 ? (
|
|
360
262
|
<View style={[baseStyles.container, baseStyles.sectionSpacing]}>
|
|
361
263
|
<TouchableOpacity
|
|
362
264
|
style={[
|
|
@@ -377,35 +279,34 @@ const SignInUsernameStep: React.FC<SignInUsernameStepProps> = ({
|
|
|
377
279
|
<Text style={[stylesheet.toggleButtonText, { color: colors.text }]}>
|
|
378
280
|
{t('signin.alreadySignedInWith') || 'Already signed in with'}
|
|
379
281
|
</Text>
|
|
380
|
-
{
|
|
282
|
+
{accountsForDisplay.length > 0 && (
|
|
381
283
|
<View style={stylesheet.avatarsContainer}>
|
|
382
|
-
{
|
|
284
|
+
{accountsForDisplay.slice(0, 5).map((account, index) => (
|
|
383
285
|
<View
|
|
384
|
-
key={account.sessionId}
|
|
286
|
+
key={`avatar-${account.sessionId}`}
|
|
385
287
|
style={[
|
|
386
288
|
stylesheet.avatarWrapper,
|
|
387
289
|
account.isCurrent && stylesheet.currentAvatarWrapper,
|
|
388
290
|
index > 0 && { marginLeft: -12 },
|
|
389
|
-
{ zIndex: Math.min(
|
|
291
|
+
{ zIndex: Math.min(accountsForDisplay.length, 5) - index },
|
|
390
292
|
{ borderColor: colors.inputBackground || colors.background || '#FFFFFF' },
|
|
391
293
|
]}
|
|
392
294
|
>
|
|
393
295
|
<Avatar
|
|
394
296
|
name={account.displayName}
|
|
395
|
-
text={account.displayName.charAt(0).toUpperCase()}
|
|
396
297
|
size={28}
|
|
397
298
|
theme={themeMode}
|
|
398
299
|
backgroundColor={colors.primary}
|
|
399
|
-
uri={account.
|
|
300
|
+
uri={account.avatarUrl}
|
|
400
301
|
/>
|
|
401
302
|
</View>
|
|
402
303
|
))}
|
|
403
304
|
</View>
|
|
404
305
|
)}
|
|
405
|
-
{!showAccounts &&
|
|
306
|
+
{!showAccounts && accountsForDisplay.length === 0 && quickAccounts.length > 0 && (
|
|
406
307
|
<View style={[stylesheet.accountCountBadge, { backgroundColor: `${colors.primary}15` }]}>
|
|
407
308
|
<Text style={[stylesheet.accountCountText, { color: colors.primary }]}>
|
|
408
|
-
{
|
|
309
|
+
{quickAccounts.length}
|
|
409
310
|
</Text>
|
|
410
311
|
</View>
|
|
411
312
|
)}
|
|
@@ -414,63 +315,15 @@ const SignInUsernameStep: React.FC<SignInUsernameStepProps> = ({
|
|
|
414
315
|
|
|
415
316
|
{showAccounts && (
|
|
416
317
|
<View style={stylesheet.accountsList}>
|
|
417
|
-
{loadingAccounts &&
|
|
318
|
+
{loadingAccounts && accountsForDisplay.length === 0 ? (
|
|
418
319
|
<View style={stylesheet.accountItem}>
|
|
419
320
|
<ActivityIndicator color={colors.primary} size="small" />
|
|
420
321
|
</View>
|
|
421
322
|
) : (
|
|
422
323
|
<>
|
|
423
|
-
{
|
|
424
|
-
{isAddAccountMode && user && (
|
|
425
|
-
<View
|
|
426
|
-
style={[
|
|
427
|
-
stylesheet.accountItem,
|
|
428
|
-
{
|
|
429
|
-
backgroundColor: colors.inputBackground,
|
|
430
|
-
},
|
|
431
|
-
]}
|
|
432
|
-
>
|
|
433
|
-
<View style={[stylesheet.accountItemAvatarWrapper, { borderColor: colors.inputBackground || colors.background || '#FFFFFF' }]}>
|
|
434
|
-
<Avatar
|
|
435
|
-
name={user.name?.full || user.username}
|
|
436
|
-
text={(user.name?.full || user.username || 'U')
|
|
437
|
-
.slice(0, 1)
|
|
438
|
-
.toUpperCase()}
|
|
439
|
-
size={36}
|
|
440
|
-
theme={themeMode}
|
|
441
|
-
backgroundColor={colors.primary}
|
|
442
|
-
uri={user.avatar && oxyServices ? oxyServices.getFileDownloadUrl(user.avatar, 'thumb') : undefined}
|
|
443
|
-
/>
|
|
444
|
-
</View>
|
|
445
|
-
<View style={stylesheet.accountItemText}>
|
|
446
|
-
<Text
|
|
447
|
-
style={[stylesheet.accountItemName, { color: colors.text }]}
|
|
448
|
-
numberOfLines={1}
|
|
449
|
-
>
|
|
450
|
-
{user.name?.full || user.username}
|
|
451
|
-
</Text>
|
|
452
|
-
{user.username && (
|
|
453
|
-
<Text
|
|
454
|
-
style={[
|
|
455
|
-
stylesheet.accountItemUsername,
|
|
456
|
-
{ color: colors.secondaryText },
|
|
457
|
-
]}
|
|
458
|
-
numberOfLines={1}
|
|
459
|
-
>
|
|
460
|
-
@{user.username}
|
|
461
|
-
</Text>
|
|
462
|
-
)}
|
|
463
|
-
</View>
|
|
464
|
-
<View style={[stylesheet.currentAccountBadgeContainer, { backgroundColor: `${colors.primary}15` }]}>
|
|
465
|
-
<Text style={[stylesheet.currentAccountBadge, { color: colors.primary }]}>
|
|
466
|
-
{t('signin.currentAccount') || 'Current'}
|
|
467
|
-
</Text>
|
|
468
|
-
</View>
|
|
469
|
-
</View>
|
|
470
|
-
)}
|
|
471
|
-
{quickAccounts.map((account) => (
|
|
324
|
+
{accountsForDisplay.map((account) => (
|
|
472
325
|
<TouchableOpacity
|
|
473
|
-
key={account.sessionId}
|
|
326
|
+
key={`account-${account.sessionId}`}
|
|
474
327
|
style={[
|
|
475
328
|
stylesheet.accountItem,
|
|
476
329
|
{
|
|
@@ -479,7 +332,7 @@ const SignInUsernameStep: React.FC<SignInUsernameStepProps> = ({
|
|
|
479
332
|
switchingSessionId === account.sessionId && stylesheet.accountItemLoading,
|
|
480
333
|
]}
|
|
481
334
|
onPress={() => handleSwitchAccount(account.sessionId)}
|
|
482
|
-
disabled={switchingSessionId === account.sessionId}
|
|
335
|
+
disabled={switchingSessionId === account.sessionId || account.isCurrent}
|
|
483
336
|
activeOpacity={0.7}
|
|
484
337
|
>
|
|
485
338
|
{switchingSessionId === account.sessionId ? (
|
|
@@ -489,11 +342,10 @@ const SignInUsernameStep: React.FC<SignInUsernameStepProps> = ({
|
|
|
489
342
|
<View style={[stylesheet.accountItemAvatarWrapper, { borderColor: colors.inputBackground || colors.background || '#FFFFFF' }]}>
|
|
490
343
|
<Avatar
|
|
491
344
|
name={account.displayName}
|
|
492
|
-
text={account.displayName.charAt(0).toUpperCase()}
|
|
493
345
|
size={36}
|
|
494
346
|
theme={themeMode}
|
|
495
347
|
backgroundColor={colors.primary}
|
|
496
|
-
uri={account.
|
|
348
|
+
uri={account.avatarUrl}
|
|
497
349
|
/>
|
|
498
350
|
</View>
|
|
499
351
|
<View style={stylesheet.accountItemText}>
|
|
@@ -515,11 +367,18 @@ const SignInUsernameStep: React.FC<SignInUsernameStepProps> = ({
|
|
|
515
367
|
</Text>
|
|
516
368
|
)}
|
|
517
369
|
</View>
|
|
370
|
+
{account.isCurrent ? (
|
|
371
|
+
<View style={[stylesheet.currentAccountBadgeContainer, { backgroundColor: `${colors.primary}20` }]}>
|
|
372
|
+
<Text style={[stylesheet.currentAccountBadge, { color: colors.primary }]}>
|
|
373
|
+
{t('signin.currentAccount') || 'Current'}
|
|
374
|
+
</Text>
|
|
375
|
+
</View>
|
|
376
|
+
) : null}
|
|
518
377
|
</>
|
|
519
378
|
)}
|
|
520
379
|
</TouchableOpacity>
|
|
521
380
|
))}
|
|
522
|
-
{
|
|
381
|
+
{sessions && sessions.length > MAX_QUICK_ACCOUNTS && (
|
|
523
382
|
<TouchableOpacity
|
|
524
383
|
style={[
|
|
525
384
|
stylesheet.accountItem,
|
|
@@ -534,8 +393,8 @@ const SignInUsernameStep: React.FC<SignInUsernameStepProps> = ({
|
|
|
534
393
|
<Ionicons name="chevron-forward" size={18} color={colors.primary} />
|
|
535
394
|
<Text style={[stylesheet.viewAllText, { color: colors.primary }]}>
|
|
536
395
|
{t('signin.viewAllAccounts', {
|
|
537
|
-
count:
|
|
538
|
-
}) || `View ${
|
|
396
|
+
count: sessions.length - MAX_QUICK_ACCOUNTS,
|
|
397
|
+
}) || `View ${sessions.length - MAX_QUICK_ACCOUNTS} more`}
|
|
539
398
|
</Text>
|
|
540
399
|
</TouchableOpacity>
|
|
541
400
|
)}
|
|
@@ -615,6 +474,7 @@ const stylesheet = StyleSheet.create({
|
|
|
615
474
|
borderWidth: 0,
|
|
616
475
|
gap: 12,
|
|
617
476
|
minHeight: 56,
|
|
477
|
+
justifyContent: 'space-between',
|
|
618
478
|
},
|
|
619
479
|
accountItemLoading: {
|
|
620
480
|
justifyContent: 'center',
|
|
@@ -641,14 +501,19 @@ const stylesheet = StyleSheet.create({
|
|
|
641
501
|
marginLeft: 4,
|
|
642
502
|
},
|
|
643
503
|
currentAccountBadgeContainer: {
|
|
644
|
-
paddingHorizontal:
|
|
645
|
-
paddingVertical:
|
|
646
|
-
borderRadius:
|
|
504
|
+
paddingHorizontal: 12,
|
|
505
|
+
paddingVertical: 5,
|
|
506
|
+
borderRadius: 12,
|
|
507
|
+
marginLeft: 'auto',
|
|
508
|
+
minWidth: 60,
|
|
509
|
+
alignItems: 'center',
|
|
510
|
+
justifyContent: 'center',
|
|
647
511
|
},
|
|
648
512
|
currentAccountBadge: {
|
|
649
|
-
fontSize:
|
|
650
|
-
|
|
651
|
-
letterSpacing: 0.
|
|
513
|
+
fontSize: 11,
|
|
514
|
+
fontFamily: fontFamilies.phuduExtraBold,
|
|
515
|
+
letterSpacing: 0.5,
|
|
516
|
+
textTransform: 'uppercase',
|
|
652
517
|
},
|
|
653
518
|
dividerContainer: {
|
|
654
519
|
flexDirection: 'row',
|
|
@@ -678,17 +543,6 @@ const stylesheet = StyleSheet.create({
|
|
|
678
543
|
currentAvatarWrapper: {
|
|
679
544
|
borderWidth: 3,
|
|
680
545
|
},
|
|
681
|
-
currentBadge: {
|
|
682
|
-
position: 'absolute',
|
|
683
|
-
bottom: -2,
|
|
684
|
-
right: -2,
|
|
685
|
-
width: 14,
|
|
686
|
-
height: 14,
|
|
687
|
-
borderRadius: 7,
|
|
688
|
-
alignItems: 'center',
|
|
689
|
-
justifyContent: 'center',
|
|
690
|
-
borderWidth: 0,
|
|
691
|
-
},
|
|
692
546
|
accountItemAvatarWrapper: {
|
|
693
547
|
borderRadius: 20,
|
|
694
548
|
borderWidth: 3,
|