@oxyhq/services 5.13.0 → 5.13.2
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 +530 -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/i18n/index.js +37 -1
- package/lib/commonjs/i18n/index.js.map +1 -1
- package/lib/commonjs/i18n/locales/ar-SA.json +128 -0
- package/lib/commonjs/i18n/locales/ca-ES.json +128 -0
- package/lib/commonjs/i18n/locales/de-DE.json +128 -0
- package/lib/commonjs/i18n/locales/en-US.json +85 -12
- package/lib/commonjs/i18n/locales/es-ES.json +58 -6
- package/lib/commonjs/i18n/locales/fr-FR.json +128 -0
- package/lib/commonjs/i18n/locales/it-IT.json +128 -0
- package/lib/commonjs/i18n/locales/ja-JP.json +127 -0
- package/lib/commonjs/i18n/locales/ko-KR.json +128 -0
- package/lib/commonjs/i18n/locales/pt-PT.json +128 -0
- package/lib/commonjs/i18n/locales/zh-CN.json +128 -0
- 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/FontLoader.js +22 -42
- package/lib/commonjs/ui/components/FontLoader.js.map +1 -1
- package/lib/commonjs/ui/components/OxyProvider.js +5 -8
- package/lib/commonjs/ui/components/OxyProvider.js.map +1 -1
- package/lib/commonjs/ui/components/StepBasedScreen.js +64 -44
- package/lib/commonjs/ui/components/StepBasedScreen.js.map +1 -1
- package/lib/commonjs/ui/components/internal/GroupedPillButtons.js +14 -35
- package/lib/commonjs/ui/components/internal/GroupedPillButtons.js.map +1 -1
- package/lib/commonjs/ui/components/internal/PinInput.js +2 -2
- package/lib/commonjs/ui/components/internal/PinInput.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 +443 -371
- 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 +43 -50
- 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 +188 -142
- 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/internal/SignInUsernameStep.js +2 -4
- package/lib/commonjs/ui/screens/internal/SignInUsernameStep.js.map +1 -1
- package/lib/commonjs/ui/screens/steps/RecoverRequestStep.js +45 -25
- package/lib/commonjs/ui/screens/steps/RecoverRequestStep.js.map +1 -1
- package/lib/commonjs/ui/screens/steps/RecoverResetPasswordStep.js +88 -53
- package/lib/commonjs/ui/screens/steps/RecoverResetPasswordStep.js.map +1 -1
- package/lib/commonjs/ui/screens/steps/RecoverSuccessStep.js +79 -58
- package/lib/commonjs/ui/screens/steps/RecoverSuccessStep.js.map +1 -1
- package/lib/commonjs/ui/screens/steps/RecoverVerifyStep.js +61 -52
- package/lib/commonjs/ui/screens/steps/RecoverVerifyStep.js.map +1 -1
- package/lib/commonjs/ui/screens/steps/SignInPasswordStep.js +218 -39
- package/lib/commonjs/ui/screens/steps/SignInPasswordStep.js.map +1 -1
- package/lib/commonjs/ui/screens/steps/SignInTotpStep.js +77 -50
- package/lib/commonjs/ui/screens/steps/SignInTotpStep.js.map +1 -1
- package/lib/commonjs/ui/screens/steps/SignInUsernameStep.js +424 -71
- package/lib/commonjs/ui/screens/steps/SignInUsernameStep.js.map +1 -1
- package/lib/commonjs/ui/screens/steps/SignUpIdentityStep.js +55 -30
- package/lib/commonjs/ui/screens/steps/SignUpIdentityStep.js.map +1 -1
- package/lib/commonjs/ui/screens/steps/SignUpSecurityStep.js +64 -46
- package/lib/commonjs/ui/screens/steps/SignUpSecurityStep.js.map +1 -1
- package/lib/commonjs/ui/screens/steps/SignUpSummaryStep.js +84 -146
- package/lib/commonjs/ui/screens/steps/SignUpSummaryStep.js.map +1 -1
- package/lib/commonjs/ui/screens/steps/SignUpWelcomeStep.js +113 -34
- package/lib/commonjs/ui/screens/steps/SignUpWelcomeStep.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 +17 -20
- package/lib/commonjs/ui/stores/authStore.js.map +1 -1
- package/lib/commonjs/ui/styles/authStyles.js +16 -8
- package/lib/commonjs/ui/styles/authStyles.js.map +1 -1
- package/lib/commonjs/ui/styles/index.js +11 -0
- package/lib/commonjs/ui/styles/index.js.map +1 -1
- package/lib/commonjs/ui/styles/spacing.js +51 -0
- package/lib/commonjs/ui/styles/spacing.js.map +1 -0
- 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/commonjs/utils/validationUtils.js +1 -1
- package/lib/module/core/HttpClient.js +232 -0
- package/lib/module/core/HttpClient.js.map +1 -0
- package/lib/module/core/OxyServices.js +528 -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/i18n/index.js +37 -1
- package/lib/module/i18n/index.js.map +1 -1
- package/lib/module/i18n/locales/ar-SA.json +128 -0
- package/lib/module/i18n/locales/ca-ES.json +128 -0
- package/lib/module/i18n/locales/de-DE.json +128 -0
- package/lib/module/i18n/locales/en-US.json +85 -12
- package/lib/module/i18n/locales/es-ES.json +58 -6
- package/lib/module/i18n/locales/fr-FR.json +128 -0
- package/lib/module/i18n/locales/it-IT.json +128 -0
- package/lib/module/i18n/locales/ja-JP.json +127 -0
- package/lib/module/i18n/locales/ko-KR.json +128 -0
- package/lib/module/i18n/locales/pt-PT.json +128 -0
- package/lib/module/i18n/locales/zh-CN.json +128 -0
- 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/FontLoader.js +23 -43
- package/lib/module/ui/components/FontLoader.js.map +1 -1
- package/lib/module/ui/components/OxyProvider.js +6 -8
- package/lib/module/ui/components/OxyProvider.js.map +1 -1
- package/lib/module/ui/components/StepBasedScreen.js +65 -45
- package/lib/module/ui/components/StepBasedScreen.js.map +1 -1
- package/lib/module/ui/components/internal/GroupedPillButtons.js +14 -35
- package/lib/module/ui/components/internal/GroupedPillButtons.js.map +1 -1
- package/lib/module/ui/components/internal/PinInput.js +2 -2
- package/lib/module/ui/components/internal/PinInput.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 +442 -370
- 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 +44 -51
- 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 +187 -143
- 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/internal/SignInUsernameStep.js +2 -4
- package/lib/module/ui/screens/internal/SignInUsernameStep.js.map +1 -1
- package/lib/module/ui/screens/steps/RecoverRequestStep.js +45 -25
- package/lib/module/ui/screens/steps/RecoverRequestStep.js.map +1 -1
- package/lib/module/ui/screens/steps/RecoverResetPasswordStep.js +89 -54
- package/lib/module/ui/screens/steps/RecoverResetPasswordStep.js.map +1 -1
- package/lib/module/ui/screens/steps/RecoverSuccessStep.js +80 -59
- package/lib/module/ui/screens/steps/RecoverSuccessStep.js.map +1 -1
- package/lib/module/ui/screens/steps/RecoverVerifyStep.js +62 -53
- package/lib/module/ui/screens/steps/RecoverVerifyStep.js.map +1 -1
- package/lib/module/ui/screens/steps/SignInPasswordStep.js +219 -40
- package/lib/module/ui/screens/steps/SignInPasswordStep.js.map +1 -1
- package/lib/module/ui/screens/steps/SignInTotpStep.js +78 -51
- package/lib/module/ui/screens/steps/SignInTotpStep.js.map +1 -1
- package/lib/module/ui/screens/steps/SignInUsernameStep.js +426 -73
- package/lib/module/ui/screens/steps/SignInUsernameStep.js.map +1 -1
- package/lib/module/ui/screens/steps/SignUpIdentityStep.js +55 -30
- package/lib/module/ui/screens/steps/SignUpIdentityStep.js.map +1 -1
- package/lib/module/ui/screens/steps/SignUpSecurityStep.js +65 -47
- package/lib/module/ui/screens/steps/SignUpSecurityStep.js.map +1 -1
- package/lib/module/ui/screens/steps/SignUpSummaryStep.js +84 -146
- package/lib/module/ui/screens/steps/SignUpSummaryStep.js.map +1 -1
- package/lib/module/ui/screens/steps/SignUpWelcomeStep.js +114 -35
- package/lib/module/ui/screens/steps/SignUpWelcomeStep.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 +17 -20
- package/lib/module/ui/stores/authStore.js.map +1 -1
- package/lib/module/ui/styles/authStyles.js +16 -8
- package/lib/module/ui/styles/authStyles.js.map +1 -1
- package/lib/module/ui/styles/index.js +1 -0
- package/lib/module/ui/styles/index.js.map +1 -1
- package/lib/module/ui/styles/spacing.js +48 -0
- package/lib/module/ui/styles/spacing.js.map +1 -0
- 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/module/utils/validationUtils.js +1 -1
- 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 +86 -73
- 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/i18n/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/FontLoader.d.ts +3 -3
- package/lib/typescript/ui/components/FontLoader.d.ts.map +1 -1
- package/lib/typescript/ui/components/OxyProvider.d.ts +2 -2
- package/lib/typescript/ui/components/OxyProvider.d.ts.map +1 -1
- package/lib/typescript/ui/components/StepBasedScreen.d.ts.map +1 -1
- package/lib/typescript/ui/components/internal/GroupedPillButtons.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 +5 -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/RecoverRequestStep.d.ts.map +1 -1
- package/lib/typescript/ui/screens/steps/RecoverResetPasswordStep.d.ts.map +1 -1
- package/lib/typescript/ui/screens/steps/RecoverSuccessStep.d.ts.map +1 -1
- package/lib/typescript/ui/screens/steps/RecoverVerifyStep.d.ts.map +1 -1
- package/lib/typescript/ui/screens/steps/SignInPasswordStep.d.ts +2 -0
- package/lib/typescript/ui/screens/steps/SignInPasswordStep.d.ts.map +1 -1
- package/lib/typescript/ui/screens/steps/SignInTotpStep.d.ts.map +1 -1
- package/lib/typescript/ui/screens/steps/SignInUsernameStep.d.ts.map +1 -1
- package/lib/typescript/ui/screens/steps/SignUpIdentityStep.d.ts.map +1 -1
- package/lib/typescript/ui/screens/steps/SignUpSecurityStep.d.ts.map +1 -1
- package/lib/typescript/ui/screens/steps/SignUpSummaryStep.d.ts.map +1 -1
- package/lib/typescript/ui/screens/steps/SignUpWelcomeStep.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 +7 -3
- package/lib/typescript/ui/stores/authStore.d.ts.map +1 -1
- package/lib/typescript/ui/styles/authStyles.d.ts +19 -2
- package/lib/typescript/ui/styles/authStyles.d.ts.map +1 -1
- package/lib/typescript/ui/styles/index.d.ts +1 -0
- package/lib/typescript/ui/styles/index.d.ts.map +1 -1
- package/lib/typescript/ui/styles/spacing.d.ts +43 -0
- package/lib/typescript/ui/styles/spacing.d.ts.map +1 -0
- 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/lib/typescript/utils/validationUtils.d.ts +1 -1
- package/package.json +1 -1
- package/src/core/HttpClient.ts +277 -0
- package/src/core/OxyServices.ts +461 -352
- package/src/core/RequestManager.ts +240 -0
- package/src/core/index.ts +10 -0
- package/src/i18n/index.ts +36 -0
- package/src/i18n/locales/ar-SA.json +128 -0
- package/src/i18n/locales/ca-ES.json +128 -0
- package/src/i18n/locales/de-DE.json +128 -0
- package/src/i18n/locales/en-US.json +85 -12
- package/src/i18n/locales/es-ES.json +58 -6
- package/src/i18n/locales/fr-FR.json +128 -0
- package/src/i18n/locales/it-IT.json +128 -0
- package/src/i18n/locales/ja-JP.json +127 -0
- package/src/i18n/locales/ko-KR.json +128 -0
- package/src/i18n/locales/pt-PT.json +128 -0
- package/src/i18n/locales/zh-CN.json +128 -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/FontLoader.tsx +17 -37
- package/src/ui/components/OxyProvider.tsx +14 -13
- package/src/ui/components/StepBasedScreen.tsx +66 -43
- package/src/ui/components/internal/GroupedPillButtons.tsx +15 -31
- package/src/ui/components/internal/PinInput.tsx +2 -2
- package/src/ui/components/internal/TextField.tsx +7 -6
- package/src/ui/context/OxyContext.tsx +441 -326
- 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 +16 -16
- package/src/ui/screens/LanguageSelectorScreen.tsx +86 -143
- package/src/ui/screens/SignInScreen.tsx +59 -43
- package/src/ui/screens/SignUpScreen.tsx +14 -15
- package/src/ui/screens/WelcomeNewUserScreen.tsx +153 -105
- package/src/ui/screens/internal/SignInPasswordStep.tsx +4 -6
- package/src/ui/screens/internal/SignInUsernameStep.tsx +1 -1
- package/src/ui/screens/steps/RecoverRequestStep.tsx +34 -24
- package/src/ui/screens/steps/RecoverResetPasswordStep.tsx +65 -36
- package/src/ui/screens/steps/RecoverSuccessStep.tsx +71 -47
- package/src/ui/screens/steps/RecoverVerifyStep.tsx +60 -50
- package/src/ui/screens/steps/SignInPasswordStep.tsx +190 -32
- package/src/ui/screens/steps/SignInTotpStep.tsx +68 -34
- package/src/ui/screens/steps/SignInUsernameStep.tsx +446 -63
- package/src/ui/screens/steps/SignUpIdentityStep.tsx +49 -35
- package/src/ui/screens/steps/SignUpSecurityStep.tsx +56 -39
- package/src/ui/screens/steps/SignUpSummaryStep.tsx +99 -89
- package/src/ui/screens/steps/SignUpWelcomeStep.tsx +88 -20
- package/src/ui/stores/accountStore.ts +285 -0
- package/src/ui/stores/authStore.ts +16 -19
- package/src/ui/styles/authStyles.ts +16 -8
- package/src/ui/styles/index.ts +1 -0
- package/src/ui/styles/spacing.ts +46 -0
- 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
- package/src/utils/validationUtils.ts +1 -1
|
@@ -13,10 +13,35 @@ interface UseSessionSocketProps {
|
|
|
13
13
|
|
|
14
14
|
export function useSessionSocket({ userId, activeSessionId, refreshSessions, logout, baseURL, onRemoteSignOut }: UseSessionSocketProps) {
|
|
15
15
|
const socketRef = useRef<any>(null);
|
|
16
|
+
const joinedRoomRef = useRef<string | null>(null);
|
|
17
|
+
|
|
18
|
+
// Store callbacks in refs to avoid re-joining when they change
|
|
19
|
+
const refreshSessionsRef = useRef(refreshSessions);
|
|
20
|
+
const logoutRef = useRef(logout);
|
|
21
|
+
const onRemoteSignOutRef = useRef(onRemoteSignOut);
|
|
22
|
+
const activeSessionIdRef = useRef(activeSessionId);
|
|
16
23
|
|
|
24
|
+
// Update refs when callbacks change
|
|
17
25
|
useEffect(() => {
|
|
18
|
-
|
|
26
|
+
refreshSessionsRef.current = refreshSessions;
|
|
27
|
+
logoutRef.current = logout;
|
|
28
|
+
onRemoteSignOutRef.current = onRemoteSignOut;
|
|
29
|
+
activeSessionIdRef.current = activeSessionId;
|
|
30
|
+
}, [refreshSessions, logout, onRemoteSignOut, activeSessionId]);
|
|
19
31
|
|
|
32
|
+
useEffect(() => {
|
|
33
|
+
if (!userId || !baseURL) {
|
|
34
|
+
// Clean up if userId or baseURL becomes invalid
|
|
35
|
+
if (socketRef.current && joinedRoomRef.current) {
|
|
36
|
+
socketRef.current.emit('leave', { userId: joinedRoomRef.current });
|
|
37
|
+
joinedRoomRef.current = null;
|
|
38
|
+
}
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const roomId = `user:${userId}`;
|
|
43
|
+
|
|
44
|
+
// Only create socket if it doesn't exist
|
|
20
45
|
if (!socketRef.current) {
|
|
21
46
|
socketRef.current = io(baseURL, {
|
|
22
47
|
transports: ['websocket'],
|
|
@@ -24,30 +49,59 @@ export function useSessionSocket({ userId, activeSessionId, refreshSessions, log
|
|
|
24
49
|
}
|
|
25
50
|
const socket = socketRef.current;
|
|
26
51
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
52
|
+
// Only join if we haven't already joined this room
|
|
53
|
+
if (joinedRoomRef.current !== roomId) {
|
|
54
|
+
// Leave previous room if switching users
|
|
55
|
+
if (joinedRoomRef.current) {
|
|
56
|
+
socket.emit('leave', { userId: joinedRoomRef.current });
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
socket.emit('join', { userId: roomId });
|
|
60
|
+
joinedRoomRef.current = roomId;
|
|
61
|
+
|
|
62
|
+
if (__DEV__) {
|
|
63
|
+
console.log('Emitting join for room:', roomId);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
30
66
|
|
|
31
|
-
|
|
32
|
-
|
|
67
|
+
// Set up event handlers (only once per socket instance)
|
|
68
|
+
const handleConnect = () => {
|
|
69
|
+
if (__DEV__) {
|
|
70
|
+
console.log('Socket connected:', socket.id);
|
|
71
|
+
}
|
|
72
|
+
};
|
|
33
73
|
|
|
34
|
-
|
|
35
|
-
|
|
74
|
+
const handleSessionUpdate = (data: { type: string; sessionId: string }) => {
|
|
75
|
+
if (__DEV__) {
|
|
76
|
+
console.log('Received session_update:', data);
|
|
77
|
+
}
|
|
36
78
|
|
|
37
|
-
//
|
|
38
|
-
|
|
79
|
+
// Use refs to get latest callback versions
|
|
80
|
+
refreshSessionsRef.current();
|
|
39
81
|
|
|
40
82
|
// If the current session was logged out, handle it specially
|
|
41
|
-
if (data.sessionId ===
|
|
42
|
-
if (
|
|
43
|
-
|
|
44
|
-
|
|
83
|
+
if (data.sessionId === activeSessionIdRef.current) {
|
|
84
|
+
if (onRemoteSignOutRef.current) {
|
|
85
|
+
onRemoteSignOutRef.current();
|
|
86
|
+
} else {
|
|
87
|
+
toast.info('You have been signed out remotely.');
|
|
88
|
+
}
|
|
89
|
+
logoutRef.current();
|
|
45
90
|
}
|
|
46
|
-
}
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
socket.on('connect', handleConnect);
|
|
94
|
+
socket.on('session_update', handleSessionUpdate);
|
|
47
95
|
|
|
48
96
|
return () => {
|
|
49
|
-
socket.
|
|
50
|
-
socket.off('session_update');
|
|
97
|
+
socket.off('connect', handleConnect);
|
|
98
|
+
socket.off('session_update', handleSessionUpdate);
|
|
99
|
+
|
|
100
|
+
// Only leave on unmount if we're still in this room
|
|
101
|
+
if (joinedRoomRef.current === roomId) {
|
|
102
|
+
socket.emit('leave', { userId: roomId });
|
|
103
|
+
joinedRoomRef.current = null;
|
|
104
|
+
}
|
|
51
105
|
};
|
|
52
|
-
}, [userId, baseURL
|
|
106
|
+
}, [userId, baseURL]); // Only depend on userId and baseURL - callbacks are in refs
|
|
53
107
|
}
|
package/src/ui/index.ts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
import isFrontend from './isFrontend';
|
|
8
8
|
|
|
9
9
|
// Real UI exports
|
|
10
|
-
let OxyProvider, OxySignInButton, OxyLogo, Avatar, FollowButton, OxyPayButton, FontLoader, setupFonts, OxyIcon, useOxy, useOxyAuth, useOxyUser, useOxyKarma, useOxyPayments, useOxyDevices, useOxyNotifications, useOxySocket, useOxyQR, OxyContextProvider, OxyContextState, OxyContextProviderProps, useFollow, ProfileScreen, OxyRouter, useAuthStore, fontFamilies, fontStyles, toast;
|
|
10
|
+
let OxyProvider, OxySignInButton, OxyLogo, Avatar, FollowButton, OxyPayButton, FontLoader, setupFonts, OxyIcon, useOxy, useOxyAuth, useOxyUser, useOxyKarma, useOxyPayments, useOxyDevices, useOxyNotifications, useOxySocket, useOxyQR, OxyContextProvider, OxyContextState, OxyContextProviderProps, useFollow, ProfileScreen, OxyRouter, useAuthStore, useAccountStore, fontFamilies, fontStyles, toast;
|
|
11
11
|
|
|
12
12
|
if (isFrontend) {
|
|
13
13
|
OxyProvider = require('./components/OxyProvider').default;
|
|
@@ -27,6 +27,7 @@ if (isFrontend) {
|
|
|
27
27
|
ProfileScreen = require('./screens/ProfileScreen').default;
|
|
28
28
|
OxyRouter = require('./navigation/OxyRouter').default;
|
|
29
29
|
useAuthStore = require('./stores/authStore').useAuthStore;
|
|
30
|
+
useAccountStore = require('./stores/accountStore').useAccountStore;
|
|
30
31
|
fontFamilies = require('./styles/fonts').fontFamilies;
|
|
31
32
|
fontStyles = require('./styles/fonts').fontStyles;
|
|
32
33
|
toast = require('../lib/sonner').toast;
|
|
@@ -51,6 +52,7 @@ if (isFrontend) {
|
|
|
51
52
|
ProfileScreen = noopComponent;
|
|
52
53
|
OxyRouter = noopComponent;
|
|
53
54
|
useAuthStore = noopHook;
|
|
55
|
+
useAccountStore = noopHook;
|
|
54
56
|
fontFamilies = {};
|
|
55
57
|
fontStyles = {};
|
|
56
58
|
toast = () => {};
|
|
@@ -74,6 +76,7 @@ export {
|
|
|
74
76
|
ProfileScreen,
|
|
75
77
|
OxyRouter,
|
|
76
78
|
useAuthStore,
|
|
79
|
+
useAccountStore,
|
|
77
80
|
fontFamilies,
|
|
78
81
|
fontStyles,
|
|
79
82
|
toast
|
|
@@ -25,6 +25,13 @@ import { useAuthStore } from '../stores/authStore';
|
|
|
25
25
|
import { Header, GroupedSection } from '../components';
|
|
26
26
|
import { useI18n } from '../hooks/useI18n';
|
|
27
27
|
import QRCode from 'react-native-qrcode-svg';
|
|
28
|
+
import { TTLCache, registerCacheForCleanup } from '../../utils/cache';
|
|
29
|
+
|
|
30
|
+
// Caches for link metadata and location searches
|
|
31
|
+
const linkMetadataCache = new TTLCache<any>(30 * 60 * 1000); // 30 minutes cache for link metadata
|
|
32
|
+
const locationSearchCache = new TTLCache<any[]>(60 * 60 * 1000); // 1 hour cache for location searches
|
|
33
|
+
registerCacheForCleanup(linkMetadataCache);
|
|
34
|
+
registerCacheForCleanup(locationSearchCache);
|
|
28
35
|
|
|
29
36
|
const AccountSettingsScreen: React.FC<BaseScreenProps> = ({
|
|
30
37
|
onClose,
|
|
@@ -369,6 +376,13 @@ const AccountSettingsScreen: React.FC<BaseScreenProps> = ({
|
|
|
369
376
|
|
|
370
377
|
|
|
371
378
|
const fetchLinkMetadata = async (url: string) => {
|
|
379
|
+
// Check cache first
|
|
380
|
+
const cacheKey = url.toLowerCase().trim();
|
|
381
|
+
const cached = linkMetadataCache.get(cacheKey);
|
|
382
|
+
if (cached) {
|
|
383
|
+
return cached;
|
|
384
|
+
}
|
|
385
|
+
|
|
372
386
|
try {
|
|
373
387
|
setIsFetchingMetadata(true);
|
|
374
388
|
console.log('Fetching metadata for URL:', url);
|
|
@@ -377,20 +391,27 @@ const AccountSettingsScreen: React.FC<BaseScreenProps> = ({
|
|
|
377
391
|
const metadata = await oxyServices.fetchLinkMetadata(url);
|
|
378
392
|
console.log('Received metadata:', metadata);
|
|
379
393
|
|
|
380
|
-
|
|
394
|
+
const result = {
|
|
381
395
|
...metadata,
|
|
382
396
|
id: Date.now().toString()
|
|
383
397
|
};
|
|
398
|
+
|
|
399
|
+
// Cache the result
|
|
400
|
+
linkMetadataCache.set(cacheKey, result);
|
|
401
|
+
return result;
|
|
384
402
|
} catch (error) {
|
|
385
403
|
console.error('Error fetching metadata:', error);
|
|
386
404
|
// Fallback to basic metadata
|
|
387
|
-
|
|
405
|
+
const fallback = {
|
|
388
406
|
url: url.startsWith('http') ? url : 'https://' + url,
|
|
389
407
|
title: url.replace(/^https?:\/\//, '').replace(/\/$/, ''),
|
|
390
408
|
description: 'Link',
|
|
391
409
|
image: undefined,
|
|
392
410
|
id: Date.now().toString()
|
|
393
411
|
};
|
|
412
|
+
// Cache fallback too (shorter TTL)
|
|
413
|
+
linkMetadataCache.set(cacheKey, fallback, 5 * 60 * 1000); // 5 minutes for fallbacks
|
|
414
|
+
return fallback;
|
|
394
415
|
} finally {
|
|
395
416
|
setIsFetchingMetadata(false);
|
|
396
417
|
}
|
|
@@ -402,12 +423,23 @@ const AccountSettingsScreen: React.FC<BaseScreenProps> = ({
|
|
|
402
423
|
return;
|
|
403
424
|
}
|
|
404
425
|
|
|
426
|
+
// Check cache first
|
|
427
|
+
const cacheKey = query.toLowerCase().trim();
|
|
428
|
+
const cached = locationSearchCache.get(cacheKey);
|
|
429
|
+
if (cached) {
|
|
430
|
+
setLocationSearchResults(cached);
|
|
431
|
+
return;
|
|
432
|
+
}
|
|
433
|
+
|
|
405
434
|
try {
|
|
406
435
|
setIsSearchingLocations(true);
|
|
407
436
|
const response = await fetch(
|
|
408
437
|
`https://nominatim.openstreetmap.org/search?format=json&q=${encodeURIComponent(query)}&limit=5&addressdetails=1`
|
|
409
438
|
);
|
|
410
439
|
const data = await response.json();
|
|
440
|
+
|
|
441
|
+
// Cache the results
|
|
442
|
+
locationSearchCache.set(cacheKey, data);
|
|
411
443
|
setLocationSearchResults(data);
|
|
412
444
|
} catch (error) {
|
|
413
445
|
console.error('Error searching locations:', error);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type React from 'react';
|
|
2
|
-
import { useState, useEffect } from 'react';
|
|
2
|
+
import { useState, useEffect, useMemo, useCallback } from 'react';
|
|
3
3
|
import {
|
|
4
4
|
View,
|
|
5
5
|
Text,
|
|
@@ -74,8 +74,8 @@ const ModernAccountSwitcherScreen: React.FC<BaseScreenProps> = ({
|
|
|
74
74
|
const isDarkTheme = theme === 'dark';
|
|
75
75
|
const { t } = useI18n();
|
|
76
76
|
|
|
77
|
-
// Modern color scheme
|
|
78
|
-
const colors = {
|
|
77
|
+
// Modern color scheme - memoized for performance
|
|
78
|
+
const colors = useMemo(() => ({
|
|
79
79
|
background: isDarkTheme ? '#000000' : '#FFFFFF',
|
|
80
80
|
surface: isDarkTheme ? '#1C1C1E' : '#F2F2F7',
|
|
81
81
|
card: isDarkTheme ? '#2C2C2E' : '#FFFFFF',
|
|
@@ -87,7 +87,7 @@ const ModernAccountSwitcherScreen: React.FC<BaseScreenProps> = ({
|
|
|
87
87
|
border: isDarkTheme ? '#38383A' : '#C6C6C8',
|
|
88
88
|
activeCard: isDarkTheme ? '#0A84FF20' : '#007AFF15',
|
|
89
89
|
shadow: isDarkTheme ? 'rgba(0,0,0,0.3)' : 'rgba(0,0,0,0.1)',
|
|
90
|
-
};
|
|
90
|
+
}), [isDarkTheme]);
|
|
91
91
|
|
|
92
92
|
// Refresh sessions when screen loads
|
|
93
93
|
useEffect(() => {
|
|
@@ -96,54 +96,72 @@ const ModernAccountSwitcherScreen: React.FC<BaseScreenProps> = ({
|
|
|
96
96
|
}
|
|
97
97
|
}, [isAuthenticated, activeSessionId]);
|
|
98
98
|
|
|
99
|
+
// Memoize session IDs to prevent unnecessary re-renders
|
|
100
|
+
const sessionIds = useMemo(() => sessions.map(s => s.sessionId).join(','), [sessions]);
|
|
101
|
+
|
|
99
102
|
// Load user profiles for sessions
|
|
103
|
+
// Production-ready: Optimized with batching, memoization, and error handling
|
|
100
104
|
useEffect(() => {
|
|
101
|
-
|
|
102
|
-
console.log('AccountSwitcherScreen - sessions length:', sessions.length);
|
|
103
|
-
console.log('AccountSwitcherScreen - activeSessionId:', activeSessionId);
|
|
104
|
-
console.log('AccountSwitcherScreen - isAuthenticated:', isAuthenticated);
|
|
105
|
+
let cancelled = false;
|
|
105
106
|
|
|
106
107
|
const loadUserProfiles = async () => {
|
|
107
|
-
if (!sessions.length || !oxyServices) return;
|
|
108
|
+
if (!sessions.length || !oxyServices || cancelled) return;
|
|
109
|
+
|
|
110
|
+
// Sessions are already deduplicated by userId at the core level (OxyContext)
|
|
111
|
+
const uniqueSessions = sessions;
|
|
108
112
|
|
|
109
|
-
|
|
113
|
+
// Initialize loading state
|
|
114
|
+
setSessionsWithUsers(uniqueSessions.map(session => ({
|
|
110
115
|
...session,
|
|
111
116
|
isLoadingProfile: true,
|
|
112
|
-
}));
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
const
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
117
|
+
})));
|
|
118
|
+
|
|
119
|
+
// Batch load profiles for better performance using batch endpoint
|
|
120
|
+
try {
|
|
121
|
+
const sessionIds = uniqueSessions.map(s => s.sessionId);
|
|
122
|
+
const batchResults = await oxyServices.getUsersBySessions(sessionIds);
|
|
123
|
+
|
|
124
|
+
// Create a map for O(1) lookup
|
|
125
|
+
const userProfileMap = new Map<string, User | null>();
|
|
126
|
+
batchResults.forEach(({ sessionId, user }) => {
|
|
127
|
+
userProfileMap.set(sessionId, user);
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
if (cancelled) return;
|
|
131
|
+
|
|
132
|
+
// Update sessions with loaded profiles - optimized with Map for O(1) lookup
|
|
133
|
+
setSessionsWithUsers(prev => {
|
|
134
|
+
return prev.map(session => {
|
|
135
|
+
const userProfile = userProfileMap.get(session.sessionId);
|
|
136
|
+
return {
|
|
137
|
+
...session,
|
|
138
|
+
userProfile: userProfile || undefined,
|
|
139
|
+
isLoadingProfile: false,
|
|
140
|
+
};
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
} catch (error) {
|
|
144
|
+
if (!cancelled && __DEV__) {
|
|
145
|
+
console.error('Failed to load user profiles:', error);
|
|
146
|
+
}
|
|
147
|
+
if (!cancelled) {
|
|
131
148
|
setSessionsWithUsers(prev =>
|
|
132
|
-
prev.map(s =>
|
|
133
|
-
s.sessionId === session.sessionId
|
|
134
|
-
? { ...s, isLoadingProfile: false }
|
|
135
|
-
: s
|
|
136
|
-
)
|
|
149
|
+
prev.map(s => ({ ...s, isLoadingProfile: false }))
|
|
137
150
|
);
|
|
138
151
|
}
|
|
139
152
|
}
|
|
140
153
|
};
|
|
141
154
|
|
|
142
155
|
loadUserProfiles();
|
|
143
|
-
}, [sessions, oxyServices]);
|
|
144
156
|
|
|
145
|
-
|
|
146
|
-
|
|
157
|
+
return () => {
|
|
158
|
+
cancelled = true;
|
|
159
|
+
};
|
|
160
|
+
}, [sessionIds, oxyServices, sessions]);
|
|
161
|
+
|
|
162
|
+
const handleSwitchSession = useCallback(async (sessionId: string) => {
|
|
163
|
+
if (sessionId === activeSessionId) return; // Already active session
|
|
164
|
+
if (switchingToUserId) return; // Already switching
|
|
147
165
|
|
|
148
166
|
setSwitchingToUserId(sessionId);
|
|
149
167
|
try {
|
|
@@ -153,14 +171,18 @@ const ModernAccountSwitcherScreen: React.FC<BaseScreenProps> = ({
|
|
|
153
171
|
onClose();
|
|
154
172
|
}
|
|
155
173
|
} catch (error) {
|
|
156
|
-
|
|
174
|
+
if (__DEV__) {
|
|
175
|
+
console.error('Switch session failed:', error);
|
|
176
|
+
}
|
|
157
177
|
toast.error(t('accountSwitcher.toasts.switchFailed') || 'There was a problem switching accounts. Please try again.');
|
|
158
178
|
} finally {
|
|
159
179
|
setSwitchingToUserId(null);
|
|
160
180
|
}
|
|
161
|
-
};
|
|
181
|
+
}, [activeSessionId, switchSession, onClose, t, switchingToUserId]);
|
|
182
|
+
|
|
183
|
+
const handleRemoveSession = useCallback(async (sessionId: string, displayName: string) => {
|
|
184
|
+
if (removingUserId) return; // Already removing
|
|
162
185
|
|
|
163
|
-
const handleRemoveSession = async (sessionId: string, displayName: string) => {
|
|
164
186
|
confirmAction(
|
|
165
187
|
t('accountSwitcher.confirms.remove', { displayName }) || `Are you sure you want to remove ${displayName} from this device? You'll need to sign in again to access this account.`,
|
|
166
188
|
async () => {
|
|
@@ -169,16 +191,18 @@ const ModernAccountSwitcherScreen: React.FC<BaseScreenProps> = ({
|
|
|
169
191
|
await removeSession(sessionId);
|
|
170
192
|
toast.success(t('accountSwitcher.toasts.removeSuccess') || 'Account removed successfully!');
|
|
171
193
|
} catch (error) {
|
|
172
|
-
|
|
194
|
+
if (__DEV__) {
|
|
195
|
+
console.error('Remove session failed:', error);
|
|
196
|
+
}
|
|
173
197
|
toast.error(t('accountSwitcher.toasts.removeFailed') || 'There was a problem removing the account. Please try again.');
|
|
174
198
|
} finally {
|
|
175
199
|
setRemovingUserId(null);
|
|
176
200
|
}
|
|
177
201
|
}
|
|
178
202
|
);
|
|
179
|
-
};
|
|
203
|
+
}, [removeSession, t, removingUserId]);
|
|
180
204
|
|
|
181
|
-
const handleLogoutAll =
|
|
205
|
+
const handleLogoutAll = useCallback(() => {
|
|
182
206
|
confirmAction(
|
|
183
207
|
t('accountSwitcher.confirms.logoutAll') || 'Are you sure you want to sign out of all accounts? This will remove all saved accounts from this device.',
|
|
184
208
|
async () => {
|
|
@@ -189,52 +213,58 @@ const ModernAccountSwitcherScreen: React.FC<BaseScreenProps> = ({
|
|
|
189
213
|
onClose();
|
|
190
214
|
}
|
|
191
215
|
} catch (error) {
|
|
192
|
-
|
|
216
|
+
if (__DEV__) {
|
|
217
|
+
console.error('Logout all failed:', error);
|
|
218
|
+
}
|
|
193
219
|
const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
|
|
194
220
|
toast.error(t('accountSwitcher.toasts.signOutAllFailed', { error: errorMessage }) || `There was a problem signing out: ${errorMessage}`);
|
|
195
221
|
}
|
|
196
222
|
}
|
|
197
223
|
);
|
|
198
|
-
};
|
|
224
|
+
}, [logoutAll, onClose, t]);
|
|
199
225
|
|
|
200
|
-
// Device session management functions
|
|
201
|
-
const loadAllDeviceSessions = async () => {
|
|
226
|
+
// Device session management functions - optimized with useCallback
|
|
227
|
+
const loadAllDeviceSessions = useCallback(async () => {
|
|
202
228
|
if (!oxyServices || !activeSessionId) return;
|
|
203
229
|
|
|
204
230
|
setLoadingDeviceSessions(true);
|
|
205
231
|
try {
|
|
206
|
-
// This would call the API to get all device sessions for the current user
|
|
207
232
|
const allSessions = await oxyServices.getDeviceSessions(activeSessionId);
|
|
208
233
|
setDeviceSessions(allSessions || []);
|
|
209
234
|
} catch (error) {
|
|
210
|
-
|
|
235
|
+
if (__DEV__) {
|
|
236
|
+
console.error('Failed to load device sessions:', error);
|
|
237
|
+
}
|
|
211
238
|
toast.error(t('accountSwitcher.toasts.deviceLoadFailed') || 'Failed to load device sessions. Please try again.');
|
|
212
239
|
} finally {
|
|
213
240
|
setLoadingDeviceSessions(false);
|
|
214
241
|
}
|
|
215
|
-
};
|
|
242
|
+
}, [oxyServices, activeSessionId, t]);
|
|
243
|
+
|
|
244
|
+
const handleRemoteSessionLogout = useCallback((sessionId: string, deviceName: string) => {
|
|
245
|
+
if (remotingLogoutSessionId) return; // Already processing
|
|
216
246
|
|
|
217
|
-
const handleRemoteSessionLogout = async (sessionId: string, deviceName: string) => {
|
|
218
247
|
confirmAction(
|
|
219
248
|
t('accountSwitcher.confirms.remoteLogout', { deviceName }) || `Are you sure you want to sign out from "${deviceName}"? This will end the session on that device.`,
|
|
220
249
|
async () => {
|
|
221
250
|
setRemoteLogoutSessionId(sessionId);
|
|
222
251
|
try {
|
|
223
252
|
await oxyServices?.logoutSession(activeSessionId || '', sessionId);
|
|
224
|
-
// Refresh device sessions list
|
|
225
253
|
await loadAllDeviceSessions();
|
|
226
254
|
toast.success(t('accountSwitcher.toasts.remoteSignOutSuccess', { deviceName }) || `Signed out from ${deviceName} successfully!`);
|
|
227
255
|
} catch (error) {
|
|
228
|
-
|
|
256
|
+
if (__DEV__) {
|
|
257
|
+
console.error('Remote logout failed:', error);
|
|
258
|
+
}
|
|
229
259
|
toast.error(t('accountSwitcher.toasts.remoteSignOutFailed') || 'There was a problem signing out from the device. Please try again.');
|
|
230
260
|
} finally {
|
|
231
261
|
setRemoteLogoutSessionId(null);
|
|
232
262
|
}
|
|
233
263
|
}
|
|
234
264
|
);
|
|
235
|
-
};
|
|
265
|
+
}, [activeSessionId, oxyServices, loadAllDeviceSessions, t, remotingLogoutSessionId]);
|
|
236
266
|
|
|
237
|
-
const handleLogoutAllDevices =
|
|
267
|
+
const handleLogoutAllDevices = useCallback(() => {
|
|
238
268
|
const otherDevicesCount = deviceSessions.filter(session => !session.isCurrent).length;
|
|
239
269
|
|
|
240
270
|
if (otherDevicesCount === 0) {
|
|
@@ -242,24 +272,33 @@ const ModernAccountSwitcherScreen: React.FC<BaseScreenProps> = ({
|
|
|
242
272
|
return;
|
|
243
273
|
}
|
|
244
274
|
|
|
275
|
+
if (loggingOutAllDevices) return; // Already processing
|
|
276
|
+
|
|
245
277
|
confirmAction(
|
|
246
278
|
t('accountSwitcher.confirms.logoutOthers', { count: otherDevicesCount }) || `Are you sure you want to sign out from all ${otherDevicesCount} other device(s)? This will end sessions on all other devices except this one.`,
|
|
247
279
|
async () => {
|
|
248
280
|
setLoggingOutAllDevices(true);
|
|
249
281
|
try {
|
|
250
282
|
await oxyServices?.logoutAllDeviceSessions(activeSessionId || '');
|
|
251
|
-
// Refresh device sessions list
|
|
252
283
|
await loadAllDeviceSessions();
|
|
253
284
|
toast.success(t('accountSwitcher.toasts.signOutOthersSuccess') || 'Signed out from all other devices successfully!');
|
|
254
285
|
} catch (error) {
|
|
255
|
-
|
|
286
|
+
if (__DEV__) {
|
|
287
|
+
console.error('Logout all devices failed:', error);
|
|
288
|
+
}
|
|
256
289
|
toast.error(t('accountSwitcher.toasts.signOutOthersFailed') || 'There was a problem signing out from other devices. Please try again.');
|
|
257
290
|
} finally {
|
|
258
291
|
setLoggingOutAllDevices(false);
|
|
259
292
|
}
|
|
260
293
|
}
|
|
261
294
|
);
|
|
262
|
-
};
|
|
295
|
+
}, [deviceSessions, activeSessionId, oxyServices, loadAllDeviceSessions, t, loggingOutAllDevices]);
|
|
296
|
+
|
|
297
|
+
// Memoize filtered sessions for performance
|
|
298
|
+
const otherSessions = useMemo(
|
|
299
|
+
() => sessionsWithUsers.filter(s => s.sessionId !== activeSessionId),
|
|
300
|
+
[sessionsWithUsers, activeSessionId]
|
|
301
|
+
);
|
|
263
302
|
|
|
264
303
|
return (
|
|
265
304
|
<View style={[styles.container, { backgroundColor: '#f2f2f2' }]}>
|
|
@@ -274,10 +313,7 @@ const ModernAccountSwitcherScreen: React.FC<BaseScreenProps> = ({
|
|
|
274
313
|
elevation="subtle"
|
|
275
314
|
rightAction={{
|
|
276
315
|
icon: "refresh",
|
|
277
|
-
onPress:
|
|
278
|
-
console.log('Manual refresh triggered');
|
|
279
|
-
refreshSessions();
|
|
280
|
-
}
|
|
316
|
+
onPress: refreshSessions
|
|
281
317
|
}}
|
|
282
318
|
/>
|
|
283
319
|
|
|
@@ -325,15 +361,13 @@ const ModernAccountSwitcherScreen: React.FC<BaseScreenProps> = ({
|
|
|
325
361
|
)}
|
|
326
362
|
|
|
327
363
|
{/* Other Accounts */}
|
|
328
|
-
{
|
|
364
|
+
{otherSessions.length > 0 && (
|
|
329
365
|
<View style={styles.section}>
|
|
330
366
|
<Text style={styles.sectionTitle}>
|
|
331
|
-
{t('accountSwitcher.sections.otherWithCount', { count:
|
|
367
|
+
{t('accountSwitcher.sections.otherWithCount', { count: otherSessions.length }) || `Other Accounts (${otherSessions.length})`}
|
|
332
368
|
</Text>
|
|
333
369
|
|
|
334
|
-
{
|
|
335
|
-
.filter(s => s.sessionId !== activeSessionId)
|
|
336
|
-
.map((sessionWithUser, index, filteredArray) => {
|
|
370
|
+
{otherSessions.map((sessionWithUser, index, filteredArray) => {
|
|
337
371
|
const isFirst = index === 0;
|
|
338
372
|
const isLast = index === filteredArray.length - 1;
|
|
339
373
|
const isSwitching = switchingToUserId === sessionWithUser.sessionId;
|
|
@@ -346,7 +380,7 @@ const ModernAccountSwitcherScreen: React.FC<BaseScreenProps> = ({
|
|
|
346
380
|
|
|
347
381
|
return (
|
|
348
382
|
<View
|
|
349
|
-
key={sessionWithUser.sessionId}
|
|
383
|
+
key={`session-${sessionWithUser.sessionId}-${index}`}
|
|
350
384
|
style={[
|
|
351
385
|
styles.settingItem,
|
|
352
386
|
isFirst && styles.firstSettingItem,
|
|
@@ -159,7 +159,7 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
159
159
|
return;
|
|
160
160
|
}
|
|
161
161
|
}
|
|
162
|
-
|
|
162
|
+
|
|
163
163
|
// Update file visibility if it differs from defaultVisibility
|
|
164
164
|
const fileVisibility = (file.metadata as any)?.visibility || 'private';
|
|
165
165
|
if (fileVisibility !== defaultVisibility) {
|
|
@@ -171,25 +171,25 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
171
171
|
// Continue anyway - selection shouldn't fail if visibility update fails
|
|
172
172
|
}
|
|
173
173
|
}
|
|
174
|
-
|
|
174
|
+
|
|
175
175
|
// Link file to entity if linkContext is provided
|
|
176
176
|
if (linkContext) {
|
|
177
177
|
try {
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
178
|
+
await oxyServices.assetLink(
|
|
179
|
+
file.id,
|
|
180
|
+
linkContext.app,
|
|
181
|
+
linkContext.entityType,
|
|
182
|
+
linkContext.entityId,
|
|
183
|
+
defaultVisibility,
|
|
184
|
+
(linkContext as any).webhookUrl
|
|
185
|
+
);
|
|
186
186
|
console.log(`Linked file ${file.id} to ${linkContext.app}/${linkContext.entityType}/${linkContext.entityId}`);
|
|
187
187
|
} catch (error) {
|
|
188
188
|
console.error('Failed to link file:', error);
|
|
189
189
|
// Continue anyway - selection shouldn't fail if linking fails
|
|
190
190
|
}
|
|
191
191
|
}
|
|
192
|
-
|
|
192
|
+
|
|
193
193
|
if (!multiSelect) {
|
|
194
194
|
onSelect?.(file);
|
|
195
195
|
if (afterSelect === 'back') {
|
|
@@ -220,7 +220,7 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
220
220
|
const map: Record<string, FileMetadata> = {};
|
|
221
221
|
files.forEach(f => { map[f.id] = f; });
|
|
222
222
|
const chosen = Array.from(selectedIds).map(id => map[id]).filter(Boolean);
|
|
223
|
-
|
|
223
|
+
|
|
224
224
|
// Update visibility and link files if needed
|
|
225
225
|
const updatePromises = chosen.map(async (file) => {
|
|
226
226
|
// Update visibility if needed
|
|
@@ -233,7 +233,7 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
233
233
|
console.error(`Failed to update visibility for ${file.id}:`, error);
|
|
234
234
|
}
|
|
235
235
|
}
|
|
236
|
-
|
|
236
|
+
|
|
237
237
|
// Link file to entity if linkContext provided
|
|
238
238
|
if (linkContext) {
|
|
239
239
|
try {
|
|
@@ -251,10 +251,10 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
251
251
|
}
|
|
252
252
|
}
|
|
253
253
|
});
|
|
254
|
-
|
|
254
|
+
|
|
255
255
|
// Wait for all updates (but don't block on failures)
|
|
256
256
|
await Promise.allSettled(updatePromises);
|
|
257
|
-
|
|
257
|
+
|
|
258
258
|
onConfirmSelection?.(chosen);
|
|
259
259
|
onClose?.();
|
|
260
260
|
}, [selectMode, multiSelect, selectedIds, files, onConfirmSelection, onClose, defaultVisibility, oxyServices, linkContext]);
|
|
@@ -1974,7 +1974,7 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
1974
1974
|
|
|
1975
1975
|
{/* Uploading banner overlay */}
|
|
1976
1976
|
{!selectMode && uploading && (
|
|
1977
|
-
<View
|
|
1977
|
+
<View style={[styles.uploadBannerContainer, { pointerEvents: 'none' }]}>
|
|
1978
1978
|
<View style={[styles.uploadBanner, { backgroundColor: themeStyles.isDarkTheme ? '#222831EE' : '#FFFFFFEE', borderColor: themeStyles.borderColor }]}>
|
|
1979
1979
|
<Ionicons name="cloud-upload" size={18} color={themeStyles.primaryColor} />
|
|
1980
1980
|
<Text style={[styles.uploadBannerText, { color: themeStyles.textColor }]}>Uploading{uploadProgress ? ` ${uploadProgress.current}/${uploadProgress.total}` : '...'}</Text>
|