Skip to content

Commit

Permalink
Merge pull request #22153 from yh-0218/yh-funcCompMigrate-16281
Browse files Browse the repository at this point in the history
migrate InitialSettingsPage to function component #16281
  • Loading branch information
danieldoglas authored Jul 27, 2023
2 parents f8bb2b1 + 5a6274c commit 82636ee
Showing 1 changed file with 159 additions and 147 deletions.
306 changes: 159 additions & 147 deletions src/pages/settings/InitialSettingsPage.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import lodashGet from 'lodash/get';
import React from 'react';
import {ScrollView, View} from 'react-native';
import React, {useState, useEffect, useRef, useMemo, useCallback} from 'react';
import {View, ScrollView} from 'react-native';
import PropTypes from 'prop-types';
import _ from 'underscore';
import {withOnyx} from 'react-native-onyx';
Expand Down Expand Up @@ -40,6 +40,7 @@ import * as ReportActionContextMenu from '../home/report/ContextMenu/ReportActio
import {CONTEXT_MENU_TYPES} from '../home/report/ContextMenu/ContextMenuActions';
import * as CurrencyUtils from '../../libs/CurrencyUtils';
import PressableWithoutFeedback from '../../components/Pressable/PressableWithoutFeedback';
import useLocalize from '../../hooks/useLocalize';

