Skip to content

Commit

Permalink
Merge pull request #35794 from tienifr/fix/34645
Browse files Browse the repository at this point in the history
Disable locale picker while signing in
  • Loading branch information
tgolen authored Mar 8, 2024
2 parents a2c24e1 + 886123a commit 0b67666
Show file tree
Hide file tree
Showing 7 changed files with 50 additions and 9 deletions.
15 changes: 13 additions & 2 deletions src/components/LocalePicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,18 @@ import {withOnyx} from 'react-native-onyx';
import useLocalize from '@hooks/useLocalize';
import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
import AccountUtils from '@libs/AccountUtils';
import * as App from '@userActions/App';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import type {Locale} from '@src/types/onyx';
import type {Account, Locale} from '@src/types/onyx';
import Picker from './Picker';
import type {PickerSize} from './Picker/types';

type LocalePickerOnyxProps = {
/** The details about the account that the user is signing in with */
account: OnyxEntry<Account>;

/** Indicates which locale the user currently has selected */
preferredLocale: OnyxEntry<Locale>;
};
Expand All @@ -21,7 +25,7 @@ type LocalePickerProps = LocalePickerOnyxProps & {
size?: PickerSize;
};

function LocalePicker({preferredLocale = CONST.LOCALES.DEFAULT, size = 'normal'}: LocalePickerProps) {
function LocalePicker({account, preferredLocale = CONST.LOCALES.DEFAULT, size = 'normal'}: LocalePickerProps) {
const theme = useTheme();
const styles = useThemeStyles();
const {translate} = useLocalize();
Expand All @@ -31,6 +35,7 @@ function LocalePicker({preferredLocale = CONST.LOCALES.DEFAULT, size = 'normal'}
keyForList: language,
isSelected: preferredLocale === language,
}));
const shouldDisablePicker = AccountUtils.isValidateCodeFormSubmitting(account);

