Skip to content

Commit

Permalink
Merge pull request Expensify#36523 from callstack-internal/pac-guerre…
Browse files Browse the repository at this point in the history
…iro/refactor/migrate-settingspreferences-to-typescript

[TS migration] Migrate 'SettingsPreferences' page to TypeScript
  • Loading branch information
deetergp authored Mar 13, 2024
2 parents 077824c + c9bb187 commit 34930fe
Show file tree
Hide file tree
Showing 8 changed files with 100 additions and 85 deletions.
17 changes: 17 additions & 0 deletions src/libs/LocaleUtils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import type {ValueOf} from 'type-fest';
import CONST from '@src/CONST';

function getLanguageFromLocale(locale: ValueOf<typeof CONST.LOCALES>): (typeof CONST.LANGUAGES)[number] {
switch (locale) {
case CONST.LOCALES.ES_ES:
case CONST.LOCALES.ES_ES_ONFIDO:
case CONST.LOCALES.ES:
return CONST.LOCALES.ES;
case CONST.LOCALES.EN:
return CONST.LOCALES.EN;
default:
return CONST.LOCALES.DEFAULT;
}
}

export default {getLanguageFromLocale};
Original file line number Diff line number Diff line change
@@ -1,28 +1,21 @@
import PropTypes from 'prop-types';
import React from 'react';
import _ from 'underscore';
import HeaderWithBackButton from '@components/HeaderWithBackButton';
import ScreenWrapper from '@components/ScreenWrapper';
import SelectionList from '@components/SelectionList';
import RadioListItem from '@components/SelectionList/RadioListItem';
import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
import useLocalize from '@hooks/useLocalize';
import Navigation from '@libs/Navigation/Navigation';
import * as App from '@userActions/App';
import CONST from '@src/CONST';