const propTypes = {
/* Onyx Props */
Expand Down Expand Up @@ -123,42 +124,44 @@ const defaultProps = {
...withCurrentUserPersonalDetailsDefaultProps,
};

class InitialSettingsPage extends React.Component {
constructor(props) {
super(props);
function InitialSettingsPage(props) {
const popoverAnchor = useRef(null);
const {translate} = useLocalize();

this.popoverAnchor = React.createRef();
const [shouldShowSignoutConfirmModal, setShouldShowSignoutConfirmModal] = useState(false);

this.getWalletBalance = this.getWalletBalance.bind(this);
this.getDefaultMenuItems = this.getDefaultMenuItems.bind(this);
this.getMenuItem = this.getMenuItem.bind(this);
this.toggleSignoutConfirmModal = this.toggleSignoutConfirmModal.bind(this);
this.signout = this.signOut.bind(this);
useEffect(() => {
Wallet.openInitialSettingsPage();
}, []);

this.state = {
shouldShowSignoutConfirmModal: false,
};
}
const toggleSignoutConfirmModal = (value) => {
setShouldShowSignoutConfirmModal(value);
};

componentDidMount() {
Wallet.openInitialSettingsPage();
}
const openProfileSettings = () => {
Navigation.navigate(ROUTES.SETTINGS_PROFILE);
};

/**
* @param {Boolean} isPaymentItem whether the item being rendered is the payments menu item
* @returns {Number} the user wallet balance
*/
getWalletBalance(isPaymentItem) {
return isPaymentItem && Permissions.canUseWallet(this.props.betas) ? CurrencyUtils.convertToDisplayString(this.props.userWallet.currentBalance) : undefined;
}
const signOut = useCallback(
(shouldForceSignout = false) => {
if (props.network.isOffline || shouldForceSignout) {
Session.signOutAndRedirectToSignIn();
return;
}

// When offline, warn the user that any actions they took while offline will be lost if they sign out
toggleSignoutConfirmModal(true);
},
[props.network.isOffline],
);

/**
* Retuns a list of default menu items
* @returns {Array} the default menu items
*/
getDefaultMenuItems() {
const policiesAvatars = _.chain(this.props.policies)
.filter((policy) => PolicyUtils.shouldShowPolicy(policy, this.props.network.isOffline))
const getDefaultMenuItems = useMemo(() => {
const policiesAvatars = _.chain(props.policies)
.filter((policy) => PolicyUtils.shouldShowPolicy(policy, props.network.isOffline))
.sortBy((policy) => policy.name.toLowerCase())
.map((policy) => ({
source: policy.avatar || ReportUtils.getDefaultWorkspaceAvatar(policy.name),
Expand All @@ -168,14 +171,14 @@ class InitialSettingsPage extends React.Component {
.value();

const policyBrickRoadIndicator =
!_.isEmpty(this.props.reimbursementAccount.errors) ||
_.chain(this.props.policies)
!_.isEmpty(props.reimbursementAccount.errors) ||
_.chain(props.policies)
.filter((policy) => policy && policy.type === CONST.POLICY.TYPE.FREE && policy.role === CONST.POLICY.ROLE.ADMIN)
.some((policy) => PolicyUtils.hasPolicyError(policy) || PolicyUtils.getPolicyBrickRoadIndicatorStatus(policy, this.props.allPolicyMembers))
.some((policy) => PolicyUtils.hasPolicyError(policy) || PolicyUtils.getPolicyBrickRoadIndicatorStatus(policy, props.allPolicyMembers))
.value()
? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR
: null;
const profileBrickRoadIndicator = UserUtils.getLoginListBrickRoadIndicator(this.props.loginList);
const profileBrickRoadIndicator = UserUtils.getLoginListBrickRoadIndicator(props.loginList);

return [
{
Expand Down Expand Up @@ -225,9 +228,7 @@ class InitialSettingsPage extends React.Component {
Navigation.navigate(ROUTES.SETTINGS_PAYMENTS);
},
brickRoadIndicator:
PaymentMethods.hasPaymentMethodError(this.props.bankAccountList, this.props.cardList) ||
!_.isEmpty(this.props.userWallet.errors) ||
!_.isEmpty(this.props.walletTerms.errors)
PaymentMethods.hasPaymentMethodError(props.bankAccountList, props.cardList) || !_.isEmpty(props.userWallet.errors) || !_.isEmpty(props.walletTerms.errors)
? 'error'
: null,
},
Expand All @@ -252,134 +253,145 @@ class InitialSettingsPage extends React.Component {
translationKey: 'initialSettingsPage.signOut',
icon: Expensicons.Exit,
action: () => {
this.signout(false);
signOut(false);
},
},
];
}

getMenuItem(item, index) {
const keyTitle = item.translationKey ? this.props.translate(item.translationKey) : item.title;
const isPaymentItem = item.translationKey === 'common.payments';
}, [
props.allPolicyMembers,
props.bankAccountList,
props.cardList,
props.loginList,
props.network.isOffline,
props.policies,
props.reimbursementAccount.errors,
props.userWallet.errors,
props.walletTerms.errors,
signOut,
]);

const getMenuItems = useMemo(() => {
/**
* @param {Boolean} isPaymentItem whether the item being rendered is the payments menu item
* @returns {Number} the user wallet balance
*/
const getWalletBalance = (isPaymentItem) =>
isPaymentItem && Permissions.canUseWallet(props.betas) ? CurrencyUtils.convertToDisplayString(props.userWallet.currentBalance) : undefined;

return (
<MenuItem
key={`${keyTitle}_${index}`}
title={keyTitle}
icon={item.icon}
iconType={item.iconType}
onPress={item.action}
iconStyles={item.iconStyles}
shouldShowRightIcon
iconRight={item.iconRight}
badgeText={this.getWalletBalance(isPaymentItem)}
fallbackIcon={item.fallbackIcon}
brickRoadIndicator={item.brickRoadIndicator}
floatRightAvatars={item.floatRightAvatars}
shouldStackHorizontally={item.shouldStackHorizontally}
floatRightAvatarSize={item.avatarSize}
ref={this.popoverAnchor}
shouldBlockSelection={Boolean(item.link)}
onSecondaryInteraction={!_.isEmpty(item.link) ? (e) => ReportActionContextMenu.showContextMenu(CONTEXT_MENU_TYPES.LINK, e, item.link, this.popoverAnchor.current) : undefined}
/>
<>
{_.map(getDefaultMenuItems, (item, index) => {
const keyTitle = item.translationKey ? translate(item.translationKey) : item.title;
const isPaymentItem = item.translationKey === 'common.payments';

return (
<MenuItem
key={`${keyTitle}_${index}`}
title={keyTitle}
icon={item.icon}
iconType={item.iconType}
onPress={item.action}
iconStyles={item.iconStyles}
shouldShowRightIcon
iconRight={item.iconRight}
badgeText={getWalletBalance(isPaymentItem)}
fallbackIcon={item.fallbackIcon}
brickRoadIndicator={item.brickRoadIndicator}
floatRightAvatars={item.floatRightAvatars}
shouldStackHorizontally={item.shouldStackHorizontally}
floatRightAvatarSize={item.avatarSize}
ref={popoverAnchor}
shouldBlockSelection={Boolean(item.link)}
onSecondaryInteraction={
!_.isEmpty(item.link) ? (e) => ReportActionContextMenu.showContextMenu(CONTEXT_MENU_TYPES.LINK, e, item.link, popoverAnchor.current) : undefined
}
/>
);
})}
</>
);
}
}, [getDefaultMenuItems, props.betas, props.userWallet.currentBalance, translate]);

toggleSignoutConfirmModal(value) {
this.setState({shouldShowSignoutConfirmModal: value});
// On the very first sign in or after clearing storage these
// details will not be present on the first render so we'll just
// return nothing for now.
if (_.isEmpty(props.currentUserPersonalDetails)) {
return null;
}

signOut(shouldForceSignout = false) {
if (!this.props.network.isOffline || shouldForceSignout) {
Session.signOutAndRedirectToSignIn();
return;
}

// When offline, warn the user that any actions they took while offline will be lost if they sign out
this.toggleSignoutConfirmModal(true);
}

openProfileSettings() {
Navigation.navigate(ROUTES.SETTINGS_PROFILE);
}

render() {
return (
<ScreenWrapper includeSafeAreaPaddingBottom={false}>
{({safeAreaPaddingBottomStyle}) => (
<>
<HeaderWithBackButton title={this.props.translate('common.settings')} />
<ScrollView
contentContainerStyle={safeAreaPaddingBottomStyle}
style={[styles.settingsPageBackground]}
>
<View style={styles.w100}>
{_.isEmpty(this.props.currentUserPersonalDetails) || _.isUndefined(this.props.currentUserPersonalDetails.displayName) ? (
<CurrentUserPersonalDetailsSkeletonView />
) : (
<View style={styles.avatarSectionWrapper}>
<Tooltip text={this.props.translate('common.profile')}>
<PressableWithoutFeedback
style={[styles.mb3]}
onPress={this.openProfileSettings}
accessibilityLabel={this.props.translate('common.profile')}
accessibilityRole={CONST.ACCESSIBILITY_ROLE.BUTTON}
>
<OfflineWithFeedback pendingAction={lodashGet(this.props.currentUserPersonalDetails, 'pendingFields.avatar', null)}>
<Avatar
imageStyles={[styles.avatarLarge]}
source={UserUtils.getAvatar(this.props.currentUserPersonalDetails.avatar, this.props.session.accountID)}
size={CONST.AVATAR_SIZE.LARGE}
/>
</OfflineWithFeedback>
</PressableWithoutFeedback>
</Tooltip>
return (
<ScreenWrapper includeSafeAreaPaddingBottom={false}>
{({safeAreaPaddingBottomStyle}) => (
<>
<HeaderWithBackButton title={translate('common.settings')} />
<ScrollView
contentContainerStyle={safeAreaPaddingBottomStyle}
style={[styles.settingsPageBackground]}
>
<View style={styles.w100}>
{_.isEmpty(props.currentUserPersonalDetails) || _.isUndefined(props.currentUserPersonalDetails.displayName) ? (
<CurrentUserPersonalDetailsSkeletonView />
) : (
<View style={styles.avatarSectionWrapper}>
<Tooltip text={translate('common.profile')}>
<PressableWithoutFeedback
style={[styles.mt1, styles.mw100]}
onPress={this.openProfileSettings}
accessibilityLabel={this.props.translate('common.profile')}
accessibilityRole={CONST.ACCESSIBILITY_ROLE.LINK}
style={[styles.mb3]}
onPress={openProfileSettings}
accessibilityLabel={translate('common.profile')}
accessibilityRole={CONST.ACCESSIBILITY_ROLE.BUTTON}
>
<Tooltip text={this.props.translate('common.profile')}>
<Text
style={[styles.textHeadline, styles.pre]}
numberOfLines={1}
>
{this.props.currentUserPersonalDetails.displayName
? this.props.currentUserPersonalDetails.displayName
: this.props.formatPhoneNumber(this.props.session.email)}
</Text>
</Tooltip>
<OfflineWithFeedback pendingAction={lodashGet(props.currentUserPersonalDetails, 'pendingFields.avatar', null)}>
<Avatar
imageStyles={[styles.avatarLarge]}
source={UserUtils.getAvatar(props.currentUserPersonalDetails.avatar, props.session.accountID)}
size={CONST.AVATAR_SIZE.LARGE}
/>
</OfflineWithFeedback>
</PressableWithoutFeedback>
{Boolean(this.props.currentUserPersonalDetails.displayName) && (
</Tooltip>
<PressableWithoutFeedback
style={[styles.mt1, styles.mw100]}
onPress={openProfileSettings}
accessibilityLabel={translate('common.profile')}
accessibilityRole={CONST.ACCESSIBILITY_ROLE.LINK}
>
<Tooltip text={translate('common.profile')}>
<Text
style={[styles.textLabelSupporting, styles.mt1]}
style={[styles.textHeadline, styles.pre]}
numberOfLines={1}
>
{this.props.formatPhoneNumber(this.props.session.email)}
{props.currentUserPersonalDetails.displayName ? props.currentUserPersonalDetails.displayName : props.formatPhoneNumber(props.session.email)}
</Text>
)}
</View>
)}
{_.map(this.getDefaultMenuItems(), (item, index) => this.getMenuItem(item, index))}

<ConfirmModal
danger
title={this.props.translate('common.areYouSure')}
prompt={this.props.translate('initialSettingsPage.signOutConfirmationText')}
confirmText={this.props.translate('initialSettingsPage.signOut')}
cancelText={this.props.translate('common.cancel')}
isVisible={this.state.shouldShowSignoutConfirmModal}
onConfirm={() => this.signOut(true)}
onCancel={() => this.toggleSignoutConfirmModal(false)}
/>
</View>
</ScrollView>
</>
)}
</ScreenWrapper>
);
}
</Tooltip>
</PressableWithoutFeedback>
{Boolean(props.currentUserPersonalDetails.displayName) && (
<Text
style={[styles.textLabelSupporting, styles.mt1]}
numberOfLines={1}
>
{props.formatPhoneNumber(props.session.email)}
</Text>
)}
</View>
)}
{getMenuItems}

<ConfirmModal
danger
title={translate('common.areYouSure')}
prompt={translate('initialSettingsPage.signOutConfirmationText')}
confirmText={translate('initialSettingsPage.signOut')}
cancelText={translate('common.cancel')}
isVisible={shouldShowSignoutConfirmModal}
onConfirm={() => signOut(true)}
onCancel={() => toggleSignoutConfirmModal(false)}
/>
</View>
</ScrollView>
</>
)}
</ScreenWrapper>
);
}

InitialSettingsPage.propTypes = propTypes;
Expand Down

0 comments on commit 82636ee

Please sign in to comment.