diff --git a/ui/app/components/app/dropdowns/network-dropdown.js b/ui/app/components/app/dropdowns/network-dropdown.js index 0bd9aed86..8907fe12a 100644 --- a/ui/app/components/app/dropdowns/network-dropdown.js +++ b/ui/app/components/app/dropdowns/network-dropdown.js @@ -7,8 +7,13 @@ import * as actions from '../../../store/actions' import { openAlert as displayInvalidCustomNetworkAlert, } from '../../../ducks/alerts/invalid-custom-network' -import { NETWORKS_ROUTE } from '../../../helpers/constants/routes' -import { isPrefixedFormattedHexString } from '../../../../../app/scripts/lib/util' +import { + NETWORKS_ROUTE, + NETWORKS_FORM_ROUTE, +} from '../../../helpers/constants/routes' +import { ENVIRONMENT_TYPE_FULLSCREEN } from '../../../../../app/scripts/lib/enums' +import { getEnvironmentType, isPrefixedFormattedHexString } from '../../../../../app/scripts/lib/util' + import { Dropdown, DropdownMenuItem } from './components/dropdown' import NetworkDropdownIcon from './components/network-dropdown-icon' @@ -44,6 +49,9 @@ function mapDispatchToProps (dispatch) { setNetworksTabAddMode: (isInAddMode) => { dispatch(actions.setNetworksTabAddMode(isInAddMode)) }, + setSelectedSettingsRpcUrl: (url) => { + dispatch(actions.setSelectedSettingsRpcUrl(url)) + }, displayInvalidCustomNetworkAlert: (networkName) => { dispatch(displayInvalidCustomNetworkAlert(networkName)) }, @@ -67,6 +75,7 @@ class NetworkDropdown extends Component { setRpcTarget: PropTypes.func.isRequired, hideNetworkDropdown: PropTypes.func.isRequired, setNetworksTabAddMode: PropTypes.func.isRequired, + setSelectedSettingsRpcUrl: PropTypes.func.isRequired, frequentRpcListDetail: PropTypes.array.isRequired, networkDropdownOpen: PropTypes.bool.isRequired, history: PropTypes.object.isRequired, @@ -176,7 +185,11 @@ class NetworkDropdown extends Component { } render () { - const { provider: { type: providerType, rpcUrl: activeNetwork }, setNetworksTabAddMode } = this.props + const { + provider: { type: providerType, rpcUrl: activeNetwork }, + setNetworksTabAddMode, + setSelectedSettingsRpcUrl, + } = this.props const rpcListDetail = this.props.frequentRpcListDetail const isOpen = this.props.networkDropdownOpen const dropdownMenuItemStyle = { @@ -337,8 +350,13 @@ class NetworkDropdown extends Component { this.props.hideNetworkDropdown()} onClick={() => { + this.props.history.push( + getEnvironmentType() === ENVIRONMENT_TYPE_FULLSCREEN + ? NETWORKS_ROUTE + : NETWORKS_FORM_ROUTE, + ) + setSelectedSettingsRpcUrl('') setNetworksTabAddMode(true) - this.props.history.push(NETWORKS_ROUTE) }} style={dropdownMenuItemStyle} > diff --git a/ui/app/helpers/constants/routes.js b/ui/app/helpers/constants/routes.js index 42ea9d060..d05a6c24c 100644 --- a/ui/app/helpers/constants/routes.js +++ b/ui/app/helpers/constants/routes.js @@ -9,6 +9,7 @@ const SECURITY_ROUTE = '/settings/security' const ABOUT_US_ROUTE = '/settings/about-us' const ALERTS_ROUTE = '/settings/alerts' const NETWORKS_ROUTE = '/settings/networks' +const NETWORKS_FORM_ROUTE = '/settings/networks/form' const CONTACT_LIST_ROUTE = '/settings/contact-list' const CONTACT_EDIT_ROUTE = '/settings/contact-list/edit-contact' const CONTACT_ADD_ROUTE = '/settings/contact-list/add-contact' @@ -75,6 +76,7 @@ const PATH_NAME_MAP = { [ABOUT_US_ROUTE]: 'About Us Page', [ALERTS_ROUTE]: 'Alerts Settings Page', [NETWORKS_ROUTE]: 'Network Settings Page', + [NETWORKS_FORM_ROUTE]: 'Network Settings Page Form', [CONTACT_LIST_ROUTE]: 'Contact List Settings Page', [`${CONTACT_EDIT_ROUTE}/:address`]: 'Edit Contact Settings Page', [CONTACT_ADD_ROUTE]: 'Add Contact Settings Page', @@ -172,6 +174,7 @@ export { CONTACT_MY_ACCOUNTS_VIEW_ROUTE, CONTACT_MY_ACCOUNTS_EDIT_ROUTE, NETWORKS_ROUTE, + NETWORKS_FORM_ROUTE, INITIALIZE_BACKUP_SEED_PHRASE_ROUTE, CONNECT_ROUTE, CONNECT_CONFIRM_PERMISSIONS_ROUTE, diff --git a/ui/app/pages/settings/networks-tab/index.scss b/ui/app/pages/settings/networks-tab/index.scss index 6aa275927..3b82a69fd 100644 --- a/ui/app/pages/settings/networks-tab/index.scss +++ b/ui/app/pages/settings/networks-tab/index.scss @@ -8,6 +8,9 @@ @media screen and (max-width: 575px) { margin-top: 0; + flex-direction: column; + overflow-x: hidden; + align-items: center; } } @@ -22,36 +25,13 @@ } } - &__back-button { - display: none; - - @media screen and (max-width: 575px) { - display: block; - background-image: url('/images/caret-left-black.svg'); - width: 18px; - height: 18px; - opacity: 0.5; - background-size: contain; - background-repeat: no-repeat; - background-position: center; - margin-right: 16px; - cursor: pointer; - position: absolute; - margin-left: 10px; - - [dir='rtl'] & { - transform: rotate(180deg); - } - } - } - &__network-form { - flex: 0.5 0 auto; - max-width: 343px; - max-height: 465px; display: flex; + flex: 1 0 auto; flex-direction: column; justify-content: space-between; + max-width: 343px; + max-height: 465px; .page-container__footer { border-top: none; @@ -78,8 +58,6 @@ &__network-form-row { @media screen and (max-width: 575px) { - display: flex; - flex-direction: column; width: 93%; } @@ -88,11 +66,14 @@ background-color: #fefae8; border: 1px solid #ffd33d; - width: 93%; border-radius: 5px; box-sizing: border-box; padding: 12px; margin: 12px 0; + + @media screen and (max-width: 575px) { + width: 93%; + } } } @@ -118,26 +99,23 @@ max-width: 343px; @media screen and (max-width: 575px) { + flex: 1; + overflow-y: auto; max-width: 100vw; width: 100vw; - overflow-y: scroll; } } - &__add-network-button-wrapper { - display: none; + &__networks-list-popup-footer { + width: 100%; + display: flex; + justify-content: center; + padding-top: 23px; + padding-bottom: 23px; + border-top: 1px solid #d8d8d8; - @media screen and (max-width: 575px) { - display: flex; - padding-top: 19px; - padding-bottom: 23px; - justify-content: center; - align-items: center; - border-top: 1px solid #d8d8d8; - - .button { - width: 178px; - } + .button { + width: 178px; } } @@ -169,11 +147,16 @@ &:hover { cursor: pointer; } + + @media screen and (max-width: 575px) { + margin: 0 4px 0 10px; + } } @media screen and (max-width: 575px) { padding: 20px 23px 21px 17px; border-bottom: 1px solid #d8d8d8; + max-width: 351px; } } @@ -188,6 +171,10 @@ margin-left: 11px; color: #6a737d; + width: 70%; + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; &:hover { cursor: pointer; @@ -215,6 +202,7 @@ position: absolute; width: 24px; height: 24px; + margin: 0 5px; [dir='rtl'] & { transform: rotate(180deg); @@ -239,6 +227,10 @@ flex-flow: row nowrap; margin: 0.75rem 0; + @media screen and (max-width: 575px) { + width: 93%; + } + .btn-default { margin-right: 0.375rem; } diff --git a/ui/app/pages/settings/networks-tab/network-form/network-form.component.js b/ui/app/pages/settings/networks-tab/network-form/network-form.component.js index f689c8ace..41131138c 100644 --- a/ui/app/pages/settings/networks-tab/network-form/network-form.component.js +++ b/ui/app/pages/settings/networks-tab/network-form/network-form.component.js @@ -30,6 +30,7 @@ export default class NetworkForm extends PureComponent { blockExplorerUrl: PropTypes.string, rpcPrefs: PropTypes.object, rpcUrls: PropTypes.array, + isFullScreen: PropTypes.bool, } state = { @@ -67,7 +68,6 @@ export default class NetworkForm extends PureComponent { } componentWillUnmount () { - this.props.onClear() this.setState({ rpcUrl: '', chainId: '', @@ -76,6 +76,11 @@ export default class NetworkForm extends PureComponent { blockExplorerUrl: '', errors: {}, }) + + // onClear will push the network settings route unless was pass false. + // Since we call onClear to cause this component to be unmounted, the + // route will already have been updated, and we avoid setting it twice. + this.props.onClear(false) } resetForm () { @@ -136,11 +141,12 @@ export default class NetworkForm extends PureComponent { onCancel = () => { const { + isFullScreen, networksTabIsInAddMode, onClear, } = this.props - if (networksTabIsInAddMode) { + if (networksTabIsInAddMode || !isFullScreen) { onClear() } else { this.resetForm() @@ -337,14 +343,14 @@ export default class NetworkForm extends PureComponent { errors, } = this.state + const deletable = !networksTabIsInAddMode && !isCurrentRpcTarget && !viewOnly + const isSubmitDisabled = ( - viewOnly || this.stateIsUnchanged() || !rpcUrl || !chainId || Object.values(errors).some((x) => x) ) - const deletable = !networksTabIsInAddMode && !isCurrentRpcTarget && !viewOnly return (
@@ -384,30 +390,34 @@ export default class NetworkForm extends PureComponent { 'optionalBlockExplorerUrl', )}
- { - deletable && ( + {!viewOnly && ( + <> + { + deletable && ( + + ) + } - ) - } - - + + + )}
) diff --git a/ui/app/pages/settings/networks-tab/networks-tab.component.js b/ui/app/pages/settings/networks-tab/networks-tab.component.js index c9450e4c5..f5a748dab 100644 --- a/ui/app/pages/settings/networks-tab/networks-tab.component.js +++ b/ui/app/pages/settings/networks-tab/networks-tab.component.js @@ -1,11 +1,12 @@ import React, { PureComponent } from 'react' import PropTypes from 'prop-types' import classnames from 'classnames' -import { SETTINGS_ROUTE } from '../../../helpers/constants/routes' -import { ENVIRONMENT_TYPE_POPUP } from '../../../../../app/scripts/lib/enums' -import { getEnvironmentType } from '../../../../../app/scripts/lib/util' import Button from '../../../components/ui/button' import LockIcon from '../../../components/ui/lock-icon' +import { + NETWORKS_ROUTE, + NETWORKS_FORM_ROUTE, +} from '../../../helpers/constants/routes' import NetworkDropdownIcon from '../../../components/app/dropdowns/components/network-dropdown-icon' import NetworkForm from './network-form' @@ -17,7 +18,6 @@ export default class NetworksTab extends PureComponent { static propTypes = { editRpc: PropTypes.func.isRequired, - history: PropTypes.object.isRequired, location: PropTypes.object.isRequired, networkIsSelected: PropTypes.bool, networksTabIsInAddMode: PropTypes.bool, @@ -30,10 +30,13 @@ export default class NetworksTab extends PureComponent { providerUrl: PropTypes.string, providerType: PropTypes.string, networkDefaultedToProvider: PropTypes.bool, + history: PropTypes.object.isRequired, + shouldRenderNetworkForm: PropTypes.bool.isRequired, + isFullScreen: PropTypes.bool.isRequired, } - UNSAFE_componentWillMount () { - this.props.setSelectedSettingsRpcUrl(null) + componentWillUnmount () { + this.props.setSelectedSettingsRpcUrl('') } isCurrentPath (pathname) { @@ -42,32 +45,19 @@ export default class NetworksTab extends PureComponent { renderSubHeader () { const { - networkIsSelected, setSelectedSettingsRpcUrl, setNetworksTabAddMode, - networksTabIsInAddMode, - networkDefaultedToProvider, } = this.props return (
-
{ - setNetworksTabAddMode(false) - setSelectedSettingsRpcUrl(null) - } - : () => this.props.history.push(SETTINGS_ROUTE) - } - /> { this.context.t('networks') }
-
- ) - : null - } + {isFullScreen && this.renderSubHeader()} +
+ {this.renderNetworksTabContent()} + {!isFullScreen && !shouldRenderNetworkForm + ? ( +
+ +
+ ) + : null + } +
) } diff --git a/ui/app/pages/settings/networks-tab/networks-tab.container.js b/ui/app/pages/settings/networks-tab/networks-tab.container.js index 7e61c5cff..83926d0b8 100644 --- a/ui/app/pages/settings/networks-tab/networks-tab.container.js +++ b/ui/app/pages/settings/networks-tab/networks-tab.container.js @@ -9,12 +9,23 @@ import { editRpc, showModal, } from '../../../store/actions' +import { NETWORKS_FORM_ROUTE } from '../../../helpers/constants/routes' +import { ENVIRONMENT_TYPE_FULLSCREEN } from '../../../../../app/scripts/lib/enums' +import { getEnvironmentType } from '../../../../../app/scripts/lib/util' import NetworksTab from './networks-tab.component' import { defaultNetworksData } from './networks-tab.constants' const defaultNetworks = defaultNetworksData.map((network) => ({ ...network, viewOnly: true })) -const mapStateToProps = (state) => { +const mapStateToProps = (state, ownProps) => { + const { location: { pathname } } = ownProps + + const environmentType = getEnvironmentType() + const isFullScreen = environmentType === ENVIRONMENT_TYPE_FULLSCREEN + const shouldRenderNetworkForm = ( + isFullScreen || Boolean(pathname.match(NETWORKS_FORM_ROUTE)) + ) + const { frequentRpcListDetail, provider, @@ -32,7 +43,7 @@ const mapStateToProps = (state) => { rpcUrl: rpc.rpcUrl, chainId: rpc.chainId, ticker: rpc.ticker, - blockExplorerUrl: (rpc.rpcPrefs && rpc.rpcPrefs.blockExplorerUrl) || '', + blockExplorerUrl: (rpc.rpcPrefs?.blockExplorerUrl) || '', } }) @@ -56,6 +67,8 @@ const mapStateToProps = (state) => { providerType: provider.type, providerUrl: provider.rpcUrl, networkDefaultedToProvider, + isFullScreen, + shouldRenderNetworkForm, } } diff --git a/ui/app/pages/settings/settings.component.js b/ui/app/pages/settings/settings.component.js index d4372eed0..5986dd39d 100644 --- a/ui/app/pages/settings/settings.component.js +++ b/ui/app/pages/settings/settings.component.js @@ -34,7 +34,7 @@ class SettingsPage extends PureComponent { currentPath: PropTypes.string, history: PropTypes.object, isAddressEntryPage: PropTypes.bool, - isPopupView: PropTypes.bool, + isPopup: PropTypes.bool, pathnameI18nKey: PropTypes.string, initialBreadCrumbRoute: PropTypes.string, breadCrumbTextKey: PropTypes.string, @@ -57,7 +57,7 @@ class SettingsPage extends PureComponent { >
{ - currentPath !== SETTINGS_ROUTE && currentPath !== NETWORKS_ROUTE && ( + currentPath !== SETTINGS_ROUTE && (
history.push(backRoute)} @@ -85,13 +85,13 @@ class SettingsPage extends PureComponent { renderTitle () { const { t } = this.context - const { isPopupView, pathnameI18nKey, addressName } = this.props + const { isPopup, pathnameI18nKey, addressName } = this.props let titleText - if (isPopupView && addressName) { + if (isPopup && addressName) { titleText = addressName - } else if (pathnameI18nKey && isPopupView) { + } else if (pathnameI18nKey && isPopup) { titleText = t(pathnameI18nKey) } else { titleText = t('settings') @@ -108,7 +108,7 @@ class SettingsPage extends PureComponent { const { t } = this.context const { currentPath, - isPopupView, + isPopup, isAddressEntryPage, pathnameI18nKey, addressName, @@ -120,7 +120,7 @@ class SettingsPage extends PureComponent { let subheaderText - if (isPopupView && isAddressEntryPage) { + if (isPopup && isAddressEntryPage) { subheaderText = t('settings') } else if (initialBreadCrumbKey) { subheaderText = t(initialBreadCrumbKey) @@ -128,7 +128,7 @@ class SettingsPage extends PureComponent { subheaderText = t(pathnameI18nKey || 'general') } - return currentPath !== NETWORKS_ROUTE && ( + return !currentPath.startsWith(NETWORKS_ROUTE) && (
diff --git a/ui/app/pages/settings/settings.container.js b/ui/app/pages/settings/settings.container.js index 8336c0314..e55319f07 100644 --- a/ui/app/pages/settings/settings.container.js +++ b/ui/app/pages/settings/settings.container.js @@ -8,33 +8,37 @@ import { getEnvironmentType } from '../../../../app/scripts/lib/util' import { getMostRecentOverviewPage } from '../../ducks/history/history' import { - ADVANCED_ROUTE, - SECURITY_ROUTE, - GENERAL_ROUTE, - ALERTS_ROUTE, ABOUT_US_ROUTE, - SETTINGS_ROUTE, + ADVANCED_ROUTE, + ALERTS_ROUTE, CONTACT_LIST_ROUTE, CONTACT_ADD_ROUTE, CONTACT_EDIT_ROUTE, - CONTACT_VIEW_ROUTE, CONTACT_MY_ACCOUNTS_ROUTE, CONTACT_MY_ACCOUNTS_EDIT_ROUTE, CONTACT_MY_ACCOUNTS_VIEW_ROUTE, + CONTACT_VIEW_ROUTE, + GENERAL_ROUTE, + NETWORKS_FORM_ROUTE, + NETWORKS_ROUTE, + SECURITY_ROUTE, + SETTINGS_ROUTE, } from '../../helpers/constants/routes' import Settings from './settings.component' const ROUTES_TO_I18N_KEYS = { - [GENERAL_ROUTE]: 'general', - [ADVANCED_ROUTE]: 'advanced', - [SECURITY_ROUTE]: 'securityAndPrivacy', [ABOUT_US_ROUTE]: 'about', + [ADVANCED_ROUTE]: 'advanced', [ALERTS_ROUTE]: 'alerts', - [CONTACT_LIST_ROUTE]: 'contacts', + [GENERAL_ROUTE]: 'general', [CONTACT_ADD_ROUTE]: 'newContact', [CONTACT_EDIT_ROUTE]: 'editContact', - [CONTACT_VIEW_ROUTE]: 'viewContact', + [CONTACT_LIST_ROUTE]: 'contacts', [CONTACT_MY_ACCOUNTS_ROUTE]: 'myAccounts', + [CONTACT_VIEW_ROUTE]: 'viewContact', + [NETWORKS_ROUTE]: 'networks', + [NETWORKS_FORM_ROUTE]: 'networks', + [SECURITY_ROUTE]: 'securityAndPrivacy', } const mapStateToProps = (state, ownProps) => { @@ -47,11 +51,12 @@ const mapStateToProps = (state, ownProps) => { const isAddContactPage = Boolean(pathname.match(CONTACT_ADD_ROUTE)) const isEditContactPage = Boolean(pathname.match(CONTACT_EDIT_ROUTE)) const isEditMyAccountsContactPage = Boolean(pathname.match(CONTACT_MY_ACCOUNTS_EDIT_ROUTE)) + const isNetworksFormPage = Boolean(pathname.match(NETWORKS_FORM_ROUTE)) - const isPopupView = getEnvironmentType() === ENVIRONMENT_TYPE_POPUP + const isPopup = getEnvironmentType() === ENVIRONMENT_TYPE_POPUP const pathnameI18nKey = ROUTES_TO_I18N_KEYS[pathname] - let backRoute + let backRoute = SETTINGS_ROUTE if (isMyAccountsPage && isAddressEntryPage) { backRoute = CONTACT_MY_ACCOUNTS_ROUTE } else if (isEditContactPage) { @@ -60,8 +65,8 @@ const mapStateToProps = (state, ownProps) => { backRoute = `${CONTACT_MY_ACCOUNTS_VIEW_ROUTE}/${pathNameTail}` } else if (isAddressEntryPage || isMyAccountsPage || isAddContactPage) { backRoute = CONTACT_LIST_ROUTE - } else { - backRoute = SETTINGS_ROUTE + } else if (isNetworksFormPage) { + backRoute = NETWORKS_ROUTE } let initialBreadCrumbRoute @@ -80,7 +85,7 @@ const mapStateToProps = (state, ownProps) => { isMyAccountsPage, backRoute, currentPath: pathname, - isPopupView, + isPopup, pathnameI18nKey, addressName, initialBreadCrumbRoute,