From 01c0c98501c02623b0cd650483d14c99566ce0af Mon Sep 17 00:00:00 2001 From: Alexander Tseung Date: Wed, 18 Jul 2018 17:47:01 -0700 Subject: Add tabs support for PageContainer --- ui/app/components/page-container/index.scss | 2 +- .../page-container-header.component.js | 28 +++++-- .../page-container/page-container.component.js | 95 ++++++++++++++++++---- .../pages/add-token/add-token.component.js | 82 ++++++------------- ui/app/components/tabs/tab/tab.component.js | 8 +- 5 files changed, 132 insertions(+), 83 deletions(-) (limited to 'ui/app') diff --git a/ui/app/components/page-container/index.scss b/ui/app/components/page-container/index.scss index 06c3ef709..14cdbacd3 100644 --- a/ui/app/components/page-container/index.scss +++ b/ui/app/components/page-container/index.scss @@ -109,7 +109,7 @@ &--selected { color: $curious-blue; - border-bottom: 3px solid $curious-blue; + border-bottom: 2px solid $curious-blue; } } diff --git a/ui/app/components/page-container/page-container-header/page-container-header.component.js b/ui/app/components/page-container/page-container-header/page-container-header.component.js index 5a5de1e5a..338598e5f 100644 --- a/ui/app/components/page-container/page-container-header/page-container-header.component.js +++ b/ui/app/components/page-container/page-container-header/page-container-header.component.js @@ -1,8 +1,8 @@ import React, { Component } from 'react' import PropTypes from 'prop-types' +import classnames from 'classnames' export default class PageContainerHeader extends Component { - static propTypes = { title: PropTypes.string, subtitle: PropTypes.string, @@ -11,8 +11,18 @@ export default class PageContainerHeader extends Component { onBackButtonClick: PropTypes.func, backButtonStyles: PropTypes.object, backButtonString: PropTypes.string, - children: PropTypes.node, - }; + tabs: PropTypes.node, + } + + renderTabs () { + const { tabs } = this.props + + return tabs && ( + + ) + } renderHeaderRow () { const { showBackButton, onBackButtonClick, backButtonStyles, backButtonString } = this.props @@ -31,15 +41,18 @@ export default class PageContainerHeader extends Component { } render () { - const { title, subtitle, onClose, children } = this.props + const { title, subtitle, onClose, tabs } = this.props return ( -
+
{ this.renderHeaderRow() } - { children } - { title &&
{ title } @@ -59,6 +72,7 @@ export default class PageContainerHeader extends Component { /> } + { this.renderTabs() }
) } diff --git a/ui/app/components/page-container/page-container.component.js b/ui/app/components/page-container/page-container.component.js index 9bfb99ade..10923d2fd 100644 --- a/ui/app/components/page-container/page-container.component.js +++ b/ui/app/components/page-container/page-container.component.js @@ -5,26 +5,93 @@ import PageContainerHeader from './page-container-header' import PageContainerFooter from './page-container-footer' export default class PageContainer extends Component { - static propTypes = { // PageContainerHeader props - title: PropTypes.string.isRequired, - subtitle: PropTypes.string, + backButtonString: PropTypes.string, + backButtonStyles: PropTypes.object, + onBackButtonClick: PropTypes.func, onClose: PropTypes.func, showBackButton: PropTypes.bool, - onBackButtonClick: PropTypes.func, - backButtonStyles: PropTypes.object, - backButtonString: PropTypes.string, + subtitle: PropTypes.string, + title: PropTypes.string.isRequired, + // Tabs-related props + defaultActiveTabIndex: PropTypes.number, + tabsComponent: PropTypes.node, // Content props - ContentComponent: PropTypes.func, - contentComponentProps: PropTypes.object, + contentComponent: PropTypes.node, // PageContainerFooter props - onCancel: PropTypes.func, cancelText: PropTypes.string, + disabled: PropTypes.bool, + onCancel: PropTypes.func, onSubmit: PropTypes.func, submitText: PropTypes.string, - disabled: PropTypes.bool, - }; + } + + state = { + activeTabIndex: 0, + } + + componentDidMount () { + const { defaultActiveTabIndex } = this.props + + if (defaultActiveTabIndex) { + this.setState({ activeTabIndex: defaultActiveTabIndex }) + } + } + + handleTabClick (tabIndex) { + const { activeTabIndex } = this.state + + if (tabIndex !== activeTabIndex) { + this.setState({ + activeTabIndex: tabIndex, + }) + } + } + + renderTabs () { + const { tabsComponent } = this.props + + if (!tabsComponent) { + return + } + + const numberOfTabs = React.Children.count(tabsComponent.props.children) + + return React.Children.map(tabsComponent.props.children, (child, index) => { + return child && React.cloneElement(child, { + onClick: index => this.handleTabClick(index), + tabIndex: index, + isActive: numberOfTabs > 1 && index === this.state.activeTabIndex, + key: index, + className: 'page-container__tab', + activeClassName: 'page-container__tab--selected', + }) + }) + } + + renderActiveTabContent () { + const { tabsComponent } = this.props + const { children } = tabsComponent.props + const { activeTabIndex } = this.state + + return children[activeTabIndex] + ? children[activeTabIndex].props.children + : children.props.children + } + + renderContent () { + const { contentComponent, tabsComponent } = this.props + + switch (true) { + case Boolean(contentComponent): + return contentComponent + case Boolean(tabsComponent): + return this.renderActiveTabContent() + default: + return null + } + } render () { const { @@ -35,8 +102,6 @@ export default class PageContainer extends Component { onBackButtonClick, backButtonStyles, backButtonString, - ContentComponent, - contentComponentProps, onCancel, cancelText, onSubmit, @@ -54,9 +119,10 @@ export default class PageContainer extends Component { onBackButtonClick={onBackButtonClick} backButtonStyles={backButtonStyles} backButtonString={backButtonString} + tabs={this.renderTabs()} />
- + { this.renderContent() }
) } - } diff --git a/ui/app/components/pages/add-token/add-token.component.js b/ui/app/components/pages/add-token/add-token.component.js index bcb93d401..59748ff46 100644 --- a/ui/app/components/pages/add-token/add-token.component.js +++ b/ui/app/components/pages/add-token/add-token.component.js @@ -1,14 +1,14 @@ import React, { Component } from 'react' -import classnames from 'classnames' import PropTypes from 'prop-types' import ethUtil from 'ethereumjs-util' import { checkExistingAddresses } from './util' import { tokenInfoGetter } from '../../../token-util' import { DEFAULT_ROUTE, CONFIRM_ADD_TOKEN_ROUTE } from '../../../routes' -import Button from '../../button' import TextField from '../../text-field' import TokenList from './token-list' import TokenSearch from './token-search' +import PageContainer from '../../page-container' +import { Tabs, Tab } from '../../tabs' const emptyAddr = '0x0000000000000000000000000000000000000000' const SEARCH_TAB = 'SEARCH' @@ -285,65 +285,33 @@ class AddToken extends Component { ) } + renderTabs () { + return ( + + + { this.renderSearchToken() } + + + { this.renderCustomTokenForm() } + + + ) + } + render () { - const { displayedTab } = this.state const { history, clearPendingTokens } = this.props return ( -
-
-
- { this.context.t('addTokens') } -
-
-
this.setState({ displayedTab: SEARCH_TAB })} - > - { this.context.t('search') } -
-
this.setState({ displayedTab: CUSTOM_TOKEN_TAB })} - > - { this.context.t('customToken') } -
-
-
-
- { - displayedTab === CUSTOM_TOKEN_TAB - ? this.renderCustomTokenForm() - : this.renderSearchToken() - } -
-
- - -
-
+ this.handleNext()} + disabled={this.hasError() || !this.hasSelected()} + onCancel={() => { + clearPendingTokens() + history.push(DEFAULT_ROUTE) + }} + /> ) } } diff --git a/ui/app/components/tabs/tab/tab.component.js b/ui/app/components/tabs/tab/tab.component.js index a59da8904..481513233 100644 --- a/ui/app/components/tabs/tab/tab.component.js +++ b/ui/app/components/tabs/tab/tab.component.js @@ -3,13 +3,13 @@ import PropTypes from 'prop-types' import classnames from 'classnames' const Tab = props => { - const { name, onClick, isActive, tabIndex } = props + const { name, onClick, isActive, tabIndex, className, activeClassName } = props return (
  • { event.preventDefault() @@ -26,6 +26,8 @@ Tab.propTypes = { onClick: PropTypes.func, isActive: PropTypes.bool, tabIndex: PropTypes.number, + className: PropTypes.string, + activeClassName: PropTypes.string, } export default Tab -- cgit