Skip to content

Commit

Permalink
fix(auth2): Remove KeyboardAvoidingView to get around iOS 17 bug (#10896
Browse files Browse the repository at this point in the history
)

* test keyboard jump

* fix(auth2): manage terrible ios keyboard
  • Loading branch information
damassi authored Oct 7, 2024
1 parent ea625b4 commit 0f612f8
Show file tree
Hide file tree
Showing 8 changed files with 61 additions and 77 deletions.
68 changes: 33 additions & 35 deletions src/app/Scenes/Onboarding/Auth2/components/AuthModal.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { Box, Flex, useTheme } from "@artsy/palette-mobile"
import { AuthContext } from "app/Scenes/Onboarding/Auth2/AuthContext"
import { MotiView } from "moti"
import { Dimensions, KeyboardAvoidingView, Platform } from "react-native"
import { Dimensions } from "react-native"
import { Easing } from "react-native-reanimated"
import { useSafeAreaInsets } from "react-native-safe-area-context"

const HEIGHT = {
LoginWelcomeStep: 320,
Expand All @@ -20,6 +21,7 @@ export const AuthModal: React.FC = ({ children }) => {
const { isModalExpanded, isMounted, currentScreen } = AuthContext.useStoreState((state) => state)

const { space } = useTheme()
const insets = useSafeAreaInsets()

const screenHeight = Dimensions.get("window").height

Expand All @@ -34,44 +36,40 @@ export const AuthModal: React.FC = ({ children }) => {
const translateY = (() => {
// Position the modal in the center of the screen, minus some padding
if (isModalExpanded) {
return 0
return insets.top + space(6)
}

return screenHeight / 2 - height / 2 - space(6)
return screenHeight - height - insets.bottom
})()

return (
<KeyboardAvoidingView
style={{ flex: 1 }}
behavior={Platform.OS === "ios" ? "padding" : "height"}
>
<Box flex={1} height="100%" justifyContent="center">
<MotiView
from={{
translateY: isModalExpanded ? 0 : screenHeight,
}}
animate={{
translateY,
}}
transition={{
type: "timing",
duration: isModalExpanded ? 800 : 600,
delay: isMounted ? 0 : 500,
easing: Easing.out(Easing.exp),
}}
style={{
width: "100%",
backgroundColor: "white",
borderRadius: space(2),
overflow: "hidden",
position: "relative",
}}
>
<Flex justifyContent="center" p={1}>
{children}
</Flex>
</MotiView>
</Box>
</KeyboardAvoidingView>
<Box flex={1} height="100%">
<MotiView
from={{
translateY: isModalExpanded ? 0 : screenHeight,
}}
animate={{
translateY,
}}
transition={{
type: "timing",
duration: isModalExpanded ? 800 : 600,
delay: isMounted ? 0 : 500,
easing: Easing.out(Easing.exp),
}}
style={{
width: "100%",
backgroundColor: "white",
borderRadius: space(2),
overflow: "hidden",
position: "relative",
}}
>
<Flex justifyContent="center" p={1}>
{children}
</Flex>
</MotiView>
</Box>
// </KeyboardAvoidingView>
)
}
3 changes: 0 additions & 3 deletions src/app/Scenes/Onboarding/Auth2/scenes/ForgotPasswordStep.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,8 @@ const ForgotPasswordStepForm: React.FC = () => {
} = useFormikContext<ForgotPasswordStepFormValues>()

const navigation = useAuthNavigation()

const screen = useAuthScreen()

const { color } = useTheme()

const forgotPasswordRef = useRef<Input>(null)

const handleBackButtonPress = () => {
Expand Down
7 changes: 1 addition & 6 deletions src/app/Scenes/Onboarding/Auth2/scenes/LoginOTPStep.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,9 @@ import {
useAuthScreen,
} from "app/Scenes/Onboarding/Auth2/hooks/useAuthNavigation"
import { useInputAutofocus } from "app/Scenes/Onboarding/Auth2/hooks/useInputAutofocus"
import { waitForSubmit } from "app/Scenes/Onboarding/Auth2/utils/waitForSubmit"
import { GlobalStore } from "app/store/GlobalStore"
import { Formik, useFormikContext } from "formik"
import { useRef, useState } from "react"
import { Keyboard } from "react-native"
import * as Yup from "yup"

interface LoginOTPStepFormValues {
Expand All @@ -36,8 +34,6 @@ export const LoginOTPStep: React.FC = () => {
otp: Yup.string().required("This field is required"),
})}
onSubmit={async ({ otp }, { setErrors, resetForm }) => {
Keyboard.dismiss()

const res = await GlobalStore.actions.auth.signIn({
oauthProvider: "email",
oauthMode: "email",
Expand All @@ -46,8 +42,6 @@ export const LoginOTPStep: React.FC = () => {
otp: otp.trim(),
})

await waitForSubmit()

if (res === "invalid_otp") {
setErrors({ otp: "Invalid two-factor authentication code" })
} else if (res !== "success") {
Expand Down Expand Up @@ -102,6 +96,7 @@ const LoginOTPStepForm: React.FC = () => {
autoCapitalize="none"
autoComplete="one-time-code"
autoCorrect={false}
blurOnSubmit={false}
error={errors.otp}
keyboardType={recoveryCodeMode ? "ascii-capable" : "number-pad"}
placeholder={recoveryCodeMode ? "Enter a recovery code" : "Enter an authentication code"}
Expand Down
16 changes: 6 additions & 10 deletions src/app/Scenes/Onboarding/Auth2/scenes/LoginPasswordStep.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,10 @@ import {
useAuthScreen,
} from "app/Scenes/Onboarding/Auth2/hooks/useAuthNavigation"
import { useInputAutofocus } from "app/Scenes/Onboarding/Auth2/hooks/useInputAutofocus"
import { waitForSubmit } from "app/Scenes/Onboarding/Auth2/utils/waitForSubmit"
import { GlobalStore } from "app/store/GlobalStore"
import { showBlockedAuthError } from "app/utils/auth/authHelpers"
import { Formik, useFormikContext } from "formik"
import { useRef } from "react"
import { Keyboard } from "react-native"
import * as Yup from "yup"

interface LoginPasswordStepFormValues {
Expand All @@ -37,17 +35,13 @@ export const LoginPasswordStep: React.FC = () => {
password: Yup.string().required("Password field is required"),
})}
onSubmit={async ({ password }, { setErrors, resetForm }) => {
Keyboard.dismiss()

const res = await GlobalStore.actions.auth.signIn({
oauthProvider: "email",
oauthMode: "email",
email: screen.params?.email,
password,
})

await waitForSubmit()

if (res === "otp_missing") {
navigation.navigate({
name: "LoginOTPStep",
Expand Down Expand Up @@ -128,11 +122,16 @@ const LoginPasswordStepForm: React.FC = () => {
autoCapitalize="none"
autoComplete="password"
autoCorrect={false}
blurOnSubmit={false}
error={values.password.length > 0 || touched.password ? errors.password : undefined}
placeholderTextColor={color("black30")}
ref={passwordRef}
returnKeyType="done"
secureTextEntry
// textContentType="oneTimeCode"
// We need to to set textContentType to password here
// enable autofill of login details from the device keychain.
textContentType="password"
testID="password"
title="Password"
value={values.password}
Expand All @@ -151,10 +150,7 @@ const LoginPasswordStepForm: React.FC = () => {
handleSubmit()
}
}}
onBlur={() => validateForm()}
// We need to to set textContentType to password here
// enable autofill of login details from the device keychain.
textContentType="password"
onBlur={validateForm}
/>

<Spacer y={2} />
Expand Down
28 changes: 18 additions & 10 deletions src/app/Scenes/Onboarding/Auth2/scenes/LoginWelcomeStep.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,15 @@ import { useRecaptcha } from "app/Components/Recaptcha/Recaptcha"
import { AuthContext } from "app/Scenes/Onboarding/Auth2/AuthContext"
import { useAuthNavigation } from "app/Scenes/Onboarding/Auth2/hooks/useAuthNavigation"
import { useInputAutofocus } from "app/Scenes/Onboarding/Auth2/hooks/useInputAutofocus"
import { waitForSubmit } from "app/Scenes/Onboarding/Auth2/utils/waitForSubmit"
import { AuthPromiseRejectType, AuthPromiseResolveType } from "app/store/AuthModel"
import { GlobalStore } from "app/store/GlobalStore"
import { navigate } from "app/system/navigation/navigate"
import { osMajorVersion } from "app/utils/platformUtil"
import { Formik, useFormikContext } from "formik"
import { MotiView } from "moti"
import React, { useRef, useState } from "react"
import { Alert, Image, InteractionManager, Keyboard, Platform } from "react-native"
import { Alert, Image, InteractionManager, Platform } from "react-native"
import { Easing } from "react-native-reanimated"
import * as Yup from "yup"

interface LoginEmailFormValues {
Expand Down Expand Up @@ -47,8 +48,6 @@ export const LoginWelcomeStep: React.FC = () => {
.required("Email field is required"),
})}
onSubmit={async ({ email }, { resetForm }) => {
Keyboard.dismiss()

// FIXME
if (!token) {
Alert.alert("Something went wrong. Please try again, or contact [email protected]")
Expand All @@ -57,8 +56,6 @@ export const LoginWelcomeStep: React.FC = () => {

const res = await GlobalStore.actions.auth.verifyUser({ email, recaptchaToken: token })

await waitForSubmit()

if (res === "user_exists") {
navigation.navigate({ name: "LoginPasswordStep", params: { email } })
} else if (res === "user_does_not_exist") {
Expand Down Expand Up @@ -119,6 +116,7 @@ const LoginWelcomeStepForm: React.FC = () => {
autoCapitalize="none"
autoComplete="email"
autoCorrect={false}
blurOnSubmit={false}
error={errors.email}
placeholderTextColor={color("black30")}
ref={emailRef}
Expand All @@ -135,15 +133,25 @@ const LoginWelcomeStepForm: React.FC = () => {
onSubmitEditing={handleSubmit}
/>

<Flex display={isModalExpanded ? "flex" : "none"}>
<MotiView
from={{ opacity: isModalExpanded ? 0 : 1 }}
animate={{ opacity: isModalExpanded ? 1 : 0 }}
transition={{ type: "timing", duration: 400, easing: Easing.linear }}
style={{ display: isModalExpanded ? "flex" : "none" }}
>
<Spacer y={2} />

<Button block width="100%" onPress={handleSubmit} loading={isSubmitting}>
Continue
</Button>
</Flex>
</MotiView>

<Flex display={isModalExpanded ? "none" : "flex"}>
<MotiView
from={{ opacity: isModalExpanded ? 1 : 0 }}
animate={{ opacity: isModalExpanded ? 0 : 1 }}
transition={{ type: "timing", duration: 400, easing: Easing.linear }}
style={{ display: isModalExpanded ? "none" : "flex" }}
>
<Spacer y={2} />

<SocialLoginButtons />
Expand All @@ -160,7 +168,7 @@ const LoginWelcomeStepForm: React.FC = () => {
Privacy Policy
</LinkText>
</Text>
</Flex>
</MotiView>
</Flex>
)
}
Expand Down
7 changes: 1 addition & 6 deletions src/app/Scenes/Onboarding/Auth2/scenes/SignUpNameStep.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,14 @@ import {
useAuthScreen,
} from "app/Scenes/Onboarding/Auth2/hooks/useAuthNavigation"
import { useInputAutofocus } from "app/Scenes/Onboarding/Auth2/hooks/useInputAutofocus"
import { waitForSubmit } from "app/Scenes/Onboarding/Auth2/utils/waitForSubmit"
import { OnboardingNavigationStack } from "app/Scenes/Onboarding/Onboarding"
import { EmailSubscriptionCheckbox } from "app/Scenes/Onboarding/OnboardingCreateAccount/EmailSubscriptionCheckbox"
import { TermsOfServiceCheckbox } from "app/Scenes/Onboarding/OnboardingCreateAccount/TermsOfServiceCheckbox"
import { GlobalStore } from "app/store/GlobalStore"
import { showBlockedAuthError } from "app/utils/auth/authHelpers"
import { Formik, useFormikContext } from "formik"
import React, { useRef, useState } from "react"
import { Alert, Keyboard } from "react-native"
import { Alert } from "react-native"
import * as Yup from "yup"

interface SignUpNameStepFormValues {
Expand Down Expand Up @@ -41,8 +40,6 @@ export const SignUpNameStep: React.FC = () => {
return
}

Keyboard.dismiss()

const res = await GlobalStore.actions.auth.signUp({
oauthProvider: "email",
oauthMode: "email",
Expand All @@ -52,8 +49,6 @@ export const SignUpNameStep: React.FC = () => {
agreedToReceiveEmails: values.agreedToReceiveEmails,
})

await waitForSubmit()

if (!res.success) {
if (res.error === "blocked_attempt") {
showBlockedAuthError("sign up")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,8 @@ import {
useAuthScreen,
} from "app/Scenes/Onboarding/Auth2/hooks/useAuthNavigation"
import { useInputAutofocus } from "app/Scenes/Onboarding/Auth2/hooks/useInputAutofocus"
import { waitForSubmit } from "app/Scenes/Onboarding/Auth2/utils/waitForSubmit"
import { Formik, useFormikContext } from "formik"
import React, { useRef } from "react"
import { Keyboard } from "react-native"
import * as Yup from "yup"

interface SignUpPasswordStepFormValues {
Expand All @@ -30,10 +28,6 @@ export const SignUpPasswordStep: React.FC = () => {
.required("Password field is required"),
})}
onSubmit={async ({ password }, { resetForm }) => {
Keyboard.dismiss()

await waitForSubmit()

navigation.navigate({
name: "SignUpNameStep",
params: {
Expand Down Expand Up @@ -88,6 +82,7 @@ const SignUpPasswordStepForm: React.FC = () => {
autoCapitalize="none"
autoComplete="password"
autoCorrect={false}
blurOnSubmit={false}
error={errors.password}
placeholder="Password"
placeholderTextColor={color("black30")}
Expand Down
2 changes: 1 addition & 1 deletion src/app/Scenes/Onboarding/Auth2/utils/waitForSubmit.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/**
* Slight delay to smooth out keyboard transitions between submission steps
*/
export const waitForSubmit = async (delay = 1500) => {
export const waitForSubmit = async (delay = 1000) => {
return new Promise((resolve: any) => setTimeout(resolve, delay))
}

0 comments on commit 0f612f8

Please sign in to comment.