@oxyhq/services 5.11.12 → 5.12.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 +48 -7
- package/lib/commonjs/core/OxyServices.js +168 -5
- package/lib/commonjs/core/OxyServices.js.map +1 -1
- package/lib/commonjs/i18n/index.js +40 -0
- package/lib/commonjs/i18n/index.js.map +1 -0
- package/lib/commonjs/i18n/locales/en-US.json +681 -0
- package/lib/commonjs/i18n/locales/es-ES.json +689 -0
- package/lib/commonjs/ui/components/GroupedItem.js +2 -1
- package/lib/commonjs/ui/components/GroupedItem.js.map +1 -1
- package/lib/commonjs/ui/components/Header.js +4 -3
- package/lib/commonjs/ui/components/Header.js.map +1 -1
- package/lib/commonjs/ui/components/OxyProvider.js +110 -103
- package/lib/commonjs/ui/components/OxyProvider.js.map +1 -1
- package/lib/commonjs/ui/components/ProfileCard.js +5 -1
- package/lib/commonjs/ui/components/ProfileCard.js.map +1 -1
- package/lib/commonjs/ui/components/Section.js +1 -1
- package/lib/commonjs/ui/components/StepBasedScreen.js +16 -16
- package/lib/commonjs/ui/components/StepBasedScreen.js.map +1 -1
- package/lib/commonjs/ui/components/internal/GroupedPillButtons.js +15 -3
- package/lib/commonjs/ui/components/internal/GroupedPillButtons.js.map +1 -1
- package/lib/commonjs/ui/components/internal/PinInput.js +10 -4
- package/lib/commonjs/ui/components/internal/PinInput.js.map +1 -1
- package/lib/commonjs/ui/context/OxyContext.js +128 -12
- package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
- package/lib/commonjs/ui/hooks/useI18n.js +22 -0
- package/lib/commonjs/ui/hooks/useI18n.js.map +1 -0
- package/lib/commonjs/ui/navigation/OxyRouter.js +11 -131
- package/lib/commonjs/ui/navigation/OxyRouter.js.map +1 -1
- package/lib/commonjs/ui/navigation/routes.js +127 -0
- package/lib/commonjs/ui/navigation/routes.js.map +1 -0
- package/lib/commonjs/ui/navigation/types.js +7 -0
- package/lib/commonjs/ui/navigation/types.js.map +1 -1
- package/lib/commonjs/ui/screens/AccountCenterScreen.js +55 -47
- package/lib/commonjs/ui/screens/AccountCenterScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/AccountOverviewScreen.js +69 -61
- package/lib/commonjs/ui/screens/AccountOverviewScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/AccountSettingsScreen.js +378 -37
- package/lib/commonjs/ui/screens/AccountSettingsScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/AccountSwitcherScreen.js +52 -34
- package/lib/commonjs/ui/screens/AccountSwitcherScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/FeedbackScreen.js +40 -36
- package/lib/commonjs/ui/screens/FeedbackScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/LanguageSelectorScreen.js +105 -78
- package/lib/commonjs/ui/screens/LanguageSelectorScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/PaymentGatewayScreen.js +1 -1
- package/lib/commonjs/ui/screens/PaymentGatewayScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/PremiumSubscriptionScreen.js +92 -60
- package/lib/commonjs/ui/screens/PremiumSubscriptionScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/ProfileScreen.js +21 -11
- package/lib/commonjs/ui/screens/ProfileScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/RecoverAccountScreen.js +30 -8
- package/lib/commonjs/ui/screens/RecoverAccountScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/SignInScreen.js +47 -26
- package/lib/commonjs/ui/screens/SignInScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/WelcomeNewUserScreen.js +31 -24
- package/lib/commonjs/ui/screens/WelcomeNewUserScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/internal/SignInPasswordStep.js +11 -7
- package/lib/commonjs/ui/screens/internal/SignInPasswordStep.js.map +1 -1
- package/lib/commonjs/ui/screens/internal/SignInUsernameStep.js +12 -6
- package/lib/commonjs/ui/screens/internal/SignInUsernameStep.js.map +1 -1
- package/lib/commonjs/ui/screens/karma/KarmaAboutScreen.js +11 -7
- package/lib/commonjs/ui/screens/karma/KarmaAboutScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/karma/KarmaCenterScreen.js +15 -11
- package/lib/commonjs/ui/screens/karma/KarmaCenterScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/karma/KarmaFAQScreen.js +19 -27
- package/lib/commonjs/ui/screens/karma/KarmaFAQScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/karma/KarmaLeaderboardScreen.js +8 -4
- package/lib/commonjs/ui/screens/karma/KarmaLeaderboardScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/karma/KarmaRewardsScreen.js +14 -10
- package/lib/commonjs/ui/screens/karma/KarmaRewardsScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/karma/KarmaRulesScreen.js +7 -3
- package/lib/commonjs/ui/screens/karma/KarmaRulesScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/steps/RecoverRequestStep.js +19 -14
- package/lib/commonjs/ui/screens/steps/RecoverRequestStep.js.map +1 -1
- package/lib/commonjs/ui/screens/steps/RecoverResetPasswordStep.js +130 -0
- package/lib/commonjs/ui/screens/steps/RecoverResetPasswordStep.js.map +1 -0
- package/lib/commonjs/ui/screens/steps/RecoverSuccessStep.js +13 -13
- package/lib/commonjs/ui/screens/steps/RecoverSuccessStep.js.map +1 -1
- package/lib/commonjs/ui/screens/steps/RecoverVerifyStep.js +14 -20
- package/lib/commonjs/ui/screens/steps/RecoverVerifyStep.js.map +1 -1
- package/lib/commonjs/ui/screens/steps/SignInPasswordStep.js +22 -8
- package/lib/commonjs/ui/screens/steps/SignInPasswordStep.js.map +1 -1
- package/lib/commonjs/ui/screens/steps/SignInTotpStep.js +161 -0
- package/lib/commonjs/ui/screens/steps/SignInTotpStep.js.map +1 -0
- package/lib/commonjs/ui/screens/steps/SignInUsernameStep.js +12 -6
- package/lib/commonjs/ui/screens/steps/SignInUsernameStep.js.map +1 -1
- package/lib/commonjs/ui/screens/steps/SignUpIdentityStep.js +10 -6
- package/lib/commonjs/ui/screens/steps/SignUpIdentityStep.js.map +1 -1
- package/lib/commonjs/ui/screens/steps/SignUpSecurityStep.js +10 -6
- package/lib/commonjs/ui/screens/steps/SignUpSecurityStep.js.map +1 -1
- package/lib/commonjs/ui/screens/steps/SignUpSummaryStep.js +34 -4
- package/lib/commonjs/ui/screens/steps/SignUpSummaryStep.js.map +1 -1
- package/lib/commonjs/ui/screens/steps/SignUpWelcomeStep.js +9 -10
- package/lib/commonjs/ui/screens/steps/SignUpWelcomeStep.js.map +1 -1
- package/lib/commonjs/ui/styles/authStyles.js +1 -2
- package/lib/commonjs/ui/styles/authStyles.js.map +1 -1
- package/lib/commonjs/utils/deviceManager.js +1 -1
- package/lib/commonjs/utils/deviceManager.js.map +1 -1
- package/lib/commonjs/utils/validationUtils.js +4 -2
- package/lib/commonjs/utils/validationUtils.js.map +1 -1
- package/lib/module/core/OxyServices.js +168 -5
- package/lib/module/core/OxyServices.js.map +1 -1
- package/lib/module/i18n/index.js +35 -0
- package/lib/module/i18n/index.js.map +1 -0
- package/lib/module/i18n/locales/en-US.json +681 -0
- package/lib/module/i18n/locales/es-ES.json +689 -0
- package/lib/module/ui/components/GroupedItem.js +2 -1
- package/lib/module/ui/components/GroupedItem.js.map +1 -1
- package/lib/module/ui/components/Header.js +4 -3
- package/lib/module/ui/components/Header.js.map +1 -1
- package/lib/module/ui/components/OxyProvider.js +109 -103
- package/lib/module/ui/components/OxyProvider.js.map +1 -1
- package/lib/module/ui/components/ProfileCard.js +5 -1
- package/lib/module/ui/components/ProfileCard.js.map +1 -1
- package/lib/module/ui/components/Section.js +1 -1
- package/lib/module/ui/components/StepBasedScreen.js +16 -16
- package/lib/module/ui/components/StepBasedScreen.js.map +1 -1
- package/lib/module/ui/components/internal/GroupedPillButtons.js +15 -3
- package/lib/module/ui/components/internal/GroupedPillButtons.js.map +1 -1
- package/lib/module/ui/components/internal/PinInput.js +9 -4
- package/lib/module/ui/components/internal/PinInput.js.map +1 -1
- package/lib/module/ui/context/OxyContext.js +128 -12
- package/lib/module/ui/context/OxyContext.js.map +1 -1
- package/lib/module/ui/hooks/useI18n.js +18 -0
- package/lib/module/ui/hooks/useI18n.js.map +1 -0
- package/lib/module/ui/navigation/OxyRouter.js +7 -124
- package/lib/module/ui/navigation/OxyRouter.js.map +1 -1
- package/lib/module/ui/navigation/routes.js +122 -0
- package/lib/module/ui/navigation/routes.js.map +1 -0
- package/lib/module/ui/navigation/types.js +19 -1
- package/lib/module/ui/navigation/types.js.map +1 -1
- package/lib/module/ui/screens/AccountCenterScreen.js +55 -47
- package/lib/module/ui/screens/AccountCenterScreen.js.map +1 -1
- package/lib/module/ui/screens/AccountOverviewScreen.js +69 -61
- package/lib/module/ui/screens/AccountOverviewScreen.js.map +1 -1
- package/lib/module/ui/screens/AccountSettingsScreen.js +378 -37
- package/lib/module/ui/screens/AccountSettingsScreen.js.map +1 -1
- package/lib/module/ui/screens/AccountSwitcherScreen.js +52 -34
- package/lib/module/ui/screens/AccountSwitcherScreen.js.map +1 -1
- package/lib/module/ui/screens/FeedbackScreen.js +40 -36
- package/lib/module/ui/screens/FeedbackScreen.js.map +1 -1
- package/lib/module/ui/screens/LanguageSelectorScreen.js +107 -80
- package/lib/module/ui/screens/LanguageSelectorScreen.js.map +1 -1
- package/lib/module/ui/screens/PaymentGatewayScreen.js +1 -1
- package/lib/module/ui/screens/PaymentGatewayScreen.js.map +1 -1
- package/lib/module/ui/screens/PremiumSubscriptionScreen.js +92 -60
- package/lib/module/ui/screens/PremiumSubscriptionScreen.js.map +1 -1
- package/lib/module/ui/screens/ProfileScreen.js +21 -11
- package/lib/module/ui/screens/ProfileScreen.js.map +1 -1
- package/lib/module/ui/screens/RecoverAccountScreen.js +30 -8
- package/lib/module/ui/screens/RecoverAccountScreen.js.map +1 -1
- package/lib/module/ui/screens/SignInScreen.js +47 -26
- package/lib/module/ui/screens/SignInScreen.js.map +1 -1
- package/lib/module/ui/screens/WelcomeNewUserScreen.js +31 -24
- package/lib/module/ui/screens/WelcomeNewUserScreen.js.map +1 -1
- package/lib/module/ui/screens/internal/SignInPasswordStep.js +11 -7
- package/lib/module/ui/screens/internal/SignInPasswordStep.js.map +1 -1
- package/lib/module/ui/screens/internal/SignInUsernameStep.js +12 -6
- package/lib/module/ui/screens/internal/SignInUsernameStep.js.map +1 -1
- package/lib/module/ui/screens/karma/KarmaAboutScreen.js +11 -7
- package/lib/module/ui/screens/karma/KarmaAboutScreen.js.map +1 -1
- package/lib/module/ui/screens/karma/KarmaCenterScreen.js +15 -11
- package/lib/module/ui/screens/karma/KarmaCenterScreen.js.map +1 -1
- package/lib/module/ui/screens/karma/KarmaFAQScreen.js +19 -27
- package/lib/module/ui/screens/karma/KarmaFAQScreen.js.map +1 -1
- package/lib/module/ui/screens/karma/KarmaLeaderboardScreen.js +8 -4
- package/lib/module/ui/screens/karma/KarmaLeaderboardScreen.js.map +1 -1
- package/lib/module/ui/screens/karma/KarmaRewardsScreen.js +14 -10
- package/lib/module/ui/screens/karma/KarmaRewardsScreen.js.map +1 -1
- package/lib/module/ui/screens/karma/KarmaRulesScreen.js +7 -3
- package/lib/module/ui/screens/karma/KarmaRulesScreen.js.map +1 -1
- package/lib/module/ui/screens/steps/RecoverRequestStep.js +19 -14
- package/lib/module/ui/screens/steps/RecoverRequestStep.js.map +1 -1
- package/lib/module/ui/screens/steps/RecoverResetPasswordStep.js +125 -0
- package/lib/module/ui/screens/steps/RecoverResetPasswordStep.js.map +1 -0
- package/lib/module/ui/screens/steps/RecoverSuccessStep.js +13 -13
- package/lib/module/ui/screens/steps/RecoverSuccessStep.js.map +1 -1
- package/lib/module/ui/screens/steps/RecoverVerifyStep.js +14 -20
- package/lib/module/ui/screens/steps/RecoverVerifyStep.js.map +1 -1
- package/lib/module/ui/screens/steps/SignInPasswordStep.js +22 -8
- package/lib/module/ui/screens/steps/SignInPasswordStep.js.map +1 -1
- package/lib/module/ui/screens/steps/SignInTotpStep.js +156 -0
- package/lib/module/ui/screens/steps/SignInTotpStep.js.map +1 -0
- package/lib/module/ui/screens/steps/SignInUsernameStep.js +12 -6
- package/lib/module/ui/screens/steps/SignInUsernameStep.js.map +1 -1
- package/lib/module/ui/screens/steps/SignUpIdentityStep.js +10 -6
- package/lib/module/ui/screens/steps/SignUpIdentityStep.js.map +1 -1
- package/lib/module/ui/screens/steps/SignUpSecurityStep.js +10 -6
- package/lib/module/ui/screens/steps/SignUpSecurityStep.js.map +1 -1
- package/lib/module/ui/screens/steps/SignUpSummaryStep.js +34 -4
- package/lib/module/ui/screens/steps/SignUpSummaryStep.js.map +1 -1
- package/lib/module/ui/screens/steps/SignUpWelcomeStep.js +9 -10
- package/lib/module/ui/screens/steps/SignUpWelcomeStep.js.map +1 -1
- package/lib/module/ui/styles/authStyles.js +1 -2
- package/lib/module/ui/styles/authStyles.js.map +1 -1
- package/lib/module/utils/deviceManager.js +1 -1
- package/lib/module/utils/deviceManager.js.map +1 -1
- package/lib/module/utils/validationUtils.js +4 -2
- package/lib/module/utils/validationUtils.js.map +1 -1
- package/lib/typescript/core/OxyServices.d.ts +58 -3
- package/lib/typescript/core/OxyServices.d.ts.map +1 -1
- package/lib/typescript/i18n/index.d.ts +4 -0
- package/lib/typescript/i18n/index.d.ts.map +1 -0
- package/lib/typescript/models/interfaces.d.ts +4 -0
- package/lib/typescript/models/interfaces.d.ts.map +1 -1
- package/lib/typescript/ui/components/GroupedItem.d.ts.map +1 -1
- package/lib/typescript/ui/components/Header.d.ts.map +1 -1
- package/lib/typescript/ui/components/OxyProvider.d.ts +1 -1
- package/lib/typescript/ui/components/OxyProvider.d.ts.map +1 -1
- package/lib/typescript/ui/components/ProfileCard.d.ts.map +1 -1
- package/lib/typescript/ui/components/StepBasedScreen.d.ts +2 -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/PinInput.d.ts +6 -3
- package/lib/typescript/ui/components/internal/PinInput.d.ts.map +1 -1
- package/lib/typescript/ui/context/OxyContext.d.ts +7 -4
- package/lib/typescript/ui/context/OxyContext.d.ts.map +1 -1
- package/lib/typescript/ui/hooks/useI18n.d.ts +5 -0
- package/lib/typescript/ui/hooks/useI18n.d.ts.map +1 -0
- package/lib/typescript/ui/navigation/OxyRouter.d.ts.map +1 -1
- package/lib/typescript/ui/navigation/routes.d.ts +9 -0
- package/lib/typescript/ui/navigation/routes.d.ts.map +1 -0
- package/lib/typescript/ui/navigation/types.d.ts +24 -10
- package/lib/typescript/ui/navigation/types.d.ts.map +1 -1
- package/lib/typescript/ui/screens/AccountCenterScreen.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/FeedbackScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/LanguageSelectorScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/PremiumSubscriptionScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/ProfileScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/RecoverAccountScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/SignInScreen.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 +2 -1
- package/lib/typescript/ui/screens/internal/SignInPasswordStep.d.ts.map +1 -1
- package/lib/typescript/ui/screens/internal/SignInUsernameStep.d.ts.map +1 -1
- package/lib/typescript/ui/screens/karma/KarmaAboutScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/karma/KarmaCenterScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/karma/KarmaFAQScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/karma/KarmaLeaderboardScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/karma/KarmaRewardsScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/karma/KarmaRulesScreen.d.ts.map +1 -1
- package/lib/typescript/ui/screens/steps/RecoverRequestStep.d.ts +4 -1
- package/lib/typescript/ui/screens/steps/RecoverRequestStep.d.ts.map +1 -1
- package/lib/typescript/ui/screens/steps/RecoverResetPasswordStep.d.ts +24 -0
- package/lib/typescript/ui/screens/steps/RecoverResetPasswordStep.d.ts.map +1 -0
- package/lib/typescript/ui/screens/steps/RecoverSuccessStep.d.ts +2 -1
- package/lib/typescript/ui/screens/steps/RecoverSuccessStep.d.ts.map +1 -1
- package/lib/typescript/ui/screens/steps/RecoverVerifyStep.d.ts +3 -1
- package/lib/typescript/ui/screens/steps/RecoverVerifyStep.d.ts.map +1 -1
- package/lib/typescript/ui/screens/steps/SignInPasswordStep.d.ts +1 -0
- package/lib/typescript/ui/screens/steps/SignInPasswordStep.d.ts.map +1 -1
- package/lib/typescript/ui/screens/steps/SignInTotpStep.d.ts +19 -0
- package/lib/typescript/ui/screens/steps/SignInTotpStep.d.ts.map +1 -0
- package/lib/typescript/ui/screens/steps/SignInUsernameStep.d.ts +2 -1
- package/lib/typescript/ui/screens/steps/SignInUsernameStep.d.ts.map +1 -1
- package/lib/typescript/ui/screens/steps/SignUpIdentityStep.d.ts +2 -1
- package/lib/typescript/ui/screens/steps/SignUpIdentityStep.d.ts.map +1 -1
- package/lib/typescript/ui/screens/steps/SignUpSecurityStep.d.ts +2 -1
- package/lib/typescript/ui/screens/steps/SignUpSecurityStep.d.ts.map +1 -1
- package/lib/typescript/ui/screens/steps/SignUpSummaryStep.d.ts +2 -1
- package/lib/typescript/ui/screens/steps/SignUpSummaryStep.d.ts.map +1 -1
- package/lib/typescript/ui/screens/steps/SignUpWelcomeStep.d.ts +2 -1
- package/lib/typescript/ui/screens/steps/SignUpWelcomeStep.d.ts.map +1 -1
- package/lib/typescript/ui/styles/authStyles.d.ts +0 -1
- package/lib/typescript/ui/styles/authStyles.d.ts.map +1 -1
- package/lib/typescript/utils/validationUtils.d.ts.map +1 -1
- package/package.json +48 -14
- package/src/core/OxyServices.ts +143 -9
- package/src/i18n/index.ts +39 -0
- package/src/i18n/locales/en-US.json +681 -0
- package/src/i18n/locales/es-ES.json +689 -0
- package/src/models/interfaces.ts +6 -1
- package/src/ui/components/GroupedItem.tsx +2 -1
- package/src/ui/components/Header.tsx +4 -3
- package/src/ui/components/OxyProvider.tsx +105 -112
- package/src/ui/components/ProfileCard.tsx +5 -1
- package/src/ui/components/Section.tsx +1 -1
- package/src/ui/components/StepBasedScreen.tsx +16 -13
- package/src/ui/components/internal/GroupedPillButtons.tsx +10 -6
- package/src/ui/components/internal/PinInput.tsx +15 -6
- package/src/ui/context/OxyContext.tsx +123 -20
- package/src/ui/hooks/useI18n.ts +12 -0
- package/src/ui/navigation/OxyRouter.tsx +15 -134
- package/src/ui/navigation/routes.ts +153 -0
- package/src/ui/navigation/types.ts +28 -10
- package/src/ui/screens/AccountCenterScreen.tsx +47 -45
- package/src/ui/screens/AccountOverviewScreen.tsx +68 -70
- package/src/ui/screens/AccountSettingsScreen.tsx +265 -41
- package/src/ui/screens/AccountSwitcherScreen.tsx +35 -33
- package/src/ui/screens/FeedbackScreen.tsx +39 -37
- package/src/ui/screens/LanguageSelectorScreen.tsx +99 -70
- package/src/ui/screens/PaymentGatewayScreen.tsx +5 -5
- package/src/ui/screens/PremiumSubscriptionScreen.tsx +56 -54
- package/src/ui/screens/ProfileScreen.tsx +14 -8
- package/src/ui/screens/RecoverAccountScreen.tsx +29 -8
- package/src/ui/screens/SignInScreen.tsx +39 -30
- package/src/ui/screens/WelcomeNewUserScreen.tsx +31 -17
- package/src/ui/screens/internal/SignInPasswordStep.tsx +11 -8
- package/src/ui/screens/internal/SignInUsernameStep.tsx +10 -8
- package/src/ui/screens/karma/KarmaAboutScreen.tsx +23 -11
- package/src/ui/screens/karma/KarmaCenterScreen.tsx +21 -11
- package/src/ui/screens/karma/KarmaFAQScreen.tsx +15 -33
- package/src/ui/screens/karma/KarmaLeaderboardScreen.tsx +6 -4
- package/src/ui/screens/karma/KarmaRewardsScreen.tsx +28 -10
- package/src/ui/screens/karma/KarmaRulesScreen.tsx +5 -3
- package/src/ui/screens/steps/RecoverRequestStep.tsx +20 -17
- package/src/ui/screens/steps/RecoverResetPasswordStep.tsx +133 -0
- package/src/ui/screens/steps/RecoverSuccessStep.tsx +12 -19
- package/src/ui/screens/steps/RecoverVerifyStep.tsx +15 -24
- package/src/ui/screens/steps/SignInPasswordStep.tsx +19 -6
- package/src/ui/screens/steps/SignInTotpStep.tsx +129 -0
- package/src/ui/screens/steps/SignInUsernameStep.tsx +11 -10
- package/src/ui/screens/steps/SignUpIdentityStep.tsx +10 -11
- package/src/ui/screens/steps/SignUpSecurityStep.tsx +10 -11
- package/src/ui/screens/steps/SignUpSummaryStep.tsx +24 -9
- package/src/ui/screens/steps/SignUpWelcomeStep.tsx +8 -14
- package/src/ui/styles/authStyles.ts +0 -1
- package/src/utils/deviceManager.ts +1 -1
- package/src/utils/validationUtils.ts +5 -3
|
@@ -3,37 +3,13 @@ import { View, Text, StyleSheet, ScrollView, Platform, TouchableOpacity, TextInp
|
|
|
3
3
|
import type { BaseScreenProps } from '../../navigation/types';
|
|
4
4
|
import { Ionicons } from '@expo/vector-icons';
|
|
5
5
|
import { Header } from '../../components';
|
|
6
|
+
import { useI18n } from '../../hooks/useI18n';
|
|
6
7
|
|
|
7
8
|
if (Platform.OS === 'android' && UIManager.setLayoutAnimationEnabledExperimental) {
|
|
8
9
|
UIManager.setLayoutAnimationEnabledExperimental(true);
|
|
9
10
|
}
|
|
10
11
|
|
|
11
|
-
const
|
|
12
|
-
{
|
|
13
|
-
q: 'What is karma?',
|
|
14
|
-
a: 'Karma is a recognition of your positive actions in the Oxy Ecosystem. It cannot be sent or received directly.'
|
|
15
|
-
},
|
|
16
|
-
{
|
|
17
|
-
q: 'How do I earn karma?',
|
|
18
|
-
a: 'By helping others, reporting bugs, contributing content, and participating in community events.'
|
|
19
|
-
},
|
|
20
|
-
{
|
|
21
|
-
q: 'Can I lose karma?',
|
|
22
|
-
a: 'Karma may be reduced for negative actions or breaking community rules.'
|
|
23
|
-
},
|
|
24
|
-
{
|
|
25
|
-
q: 'What can I do with karma?',
|
|
26
|
-
a: 'Unlock rewards, badges, and special features as you earn more karma.'
|
|
27
|
-
},
|
|
28
|
-
{
|
|
29
|
-
q: 'Can I transfer karma to others?',
|
|
30
|
-
a: 'No, karma cannot be sent or received. It is only earned by your actions.'
|
|
31
|
-
},
|
|
32
|
-
{
|
|
33
|
-
q: 'How do I get support?',
|
|
34
|
-
a: 'Contact Oxy support via the app or website for any karma-related questions.'
|
|
35
|
-
},
|
|
36
|
-
];
|
|
12
|
+
const FAQ_KEYS = ['what', 'earn', 'lose', 'use', 'transfer', 'support'] as const;
|
|
37
13
|
|
|
38
14
|
/**
|
|
39
15
|
* KarmaFAQScreen - Optimized for performance
|
|
@@ -45,6 +21,7 @@ const FAQS = [
|
|
|
45
21
|
* - React.memo wrapper to prevent re-renders when props haven't changed
|
|
46
22
|
*/
|
|
47
23
|
const KarmaFAQScreen: React.FC<BaseScreenProps> = ({ goBack, theme }) => {
|
|
24
|
+
const { t } = useI18n();
|
|
48
25
|
const [expanded, setExpanded] = useState<number | null>(0);
|
|
49
26
|
const [search, setSearch] = useState('');
|
|
50
27
|
|
|
@@ -63,14 +40,19 @@ const KarmaFAQScreen: React.FC<BaseScreenProps> = ({ goBack, theme }) => {
|
|
|
63
40
|
}, [theme]);
|
|
64
41
|
|
|
65
42
|
// Memoize filtered FAQs to prevent filtering on every render
|
|
43
|
+
const faqs = useMemo(() => FAQ_KEYS.map(key => ({
|
|
44
|
+
q: t(`karma.faq.items.${key}.q`) || '',
|
|
45
|
+
a: t(`karma.faq.items.${key}.a`) || '',
|
|
46
|
+
})), [t]);
|
|
47
|
+
|
|
66
48
|
const filteredFaqs = useMemo(() => {
|
|
67
|
-
if (!search.trim()) return
|
|
49
|
+
if (!search.trim()) return faqs;
|
|
68
50
|
const searchLower = search.toLowerCase();
|
|
69
|
-
return
|
|
51
|
+
return faqs.filter(faq =>
|
|
70
52
|
faq.q.toLowerCase().includes(searchLower) ||
|
|
71
53
|
faq.a.toLowerCase().includes(searchLower)
|
|
72
54
|
);
|
|
73
|
-
}, [search]);
|
|
55
|
+
}, [search, faqs]);
|
|
74
56
|
|
|
75
57
|
// Memoize toggle handler to prevent recreation on every render
|
|
76
58
|
const handleToggle = useCallback((idx: number) => {
|
|
@@ -81,8 +63,8 @@ const KarmaFAQScreen: React.FC<BaseScreenProps> = ({ goBack, theme }) => {
|
|
|
81
63
|
return (
|
|
82
64
|
<View style={[styles.container, { backgroundColor: themeStyles.backgroundColor }]}>
|
|
83
65
|
<Header
|
|
84
|
-
title=
|
|
85
|
-
subtitle=
|
|
66
|
+
title={t('karma.faq.title') || 'Karma FAQ'}
|
|
67
|
+
subtitle={t('karma.faq.subtitle') || 'Frequently asked questions about karma'}
|
|
86
68
|
subtitleVariant="muted"
|
|
87
69
|
theme={theme}
|
|
88
70
|
onBack={goBack}
|
|
@@ -92,7 +74,7 @@ const KarmaFAQScreen: React.FC<BaseScreenProps> = ({ goBack, theme }) => {
|
|
|
92
74
|
<Ionicons name="search-outline" size={20} color={themeStyles.primaryColor} style={{ marginRight: 8 }} />
|
|
93
75
|
<TextInput
|
|
94
76
|
style={[styles.searchInput, { color: themeStyles.textColor }]}
|
|
95
|
-
placeholder=
|
|
77
|
+
placeholder={t('karma.faq.search') || 'Search FAQ...'}
|
|
96
78
|
placeholderTextColor={themeStyles.isDarkTheme ? '#aaa' : '#888'}
|
|
97
79
|
value={search}
|
|
98
80
|
onChangeText={setSearch}
|
|
@@ -102,7 +84,7 @@ const KarmaFAQScreen: React.FC<BaseScreenProps> = ({ goBack, theme }) => {
|
|
|
102
84
|
<ScrollView contentContainerStyle={styles.contentContainer}>
|
|
103
85
|
{filteredFaqs.length === 0 ? (
|
|
104
86
|
<Text style={[styles.noResults, { color: themeStyles.textColor }]}>
|
|
105
|
-
No FAQ items found matching "{search}"
|
|
87
|
+
{t('karma.faq.noResults', { query: search }) || `No FAQ items found matching "${search}"`}
|
|
106
88
|
</Text>
|
|
107
89
|
) : (
|
|
108
90
|
filteredFaqs.map((faq, idx) => (
|
|
@@ -5,9 +5,11 @@ import type { BaseScreenProps } from '../../navigation/types';
|
|
|
5
5
|
import { useOxy } from '../../context/OxyContext';
|
|
6
6
|
import Avatar from '../../components/Avatar';
|
|
7
7
|
import { Header } from '../../components';
|
|
8
|
+
import { useI18n } from '../../hooks/useI18n';
|
|
8
9
|
|
|
9
10
|
const KarmaLeaderboardScreen: React.FC<BaseScreenProps> = ({ goBack, theme, navigate }) => {
|
|
10
11
|
const { oxyServices } = useOxy();
|
|
12
|
+
const { t } = useI18n();
|
|
11
13
|
const [leaderboard, setLeaderboard] = useState<any[]>([]);
|
|
12
14
|
const [isLoading, setIsLoading] = useState(true);
|
|
13
15
|
const [error, setError] = useState<string | null>(null);
|
|
@@ -29,8 +31,8 @@ const KarmaLeaderboardScreen: React.FC<BaseScreenProps> = ({ goBack, theme, navi
|
|
|
29
31
|
return (
|
|
30
32
|
<View style={[styles.container, { backgroundColor }]}>
|
|
31
33
|
<Header
|
|
32
|
-
title=
|
|
33
|
-
subtitle=
|
|
34
|
+
title={t('karma.leaderboard.title') || 'Karma Leaderboard'}
|
|
35
|
+
subtitle={t('karma.leaderboard.subtitle') || 'Top contributors in the community'}
|
|
34
36
|
theme={theme}
|
|
35
37
|
onBack={goBack}
|
|
36
38
|
elevation="subtle"
|
|
@@ -42,13 +44,13 @@ const KarmaLeaderboardScreen: React.FC<BaseScreenProps> = ({ goBack, theme, navi
|
|
|
42
44
|
) : (
|
|
43
45
|
<ScrollView contentContainerStyle={styles.listContainer}>
|
|
44
46
|
{leaderboard.length === 0 ? (
|
|
45
|
-
<Text style={[styles.placeholder, { color: textColor }]}>No leaderboard data
|
|
47
|
+
<Text style={[styles.placeholder, { color: textColor }]}>{t('karma.leaderboard.empty') || 'No leaderboard data.'}</Text>
|
|
46
48
|
) : (
|
|
47
49
|
leaderboard.map((entry, idx) => (
|
|
48
50
|
<TouchableOpacity
|
|
49
51
|
key={entry.userId}
|
|
50
52
|
style={[styles.row, idx < 3 && { backgroundColor: '#f7eaff' }]}
|
|
51
|
-
onPress={() => navigate && navigate('
|
|
53
|
+
onPress={() => navigate && navigate('Profile', { userId: entry.userId, username: entry.username })}
|
|
52
54
|
activeOpacity={0.7}
|
|
53
55
|
>
|
|
54
56
|
<Text style={[styles.rank, { color: primaryColor }]}>{idx + 1}</Text>
|
|
@@ -2,8 +2,10 @@ import type React from 'react';
|
|
|
2
2
|
import { View, Text, StyleSheet, ScrollView, Platform } from 'react-native';
|
|
3
3
|
import type { BaseScreenProps } from '../../navigation/types';
|
|
4
4
|
import { Header } from '../../components';
|
|
5
|
+
import { useI18n } from '../../hooks/useI18n';
|
|
5
6
|
|
|
6
7
|
const KarmaRewardsScreen: React.FC<BaseScreenProps> = ({ goBack, theme }) => {
|
|
8
|
+
const { t } = useI18n();
|
|
7
9
|
const isDarkTheme = theme === 'dark';
|
|
8
10
|
const backgroundColor = isDarkTheme ? '#121212' : '#FFFFFF';
|
|
9
11
|
const textColor = isDarkTheme ? '#FFFFFF' : '#000000';
|
|
@@ -13,27 +15,43 @@ const KarmaRewardsScreen: React.FC<BaseScreenProps> = ({ goBack, theme }) => {
|
|
|
13
15
|
return (
|
|
14
16
|
<View style={[styles.container, { backgroundColor }]}>
|
|
15
17
|
<Header
|
|
16
|
-
title=
|
|
17
|
-
subtitle=
|
|
18
|
+
title={t('karma.rewards.title') || 'Karma Rewards'}
|
|
19
|
+
subtitle={t('karma.rewards.subtitle') || 'Unlock special features and recognition'}
|
|
18
20
|
theme={theme}
|
|
19
21
|
onBack={goBack}
|
|
20
22
|
elevation="subtle"
|
|
21
23
|
/>
|
|
22
24
|
<ScrollView contentContainerStyle={styles.contentContainer}>
|
|
23
|
-
<Text style={[styles.paragraph, { color: textColor }]}>
|
|
25
|
+
<Text style={[styles.paragraph, { color: textColor }]}>
|
|
26
|
+
{t('karma.rewards.intro') || 'Unlock special features and recognition by earning karma!'}
|
|
27
|
+
</Text>
|
|
24
28
|
<View style={styles.rewardBox}>
|
|
25
|
-
<Text style={[styles.rewardTitle, { color: primaryColor }]}
|
|
26
|
-
|
|
29
|
+
<Text style={[styles.rewardTitle, { color: primaryColor }]}>
|
|
30
|
+
{t('karma.rewards.earlyAccess.title') || '🎉 Early Access'}
|
|
31
|
+
</Text>
|
|
32
|
+
<Text style={[styles.rewardDesc, { color: textColor }]}>
|
|
33
|
+
{t('karma.rewards.earlyAccess.desc') || 'Get early access to new features with 100+ karma.'}
|
|
34
|
+
</Text>
|
|
27
35
|
</View>
|
|
28
36
|
<View style={styles.rewardBox}>
|
|
29
|
-
<Text style={[styles.rewardTitle, { color: primaryColor }]}
|
|
30
|
-
|
|
37
|
+
<Text style={[styles.rewardTitle, { color: primaryColor }]}>
|
|
38
|
+
{t('karma.rewards.badge.title') || '🏅 Community Badge'}
|
|
39
|
+
</Text>
|
|
40
|
+
<Text style={[styles.rewardDesc, { color: textColor }]}>
|
|
41
|
+
{t('karma.rewards.badge.desc') || 'Earn a special badge for 500+ karma.'}
|
|
42
|
+
</Text>
|
|
31
43
|
</View>
|
|
32
44
|
<View style={styles.rewardBox}>
|
|
33
|
-
<Text style={[styles.rewardTitle, { color: primaryColor }]}
|
|
34
|
-
|
|
45
|
+
<Text style={[styles.rewardTitle, { color: primaryColor }]}>
|
|
46
|
+
{t('karma.rewards.featured.title') || '🌟 Featured Member'}
|
|
47
|
+
</Text>
|
|
48
|
+
<Text style={[styles.rewardDesc, { color: textColor }]}>
|
|
49
|
+
{t('karma.rewards.featured.desc') || 'Be featured in the community for 1000+ karma.'}
|
|
50
|
+
</Text>
|
|
35
51
|
</View>
|
|
36
|
-
<Text style={[styles.paragraph, { color: textColor, marginTop: 24 }]}>
|
|
52
|
+
<Text style={[styles.paragraph, { color: textColor, marginTop: 24 }]}>
|
|
53
|
+
{t('karma.rewards.moreComing') || 'More rewards coming soon!'}
|
|
54
|
+
</Text>
|
|
37
55
|
</ScrollView>
|
|
38
56
|
</View>
|
|
39
57
|
);
|
|
@@ -4,9 +4,11 @@ import { View, Text, StyleSheet, ScrollView, ActivityIndicator } from 'react-nat
|
|
|
4
4
|
import type { BaseScreenProps } from '../../navigation/types';
|
|
5
5
|
import { useOxy } from '../../context/OxyContext';
|
|
6
6
|
import { Header } from '../../components';
|
|
7
|
+
import { useI18n } from '../../hooks/useI18n';
|
|
7
8
|
|
|
8
9
|
const KarmaRulesScreen: React.FC<BaseScreenProps> = ({ goBack, theme }) => {
|
|
9
10
|
const { oxyServices } = useOxy();
|
|
11
|
+
const { t } = useI18n();
|
|
10
12
|
const [rules, setRules] = useState<any[]>([]);
|
|
11
13
|
const [isLoading, setIsLoading] = useState(true);
|
|
12
14
|
const [error, setError] = useState<string | null>(null);
|
|
@@ -28,8 +30,8 @@ const KarmaRulesScreen: React.FC<BaseScreenProps> = ({ goBack, theme }) => {
|
|
|
28
30
|
return (
|
|
29
31
|
<View style={[styles.container, { backgroundColor }]}>
|
|
30
32
|
<Header
|
|
31
|
-
title=
|
|
32
|
-
subtitle=
|
|
33
|
+
title={t('karma.rules.title') || 'Karma Rules'}
|
|
34
|
+
subtitle={t('karma.rules.subtitle') || 'How to earn karma points'}
|
|
33
35
|
theme={theme}
|
|
34
36
|
onBack={goBack}
|
|
35
37
|
elevation="subtle"
|
|
@@ -41,7 +43,7 @@ const KarmaRulesScreen: React.FC<BaseScreenProps> = ({ goBack, theme }) => {
|
|
|
41
43
|
) : (
|
|
42
44
|
<ScrollView contentContainerStyle={styles.listContainer}>
|
|
43
45
|
{rules.length === 0 ? (
|
|
44
|
-
<Text style={[styles.placeholder, { color: textColor }]}>No rules found
|
|
46
|
+
<Text style={[styles.placeholder, { color: textColor }]}>{t('karma.rules.empty') || 'No rules found.'}</Text>
|
|
45
47
|
) : (
|
|
46
48
|
rules.map((rule, idx) => (
|
|
47
49
|
<View key={rule.id || idx} style={styles.ruleRow}>
|
|
@@ -1,17 +1,21 @@
|
|
|
1
1
|
import type React from 'react';
|
|
2
|
+
import type { RouteName } from '../../navigation/routes';
|
|
2
3
|
import { useRef } from 'react';
|
|
3
4
|
import { View, Text } from 'react-native';
|
|
4
5
|
import { Ionicons } from '@expo/vector-icons';
|
|
5
6
|
import HighFive from '../../../assets/illustrations/HighFive';
|
|
6
7
|
import TextField from '../../components/internal/TextField';
|
|
7
8
|
import GroupedPillButtons from '../../components/internal/GroupedPillButtons';
|
|
9
|
+
import { toast } from '../../../lib/sonner';
|
|
10
|
+
import type { OxyServices } from '../../../core';
|
|
11
|
+
import { useI18n } from '../../hooks/useI18n';
|
|
8
12
|
|
|
9
13
|
interface RecoverRequestStepProps {
|
|
10
14
|
// Common props from StepBasedScreen
|
|
11
15
|
colors: any;
|
|
12
16
|
styles: any;
|
|
13
17
|
theme: string;
|
|
14
|
-
navigate: (screen:
|
|
18
|
+
navigate: (screen: RouteName, props?: Record<string, any>) => void;
|
|
15
19
|
|
|
16
20
|
// Step navigation
|
|
17
21
|
nextStep: () => void;
|
|
@@ -29,6 +33,7 @@ interface RecoverRequestStepProps {
|
|
|
29
33
|
setErrorMessage: (message: string) => void;
|
|
30
34
|
isLoading: boolean;
|
|
31
35
|
setIsLoading: (loading: boolean) => void;
|
|
36
|
+
oxyServices?: OxyServices;
|
|
32
37
|
}
|
|
33
38
|
|
|
34
39
|
const RecoverRequestStep: React.FC<RecoverRequestStepProps> = ({
|
|
@@ -42,17 +47,19 @@ const RecoverRequestStep: React.FC<RecoverRequestStepProps> = ({
|
|
|
42
47
|
setErrorMessage,
|
|
43
48
|
isLoading,
|
|
44
49
|
setIsLoading,
|
|
50
|
+
oxyServices,
|
|
45
51
|
}) => {
|
|
46
52
|
const inputRef = useRef<any>(null);
|
|
53
|
+
const { t } = useI18n();
|
|
47
54
|
|
|
48
55
|
const handleIdentifierChange = (text: string) => {
|
|
49
56
|
setIdentifier(text);
|
|
50
57
|
if (errorMessage) setErrorMessage('');
|
|
51
58
|
};
|
|
52
59
|
|
|
53
|
-
const handleRequest = () => {
|
|
60
|
+
const handleRequest = async () => {
|
|
54
61
|
if (!identifier || identifier.length < 3) {
|
|
55
|
-
setErrorMessage('Please enter your
|
|
62
|
+
setErrorMessage(t('recover.username.errorRequired') || 'Please enter your username.');
|
|
56
63
|
setTimeout(() => inputRef.current?.focus(), 0);
|
|
57
64
|
return;
|
|
58
65
|
}
|
|
@@ -60,11 +67,11 @@ const RecoverRequestStep: React.FC<RecoverRequestStepProps> = ({
|
|
|
60
67
|
setErrorMessage('');
|
|
61
68
|
setIsLoading(true);
|
|
62
69
|
|
|
63
|
-
|
|
64
|
-
|
|
70
|
+
try {
|
|
71
|
+
toast.info(t('recover.noEmail'));
|
|
72
|
+
} finally {
|
|
65
73
|
setIsLoading(false);
|
|
66
|
-
|
|
67
|
-
}, 1200);
|
|
74
|
+
}
|
|
68
75
|
};
|
|
69
76
|
|
|
70
77
|
const handleRequestWithFocus = () => {
|
|
@@ -78,18 +85,14 @@ const RecoverRequestStep: React.FC<RecoverRequestStepProps> = ({
|
|
|
78
85
|
<>
|
|
79
86
|
<HighFive width={100} height={100} />
|
|
80
87
|
<View style={styles.modernHeader}>
|
|
81
|
-
<Text style={[styles.modernTitle, { color: colors.text }]}>
|
|
82
|
-
|
|
83
|
-
</Text>
|
|
84
|
-
<Text style={[styles.modernSubtitle, { color: colors.secondaryText }]}>
|
|
85
|
-
Enter your email or username to receive a 6-digit code.
|
|
86
|
-
</Text>
|
|
88
|
+
<Text style={[styles.modernTitle, { color: colors.text }]}>{t('recover.title')}</Text>
|
|
89
|
+
<Text style={[styles.modernSubtitle, { color: colors.secondaryText }]}>{t('recover.noEmail')}</Text>
|
|
87
90
|
</View>
|
|
88
91
|
|
|
89
92
|
<View style={styles.modernInputContainer}>
|
|
90
93
|
<TextField
|
|
91
94
|
ref={inputRef}
|
|
92
|
-
label=
|
|
95
|
+
label={t('recover.username.label')}
|
|
93
96
|
leading={<Ionicons name="mail-outline" size={24} color={colors.secondaryText} />}
|
|
94
97
|
value={identifier}
|
|
95
98
|
onChangeText={handleIdentifierChange}
|
|
@@ -107,15 +110,15 @@ const RecoverRequestStep: React.FC<RecoverRequestStepProps> = ({
|
|
|
107
110
|
<GroupedPillButtons
|
|
108
111
|
buttons={[
|
|
109
112
|
{
|
|
110
|
-
text: '
|
|
113
|
+
text: t('common.actions.back'),
|
|
111
114
|
onPress: () => navigate('SignIn'),
|
|
112
115
|
icon: 'arrow-back',
|
|
113
116
|
variant: 'transparent',
|
|
114
117
|
},
|
|
115
118
|
{
|
|
116
|
-
text: '
|
|
119
|
+
text: t('common.actions.continue'),
|
|
117
120
|
onPress: handleRequest,
|
|
118
|
-
icon: '
|
|
121
|
+
icon: 'information-circle-outline',
|
|
119
122
|
variant: 'primary',
|
|
120
123
|
loading: isLoading,
|
|
121
124
|
disabled: isLoading,
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import type React from 'react';
|
|
2
|
+
import type { RouteName } from '../../navigation/routes';
|
|
3
|
+
import { View, Text } from 'react-native';
|
|
4
|
+
import { Ionicons } from '@expo/vector-icons';
|
|
5
|
+
import GroupedPillButtons from '../../components/internal/GroupedPillButtons';
|
|
6
|
+
import TextField from '../../components/internal/TextField';
|
|
7
|
+
import { useI18n } from '../../hooks/useI18n';
|
|
8
|
+
|
|
9
|
+
interface RecoverResetPasswordStepProps {
|
|
10
|
+
// Common props
|
|
11
|
+
colors: any;
|
|
12
|
+
styles: any;
|
|
13
|
+
theme: string;
|
|
14
|
+
navigate: (screen: RouteName, props?: Record<string, any>) => void;
|
|
15
|
+
|
|
16
|
+
// Navigation
|
|
17
|
+
nextStep: () => void;
|
|
18
|
+
prevStep: () => void;
|
|
19
|
+
|
|
20
|
+
// From previous steps
|
|
21
|
+
identifier: string;
|
|
22
|
+
verificationCode: string;
|
|
23
|
+
|
|
24
|
+
// Local state
|
|
25
|
+
password: string;
|
|
26
|
+
confirmPassword: string;
|
|
27
|
+
setPassword: (s: string) => void;
|
|
28
|
+
setConfirmPassword: (s: string) => void;
|
|
29
|
+
errorMessage: string;
|
|
30
|
+
setErrorMessage: (s: string) => void;
|
|
31
|
+
isLoading: boolean;
|
|
32
|
+
setIsLoading: (b: boolean) => void;
|
|
33
|
+
|
|
34
|
+
// Services
|
|
35
|
+
oxyServices: any;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const RecoverResetPasswordStep: React.FC<RecoverResetPasswordStepProps> = ({
|
|
39
|
+
colors,
|
|
40
|
+
styles,
|
|
41
|
+
nextStep,
|
|
42
|
+
prevStep,
|
|
43
|
+
identifier,
|
|
44
|
+
verificationCode,
|
|
45
|
+
password,
|
|
46
|
+
confirmPassword,
|
|
47
|
+
setPassword,
|
|
48
|
+
setConfirmPassword,
|
|
49
|
+
errorMessage,
|
|
50
|
+
setErrorMessage,
|
|
51
|
+
isLoading,
|
|
52
|
+
setIsLoading,
|
|
53
|
+
oxyServices,
|
|
54
|
+
}) => {
|
|
55
|
+
const { t } = useI18n();
|
|
56
|
+
const handleReset = async () => {
|
|
57
|
+
if (!password || password.length < 8) {
|
|
58
|
+
setErrorMessage(t('recover.password.minLength') || 'Password must be at least 8 characters long');
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
if (password !== confirmPassword) {
|
|
62
|
+
setErrorMessage(t('recover.password.mismatch') || 'Passwords do not match');
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
setErrorMessage('');
|
|
66
|
+
setIsLoading(true);
|
|
67
|
+
try {
|
|
68
|
+
const code = verificationCode?.trim();
|
|
69
|
+
if (!code) throw new Error(t('recover.missingCode') || 'Missing code');
|
|
70
|
+
|
|
71
|
+
// Heuristic: recovery key starts with 'oxy-' or longer strings, backup codes have dashes of short format, else assume TOTP
|
|
72
|
+
if (code.toLowerCase().startsWith('oxy-') || code.length >= 16) {
|
|
73
|
+
await oxyServices.resetPasswordWithRecoveryKey(identifier, code, password);
|
|
74
|
+
} else if (/[A-Za-z0-9]+-[A-Za-z0-9]+/.test(code)) {
|
|
75
|
+
await oxyServices.resetPasswordWithBackupCode(identifier, code, password);
|
|
76
|
+
} else {
|
|
77
|
+
await oxyServices.resetPasswordWithTotp(identifier, code, password);
|
|
78
|
+
}
|
|
79
|
+
nextStep();
|
|
80
|
+
} catch (e: any) {
|
|
81
|
+
setErrorMessage(e?.message || t('recover.password.resetFailed') || 'Failed to reset password');
|
|
82
|
+
} finally {
|
|
83
|
+
setIsLoading(false);
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
return (
|
|
88
|
+
<>
|
|
89
|
+
<View style={styles.modernHeader}>
|
|
90
|
+
<Text style={[styles.modernTitle, { color: colors.text }]}>{t('recover.newPassword')}</Text>
|
|
91
|
+
<Text style={[styles.modernSubtitle, { color: colors.secondaryText }]}>{t('recover.title')} @{identifier}</Text>
|
|
92
|
+
</View>
|
|
93
|
+
|
|
94
|
+
<View style={styles.modernInputContainer}>
|
|
95
|
+
<TextField
|
|
96
|
+
label={t('common.labels.password')}
|
|
97
|
+
leading={<Ionicons name="lock-closed-outline" size={24} color={colors.secondaryText} />}
|
|
98
|
+
value={password}
|
|
99
|
+
onChangeText={setPassword}
|
|
100
|
+
secureTextEntry
|
|
101
|
+
autoCapitalize="none"
|
|
102
|
+
autoCorrect={false}
|
|
103
|
+
variant="filled"
|
|
104
|
+
error={errorMessage || undefined}
|
|
105
|
+
onSubmitEditing={handleReset}
|
|
106
|
+
autoFocus
|
|
107
|
+
/>
|
|
108
|
+
|
|
109
|
+
<TextField
|
|
110
|
+
label={t('common.labels.confirmPassword')}
|
|
111
|
+
leading={<Ionicons name="lock-closed-outline" size={24} color={colors.secondaryText} />}
|
|
112
|
+
value={confirmPassword}
|
|
113
|
+
onChangeText={setConfirmPassword}
|
|
114
|
+
secureTextEntry
|
|
115
|
+
autoCapitalize="none"
|
|
116
|
+
autoCorrect={false}
|
|
117
|
+
variant="filled"
|
|
118
|
+
onSubmitEditing={handleReset}
|
|
119
|
+
/>
|
|
120
|
+
</View>
|
|
121
|
+
|
|
122
|
+
<GroupedPillButtons
|
|
123
|
+
buttons={[
|
|
124
|
+
{ text: t('common.actions.back'), onPress: prevStep, icon: 'arrow-back', variant: 'transparent' },
|
|
125
|
+
{ text: t('common.actions.resetPassword'), onPress: handleReset, icon: 'key-outline', variant: 'primary', loading: isLoading, disabled: isLoading },
|
|
126
|
+
]}
|
|
127
|
+
colors={colors}
|
|
128
|
+
/>
|
|
129
|
+
</>
|
|
130
|
+
);
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
export default RecoverResetPasswordStep;
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import type React from 'react';
|
|
2
|
+
import type { RouteName } from '../../navigation/routes';
|
|
2
3
|
import { View, Text } from 'react-native';
|
|
3
4
|
import { Ionicons } from '@expo/vector-icons';
|
|
4
5
|
import GroupedPillButtons from '../../components/internal/GroupedPillButtons';
|
|
6
|
+
import { useI18n } from '../../hooks/useI18n';
|
|
5
7
|
|
|
6
8
|
interface RecoverSuccessStepProps {
|
|
7
9
|
// Common props from StepBasedScreen
|
|
8
10
|
colors: any;
|
|
9
11
|
styles: any;
|
|
10
12
|
theme: string;
|
|
11
|
-
navigate: (screen:
|
|
13
|
+
navigate: (screen: RouteName, props?: Record<string, any>) => void;
|
|
12
14
|
|
|
13
15
|
// Step navigation
|
|
14
16
|
nextStep: () => void;
|
|
@@ -32,13 +34,14 @@ const RecoverSuccessStep: React.FC<RecoverSuccessStepProps> = ({
|
|
|
32
34
|
allStepData,
|
|
33
35
|
successMessage,
|
|
34
36
|
}) => {
|
|
37
|
+
const { t } = useI18n();
|
|
35
38
|
// Extract identifier from previous steps
|
|
36
39
|
const requestData = allStepData[0] || {};
|
|
37
40
|
const { identifier } = requestData;
|
|
38
41
|
|
|
39
42
|
const handleContinueToReset = () => {
|
|
40
|
-
// Navigate to
|
|
41
|
-
navigate('
|
|
43
|
+
// Navigate back to SignIn and let host app open its reset flow
|
|
44
|
+
navigate('SignIn', { showReset: true, identifier });
|
|
42
45
|
};
|
|
43
46
|
|
|
44
47
|
const handleBackToSignIn = () => {
|
|
@@ -66,12 +69,8 @@ const RecoverSuccessStep: React.FC<RecoverSuccessStepProps> = ({
|
|
|
66
69
|
</View>
|
|
67
70
|
|
|
68
71
|
<View style={styles.modernHeader}>
|
|
69
|
-
<Text style={[styles.modernTitle, { color: colors.text }]}>
|
|
70
|
-
|
|
71
|
-
</Text>
|
|
72
|
-
<Text style={[styles.modernSubtitle, { color: colors.secondaryText }]}>
|
|
73
|
-
Your account has been successfully verified.
|
|
74
|
-
</Text>
|
|
72
|
+
<Text style={[styles.modernTitle, { color: colors.text }]}>{t('recover.title')}</Text>
|
|
73
|
+
<Text style={[styles.modernSubtitle, { color: colors.secondaryText }]}>{successMessage || t('recover.resetSuccess')}</Text>
|
|
75
74
|
</View>
|
|
76
75
|
|
|
77
76
|
<View style={styles.modernInputContainer}>
|
|
@@ -84,10 +83,10 @@ const RecoverSuccessStep: React.FC<RecoverSuccessStepProps> = ({
|
|
|
84
83
|
marginBottom: 24,
|
|
85
84
|
}}>
|
|
86
85
|
<Text style={[styles.footerText, { color: colors.text, fontSize: 16, marginBottom: 8 }]}>
|
|
87
|
-
What's next?
|
|
86
|
+
{t('recover.whatsNextTitle') || "What's next?"}
|
|
88
87
|
</Text>
|
|
89
88
|
<Text style={[styles.footerText, { color: colors.secondaryText, fontSize: 14, lineHeight: 20 }]}>
|
|
90
|
-
You can now reset your password or return to sign in with your existing credentials.
|
|
89
|
+
{t('recover.whatsNextBody') || 'You can now reset your password or return to sign in with your existing credentials.'}
|
|
91
90
|
</Text>
|
|
92
91
|
</View>
|
|
93
92
|
|
|
@@ -102,7 +101,7 @@ const RecoverSuccessStep: React.FC<RecoverSuccessStepProps> = ({
|
|
|
102
101
|
}}>
|
|
103
102
|
<Ionicons name="shield-checkmark" size={20} color={colors.success} style={{ marginRight: 8 }} />
|
|
104
103
|
<Text style={[styles.footerText, { color: colors.success, fontSize: 14, flex: 1 }]}>
|
|
105
|
-
{successMessage || 'Your account recovery is complete and secure.'}
|
|
104
|
+
{successMessage || t('recover.completeSecure') || 'Your account recovery is complete and secure.'}
|
|
106
105
|
</Text>
|
|
107
106
|
</View>
|
|
108
107
|
</View>
|
|
@@ -110,17 +109,11 @@ const RecoverSuccessStep: React.FC<RecoverSuccessStepProps> = ({
|
|
|
110
109
|
<GroupedPillButtons
|
|
111
110
|
buttons={[
|
|
112
111
|
{
|
|
113
|
-
text: '
|
|
112
|
+
text: t('common.actions.signIn'),
|
|
114
113
|
onPress: handleBackToSignIn,
|
|
115
114
|
icon: 'arrow-back',
|
|
116
115
|
variant: 'transparent',
|
|
117
116
|
},
|
|
118
|
-
{
|
|
119
|
-
text: 'Reset Password',
|
|
120
|
-
onPress: handleContinueToReset,
|
|
121
|
-
icon: 'key-outline',
|
|
122
|
-
variant: 'primary',
|
|
123
|
-
},
|
|
124
117
|
]}
|
|
125
118
|
colors={colors}
|
|
126
119
|
/>
|
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
import type React from 'react';
|
|
2
|
+
import type { RouteName } from '../../navigation/routes';
|
|
2
3
|
import { View, Text } from 'react-native';
|
|
3
4
|
import { Ionicons } from '@expo/vector-icons';
|
|
4
5
|
import GroupedPillButtons from '../../components/internal/GroupedPillButtons';
|
|
5
6
|
import PinInput from '../../components/internal/PinInput';
|
|
7
|
+
import { toast } from '../../../lib/sonner';
|
|
8
|
+
import { useI18n } from '../../hooks/useI18n';
|
|
6
9
|
|
|
7
10
|
interface RecoverVerifyStepProps {
|
|
8
11
|
// Common props from StepBasedScreen
|
|
9
12
|
colors: any;
|
|
10
13
|
styles: any;
|
|
11
14
|
theme: string;
|
|
12
|
-
navigate: (screen:
|
|
15
|
+
navigate: (screen: RouteName, props?: Record<string, any>) => void;
|
|
13
16
|
|
|
14
17
|
// Step navigation
|
|
15
18
|
nextStep: () => void;
|
|
@@ -30,6 +33,7 @@ interface RecoverVerifyStepProps {
|
|
|
30
33
|
setSuccessMessage: (message: string) => void;
|
|
31
34
|
isLoading: boolean;
|
|
32
35
|
setIsLoading: (loading: boolean) => void;
|
|
36
|
+
identifier?: string;
|
|
33
37
|
}
|
|
34
38
|
|
|
35
39
|
const RecoverVerifyStep: React.FC<RecoverVerifyStepProps> = ({
|
|
@@ -45,39 +49,26 @@ const RecoverVerifyStep: React.FC<RecoverVerifyStepProps> = ({
|
|
|
45
49
|
setSuccessMessage,
|
|
46
50
|
isLoading,
|
|
47
51
|
setIsLoading,
|
|
52
|
+
identifier,
|
|
48
53
|
}) => {
|
|
49
|
-
const
|
|
54
|
+
const { t } = useI18n();
|
|
55
|
+
const handleVerifyCode = async () => {
|
|
50
56
|
setErrorMessage('');
|
|
51
57
|
setSuccessMessage('');
|
|
52
58
|
|
|
53
59
|
if (verificationCode.length !== 6) {
|
|
54
|
-
setErrorMessage('
|
|
60
|
+
setErrorMessage(t('recover.enterCode'));
|
|
55
61
|
return;
|
|
56
62
|
}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
// Simulate verification
|
|
61
|
-
setTimeout(() => {
|
|
62
|
-
setIsLoading(false);
|
|
63
|
-
if (verificationCode === '123456') { // Simulate correct code
|
|
64
|
-
setSuccessMessage('Your account has been verified! You can now reset your password.');
|
|
65
|
-
nextStep(); // Move to success step
|
|
66
|
-
} else {
|
|
67
|
-
setErrorMessage('Invalid code. Please try again.');
|
|
68
|
-
}
|
|
69
|
-
}, 1200);
|
|
63
|
+
// For recovery via TOTP, proceed to reset step; server will validate during reset
|
|
64
|
+
nextStep();
|
|
70
65
|
};
|
|
71
66
|
|
|
72
67
|
return (
|
|
73
68
|
<>
|
|
74
69
|
<View style={styles.modernHeader}>
|
|
75
|
-
<Text style={[styles.modernTitle, { color: colors.text }]}>
|
|
76
|
-
|
|
77
|
-
</Text>
|
|
78
|
-
<Text style={[styles.modernSubtitle, { color: colors.secondaryText }]}>
|
|
79
|
-
Enter the 6-digit code sent to your email or phone.
|
|
80
|
-
</Text>
|
|
70
|
+
<Text style={[styles.modernTitle, { color: colors.text }]}>{t('recover.verify.title')}</Text>
|
|
71
|
+
<Text style={[styles.modernSubtitle, { color: colors.secondaryText }]}>{t('recover.enterCode')}</Text>
|
|
81
72
|
</View>
|
|
82
73
|
|
|
83
74
|
<View style={styles.modernInputContainer}>
|
|
@@ -130,13 +121,13 @@ const RecoverVerifyStep: React.FC<RecoverVerifyStepProps> = ({
|
|
|
130
121
|
<GroupedPillButtons
|
|
131
122
|
buttons={[
|
|
132
123
|
{
|
|
133
|
-
text: '
|
|
124
|
+
text: t('common.actions.back'),
|
|
134
125
|
onPress: prevStep,
|
|
135
126
|
icon: 'arrow-back',
|
|
136
127
|
variant: 'transparent',
|
|
137
128
|
},
|
|
138
129
|
{
|
|
139
|
-
text: '
|
|
130
|
+
text: t('recover.verify.action'),
|
|
140
131
|
onPress: handleVerifyCode,
|
|
141
132
|
icon: 'checkmark-circle-outline',
|
|
142
133
|
variant: 'primary',
|