diff --git a/src/app/Scenes/Onboarding/Auth2/scenes/ForgotPasswordStep.tsx b/src/app/Scenes/Onboarding/Auth2/scenes/ForgotPasswordStep.tsx
index bd711f92e1a..b8bf9b37eb2 100644
--- a/src/app/Scenes/Onboarding/Auth2/scenes/ForgotPasswordStep.tsx
+++ b/src/app/Scenes/Onboarding/Auth2/scenes/ForgotPasswordStep.tsx
@@ -146,7 +146,7 @@ const ForgotPasswordStepForm: React.FC = () => {
haptic="impactMedium"
testID="returnToLoginButton"
>
- Return to login
+ Return to Login
diff --git a/src/app/Scenes/Onboarding/Auth2/scenes/LoginOTPStep.tsx b/src/app/Scenes/Onboarding/Auth2/scenes/LoginOTPStep.tsx
index 4832a2a8af7..4c9d0fc6093 100644
--- a/src/app/Scenes/Onboarding/Auth2/scenes/LoginOTPStep.tsx
+++ b/src/app/Scenes/Onboarding/Auth2/scenes/LoginOTPStep.tsx
@@ -15,7 +15,7 @@ import {
} from "app/Scenes/Onboarding/Auth2/hooks/useAuthNavigation"
import { useInputAutofocus } from "app/Scenes/Onboarding/Auth2/hooks/useInputAutofocus"
import { GlobalStore } from "app/store/GlobalStore"
-import { Formik, useFormikContext } from "formik"
+import { Formik } from "formik"
import { useRef, useState } from "react"
import * as Yup from "yup"
@@ -24,13 +24,22 @@ interface LoginOTPStepFormValues {
}
export const LoginOTPStep: React.FC = () => {
+ const [codeType, setCodeType] = useState<"authentication" | "recovery">("authentication")
+
+ const navigation = useAuthNavigation()
const screen = useAuthScreen()
+ const otpRef = useRef(null)
+
+ const { color } = useTheme()
+
+ useInputAutofocus({
+ screenName: "LoginOTPStep",
+ inputRef: otpRef,
+ })
return (
initialValues={{ otp: "" }}
- validateOnChange={true}
- validateOnMount={false}
validationSchema={Yup.object().shape({
otp: Yup.string().required("This field is required"),
})}
@@ -54,101 +63,99 @@ export const LoginOTPStep: React.FC = () => {
}
}}
>
-
-
- )
-}
-
-const LoginOTPStepForm: React.FC = () => {
- const [recoveryCodeMode, setRecoveryCodeMode] = useState(false)
-
- const {
- errors,
- handleChange,
- handleSubmit,
- isSubmitting,
- isValid,
- setErrors,
- validateForm,
- values,
- resetForm,
- } = useFormikContext()
+ {({
+ errors,
+ handleChange,
+ handleSubmit,
+ isSubmitting,
+ isValid,
+ validateForm,
+ values,
+ resetForm,
+ }) => (
+
+ {
+ navigation.goBack()
+ resetForm()
+ setCodeType("authentication")
+ }}
+ />
+
+
+
+ Authentication Code
+
+ {
+ handleChange("otp")(text)
+ }}
+ onBlur={() => validateForm()}
+ />
+
+
+
+ {screen.params?.otpMode === "on_demand" && (
+ <>
+
+
+
+ Your safety and security are important to us. Please check your email for a one-time
+ authentication code to complete your login.
+
+ >
+ )}
- const navigation = useAuthNavigation()
- const screen = useAuthScreen()
- const otpRef = useRef(null)
-
- const { color } = useTheme()
-
- useInputAutofocus({
- screenName: "LoginOTPStep",
- inputRef: otpRef,
- })
+
- const handleBackButtonPress = () => {
- resetForm()
- navigation.goBack()
- setRecoveryCodeMode(false)
- }
+
- return (
-
-
-
- {
- // Hide error when the user starts to type again
- if (errors.otp) {
- setErrors({ otp: undefined })
- validateForm()
- }
- handleChange("otp")(text)
- }}
- onBlur={() => validateForm()}
- />
-
-
-
- {screen.params?.otpMode === "on_demand" && (
- <>
-
- Your safety and security are important to us. Please check your email for a one-time
- authentication code to complete your login.
-
- >
+ {screen.params?.otpMode === "standard" && (
+ {
+ if (codeType === "authentication") {
+ setCodeType("recovery")
+ } else {
+ setCodeType("authentication")
+ }
+ }}
+ >
+
+ {codeType === "authentication"
+ ? "Enter recovery code instead"
+ : "Enter authentication code"}
+
+
+ )}
+
)}
-
-
-
-
-
-
-
- {
- setRecoveryCodeMode((mode) => !mode)
- }}
- >
-
- {recoveryCodeMode ? "Enter authentication code" : "Enter recovery code instead"}
-
-
-
+
)
}
diff --git a/src/app/Scenes/Onboarding/Auth2/scenes/LoginWelcomeStep.tsx b/src/app/Scenes/Onboarding/Auth2/scenes/LoginWelcomeStep.tsx
index 2a093ce4023..1798a6d5373 100644
--- a/src/app/Scenes/Onboarding/Auth2/scenes/LoginWelcomeStep.tsx
+++ b/src/app/Scenes/Onboarding/Auth2/scenes/LoginWelcomeStep.tsx
@@ -128,7 +128,7 @@ const LoginWelcomeStepForm: React.FC = () => {
ref={emailRef}
spellCheck={false}
keyboardType="email-address"
- textContentType="none"
+ textContentType="username"
returnKeyType="next"
title="Email"
value={values.email}
diff --git a/src/app/Scenes/Onboarding/Auth2/scenes/__tests__/LoginOTPStep.test.tsx b/src/app/Scenes/Onboarding/Auth2/scenes/__tests__/LoginOTPStep.test.tsx
deleted file mode 100644
index 3c49297b976..00000000000
--- a/src/app/Scenes/Onboarding/Auth2/scenes/__tests__/LoginOTPStep.test.tsx
+++ /dev/null
@@ -1,5 +0,0 @@
-describe("LoginOTPStep", () => {
- it("renders correctly", () => {
- // TODO
- })
-})
diff --git a/src/app/Scenes/Onboarding/Auth2/scenes/__tests__/LoginOTPStep.tests.tsx b/src/app/Scenes/Onboarding/Auth2/scenes/__tests__/LoginOTPStep.tests.tsx
new file mode 100644
index 00000000000..6af50e62e27
--- /dev/null
+++ b/src/app/Scenes/Onboarding/Auth2/scenes/__tests__/LoginOTPStep.tests.tsx
@@ -0,0 +1,46 @@
+import { fireEvent, screen } from "@testing-library/react-native"
+import { LoginOTPStep } from "app/Scenes/Onboarding/Auth2/scenes/LoginOTPStep"
+import { renderWithWrappers } from "app/utils/tests/renderWithWrappers"
+
+const mockUseAuthScreen = jest.fn()
+
+jest.mock("app/Scenes/Onboarding/Auth2/hooks/useAuthNavigation", () => ({
+ useAuthNavigation: jest.fn(),
+ useAuthScreen: () => mockUseAuthScreen(),
+}))
+
+describe("LoginOTPStep", () => {
+ beforeEach(() => {
+ mockUseAuthScreen.mockReturnValue({ params: { otpMode: "standard" } })
+ })
+
+ it("renders correctly", () => {
+ renderWithWrappers()
+
+ expect(screen.getByText("Authentication Code")).toBeDefined()
+ expect(screen.getByText("Authentication code")).toBeDefined()
+ })
+
+ it("allows the user to switch between authentication and recovery codes", () => {
+ renderWithWrappers()
+
+ const recoveryCodeButton = screen.getByText("Enter recovery code instead")
+ expect(recoveryCodeButton).toBeDefined()
+
+ fireEvent.press(recoveryCodeButton)
+
+ expect(screen.getByText("Recovery code")).toBeDefined()
+ })
+
+ it("renders instructions when OTP mode is 'on_demand'", () => {
+ mockUseAuthScreen.mockReturnValue({ params: { otpMode: "on_demand" } })
+
+ renderWithWrappers()
+
+ expect(
+ screen.getByText(
+ "Your safety and security are important to us. Please check your email for a one-time authentication code to complete your login."
+ )
+ ).toBeDefined()
+ })
+})