Skip to content

Commit

Permalink
Merge pull request #33743 from shubham1206agra/fix-footer
Browse files Browse the repository at this point in the history
Fix focus on footer link selection
  • Loading branch information
tylerkaraszewski authored Jan 9, 2024
2 parents 5cb22df + f37fc39 commit 0899e3a
Show file tree
Hide file tree
Showing 6 changed files with 69 additions and 20 deletions.
9 changes: 9 additions & 0 deletions src/pages/signin/LoginForm/BaseLoginForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,15 @@ function LoginForm(props) {
isInputFocused() {
return input.current && input.current.isFocused();
},
clearDataAndFocus(clearLogin = true) {
if (!input.current) {
return;
}
if (clearLogin) {
Session.clearSignInData();
}
input.current.focus();
},
}));

const formErrorText = useMemo(() => (formError ? translate(formError) : ''), [formError, translate]);
Expand Down
20 changes: 18 additions & 2 deletions src/pages/signin/LoginForm/index.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,24 @@
import PropTypes from 'prop-types';
import React from 'react';
import refPropTypes from '@components/refPropTypes';
import BaseLoginForm from './BaseLoginForm';

const propTypes = {
/** Function used to scroll to the top of the page */
scrollPageToTop: PropTypes.func,

/** A reference so we can expose clearDataAndFocus */
innerRef: refPropTypes,
};
const defaultProps = {
scrollPageToTop: undefined,
innerRef: () => {},
};

