From d0d0103bb52cbc032a3b3ea2a2ff5edbf67b0d19 Mon Sep 17 00:00:00 2001 From: Alexander Tseung Date: Mon, 17 Sep 2018 09:56:59 -0700 Subject: Add Modal component --- ui/app/components/modal/index.js | 2 + ui/app/components/modal/index.scss | 60 +++++++++++++++++ ui/app/components/modal/modal-content/index.js | 1 + ui/app/components/modal/modal-content/index.scss | 19 ++++++ .../modal/modal-content/modal-content.component.js | 24 +++++++ ui/app/components/modal/modal.component.js | 78 ++++++++++++++++++++++ 6 files changed, 184 insertions(+) create mode 100644 ui/app/components/modal/index.js create mode 100644 ui/app/components/modal/index.scss create mode 100644 ui/app/components/modal/modal-content/index.js create mode 100644 ui/app/components/modal/modal-content/index.scss create mode 100644 ui/app/components/modal/modal-content/modal-content.component.js create mode 100644 ui/app/components/modal/modal.component.js (limited to 'ui/app/components/modal') diff --git a/ui/app/components/modal/index.js b/ui/app/components/modal/index.js new file mode 100644 index 000000000..58309abbe --- /dev/null +++ b/ui/app/components/modal/index.js @@ -0,0 +1,2 @@ +export { default } from './modal.component' +export { default as ModalContent } from './modal-content' diff --git a/ui/app/components/modal/index.scss b/ui/app/components/modal/index.scss new file mode 100644 index 000000000..e57156d71 --- /dev/null +++ b/ui/app/components/modal/index.scss @@ -0,0 +1,60 @@ +@import './modal-content/index'; + +.modal-container { + width: 100%; + height: 100%; + background-color: #fff; + display: flex; + flex-flow: column; + border-radius: 8px; + + &__content { + overflow-y: auto; + flex: 1; + display: flex; + flex-direction: column; + align-items: center; + padding: 16px 32px; + + @media screen and (max-width: 575px) { + justify-content: center; + padding: 28px 20px; + } + } + + &__header { + position: relative; + display: flex; + padding: 12px; + justify-content: center; + border-bottom: 1px solid #d2d8dd; + } + + &__header-close::after { + content: '\00D7'; + font-size: 40px; + color: $dusty-gray; + position: absolute; + top: -5px; + right: 10px; + cursor: pointer; + } + + &__footer { + display: flex; + flex-flow: row; + justify-content: center; + border-top: 1px solid #d2d8dd; + padding: 16px; + flex: 0 0 auto; + + &-button { + min-width: 0; + margin-right: 16px; + + &:last-of-type { + margin-right: 0; + } + } + } +} diff --git a/ui/app/components/modal/modal-content/index.js b/ui/app/components/modal/modal-content/index.js new file mode 100644 index 000000000..733cfb3b8 --- /dev/null +++ b/ui/app/components/modal/modal-content/index.js @@ -0,0 +1 @@ +export { default } from './modal-content.component' diff --git a/ui/app/components/modal/modal-content/index.scss b/ui/app/components/modal/modal-content/index.scss new file mode 100644 index 000000000..560505b84 --- /dev/null +++ b/ui/app/components/modal/modal-content/index.scss @@ -0,0 +1,19 @@ +.modal-content { + flex: 1; + display: flex; + flex-direction: column; + align-items: center; + padding: 16px 0; + + &__title { + font-size: 1.5rem; + font-weight: 500; + padding: 16px 0; + text-align: center; + } + + &__description { + text-align: center; + font-size: .875rem; + } +} diff --git a/ui/app/components/modal/modal-content/modal-content.component.js b/ui/app/components/modal/modal-content/modal-content.component.js new file mode 100644 index 000000000..8beb854e0 --- /dev/null +++ b/ui/app/components/modal/modal-content/modal-content.component.js @@ -0,0 +1,24 @@ +import React, { PureComponent } from 'react' +import PropTypes from 'prop-types' + +export default class ModalContent extends PureComponent { + static propTypes = { + title: PropTypes.string, + description: PropTypes.string, + } + + render () { + const { title, description } = this.props + + return ( +
+
+ { title } +
+
+ { description } +
+
+ ) + } +} diff --git a/ui/app/components/modal/modal.component.js b/ui/app/components/modal/modal.component.js new file mode 100644 index 000000000..81bdd0010 --- /dev/null +++ b/ui/app/components/modal/modal.component.js @@ -0,0 +1,78 @@ +import React, { PureComponent } from 'react' +import PropTypes from 'prop-types' +import Button from '../button' + +export default class Modal extends PureComponent { + static propTypes = { + children: PropTypes.node, + // Header text + headerText: PropTypes.string, + // Submit button (right button) + onSubmit: PropTypes.func, + submitType: PropTypes.string, + submitText: PropTypes.string, + // Cancel button (left button) + onCancel: PropTypes.func, + cancelType: PropTypes.string, + cancelText: PropTypes.string, + } + + static defaultProps = { + submitType: 'primary', + cancelType: 'default', + } + + render () { + const { + children, + headerText, + onSubmit, + submitType, + submitText, + onCancel, + cancelType, + cancelText, + } = this.props + + return ( +
+ { + headerText && ( +
+
+ { headerText } +
+
onCancel()} + /> +
+ ) + } +
+ { children } +
+
+ { + onCancel && ( + + ) + } + +
+
+ ) + } +} -- cgit From 95e1eff4ca3d784d6fcba21035a535f8f3398cdc Mon Sep 17 00:00:00 2001 From: Alexander Tseung Date: Mon, 17 Sep 2018 18:32:35 -0700 Subject: Add TransactionDetails modal --- ui/app/components/modal/index.scss | 8 +++++--- ui/app/components/modal/modal.component.js | 18 +++++++++++++++++- 2 files changed, 22 insertions(+), 4 deletions(-) (limited to 'ui/app/components/modal') diff --git a/ui/app/components/modal/index.scss b/ui/app/components/modal/index.scss index e57156d71..2beb14633 100644 --- a/ui/app/components/modal/index.scss +++ b/ui/app/components/modal/index.scss @@ -8,12 +8,13 @@ flex-flow: column; border-radius: 8px; + @media screen and (max-width: 575px) { + max-height: 450px; + } + &__content { overflow-y: auto; flex: 1; - display: flex; - flex-direction: column; - align-items: center; padding: 16px 32px; @media screen and (max-width: 575px) { @@ -28,6 +29,7 @@ padding: 12px; justify-content: center; border-bottom: 1px solid #d2d8dd; + flex: 0 0 auto; } &__header-close::after { diff --git a/ui/app/components/modal/modal.component.js b/ui/app/components/modal/modal.component.js index 81bdd0010..f9d8c5867 100644 --- a/ui/app/components/modal/modal.component.js +++ b/ui/app/components/modal/modal.component.js @@ -22,6 +22,22 @@ export default class Modal extends PureComponent { cancelType: 'default', } + handleClose = () => { + const { onCancel, onSubmit } = this.props + + /** + * The close button should be used to dismiss the modal, without performing any actions, which + * is typically what props.onCancel does. However, if props.onCancel is undefined, that should + * mean that the modal is a simple notification modal and props.onSubmit can be used to dismiss + * it. + */ + if (onCancel && typeof onCancel === 'function') { + onCancel() + } else { + onSubmit() + } + } + render () { const { children, @@ -44,7 +60,7 @@ export default class Modal extends PureComponent {
onCancel()} + onClick={this.handleClose} />
) -- cgit From 2cfdc95eebc3e0a878017090f22e5136cff709a6 Mon Sep 17 00:00:00 2001 From: Alexander Tseung Date: Wed, 19 Sep 2018 14:30:52 -0700 Subject: Add unit tests --- .../modal/modal-content/modal-content.component.js | 20 ++-- .../tests/modal-content.component.test.js | 44 ++++++++ .../components/modal/tests/modal.component.test.js | 117 +++++++++++++++++++++ 3 files changed, 175 insertions(+), 6 deletions(-) create mode 100644 ui/app/components/modal/modal-content/tests/modal-content.component.test.js create mode 100644 ui/app/components/modal/tests/modal.component.test.js (limited to 'ui/app/components/modal') diff --git a/ui/app/components/modal/modal-content/modal-content.component.js b/ui/app/components/modal/modal-content/modal-content.component.js index 8beb854e0..ecec0ee5b 100644 --- a/ui/app/components/modal/modal-content/modal-content.component.js +++ b/ui/app/components/modal/modal-content/modal-content.component.js @@ -12,12 +12,20 @@ export default class ModalContent extends PureComponent { return (
-
- { title } -
-
- { description } -
+ { + title && ( +
+ { title } +
+ ) + } + { + description && ( +
+ { description } +
+ ) + }
) } diff --git a/ui/app/components/modal/modal-content/tests/modal-content.component.test.js b/ui/app/components/modal/modal-content/tests/modal-content.component.test.js new file mode 100644 index 000000000..17af09f45 --- /dev/null +++ b/ui/app/components/modal/modal-content/tests/modal-content.component.test.js @@ -0,0 +1,44 @@ +import React from 'react' +import assert from 'assert' +import { shallow } from 'enzyme' +import ModalContent from '../modal-content.component' + +describe('ModalContent Component', () => { + it('should render a title', () => { + const wrapper = shallow( + + ) + + assert.equal(wrapper.find('.modal-content__title').length, 1) + assert.equal(wrapper.find('.modal-content__title').text(), 'Modal Title') + assert.equal(wrapper.find('.modal-content__description').length, 0) + }) + + it('should render a description', () => { + const wrapper = shallow( + + ) + + assert.equal(wrapper.find('.modal-content__title').length, 0) + assert.equal(wrapper.find('.modal-content__description').length, 1) + assert.equal(wrapper.find('.modal-content__description').text(), 'Modal Description') + }) + + it('should render both a title and a description', () => { + const wrapper = shallow( + + ) + + assert.equal(wrapper.find('.modal-content__title').length, 1) + assert.equal(wrapper.find('.modal-content__title').text(), 'Modal Title') + assert.equal(wrapper.find('.modal-content__description').length, 1) + assert.equal(wrapper.find('.modal-content__description').text(), 'Modal Description') + }) +}) diff --git a/ui/app/components/modal/tests/modal.component.test.js b/ui/app/components/modal/tests/modal.component.test.js new file mode 100644 index 000000000..31457751f --- /dev/null +++ b/ui/app/components/modal/tests/modal.component.test.js @@ -0,0 +1,117 @@ +import React from 'react' +import assert from 'assert' +import { shallow } from 'enzyme' +import sinon from 'sinon' +import Modal from '../modal.component' +import Button from '../../button' + +describe('Modal Component', () => { + it('should render a modal with a submit button', () => { + const wrapper = shallow() + + assert.equal(wrapper.find('.modal-container').length, 1) + const buttons = wrapper.find(Button) + assert.equal(buttons.length, 1) + assert.equal(buttons.at(0).props().type, 'primary') + }) + + it('should render a modal with a cancel and a submit button', () => { + const handleCancel = sinon.spy() + const handleSubmit = sinon.spy() + const wrapper = shallow( + + ) + + const buttons = wrapper.find(Button) + assert.equal(buttons.length, 2) + const cancelButton = buttons.at(0) + const submitButton = buttons.at(1) + + assert.equal(cancelButton.props().type, 'default') + assert.equal(cancelButton.props().children, 'Cancel') + assert.equal(handleCancel.callCount, 0) + cancelButton.simulate('click') + assert.equal(handleCancel.callCount, 1) + + assert.equal(submitButton.props().type, 'primary') + assert.equal(submitButton.props().children, 'Submit') + assert.equal(handleSubmit.callCount, 0) + submitButton.simulate('click') + assert.equal(handleSubmit.callCount, 1) + }) + + it('should render a modal with different button types', () => { + const wrapper = shallow( + {}} + cancelText="Cancel" + cancelType="secondary" + onSubmit={() => {}} + submitText="Submit" + submitType="confirm" + /> + ) + + const buttons = wrapper.find(Button) + assert.equal(buttons.length, 2) + assert.equal(buttons.at(0).props().type, 'secondary') + assert.equal(buttons.at(1).props().type, 'confirm') + }) + + it('should render a modal with children', () => { + const wrapper = shallow( + {}} + cancelText="Cancel" + onSubmit={() => {}} + submitText="Submit" + > +
+ + ) + + assert.ok(wrapper.find('.test-class')) + }) + + it('should render a modal with a header', () => { + const handleCancel = sinon.spy() + const handleSubmit = sinon.spy() + const wrapper = shallow( + + ) + + assert.ok(wrapper.find('.modal-container__header')) + assert.equal(wrapper.find('.modal-container__header-text').text(), 'My Header') + assert.equal(handleCancel.callCount, 0) + assert.equal(handleSubmit.callCount, 0) + wrapper.find('.modal-container__header-close').simulate('click') + assert.equal(handleCancel.callCount, 1) + assert.equal(handleSubmit.callCount, 0) + }) + + it('should call onSubmit when onCancel is undefined and the header close button is clicked', () => { + const handleSubmit = sinon.spy() + const wrapper = shallow( + + ) + + assert.equal(handleSubmit.callCount, 0) + wrapper.find('.modal-container__header-close').simulate('click') + assert.equal(handleSubmit.callCount, 1) + }) +}) -- cgit From 431beb943675f2e9b7b5e5ce9c7f55d45f10905f Mon Sep 17 00:00:00 2001 From: Alexander Tseung Date: Thu, 20 Sep 2018 19:35:45 -0700 Subject: Fix multiplyCurrencies. Add onClose prop for Modal component. Remove hideModal from modal components. --- ui/app/components/modal/modal.component.js | 20 +++----------------- .../components/modal/tests/modal.component.test.js | 16 +--------------- 2 files changed, 4 insertions(+), 32 deletions(-) (limited to 'ui/app/components/modal') diff --git a/ui/app/components/modal/modal.component.js b/ui/app/components/modal/modal.component.js index f9d8c5867..2a75b559b 100644 --- a/ui/app/components/modal/modal.component.js +++ b/ui/app/components/modal/modal.component.js @@ -7,6 +7,7 @@ export default class Modal extends PureComponent { children: PropTypes.node, // Header text headerText: PropTypes.string, + onClose: PropTypes.func, // Submit button (right button) onSubmit: PropTypes.func, submitType: PropTypes.string, @@ -22,26 +23,11 @@ export default class Modal extends PureComponent { cancelType: 'default', } - handleClose = () => { - const { onCancel, onSubmit } = this.props - - /** - * The close button should be used to dismiss the modal, without performing any actions, which - * is typically what props.onCancel does. However, if props.onCancel is undefined, that should - * mean that the modal is a simple notification modal and props.onSubmit can be used to dismiss - * it. - */ - if (onCancel && typeof onCancel === 'function') { - onCancel() - } else { - onSubmit() - } - } - render () { const { children, headerText, + onClose, onSubmit, submitType, submitText, @@ -60,7 +46,7 @@ export default class Modal extends PureComponent {
) diff --git a/ui/app/components/modal/tests/modal.component.test.js b/ui/app/components/modal/tests/modal.component.test.js index 31457751f..8cce1a808 100644 --- a/ui/app/components/modal/tests/modal.component.test.js +++ b/ui/app/components/modal/tests/modal.component.test.js @@ -88,6 +88,7 @@ describe('Modal Component', () => { onSubmit={handleSubmit} submitText="Submit" headerText="My Header" + onClose={handleCancel} /> ) @@ -99,19 +100,4 @@ describe('Modal Component', () => { assert.equal(handleCancel.callCount, 1) assert.equal(handleSubmit.callCount, 0) }) - - it('should call onSubmit when onCancel is undefined and the header close button is clicked', () => { - const handleSubmit = sinon.spy() - const wrapper = shallow( - - ) - - assert.equal(handleSubmit.callCount, 0) - wrapper.find('.modal-container__header-close').simulate('click') - assert.equal(handleSubmit.callCount, 1) - }) }) -- cgit