return (
<Picker
Expand All @@ -42,7 +47,10 @@ function LocalePicker({preferredLocale = CONST.LOCALES.DEFAULT, size = 'normal'}

App.setLocale(locale);
}}
isDisabled={shouldDisablePicker}
items={localesToLanguages}
shouldAllowDisabledStyle={false}
shouldShowOnlyTextWhenDisabled={false}
size={size}
value={preferredLocale}
containerStyles={size === 'small' ? styles.pickerContainerSmall : {}}
Expand All @@ -54,6 +62,9 @@ function LocalePicker({preferredLocale = CONST.LOCALES.DEFAULT, size = 'normal'}
LocalePicker.displayName = 'LocalePicker';

export default withOnyx<LocalePickerProps, LocalePickerOnyxProps>({
account: {
key: ONYXKEYS.ACCOUNT,
},
preferredLocale: {
key: ONYXKEYS.NVP_PREFERRED_LOCALE,
},
Expand Down
14 changes: 11 additions & 3 deletions src/components/Picker/BasePicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@ function BasePicker<TPickerValue>(
containerStyles,
placeholder = {},
size = 'normal',
shouldAllowDisabledStyle = true,
shouldFocusPicker = false,
shouldShowOnlyTextWhenDisabled = true,
onBlur = () => {},
additionalPickerEvents = () => {},
}: BasePickerProps<TPickerValue>,
Expand Down Expand Up @@ -155,7 +157,7 @@ function BasePicker<TPickerValue>(

const hasError = !!errorText;

if (isDisabled) {
if (isDisabled && shouldShowOnlyTextWhenDisabled) {
return (
<View>
{!!label && (
Expand All @@ -176,14 +178,20 @@ function BasePicker<TPickerValue>(
<>
<View
ref={root}
style={[styles.pickerContainer, isDisabled && styles.inputDisabled, containerStyles, isHighlighted && styles.borderColorFocus, hasError && styles.borderColorDanger]}
style={[
styles.pickerContainer,
isDisabled && shouldAllowDisabledStyle && styles.inputDisabled,
containerStyles,
isHighlighted && styles.borderColorFocus,
hasError && styles.borderColorDanger,
]}
>
{label && <Text style={[styles.pickerLabel, styles.textLabelSupporting, styles.pointerEventsNone]}>{label}</Text>}
<RNPickerSelect
onValueChange={onValueChange}
// We add a text color to prevent white text on white background dropdown items on Windows
items={items.map((item) => ({...item, color: itemColor}))}
style={size === 'normal' ? styles.picker(isDisabled, backgroundColor) : styles.pickerSmall(backgroundColor)}
style={size === 'normal' ? styles.picker(isDisabled, backgroundColor) : styles.pickerSmall(isDisabled, backgroundColor)}
useNativeAndroidPickerStyle={false}
placeholder={pickerPlaceholder}
value={value}
Expand Down
6 changes: 6 additions & 0 deletions src/components/Picker/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,15 @@ type BasePickerProps<TPickerValue> = {
/** The ID used to uniquely identify the input in a Form */
inputID?: string;

/** Show disabled style when disabled */
shouldAllowDisabledStyle?: boolean;

/** Saves a draft of the input value when used in a form */
shouldSaveDraft?: boolean;

/** Show only picker's label and value when disabled */
shouldShowOnlyTextWhenDisabled?: boolean;

/** A callback method that is called when the value changes and it receives the selected value as an argument */
onInputChange: (value: TPickerValue, index?: number) => void;

Expand Down
8 changes: 8 additions & 0 deletions src/libs/AccountUtils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import type {OnyxEntry} from 'react-native-onyx';
import CONST from '@src/CONST';
import type {Account} from '@src/types/onyx';

const isValidateCodeFormSubmitting = (account: OnyxEntry<Account>) =>
!!account?.isLoading && account.loadingForm === (account.requiresTwoFactorAuth ? CONST.FORMS.VALIDATE_TFA_CODE_FORM : CONST.FORMS.VALIDATE_CODE_FORM);

export default {isValidateCodeFormSubmitting};
4 changes: 2 additions & 2 deletions src/pages/signin/ValidateCodeForm/BaseValidateCodeForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import useNetwork from '@hooks/useNetwork';
import usePrevious from '@hooks/usePrevious';
import useStyleUtils from '@hooks/useStyleUtils';
import useThemeStyles from '@hooks/useThemeStyles';
import AccountUtils from '@libs/AccountUtils';
import canFocusInputOnScreenFocus from '@libs/canFocusInputOnScreenFocus';
import * as ErrorUtils from '@libs/ErrorUtils';
import * as ValidationUtils from '@libs/ValidationUtils';
Expand Down Expand Up @@ -76,8 +77,7 @@ function BaseValidateCodeForm({account, credentials, session, autoComplete, isUs
const hasError = !!account && !isEmptyObject(account?.errors) && !needToClearError;
const isLoadingResendValidationForm = account?.loadingForm === CONST.FORMS.RESEND_VALIDATE_CODE_FORM;
const shouldDisableResendValidateCode = isOffline ?? account?.isLoading;
const isValidateCodeFormSubmitting =
account?.isLoading && account?.loadingForm === (account?.requiresTwoFactorAuth ? CONST.FORMS.VALIDATE_TFA_CODE_FORM : CONST.FORMS.VALIDATE_CODE_FORM);
const isValidateCodeFormSubmitting = AccountUtils.isValidateCodeFormSubmitting(account);

useEffect(() => {
if (!(inputValidateCodeRef.current && hasError && (session?.autoAuthState === CONST.AUTO_AUTH_STATE.FAILED || account?.isLoading))) {
Expand Down
4 changes: 2 additions & 2 deletions src/styles/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -750,7 +750,7 @@ const styles = (theme: ThemeColors) =>
height: 140,
},

pickerSmall: (backgroundColor = theme.highlightBG) =>
pickerSmall: (disabled = false, backgroundColor = theme.highlightBG) =>
({
inputIOS: {
fontFamily: FontUtils.fontFamily.platform.EXP_NEUE,
Expand Down Expand Up @@ -792,7 +792,7 @@ const styles = (theme: ThemeColors) =>
height: 26,
opacity: 1,
backgroundColor,
...cursor.cursorPointer,
...(disabled ? cursor.cursorDisabled : cursor.cursorPointer),
},
inputAndroid: {
fontFamily: FontUtils.fontFamily.platform.EXP_NEUE,
Expand Down
8 changes: 8 additions & 0 deletions tests/perf-test/SignInPage.perf-test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,14 @@ import * as TestHelper from '../utils/TestHelper';
import waitForBatchedUpdates from '../utils/waitForBatchedUpdates';
import wrapOnyxWithWaitForBatchedUpdates from '../utils/wrapOnyxWithWaitForBatchedUpdates';

jest.mock('../../src/libs/Log');

jest.mock('../../src/libs/API', () => ({
write: jest.fn(),
makeRequestWithSideEffects: jest.fn(),
read: jest.fn(),
}));

const mockedNavigate = jest.fn();
jest.mock('@react-navigation/native', () => {
const actualNav = jest.requireActual('@react-navigation/native');
Expand Down

0 comments on commit 0b67666

Please sign in to comment.