function LoginForm(props) {
function LoginForm({innerRef, ...props}) {
return (
<BaseLoginForm
ref={innerRef}
// eslint-disable-next-line react/jsx-props-no-spreading
{...props}
/>
Expand All @@ -23,4 +29,14 @@ LoginForm.displayName = 'LoginForm';
LoginForm.propTypes = propTypes;
LoginForm.defaultProps = defaultProps;

export default LoginForm;
const LoginFormWithRef = React.forwardRef((props, ref) => (
<LoginForm
// eslint-disable-next-line react/jsx-props-no-spreading
{...props}
innerRef={ref}
/>
));

LoginFormWithRef.displayName = 'LoginFormWithRef';

export default LoginFormWithRef;
30 changes: 27 additions & 3 deletions src/pages/signin/LoginForm/index.native.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,23 @@
import PropTypes from 'prop-types';
import React, {useEffect, useRef} from 'react';
import _ from 'underscore';
import refPropTypes from '@components/refPropTypes';
import AppStateMonitor from '@libs/AppStateMonitor';
import BaseLoginForm from './BaseLoginForm';

const propTypes = {
/** Function used to scroll to the top of the page */
scrollPageToTop: PropTypes.func,

/** A reference so we can expose clearDataAndFocus */
innerRef: refPropTypes,
};
const defaultProps = {
scrollPageToTop: undefined,
innerRef: () => {},
};

function LoginForm(props) {
function LoginForm({innerRef, ...props}) {
const loginFormRef = useRef();
const {scrollPageToTop} = props;

Expand All @@ -36,7 +42,15 @@ function LoginForm(props) {
<BaseLoginForm
// eslint-disable-next-line react/jsx-props-no-spreading
{...props}
ref={(ref) => (loginFormRef.current = ref)}
ref={(ref) => {
loginFormRef.current = ref;
if (typeof innerRef === 'function') {
innerRef(ref);
} else if (innerRef && _.has(innerRef, 'current')) {
// eslint-disable-next-line no-param-reassign
innerRef.current = ref;
}
}}
/>
);
}
Expand All @@ -45,4 +59,14 @@ LoginForm.displayName = 'LoginForm';
LoginForm.propTypes = propTypes;
LoginForm.defaultProps = defaultProps;

export default LoginForm;
const LoginFormWithRef = React.forwardRef((props, ref) => (
<LoginForm
// eslint-disable-next-line react/jsx-props-no-spreading
{...props}
innerRef={ref}
/>
));

LoginFormWithRef.displayName = 'LoginFormWithRef';

export default LoginFormWithRef;
8 changes: 8 additions & 0 deletions src/pages/signin/SignInPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ function SignInPageInner({credentials, account, isInModal, activeClients, prefer
const shouldShowSmallScreen = isSmallScreenWidth || isInModal;
const safeAreaInsets = useSafeAreaInsets();
const signInPageLayoutRef = useRef();
const loginFormRef = useRef();
/** This state is needed to keep track of if user is using recovery code instead of 2fa code,
* and we need it here since welcome text(`welcomeText`) also depends on it */
const [isUsingRecoveryCode, setIsUsingRecoveryCode] = useState(false);
Expand Down Expand Up @@ -242,6 +243,11 @@ function SignInPageInner({credentials, account, isInModal, activeClients, prefer
Log.warn('SignInPage in unexpected state!');
}

const navigateFocus = () => {
signInPageLayoutRef.current.scrollPageToTop();
loginFormRef.current.clearDataAndFocus();
};

return (
// Bottom SafeAreaView is removed so that login screen svg displays correctly on mobile.
// The SVG should flow under the Home Indicator on iOS.
Expand All @@ -253,10 +259,12 @@ function SignInPageInner({credentials, account, isInModal, activeClients, prefer
shouldShowWelcomeText={shouldShowWelcomeText}
ref={signInPageLayoutRef}
shouldShowSmallScreen={shouldShowSmallScreen}
navigateFocus={navigateFocus}
>
{/* LoginForm must use the isVisible prop. This keeps it mounted, but visually hidden
so that password managers can access the values. Conditionally rendering this component will break this feature. */}
<LoginForm
ref={loginFormRef}
isInModal={isInModal}
isVisible={shouldShowLoginForm}
blurOnSubmit={account.validated === false}
Expand Down
18 changes: 5 additions & 13 deletions src/pages/signin/SignInPageLayout/Footer.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,27 +15,19 @@ import useThemeStyles from '@hooks/useThemeStyles';
import Licenses from '@pages/signin/Licenses';
import Socials from '@pages/signin/Socials';
import variables from '@styles/variables';
import * as Session from '@userActions/Session';
import CONST from '@src/CONST';

const propTypes = {
...withLocalizePropTypes,
scrollPageToTop: PropTypes.func.isRequired,
navigateFocus: PropTypes.func.isRequired,
shouldShowSmallScreen: PropTypes.bool,
};

const defaultProps = {
shouldShowSmallScreen: false,
};

const navigateHome = (scrollPageToTop) => {
scrollPageToTop();

// We need to clear sign in data in case the user is already in the ValidateCodeForm or PasswordForm pages
Session.clearSignInData();
};

const columns = ({scrollPageToTop}) => [
const columns = ({navigateFocus}) => [
{
translationPath: 'footer.features',
rows: [
Expand Down Expand Up @@ -135,11 +127,11 @@ const columns = ({scrollPageToTop}) => [
translationPath: 'footer.getStarted',
rows: [
{
onPress: () => navigateHome(scrollPageToTop),
onPress: () => navigateFocus(),
translationPath: 'footer.createAccount',
},
{
onPress: () => navigateHome(scrollPageToTop),
onPress: () => navigateFocus(),
translationPath: 'footer.logIn',
},
],
Expand Down Expand Up @@ -172,7 +164,7 @@ function Footer(props) {
) : null}
<View style={pageFooterWrapper}>
<View style={footerColumns}>
{_.map(columns({scrollPageToTop: props.scrollPageToTop}), (column, i) => (
{_.map(columns({navigateFocus: props.navigateFocus}), (column, i) => (
<View
key={column.translationPath}
style={footerColumn}
Expand Down
4 changes: 2 additions & 2 deletions src/pages/signin/SignInPageLayout/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ function SignInPageLayout(props) {
customHeadline={props.customHeadline}
customHeroBody={props.customHeroBody}
/>
<Footer scrollPageToTop={scrollPageToTop} />
<Footer navigateFocus={props.navigateFocus} />
</View>
</View>
</View>
Expand Down Expand Up @@ -179,7 +179,7 @@ function SignInPageLayout(props) {
</View>
<View style={[styles.flex0]}>
<Footer
scrollPageToTop={scrollPageToTop}
navigateFocus={props.navigateFocus}
shouldShowSmallScreen
/>
</View>
Expand Down

0 comments on commit 0899e3a

Please sign in to comment.