diff options
author | Kevin Serrano <kevgagser@gmail.com> | 2018-10-15 08:32:29 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-10-15 08:32:29 +0800 |
commit | 85884b21afe6e5e85b58123b24e72776d1437cc6 (patch) | |
tree | 6dbec947089691c0dffd5febbe6e92c1f712e40f /ui/app/components/page-container | |
parent | db981b827b07c946e17d3a8aeaefd2143c236ef7 (diff) | |
parent | 7f6b488c04e6ea12b2ef24ac936b6a236ad904c2 (diff) | |
download | tangerine-wallet-browser-85884b21afe6e5e85b58123b24e72776d1437cc6.tar.gz tangerine-wallet-browser-85884b21afe6e5e85b58123b24e72776d1437cc6.tar.zst tangerine-wallet-browser-85884b21afe6e5e85b58123b24e72776d1437cc6.zip |
Merge pull request #5512 from MetaMask/v4.14.0
Version 4.14.0
Diffstat (limited to 'ui/app/components/page-container')
6 files changed, 305 insertions, 45 deletions
diff --git a/ui/app/components/page-container/index.scss b/ui/app/components/page-container/index.scss index 06c3ef709..6742e3082 100644 --- a/ui/app/components/page-container/index.scss +++ b/ui/app/components/page-container/index.scss @@ -43,16 +43,39 @@ &__footer { display: flex; - flex-flow: row; + flex-flow: column; justify-content: center; border-top: 1px solid $geyser; - padding: 16px; flex: 0 0 auto; .btn-default, .btn-confirm { font-size: 1rem; } + + header { + display: flex; + flex-flow: row; + justify-content: center; + padding: 16px; + flex: 0 0 auto; + } + + footer { + display: flex; + flex-flow: row; + justify-content: space-around; + padding: 0 16px 16px; + flex: 0 0 auto; + + a, a:hover { + text-decoration: none; + cursor: pointer; + font-size: 0.75rem; + text-transform: uppercase; + color: #2f9ae0; + } + } } &__footer-button { @@ -109,7 +132,7 @@ &--selected { color: $curious-blue; - border-bottom: 3px solid $curious-blue; + border-bottom: 2px solid $curious-blue; } } @@ -182,5 +205,7 @@ max-height: 82vh; min-height: 570px; flex: 0 0 auto; + margin-right: auto; + margin-left: auto; } } diff --git a/ui/app/components/page-container/page-container-footer/page-container-footer.component.js b/ui/app/components/page-container/page-container-footer/page-container-footer.component.js index 3d15df294..773fe1f56 100644 --- a/ui/app/components/page-container/page-container-footer/page-container-footer.component.js +++ b/ui/app/components/page-container/page-container-footer/page-container-footer.component.js @@ -5,6 +5,7 @@ import Button from '../../button' export default class PageContainerFooter extends Component { static propTypes = { + children: PropTypes.node, onCancel: PropTypes.func, cancelText: PropTypes.string, onSubmit: PropTypes.func, @@ -19,6 +20,7 @@ export default class PageContainerFooter extends Component { render () { const { + children, onCancel, cancelText, onSubmit, @@ -30,24 +32,32 @@ export default class PageContainerFooter extends Component { return ( <div className="page-container__footer"> - <Button - type="default" - large - className="page-container__footer-button" - onClick={e => onCancel(e)} - > - { cancelText || this.context.t('cancel') } - </Button> - - <Button - type={submitButtonType || 'primary'} - large - className="page-container__footer-button" - disabled={disabled} - onClick={e => onSubmit(e)} - > - { submitText || this.context.t('next') } - </Button> + <header> + <Button + type="default" + large + className="page-container__footer-button" + onClick={e => onCancel(e)} + > + { cancelText || this.context.t('cancel') } + </Button> + + <Button + type={submitButtonType || 'primary'} + large + className="page-container__footer-button" + disabled={disabled} + onClick={e => onSubmit(e)} + > + { submitText || this.context.t('next') } + </Button> + </header> + + {children && ( + <footer> + {children} + </footer> + )} </div> ) diff --git a/ui/app/components/page-container/page-container-footer/tests/page-container-footer.component.test.js b/ui/app/components/page-container/page-container-footer/tests/page-container-footer.component.test.js index e69de29bb..64efabab0 100644 --- a/ui/app/components/page-container/page-container-footer/tests/page-container-footer.component.test.js +++ b/ui/app/components/page-container/page-container-footer/tests/page-container-footer.component.test.js @@ -0,0 +1,79 @@ +import React from 'react' +import assert from 'assert' +import { shallow } from 'enzyme' +import sinon from 'sinon' +import Button from '../../../button' +import PageFooter from '../page-container-footer.component' + +describe('Page Footer', () => { + let wrapper + const onCancel = sinon.spy() + const onSubmit = sinon.spy() + + beforeEach(() => { + wrapper = shallow(<PageFooter + onCancel = {onCancel} + onSubmit = {onSubmit} + cancelText = {'Cancel'} + submitText = {'Submit'} + disabled = {false} + submitButtonType = {'Test Type'} + />) + }) + + it('renders page container footer', () => { + assert.equal(wrapper.find('.page-container__footer').length, 1) + }) + + it('should render a footer inside page-container__footer when given children', () => { + const wrapper = shallow( + <PageFooter> + <div>Works</div> + </PageFooter>, + { context: { t: sinon.spy((k) => `[${k}]`) } } + ) + + assert.equal(wrapper.find('.page-container__footer footer').length, 1) + }) + + it('renders two button components', () => { + assert.equal(wrapper.find(Button).length, 2) + }) + + describe('Cancel Button', () => { + + it('has button type of default', () => { + assert.equal(wrapper.find('.page-container__footer-button').first().prop('type'), 'default') + }) + + it('has children text of Cancel', () => { + assert.equal(wrapper.find('.page-container__footer-button').first().prop('children'), 'Cancel') + }) + + it('should call cancel when click is simulated', () => { + wrapper.find('.page-container__footer-button').first().prop('onClick')() + assert.equal(onCancel.callCount, 1) + }) + + }) + + describe('Submit Button', () => { + + it('assigns button type based on props', () => { + assert.equal(wrapper.find('.page-container__footer-button').last().prop('type'), 'Test Type') + }) + + it('has disabled prop', () => { + assert.equal(wrapper.find('.page-container__footer-button').last().prop('disabled'), false) + }) + + it('has children text when submitText prop exists', () => { + assert.equal(wrapper.find('.page-container__footer-button').last().prop('children'), 'Submit') + }) + + it('should call submit when click is simulated', () => { + wrapper.find('.page-container__footer-button').last().prop('onClick')() + assert.equal(onSubmit.callCount, 1) + }) + }) +}) 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..a8458604e 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 && ( + <ul className="page-container__tabs"> + { tabs } + </ul> + ) + } 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 ( - <div className="page-container__header"> + <div className={ + classnames( + 'page-container__header', + { 'page-container__header--no-padding-bottom': Boolean(tabs) } + ) + }> { this.renderHeaderRow() } - { children } - { title && <div className="page-container__title"> { title } @@ -59,6 +72,7 @@ export default class PageContainerHeader extends Component { /> } + { this.renderTabs() } </div> ) } diff --git a/ui/app/components/page-container/page-container-header/tests/page-container-header.component.test.js b/ui/app/components/page-container/page-container-header/tests/page-container-header.component.test.js index e69de29bb..59304b2bd 100644 --- a/ui/app/components/page-container/page-container-header/tests/page-container-header.component.test.js +++ b/ui/app/components/page-container/page-container-header/tests/page-container-header.component.test.js @@ -0,0 +1,82 @@ +import React from 'react' +import assert from 'assert' +import { shallow } from 'enzyme' +import sinon from 'sinon' +import PageContainerHeader from '../page-container-header.component' + +describe('Page Container Header', () => { + let wrapper, style, onBackButtonClick, onClose + + beforeEach(() => { + style = {test: 'style'} + onBackButtonClick = sinon.spy() + onClose = sinon.spy() + + wrapper = shallow(<PageContainerHeader + showBackButton = {true} + onBackButtonClick = {onBackButtonClick} + backButtonStyles = {style} + title = {'Test Title'} + subtitle = {'Test Subtitle'} + tabs = {'Test Tab'} + onClose = {onClose} + />) + }) + + describe('Render Header Row', () => { + + it('renders back button', () => { + assert.equal(wrapper.find('.page-container__back-button').length, 1) + assert.equal(wrapper.find('.page-container__back-button').text(), 'Back') + }) + + it('ensures style prop', () => { + assert.equal(wrapper.find('.page-container__back-button').props().style, style) + }) + + it('should call back button when click is simulated', () => { + wrapper.find('.page-container__back-button').prop('onClick')() + assert.equal(onBackButtonClick.callCount, 1) + }) + }) + + describe('Render', () => { + let header, headerRow, pageTitle, pageSubtitle, pageClose, pageTab + + beforeEach(() => { + header = wrapper.find('.page-container__header--no-padding-bottom') + headerRow = wrapper.find('.page-container__header-row') + pageTitle = wrapper.find('.page-container__title') + pageSubtitle = wrapper.find('.page-container__subtitle') + pageClose = wrapper.find('.page-container__header-close') + pageTab = wrapper.find('.page-container__tabs') + }) + + it('renders page container', () => { + assert.equal(header.length, 1) + assert.equal(headerRow.length, 1) + assert.equal(pageTitle.length, 1) + assert.equal(pageSubtitle.length, 1) + assert.equal(pageClose.length, 1) + assert.equal(pageTab.length, 1) + }) + + it('renders title', () => { + assert.equal(pageTitle.text(), 'Test Title') + }) + + it('renders subtitle', () => { + assert.equal(pageSubtitle.text(), 'Test Subtitle') + }) + + it('renders tabs', () => { + assert.equal(pageTab.text(), 'Test Tab') + }) + + it('should call close when click is simulated', () => { + pageClose.prop('onClick')() + assert.equal(onClose.callCount, 1) + }) + }) + +}) diff --git a/ui/app/components/page-container/page-container.component.js b/ui/app/components/page-container/page-container.component.js index 9bfb99ade..3a2274a29 100644 --- a/ui/app/components/page-container/page-container.component.js +++ b/ui/app/components/page-container/page-container.component.js @@ -1,30 +1,82 @@ -import React, { Component } from 'react' +import React, { PureComponent } from 'react' import PropTypes from 'prop-types' import PageContainerHeader from './page-container-header' import PageContainerFooter from './page-container-footer' -export default class PageContainer extends Component { - +export default class PageContainer extends PureComponent { 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: this.props.defaultActiveTabIndex || 0, + } + + handleTabClick (activeTabIndex) { + this.setState({ activeTabIndex }) + } + + renderTabs () { + const { tabsComponent } = this.props + + if (!tabsComponent) { + return + } + + const numberOfTabs = React.Children.count(tabsComponent.props.children) + + return React.Children.map(tabsComponent.props.children, (child, tabIndex) => { + return child && React.cloneElement(child, { + onClick: index => this.handleTabClick(index), + tabIndex, + isActive: numberOfTabs > 1 && tabIndex === this.state.activeTabIndex, + key: tabIndex, + 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 + + if (contentComponent) { + return contentComponent + } else if (tabsComponent) { + return this.renderActiveTabContent() + } else { + return null + } + } render () { const { @@ -35,8 +87,6 @@ export default class PageContainer extends Component { onBackButtonClick, backButtonStyles, backButtonString, - ContentComponent, - contentComponentProps, onCancel, cancelText, onSubmit, @@ -54,9 +104,10 @@ export default class PageContainer extends Component { onBackButtonClick={onBackButtonClick} backButtonStyles={backButtonStyles} backButtonString={backButtonString} + tabs={this.renderTabs()} /> <div className="page-container__content"> - <ContentComponent { ...contentComponentProps } /> + { this.renderContent() } </div> <PageContainerFooter onCancel={onCancel} @@ -68,5 +119,4 @@ export default class PageContainer extends Component { </div> ) } - } |