const propTypes = {
...withLocalizePropTypes,
function LanguagePage() {
const {translate, preferredLocale} = useLocalize();

/** The preferred language of the App */
preferredLocale: PropTypes.string.isRequired,
};

function LanguagePage(props) {
const localesToLanguages = _.map(CONST.LANGUAGES, (language) => ({
const localesToLanguages = CONST.LANGUAGES.map((language) => ({
value: language,
text: props.translate(`languagePage.languages.${language}.label`),
text: translate(`languagePage.languages.${language}.label`),
keyForList: language,
isSelected: props.preferredLocale === language,
isSelected: preferredLocale === language,
}));

return (
Expand All @@ -31,20 +24,19 @@ function LanguagePage(props) {
testID={LanguagePage.displayName}
>
<HeaderWithBackButton
title={props.translate('languagePage.language')}
title={translate('languagePage.language')}
onBackButtonPress={() => Navigation.goBack()}
/>
<SelectionList
sections={[{data: localesToLanguages}]}
ListItem={RadioListItem}
onSelectRow={(language) => App.setLocaleAndNavigate(language.value)}
initiallyFocusedOptionKey={_.find(localesToLanguages, (locale) => locale.isSelected).keyForList}
initiallyFocusedOptionKey={localesToLanguages.find((locale) => locale.isSelected)?.keyForList}
/>
</ScreenWrapper>
);
}

LanguagePage.displayName = 'LanguagePage';
LanguagePage.propTypes = propTypes;

export default withLocalize(LanguagePage);
export default LanguagePage;
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import lodashGet from 'lodash/get';
import PropTypes from 'prop-types';
import React from 'react';
import {View} from 'react-native';
import type {OnyxEntry} from 'react-native-onyx';
import {withOnyx} from 'react-native-onyx';
import HeaderWithBackButton from '@components/HeaderWithBackButton';
import * as Illustrations from '@components/Icon/Illustrations';
Expand All @@ -15,33 +14,28 @@ import Text from '@components/Text';
import useLocalize from '@hooks/useLocalize';
import useThemeStyles from '@hooks/useThemeStyles';
import useWindowDimensions from '@hooks/useWindowDimensions';
import LocaleUtils from '@libs/LocaleUtils';
import Navigation from '@libs/Navigation/Navigation';
import * as User from '@userActions/User';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
import type {PreferredTheme, PriorityMode, User as UserType} from '@src/types/onyx';

const propTypes = {
type PreferencesPageOnyxProps = {
/** The chat priority mode */
priorityMode: PropTypes.string,
priorityMode: PriorityMode;

/** The app's color theme */
preferredTheme: PropTypes.string,
preferredTheme: PreferredTheme;

/** The details about the user that is signed in */
user: PropTypes.shape({
/** Whether or not the user is subscribed to news updates */
isSubscribedToNewsletter: PropTypes.bool,
}),
user: OnyxEntry<UserType>;
};

const defaultProps = {
priorityMode: CONST.PRIORITY_MODE.DEFAULT,
preferredTheme: CONST.DEFAULT_THEME,
user: {},
};
type PreferencesPageProps = PreferencesPageOnyxProps;

function PreferencesPage(props) {
function PreferencesPage({priorityMode, preferredTheme, user}: PreferencesPageProps) {
const styles = useThemeStyles();
const {translate, preferredLocale} = useLocalize();
const {isSmallScreenWidth} = useWindowDimensions();
Expand Down Expand Up @@ -83,7 +77,7 @@ function PreferencesPage(props) {
<View style={[styles.flex1, styles.alignItemsEnd]}>
<Switch
accessibilityLabel={translate('preferencesPage.receiveRelevantFeatureUpdatesAndExpensifyNews')}
isOn={lodashGet(props.user, 'isSubscribedToNewsletter', true)}
isOn={user?.isSubscribedToNewsletter ?? true}
onToggle={User.updateNewsletterSubscription}
/>
</View>
Expand All @@ -95,28 +89,28 @@ function PreferencesPage(props) {
<View style={[styles.flex1, styles.alignItemsEnd]}>
<Switch
accessibilityLabel={translate('preferencesPage.muteAllSounds')}
isOn={lodashGet(props.user, 'isMutedAllSounds', false)}
isOn={user?.isMutedAllSounds ?? false}
onToggle={User.setMuteAllSounds}
/>
</View>
</View>
<MenuItemWithTopDescription
shouldShowRightIcon
title={translate(`priorityModePage.priorityModes.${props.priorityMode}.label`)}
title={translate(`priorityModePage.priorityModes.${priorityMode ?? CONST.PRIORITY_MODE.DEFAULT}.label`)}
description={translate('priorityModePage.priorityMode')}
onPress={() => Navigation.navigate(ROUTES.SETTINGS_PRIORITY_MODE)}
wrapperStyle={styles.sectionMenuItemTopDescription}
/>
<MenuItemWithTopDescription
shouldShowRightIcon
title={translate(`languagePage.languages.${preferredLocale}.label`)}
title={translate(`languagePage.languages.${LocaleUtils.getLanguageFromLocale(preferredLocale)}.label`)}
description={translate('languagePage.language')}
onPress={() => Navigation.navigate(ROUTES.SETTINGS_LANGUAGE)}
wrapperStyle={styles.sectionMenuItemTopDescription}
/>
<MenuItemWithTopDescription
shouldShowRightIcon
title={translate(`themePage.themes.${props.preferredTheme || CONST.THEME.DEFAULT}.label`)}
title={translate(`themePage.themes.${preferredTheme ?? CONST.THEME.DEFAULT}.label`)}
description={translate('themePage.theme')}
onPress={() => Navigation.navigate(ROUTES.SETTINGS_THEME)}
wrapperStyle={styles.sectionMenuItemTopDescription}
Expand All @@ -129,11 +123,9 @@ function PreferencesPage(props) {
);
}

PreferencesPage.propTypes = propTypes;
PreferencesPage.defaultProps = defaultProps;
PreferencesPage.displayName = 'PreferencesPage';

export default withOnyx({
export default withOnyx<PreferencesPageProps, PreferencesPageOnyxProps>({
priorityMode: {
key: ONYXKEYS.NVP_PRIORITY_MODE,
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,49 +1,54 @@
import PropTypes from 'prop-types';
import React, {useCallback} from 'react';
import {withOnyx} from 'react-native-onyx';
import _, {compose} from 'underscore';
import type {ValueOf} from 'type-fest';
import HeaderWithBackButton from '@components/HeaderWithBackButton';
import ScreenWrapper from '@components/ScreenWrapper';
import SelectionList from '@components/SelectionList';
import RadioListItem from '@components/SelectionList/RadioListItem';
import Text from '@components/Text';
import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
import useLocalize from '@hooks/useLocalize';
import useThemeStyles from '@hooks/useThemeStyles';
import Navigation from '@libs/Navigation/Navigation';
import * as User from '@userActions/User';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import type {PriorityMode} from '@src/types/onyx';

const propTypes = {
/** The chat priority mode */
priorityMode: PropTypes.string,

...withLocalizePropTypes,
type PriorityModeItem = {
value: ValueOf<typeof CONST.PRIORITY_MODE>;
text: string;
alternateText: string;
keyForList: ValueOf<typeof CONST.PRIORITY_MODE>;
isSelected: boolean;
};

const defaultProps = {
priorityMode: CONST.PRIORITY_MODE.DEFAULT,
type PriorityModePageOnyxProps = {
/** The chat priority mode */
priorityMode: PriorityMode;
};

function PriorityModePage(props) {
type PriorityModePageProps = PriorityModePageOnyxProps;

function PriorityModePage({priorityMode}: PriorityModePageProps) {
const {translate} = useLocalize();
const styles = useThemeStyles();
const priorityModes = _.map(_.values(CONST.PRIORITY_MODE), (mode) => ({
const priorityModes = Object.values(CONST.PRIORITY_MODE).map<PriorityModeItem>((mode) => ({
value: mode,
text: props.translate(`priorityModePage.priorityModes.${mode}.label`),
alternateText: props.translate(`priorityModePage.priorityModes.${mode}.description`),
text: translate(`priorityModePage.priorityModes.${mode}.label`),
alternateText: translate(`priorityModePage.priorityModes.${mode}.description`),
keyForList: mode,
isSelected: props.priorityMode === mode,
isSelected: priorityMode === mode,
}));

const updateMode = useCallback(
(mode) => {
if (mode.value === props.priorityMode) {
(mode: PriorityModeItem) => {
if (mode.value === priorityMode) {
Navigation.goBack();
return;
}
User.updateChatPriorityMode(mode.value);
},
[props.priorityMode],
[priorityMode],
);

return (
Expand All @@ -52,29 +57,24 @@ function PriorityModePage(props) {
testID={PriorityModePage.displayName}
>
<HeaderWithBackButton
title={props.translate('priorityModePage.priorityMode')}
title={translate('priorityModePage.priorityMode')}
onBackButtonPress={() => Navigation.goBack()}
/>
<Text style={[styles.mh5, styles.mv3]}>{props.translate('priorityModePage.explainerText')}</Text>
<Text style={[styles.mh5, styles.mv3]}>{translate('priorityModePage.explainerText')}</Text>
<SelectionList
sections={[{data: priorityModes}]}
ListItem={RadioListItem}
onSelectRow={updateMode}
initiallyFocusedOptionKey={_.find(priorityModes, (mode) => mode.isSelected).keyForList}
initiallyFocusedOptionKey={priorityModes.find((mode) => mode.isSelected)?.keyForList}
/>
</ScreenWrapper>
);
}

PriorityModePage.displayName = 'PriorityModePage';
PriorityModePage.propTypes = propTypes;
PriorityModePage.defaultProps = defaultProps;

export default compose(
withLocalize,
withOnyx({
priorityMode: {
key: ONYXKEYS.NVP_PRIORITY_MODE,
},
}),
)(PriorityModePage);
export default withOnyx<PriorityModePageProps, PriorityModePageOnyxProps>({
priorityMode: {
key: ONYXKEYS.NVP_PRIORITY_MODE,
},
})(PriorityModePage);
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import PropTypes from 'prop-types';
import React from 'react';
import {withOnyx} from 'react-native-onyx';
import _ from 'underscore';
import HeaderWithBackButton from '@components/HeaderWithBackButton';
import ScreenWrapper from '@components/ScreenWrapper';
import SelectionList from '@components/SelectionList';
Expand All @@ -13,24 +11,24 @@ import Navigation from '@libs/Navigation/Navigation';
import * as User from '@userActions/User';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import type {PreferredTheme} from '@src/types/onyx';

const propTypes = {
type ThemePageOnyxProps = {
/** The theme of the app */
preferredTheme: PropTypes.string,
preferredTheme: PreferredTheme;
};

const defaultProps = {
preferredTheme: CONST.THEME.DEFAULT,
};
type ThemePageProps = ThemePageOnyxProps;

function ThemePage(props) {
function ThemePage({preferredTheme}: ThemePageProps) {
const styles = useThemeStyles();
const {translate} = useLocalize();
const localesToThemes = _.map(_.values(_.omit(CONST.THEME, 'DEFAULT', 'FALLBACK')), (theme) => ({
const {DEFAULT, FALLBACK, ...themes} = CONST.THEME;
const localesToThemes = Object.values(themes).map((theme) => ({
value: theme,
text: translate(`themePage.themes.${theme}.label`),
keyForList: theme,
isSelected: (props.preferredTheme || CONST.THEME.DEFAULT) === theme,
isSelected: (preferredTheme ?? CONST.THEME.DEFAULT) === theme,
}));

return (
Expand All @@ -51,17 +49,15 @@ function ThemePage(props) {
sections={[{data: localesToThemes}]}
ListItem={RadioListItem}
onSelectRow={(theme) => User.updateTheme(theme.value)}
initiallyFocusedOptionKey={_.find(localesToThemes, (theme) => theme.isSelected).keyForList}
initiallyFocusedOptionKey={localesToThemes.find((theme) => theme.isSelected)?.keyForList}
/>
</ScreenWrapper>
);
}

ThemePage.displayName = 'ThemePage';
ThemePage.propTypes = propTypes;
ThemePage.defaultProps = defaultProps;

export default withOnyx({
export default withOnyx<ThemePageProps, ThemePageOnyxProps>({
preferredTheme: {
key: ONYXKEYS.PREFERRED_THEME,
},
Expand Down
7 changes: 7 additions & 0 deletions src/types/onyx/PreferredTheme.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import type {OnyxEntry} from 'react-native-onyx';
import type {ValueOf} from 'type-fest';
import type CONST from '@src/CONST';

type PreferredTheme = OnyxEntry<ValueOf<typeof CONST.THEME>>;

export default PreferredTheme;
7 changes: 7 additions & 0 deletions src/types/onyx/PriorityMode.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import type {OnyxEntry} from 'react-native-onyx';
import type {ValueOf} from 'type-fest';
import type CONST from '@src/CONST';

type PriorityMode = OnyxEntry<ValueOf<typeof CONST.PRIORITY_MODE>>;

export default PriorityMode;
4 changes: 4 additions & 0 deletions src/types/onyx/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ import type {PolicyMembers} from './PolicyMember';
import type PolicyMember from './PolicyMember';
import type {PolicyReportField, PolicyReportFields} from './PolicyReportField';
import type {PolicyTag, PolicyTagList, PolicyTags} from './PolicyTag';
import type PreferredTheme from './PreferredTheme';
import type PriorityMode from './PriorityMode';
import type PrivatePersonalDetails from './PrivatePersonalDetails';
import type RecentlyUsedCategories from './RecentlyUsedCategories';
import type RecentlyUsedReportFields from './RecentlyUsedReportFields';
Expand Down Expand Up @@ -114,6 +116,8 @@ export type {
PolicyTag,
PolicyTags,
PolicyTagList,
PreferredTheme,
PriorityMode,
PrivatePersonalDetails,
RecentWaypoint,
RecentlyUsedCategories,
Expand Down

0 comments on commit 34930fe

Please sign in to comment.