diff options
| -rw-r--r-- | app/assets/css/style.css | 1 | ||||
| -rw-r--r-- | app/components/Settings.css | 125 | ||||
| -rw-r--r-- | app/components/Settings.js | 152 | ||||
| -rw-r--r-- | app/components/SettingsStyles.js | 140 | ||||
| -rw-r--r-- | test/components/Settings.spec.js | 77 |
5 files changed, 259 insertions, 236 deletions
diff --git a/app/assets/css/style.css b/app/assets/css/style.css index eb4353b67e..d3da3124a0 100644 --- a/app/assets/css/style.css +++ b/app/assets/css/style.css @@ -10,7 +10,6 @@ @import '../../components/CustomScrollbars.css'; @import '../../components/Login.css'; @import '../../components/Connect.css'; -@import '../../components/Settings.css'; @import '../../components/AdvancedSettings.css'; @import '../../components/Account.css'; @import '../../components/Support.css'; diff --git a/app/components/Settings.css b/app/components/Settings.css deleted file mode 100644 index 9e49c814f9..0000000000 --- a/app/components/Settings.css +++ /dev/null @@ -1,125 +0,0 @@ -.settings { - background: #192E45; - height: 100%; -} - -.settings__container { - display: flex; - flex-direction: column; - height: 100%; -} - -.settings__header { - flex: 0 0 auto; - padding: 40px 24px 24px; - position: relative; /* anchor for close button */ -} - -.settings__content { - flex: 1 1 auto; - display: flex; - flex-direction: column; - justify-content: space-between; -} - -.settings__close { - position: absolute; - display: block; - border: 0; - padding: 0; - margin: 0; - width: 24px; - height: 24px; - top: 24px; - left: 12px; - background-color: transparent; - background-image: url(../assets/images/icon-close.svg); - opacity: 0.6; - z-index: 1; /* part of .settings__container covers the button */ -} - -.settings__title { - font-family: DINPro; - font-size: 32px; - font-weight: 900; - line-height: 40px; - color: #FFFFFF; -} - -.settings__cell { - background-color:rgba(41,71,115,1); - padding: 15px 24px; - display: flex; - flex-direction: row; - align-items: center; -} - -.settings__cell-disclosure { - display: block; - margin-left: 8px; - color: rgba(255, 255, 255, 0.8); -} - -.settings__cell-spacer { - height: 24px; -} - -.settings__cell--selected, -.settings__cell--selected:hover { - background-color: #44AD4D; -} - -.settings__cell--active:hover { - background-color: rgba(41,71,115,0.9); -} - -.settings__cell + .settings__cell { - margin-top: 1px; -} - -.settings__cell-label { - font-family: DINPro; - font-size: 20px; - font-weight: 900; - line-height: 26px; - color: #FFFFFF; - flex: 1 0 auto; -} - -.settings__cell-icon { - width: 16px; - flex: 0 0 auto; - color: rgba(255, 255, 255, 0.8); -} - -.settings__cell-value { - flex: 0 0 auto; -} - -.settings__account-paid-until-label { - font-family: "Open Sans"; - font-size: 13px; - font-weight: 800; - line-height: 26px; /* matches .cell-label */ - color: rgba(255, 255, 255, 0.8); - text-transform: uppercase; -} - -.settings__account-paid-until-label--error { - color: #d0021b; -} - -.settings__cell-footer { - padding: 8px 24px 24px; - font-family: "Open Sans"; - font-size: 13px; - font-weight: 600; - line-height: 20px; - color: rgba(255,255,255,0.8); -} - -.settings__footer { - padding: 24px; -} - -.settings__footer .button + .button { margin-top: 16px; } diff --git a/app/components/Settings.js b/app/components/Settings.js index 25a3e6df47..5c991978e9 100644 --- a/app/components/Settings.js +++ b/app/components/Settings.js @@ -1,9 +1,10 @@ // @flow import moment from 'moment'; -import React, { Component } from 'react'; -import { If, Then, Else } from 'react-if'; +import React from 'react'; +import { Component, Text, Image, Button, View } from "reactxp"; import { Layout, Container, Header } from './Layout'; import CustomScrollbars from './CustomScrollbars'; +import styles from "./SettingsStyles"; import Img from './Img'; import type { AccountReduxState } from '../redux/account/reducers'; @@ -39,88 +40,83 @@ export default class Settings extends Component { <Layout> <Header hidden={ true } style={ 'defaultDark' } /> <Container> - <div className="settings"> - <button className="settings__close" onClick={ this.props.onClose } /> - <div className="settings__container"> - <div className="settings__header"> - <h2 className="settings__title">Settings</h2> - </div> - <CustomScrollbars autoHide={ true }> - <div className="settings__content"> - <div className="settings__main"> + <View style={styles.settings}> + <Button style={styles.settings__close} onPress={ this.props.onClose } testName="settings__close"> + <Img style={styles.settings__close_icon} source="icon-close" tintColor="currentColor"/> + </Button> - { /* show account options when logged in */ } - <If condition={ isLoggedIn }> - <Then> - <div className="settings__account"> + <View style={styles.settings__container}> + <View style={styles.settings__header}> + <Text style={styles.settings__title}>Settings</Text> + </View> - <div className="settings__view-account settings__cell settings__cell--active" onClick={ this.props.onViewAccount }> - <div className="settings__cell-label">Account</div> - <div className="settings__cell-value"> - <If condition={ isOutOfTime }> - <Then> - <span className="settings__account-paid-until-label settings__account-paid-until-label--error">OUT OF TIME</span> - </Then> - <Else> - <span className="settings__account-paid-until-label">{ formattedExpiry }</span> - </Else> - </If> - </div> - <div className="settings__cell-disclosure"> - <Img source="icon-chevron" tintColor="currentColor" /> - </div> - </div> - <div className="settings__cell-spacer"></div> - </div> - </Then> - </If> + <View style={styles.settings__content}> + <View style={styles.settings__main}> + {/* show account options when logged in */} + {isLoggedIn ? ( + <View style={styles.settings_account} testName="settings__account"> + <Button onPress={ this.props.onViewAccount } testName="settings__view_account"> + <View style={styles.settings__cell}> + <Text style={styles.settings__cell_label}>Account</Text> + <View style={styles.settings__cell_value}> + {isOutOfTime ? ( + <Text style={styles.settings__account_paid_until_label__error} testName="settings__account_paid_until_label">OUT OF TIME</Text> + ) : ( + <Text style={styles.settings__account_paid_until_label} testName="settings__account_paid_until_label">{formattedExpiry}</Text> + )} + </View> + <Img style={styles.settings__cell_disclosure} source="icon-chevron" tintColor="currentColor"/> + </View> + </Button> + <View style={styles.settings__cell_spacer} /> + </View> + ) : null} - <If condition={ isLoggedIn }> - <Then> - <div className="settings__advanced"> - <div className="settings__cell settings__cell--active" onClick={ this.props.onViewAdvancedSettings }> - <div className="settings__cell-label">Advanced</div> - <div className="settings__cell-value"> - <div className="settings__cell-disclosure"> - <Img source="icon-chevron" tintColor="currentColor" /> - </div> - </div> - </div> - <div className="settings__cell-spacer"></div> - </div> - </Then> - </If> + {isLoggedIn ? ( + <Button onPress={ this.props.onViewAdvancedSettings }> + <View style={styles.settings__cell}> + <Text style={styles.settings__cell_label}>Advanced</Text> + <Img style={styles.settings__cell_disclosure} source="icon-chevron" tintColor="currentColor"/> + </View> + <View style={styles.settings__cell_spacer}></View> + </Button> + ) : null} - <div className="settings__external"> - <div className="settings__cell settings__cell--active" onClick={ this.props.onExternalLink.bind(this, 'faq') }> - <div className="settings__cell-label">FAQs</div> - <div className="settings__cell-icon"> - <Img source="icon-extLink" tintColor="currentColor" /> - </div> - </div> - <div className="settings__cell settings__cell--active" onClick={ this.props.onExternalLink.bind(this, 'guides') }> - <div className="settings__cell-label">Guides</div> - <div className="settings__cell-icon"> - <Img source="icon-extLink" tintColor="currentColor" /> - </div> - </div> - <div className="settings__view-support settings__cell settings__cell--active" onClick={ this.props.onViewSupport }> - <div className="settings__cell-label">Report a problem</div> - <div className="settings__cell-disclosure"> - <Img source="icon-extLink" tintColor="currentColor" /> - </div> - </div> - </div> - </div> + <View style={styles.settings__external} testName="settings__external"> - <div className="settings__footer"> - <button className="settings__quit button button--negative" onClick={ this.props.onQuit }>Quit app</button> - </div> + <Button onPress={ this.props.onExternalLink.bind(this, "faq") } testName="settings__external_link"> + <View style={styles.settings__cell}> + <Text style={styles.settings__cell_label}>FAQs</Text> + <Img style={styles.settings__cell_icon} source="icon-extLink" tintColor="currentColor"/> + </View> + </Button> - </div> - </CustomScrollbars> - </div> - </div> + <Button onPress={ this.props.onExternalLink.bind(this, "guides") } testName="settings__external_link"> + <View style={styles.settings__cell}> + <Text style={styles.settings__cell_label}>Guides</Text> + <Img style={styles.settings__cell_icon} source="icon-extLink" tintColor="currentColor"/> + </View> + </Button> + + <Button onPress={ this.props.onViewSupport } testName="settings__view_support"> + <View style={styles.settings__cell}> + <Text style={styles.settings__cell_label}>Contact support</Text> + <Img style={styles.settings__cell_icon} source="icon-chevron" tintColor="currentColor"/> + </View> + </Button> + + </View> + </View> + + <View style={styles.settings__footer}> + <Button style={styles.settings__footer_button} onPress={this.props.onQuit} testName="settings__quit"> + <Text style={styles.settings__footer_button_label}>Quit app</Text> + </Button> + </View> + </View> + </View> + </View> +>>>>>>> Settings in reactxp </Container> </Layout> ); diff --git a/app/components/SettingsStyles.js b/app/components/SettingsStyles.js new file mode 100644 index 0000000000..b3cc72e84a --- /dev/null +++ b/app/components/SettingsStyles.js @@ -0,0 +1,140 @@ +import { Styles } from "reactxp"; + +const styles = { + settings: + Styles.createViewStyle({ + backgroundColor: '#192E45', + height: '100%' + }), + settings__container: + Styles.createViewStyle({ + flexDirection: "column", + height: '100%' + }), + settings__header: + Styles.createViewStyle({ + flex: 0, + paddingTop: 12, + paddingBottom: 12, + paddingLeft: 24, + paddingRight: 24, + position: "relative" /* anchor for close button */ + }), + settings__content: + Styles.createViewStyle({ + flexDirection: "column", + flex: 1, + }), + settings__close: + Styles.createViewStyle({ + flexDirection: "row", + alignItems: "center", + justifyContent: "flex-start", + marginTop: 0, + marginLeft: 12, + }), + settings__close_icon: + Styles.createViewStyle({ + width: 24, + height: 24, + flex: 0, + opacity: 0.6, + marginRight: 8, + }), + settings__title: + Styles.createTextStyle({ + fontFamily: "DINPro", + fontSize: 32, + fontWeight: "900", + lineHeight: 40, + color: "#FFFFFF" + }), + settings__cell: + Styles.createViewStyle({ + backgroundColor: "rgba(41,71,115,1)", + paddingTop: 15, + paddingBottom: 15, + paddingLeft: 24, + paddingRight: 24, + marginLeft: -6, //Because of button.css, when removed remove this + marginRight: -6, //Because of button.css, when removed remove this + marginTop: -1, //Because of button.css, when removed remove this + marginBottom: 0, //Because of button.css, when removed remove this + flex: 1, + flexDirection: "row", + alignItems: "center", + justifyContent: "space-between" + }), + settings__cell_disclosure: + Styles.createViewStyle({ + marginLeft: 8 + }), + settings__cell_spacer: + Styles.createViewStyle({ + height: 24, + flex: 0 + }), + settings__cell__active_hover: + Styles.createViewStyle({ + backgroundColor: "rgba(41,71,115,0.9)" + }), + settings__cell_label: + Styles.createTextStyle({ + fontFamily: "DINPro", + fontSize: 20, + fontWeight: "900", + lineHeight: 26, + color: "#FFFFFF" + }), + settings__cell_icon: + Styles.createViewStyle({ + width: 16, + height: 16, + flex: 0, + marginRight: 8, + opacity: 0.8 + }), + settings__account_paid_until_label: + Styles.createTextStyle({ + fontFamily: "Open Sans", + fontSize: 13, + fontWeight: "800", + color: "rgba(255, 255, 255, 0.8)" + }), + settings__account_paid_until_label__error: + Styles.createViewStyle({ + color: "#d0021b" + }), + settings__footer_button_label: + Styles.createTextStyle({ + fontFamily: "DINPro", + fontSize: 20, + fontWeight: "900", + lineHeight: 26, + color: "rgba(255,255,255,0.8)" + }), + settings__footer_button: + Styles.createViewStyle({ + backgroundColor: "rgba(208,2,27,1)", + paddingTop: 7, + paddingLeft: 12, + paddingRight: 12, + paddingBottom: 9, + borderRadius: 4, + justifyContent: "center", + alignItems: "center", + width: '100%', + }), + settings__footer: + Styles.createViewStyle({ + width: '100%', + justifyContent: "center", + alignItems: "center", + paddingTop: 24, + paddingLeft: 24, + paddingRight: 24, + paddingBottom: 24, + }) +}; + +module.exports = styles; diff --git a/test/components/Settings.spec.js b/test/components/Settings.spec.js index cc38c54616..2baede24a2 100644 --- a/test/components/Settings.spec.js +++ b/test/components/Settings.spec.js @@ -2,9 +2,11 @@ import { expect } from 'chai'; import React from 'react'; -import ReactTestUtils, { Simulate } from 'react-dom/test-utils'; import Settings from '../../app/components/Settings'; +import { shallow } from 'enzyme'; +require('../setup/enzyme'); + import type { AccountReduxState } from '../../app/redux/account/reducers'; import type { SettingsReduxState } from '../../app/redux/settings/reducers'; import type { SettingsProps } from '../../app/components/Settings'; @@ -59,91 +61,85 @@ describe('components/Settings', () => { return Object.assign({}, defaultProps, mergeProps); }; - const render = (props: SettingsProps): Settings => { - return ReactTestUtils.renderIntoDocument( - <Settings { ...props } /> - ); - }; - it('should show quit button when logged out', () => { const props = makeProps(loggedOutAccountState, settingsState); - ReactTestUtils.findRenderedDOMComponentWithClass(render(props), 'settings__quit'); + getComponent(render(props), 'settings__quit'); }); it('should show quit button when logged in', () => { const props = makeProps(loggedInAccountState, settingsState); - ReactTestUtils.findRenderedDOMComponentWithClass(render(props), 'settings__quit'); + getComponent(render(props), 'settings__quit'); }); it('should show external links when logged out', () => { const props = makeProps(loggedOutAccountState, settingsState); - ReactTestUtils.findRenderedDOMComponentWithClass(render(props), 'settings__external'); + getComponent(render(props), 'settings__external'); }); it('should show external links when logged in', () => { const props = makeProps(loggedInAccountState, settingsState); - ReactTestUtils.findRenderedDOMComponentWithClass(render(props), 'settings__external'); + getComponent(render(props), 'settings__external'); }); it('should show account section when logged in', () => { const props = makeProps(loggedInAccountState, settingsState); - ReactTestUtils.findRenderedDOMComponentWithClass(render(props), 'settings__account'); + getComponent(render(props), 'settings__account'); }); it('should hide account section when logged out', () => { const props = makeProps(loggedOutAccountState, settingsState); - const elements = ReactTestUtils.scryRenderedDOMComponentsWithClass(render(props), 'settings__account'); - expect(elements).to.be.empty; + const elements = getComponent(render(props), 'settings__account'); + expect(elements).to.have.length(0); }); it('should hide account link when not logged in', () => { const props = makeProps(loggedOutAccountState, settingsState); - const elements = ReactTestUtils.scryRenderedDOMComponentsWithClass(render(props), 'settings__view-account'); - expect(elements).to.be.empty; + const elements = getComponent(render(props), 'settings__view_account'); + expect(elements).to.have.length(0); }); it('should show out-of-time message for unpaid account', () => { const props = makeProps(unpaidAccountState, settingsState); - const domNode = ReactTestUtils.findRenderedDOMComponentWithClass(render(props), 'settings__account-paid-until-label'); - expect(domNode.textContent).to.contain('OUT OF TIME'); + const component = getComponent(render(props), 'settings__account_paid_until_label'); + expect(component.contains('OUT OF TIME')).to.equal(true); }); it('should hide out-of-time message for paid account', () => { const props = makeProps(loggedInAccountState, settingsState); - const domNode = ReactTestUtils.findRenderedDOMComponentWithClass(render(props), 'settings__account-paid-until-label'); - expect(domNode.textContent).to.not.contain('OUT OF TIME'); + const component = getComponent(render(props), 'settings__account_paid_until_label'); + expect(component.contains('OUT OF TIME')).to.equal(false); }); it('should call close callback', (done) => { const props = makeProps(loggedOutAccountState, settingsState, { onClose: () => done() }); - const domNode = ReactTestUtils.findRenderedDOMComponentWithClass(render(props), 'settings__close'); - Simulate.click(domNode); + const component = getComponent(render(props), 'settings__close'); + click(component); }); it('should call quit callback', (done) => { const props = makeProps(loggedOutAccountState, settingsState, { onQuit: () => done() }); - const domNode = ReactTestUtils.findRenderedDOMComponentWithClass(render(props), 'settings__quit'); - Simulate.click(domNode); + const component = getComponent(render(props), 'settings__quit'); + click(component); }); it('should call account callback', (done) => { const props = makeProps(loggedInAccountState, settingsState, { onViewAccount: () => done() }); - const domNode = ReactTestUtils.findRenderedDOMComponentWithClass(render(props), 'settings__view-account'); - Simulate.click(domNode); + const component = getComponent(render(props), 'settings__view_account'); + click(component); }); it('should call support callback', (done) => { const props = makeProps(loggedInAccountState, settingsState, { onViewSupport: () => done() }); - const domNode = ReactTestUtils.findRenderedDOMComponentWithClass(render(props), 'settings__view-support'); - Simulate.click(domNode); + const component = getComponent(render(props), 'settings__view_support'); + click(component); }); it('should call external links callback', () => { @@ -153,12 +149,29 @@ describe('components/Settings', () => { collectedExternalLinkTypes.push(type); } }); - const container = ReactTestUtils.findRenderedDOMComponentWithClass(render(props), 'settings__external'); - Array.from(container.childNodes) - .filter((elm: HTMLElement) => elm.classList.contains('settings__cell')) - .forEach((elm) => Simulate.click(elm)); + const container = getComponent(render(props), 'settings__external'); + container.find({ testName: 'settings__external_link' }) + .forEach((element) => click(element)); expect(collectedExternalLinkTypes).to.include.ordered.members(['faq', 'guides']); }); }); + +function render(props) { + return shallow( + <Settings {...props} /> + ); +} + +function getComponent(container, testName) { + return container.findWhere( n => n.prop('testName') === testName); +} + +function hasChild(container, testName) { + return getComponent(container, testName).length > 0; +} + +function click(component) { + component.prop('onPress')(); +} |
