diff --git a/app/components/UI/AccountOverview/index.test.tsx b/app/components/UI/AccountOverview/index.test.tsx index 303d3fe177d..e178aaf3e80 100644 --- a/app/components/UI/AccountOverview/index.test.tsx +++ b/app/components/UI/AccountOverview/index.test.tsx @@ -48,6 +48,7 @@ describe('AccountOverview', () => { address: '0xe7E125654064EEa56229f273dA586F10DF96B0a1', balanceFiat: 1604.2, label: 'Account 1', + name: '', }; const { toJSON } = renderWithProvider( , diff --git a/app/components/UI/AccountOverview/index.js b/app/components/UI/AccountOverview/index.tsx similarity index 75% rename from app/components/UI/AccountOverview/index.js rename to app/components/UI/AccountOverview/index.tsx index 73e326e6c8e..120fc436056 100644 --- a/app/components/UI/AccountOverview/index.js +++ b/app/components/UI/AccountOverview/index.tsx @@ -1,5 +1,5 @@ -import PropTypes from 'prop-types'; -import React, { PureComponent } from 'react'; +// this whole file is unused; https://github.com/metaMask/metamask-mobile/pull/6085 +import React, { PureComponent, RefObject } from 'react'; import { InteractionManager, ScrollView, @@ -7,8 +7,10 @@ import { TextInput, TouchableOpacity, View, + ViewStyle, + TextStyle, } from 'react-native'; -import { connect } from 'react-redux'; +import { connect, ConnectedProps } from 'react-redux'; import { strings } from '../../../../locales/i18n'; import { WalletViewSelectorsIDs } from '../../../../e2e/selectors/wallet/WalletView.selectors'; import { showAlert } from '../../../actions/alert'; @@ -42,12 +44,36 @@ import { createAccountSelectorNavDetails } from '../../Views/AccountSelector'; import Text, { TextVariant, } from '../../../component-library/components/Texts/Text'; -import { withMetricsAwareness } from '../../../components/hooks/useMetrics'; +import { IUseMetricsHook, withMetricsAwareness } from '../../hooks/useMetrics'; import { isPortfolioUrl } from '../../../util/url'; import { toLowerCaseEquals } from '../../../util/general'; +import { Dispatch } from 'redux'; +import { ThemeColors } from '@metamask/design-tokens/dist/types/js/themes/types'; +import { RootState } from 'app/reducers'; -const createStyles = (colors) => - StyleSheet.create({ +interface StylesType { + scrollView: ViewStyle; + wrapper: ViewStyle; + info: ViewStyle; + data: ViewStyle; + label: TextStyle; + labelInput: ViewStyle; + labelWrapper: ViewStyle; + tag: ViewStyle; + tagText: TextStyle; + addressWrapper: ViewStyle; + address: TextStyle; + amountFiat: TextStyle; + identiconBorder: ViewStyle; + onboardingWizardLabel: ViewStyle; + actions: ViewStyle; + netWorthContainer: ViewStyle; + portfolioLink: ViewStyle; + portfolioIcon: TextStyle; +} + +const createStyles = (colors: ThemeColors): StylesType => + StyleSheet.create({ scrollView: { backgroundColor: colors.background.default, }, @@ -134,6 +160,7 @@ const createStyles = (colors) => flexDirection: 'row', }, netWorthContainer: { + // @ts-expect-error TODO (js-ts migration followups): delete this line since it's not a real css property (should be justifyContent) justifyItems: 'center', alignItems: 'center', flexDirection: 'row', @@ -141,70 +168,31 @@ const createStyles = (colors) => portfolioLink: { marginLeft: 5 }, portfolioIcon: { color: colors.primary.default }, }); +interface State { + accountLabelEditable: boolean; + accountLabel: string; + originalAccountLabel: string; + ens: string | undefined; +} /** * View that's part of the component * which shows information about the selected account */ -class AccountOverview extends PureComponent { - static propTypes = { - /** - * String that represents the selected address - */ - selectedAddress: PropTypes.string, - /** - /* InternalAccounts object required to get account name - */ - internalAccounts: PropTypes.object, - /** - * Object that represents the selected account - */ - account: PropTypes.object, - /** - /* Triggers global alert - */ - showAlert: PropTypes.func, - /** - * whether component is being rendered from onboarding wizard - */ - onboardingWizard: PropTypes.bool, - /** - * Used to get child ref - */ - onRef: PropTypes.func, - /** - * Prompts protect wallet modal - */ - protectWalletModalVisible: PropTypes.func, - /** - /* navigation object required to access the props - /* passed by the parent component - */ - navigation: PropTypes.object, - /** - * The chain ID for the current selected network - */ - chainId: PropTypes.string, - /** - * Current opens tabs in browser - */ - browserTabs: PropTypes.array, - /** - * Metrics injected by withMetricsAwareness HOC - */ - metrics: PropTypes.object, - }; +class AccountOverview extends PureComponent { + static contextType = ThemeContext; - state = { + state: State = { accountLabelEditable: false, accountLabel: '', originalAccountLabel: '', ens: undefined, }; - editableLabelRef = React.createRef(); - scrollViewContainer = React.createRef(); - mainView = React.createRef(); + editableLabelRef: RefObject = React.createRef(); + scrollViewContainer: RefObject = React.createRef(); + mainView: RefObject = React.createRef(); + input: RefObject = React.createRef(); openAccountSelector = () => { const { onboardingWizard, navigation } = this.props; @@ -212,14 +200,14 @@ class AccountOverview extends PureComponent { navigation.navigate(...createAccountSelectorNavDetails({})); }; - isAccountLabelDefined = (accountLabel) => + isAccountLabelDefined = (accountLabel: string): boolean => !!accountLabel && !!accountLabel.trim().length; - input = React.createRef(); - componentDidMount = () => { const { internalAccounts, selectedAddress, onRef } = this.props; - const accountLabel = renderAccountName(selectedAddress, internalAccounts); + // TODO (js-ts migration followups): properly guard the case where selectedAddress is undefined + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const accountLabel = renderAccountName(selectedAddress!, internalAccounts); this.setState({ accountLabel }); onRef && onRef(this); InteractionManager.runAfterInteractions(() => { @@ -227,11 +215,12 @@ class AccountOverview extends PureComponent { }); if (!this.isAccountLabelDefined(accountLabel)) { - Engine.setAccountLabel(selectedAddress, 'Account'); + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + Engine.setAccountLabel(selectedAddress!, 'Account'); } }; - componentDidUpdate(prevProps) { + componentDidUpdate(prevProps: Props) { if ( prevProps.account.address !== this.props.account.address || prevProps.chainId !== this.props.chainId @@ -251,30 +240,38 @@ class AccountOverview extends PureComponent { ); Engine.setAccountLabel( - selectedAddress, + // TODO (js-ts migration followups): properly guard the case where selectedAddress is undefined + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + selectedAddress!, this.isAccountLabelDefined(accountLabel) ? accountLabel - : accountWithMatchingToAddress.metadata.name, + : // TODO (js-ts migration followups): properly guard the case where accountWithMatchingToAddress is undefined + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + accountWithMatchingToAddress!.metadata.name, ); this.setState({ accountLabelEditable: false }); }; - onAccountLabelChange = (accountLabel) => { + onAccountLabelChange = (accountLabel: string) => { this.setState({ accountLabel }); }; setAccountLabelEditable = () => { const { internalAccounts, selectedAddress } = this.props; - const accountLabel = renderAccountName(selectedAddress, internalAccounts); + // TODO (js-ts migration followups): properly guard the case where selectedAddress is undefined + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const accountLabel = renderAccountName(selectedAddress!, internalAccounts); this.setState({ accountLabelEditable: true, accountLabel }); setTimeout(() => { - this.input && this.input.current && this.input.current.focus(); + this.input.current?.focus(); }, 100); }; cancelAccountLabelEdition = () => { const { internalAccounts, selectedAddress } = this.props; - const accountLabel = renderAccountName(selectedAddress, internalAccounts); + // TODO (js-ts migration followups): properly guard the case where selectedAddress is undefined + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const accountLabel = renderAccountName(selectedAddress!, internalAccounts); this.setState({ accountLabelEditable: false, accountLabel }); }; @@ -303,7 +300,7 @@ class AccountOverview extends PureComponent { onOpenPortfolio = () => { const { navigation, browserTabs } = this.props; - const existingPortfolioTab = browserTabs.find((tab) => + const existingPortfolioTab = browserTabs.find((tab: $FIXME) => isPortfolioUrl(tab.url), ); let existingTabId; @@ -442,7 +439,7 @@ class AccountOverview extends PureComponent { } } -const mapStateToProps = (state) => ({ +const mapStateToProps = (state: RootState) => ({ selectedAddress: selectSelectedInternalAccountChecksummedAddress(state), internalAccounts: selectInternalAccounts(state), currentCurrency: selectCurrentCurrency(state), @@ -450,16 +447,25 @@ const mapStateToProps = (state) => ({ browserTabs: state.browser.tabs, }); -const mapDispatchToProps = (dispatch) => ({ - showAlert: (config) => dispatch(showAlert(config)), +const mapDispatchToProps = (dispatch: Dispatch) => ({ + showAlert: ((config) => dispatch(showAlert(config))) as typeof showAlert, protectWalletModalVisible: () => dispatch(protectWalletModalVisible()), - newAssetTransaction: (selectedAsset) => + newAssetTransaction: (selectedAsset: $FIXME) => dispatch(newAssetTransaction(selectedAsset)), }); AccountOverview.contextType = ThemeContext; -export default connect( - mapStateToProps, - mapDispatchToProps, -)(withMetricsAwareness(AccountOverview)); +const connector = connect(mapStateToProps, mapDispatchToProps); + +interface Props extends ConnectedProps { + account: { + address: string; + name: string; + }; + onboardingWizard?: boolean; + onRef?: (ref: AccountOverview) => void; + navigation?: $FIXME; + metrics: IUseMetricsHook; +} +export default connector(withMetricsAwareness(AccountOverview)); diff --git a/app/components/hooks/useMetrics/withMetricsAwareness.test.tsx b/app/components/hooks/useMetrics/withMetricsAwareness.test.tsx index 4823fb818ee..60c7739ed2c 100644 --- a/app/components/hooks/useMetrics/withMetricsAwareness.test.tsx +++ b/app/components/hooks/useMetrics/withMetricsAwareness.test.tsx @@ -3,11 +3,11 @@ import { render } from '@testing-library/react-native'; import withMetricsAwareness from './withMetricsAwareness'; import useMetrics from './useMetrics'; import { View } from 'react-native'; -import { IWithMetricsAwarenessProps } from './withMetricsAwareness.types'; +import { IUseMetricsHook } from './useMetrics.types'; jest.mock('./useMetrics'); -class MockComponent extends Component { +class MockComponent extends Component<{ metrics: IUseMetricsHook }> { render() { return ; } diff --git a/app/components/hooks/useMetrics/withMetricsAwareness.tsx b/app/components/hooks/useMetrics/withMetricsAwareness.tsx index 8ae16c69a03..eb745774939 100644 --- a/app/components/hooks/useMetrics/withMetricsAwareness.tsx +++ b/app/components/hooks/useMetrics/withMetricsAwareness.tsx @@ -1,11 +1,10 @@ import React, { ComponentType } from 'react'; import useMetrics from './useMetrics'; -import { IWithMetricsAwarenessProps } from './withMetricsAwareness.types'; +import { IUseMetricsHook } from './useMetrics.types'; const withMetricsAwareness = - // TODO: Replace "any" with type - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (Children: ComponentType) => (props: any) => - ; +

(Children: ComponentType

) => + (props: Omit) => + ; export default withMetricsAwareness; diff --git a/app/components/hooks/useMetrics/withMetricsAwareness.types.ts b/app/components/hooks/useMetrics/withMetricsAwareness.types.ts deleted file mode 100644 index b12934439ac..00000000000 --- a/app/components/hooks/useMetrics/withMetricsAwareness.types.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { IUseMetricsHook } from './useMetrics.types'; - -export interface IWithMetricsAwarenessProps { - metrics: IUseMetricsHook; -} diff --git a/app/declarations/index.d.ts b/app/declarations/index.d.ts index 094baa70c44..5b3568d8335 100644 --- a/app/declarations/index.d.ts +++ b/app/declarations/index.d.ts @@ -293,3 +293,5 @@ declare module '@metamask/react-native-actionsheet' { const ActionSheet; export default ActionSheet; } + +type $FIXME = any; // eslint-disable-line @typescript-eslint/no-explicit-any