summaryrefslogtreecommitdiff
path: root/web-ui/src/common
diff options
context:
space:
mode:
Diffstat (limited to 'web-ui/src/common')
-rw-r--r--web-ui/src/common/back_link/back_link.js42
-rw-r--r--web-ui/src/common/back_link/back_link.scss35
-rw-r--r--web-ui/src/common/back_link/back_link.spec.js41
-rw-r--r--web-ui/src/common/header/header.js12
-rw-r--r--web-ui/src/common/header/header.spec.js13
-rw-r--r--web-ui/src/common/link_button/link_button.js58
-rw-r--r--web-ui/src/common/link_button/link_button.scss49
-rw-r--r--web-ui/src/common/link_button/link_button.spec.js20
-rw-r--r--web-ui/src/common/snackbar_notification/snackbar_notification.js65
-rw-r--r--web-ui/src/common/snackbar_notification/snackbar_notification.scss22
-rw-r--r--web-ui/src/common/snackbar_notification/snackbar_notification.spec.js31
-rw-r--r--web-ui/src/common/submit_button/submit_button.js3
-rw-r--r--web-ui/src/common/util.js21
-rw-r--r--web-ui/src/common/util.spec.js35
14 files changed, 439 insertions, 8 deletions
diff --git a/web-ui/src/common/back_link/back_link.js b/web-ui/src/common/back_link/back_link.js
new file mode 100644
index 00000000..bb5ffbea
--- /dev/null
+++ b/web-ui/src/common/back_link/back_link.js
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2017 ThoughtWorks, Inc.
+ *
+ * Pixelated is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Pixelated is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Pixelated. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+import React from 'react';
+
+import './back_link.scss';
+
+const icon = <i className='fa fa-angle-left' aria-hidden='true' />;
+
+const button = (text, options) => (
+ <button className='link' {...options}>{icon}<span>{text}</span></button>
+);
+
+const link = (text, options) => (
+ <a className='link' {...options}>{icon}<span>{text}</span></a>
+);
+
+const BackLink = ({ text, ...other }) => (
+ <div className='link-content'>
+ { other.href ? link(text, other) : button(text, other) }
+ </div>
+);
+
+BackLink.propTypes = {
+ text: React.PropTypes.string.isRequired
+};
+
+export default BackLink;
diff --git a/web-ui/src/common/back_link/back_link.scss b/web-ui/src/common/back_link/back_link.scss
new file mode 100644
index 00000000..5541d9d9
--- /dev/null
+++ b/web-ui/src/common/back_link/back_link.scss
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2017 ThoughtWorks, Inc.
+ *
+ * Pixelated is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Pixelated is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Pixelated. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+@import "~scss/base/colors";
+
+.link {
+ color: $dark_blue;
+ font-style: italic;
+ font-size: 0.8em;
+ margin: 0;
+ padding: 0;
+ border: 0;
+ background: transparent;
+
+ .fa {
+ font-size: 1.6em;
+ position: relative;
+ top: 3px;
+ margin-right: 0.3em;
+ }
+}
diff --git a/web-ui/src/common/back_link/back_link.spec.js b/web-ui/src/common/back_link/back_link.spec.js
new file mode 100644
index 00000000..5f49a6f9
--- /dev/null
+++ b/web-ui/src/common/back_link/back_link.spec.js
@@ -0,0 +1,41 @@
+import { shallow } from 'enzyme';
+import expect from 'expect';
+import React from 'react';
+import BackLink from 'src/common/back_link/back_link';
+
+describe('BackLink', () => {
+ context('as link', () => {
+ let backLink;
+
+ beforeEach(() => {
+ backLink = shallow(<BackLink text='Back to inbox' href='/' />);
+ });
+
+ it('renders link with text', () => {
+ expect(backLink.find('a').text()).toEqual('Back to inbox');
+ });
+
+ it('adds link action', () => {
+ expect(backLink.find('a').props().href).toEqual('/');
+ });
+ });
+
+ context('as button', () => {
+ let backLink;
+ let mockClick;
+
+ beforeEach(() => {
+ mockClick = expect.createSpy();
+ backLink = shallow(<BackLink text='Back to inbox' onClick={mockClick} />);
+ });
+
+ it('renders button with text', () => {
+ expect(backLink.find('button').text()).toEqual('Back to inbox');
+ });
+
+ it('adds button click event', () => {
+ backLink.find('button').simulate('click');
+ expect(mockClick).toHaveBeenCalled();
+ });
+ });
+});
diff --git a/web-ui/src/common/header/header.js b/web-ui/src/common/header/header.js
index 715d54c6..3ad924c0 100644
--- a/web-ui/src/common/header/header.js
+++ b/web-ui/src/common/header/header.js
@@ -19,7 +19,7 @@ import React from 'react';
import Logout from 'src/common/logout/logout';
import './header.scss';
-export const Header = () => (
+export const Header = ({ renderLogout }) => (
<header className='header-wrapper'>
<div className='header-content'>
<a href='/'>
@@ -30,10 +30,18 @@ export const Header = () => (
/>
</a>
<div className='header-icons'>
- <Logout />
+ { renderLogout ? <Logout /> : <div /> }
</div>
</div>
</header>
);
+Header.propTypes = {
+ renderLogout: React.PropTypes.bool
+};
+
+Header.defaultProps = {
+ renderLogout: false
+};
+
export default Header;
diff --git a/web-ui/src/common/header/header.spec.js b/web-ui/src/common/header/header.spec.js
index 81a952c7..0c11713b 100644
--- a/web-ui/src/common/header/header.spec.js
+++ b/web-ui/src/common/header/header.spec.js
@@ -11,11 +11,16 @@ describe('Header', () => {
header = shallow(<Header />);
});
- it('renders the header containing the logout button', () => {
- expect(header.find('header').find(Logout)).toExist();
- });
-
it('renders the header pixelated logo', () => {
expect(header.find('header').find('img').props().alt).toEqual('Pixelated');
});
+
+ it('renders the header containing the logout button when renderLogout is true', () => {
+ header = shallow(<Header renderLogout />);
+ expect(header.find('header').find(Logout).length).toEqual(1);
+ });
+
+ it('hides logout button when renderLogout is false', () => {
+ expect(header.find('header').find(Logout).length).toEqual(0);
+ });
});
diff --git a/web-ui/src/common/link_button/link_button.js b/web-ui/src/common/link_button/link_button.js
new file mode 100644
index 00000000..e7fd80b0
--- /dev/null
+++ b/web-ui/src/common/link_button/link_button.js
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2017 ThoughtWorks, Inc.
+ *
+ * Pixelated is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Pixelated is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Pixelated. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+import React from 'react';
+import FlatButton from 'material-ui/FlatButton';
+
+import './link_button.scss';
+
+const labelStyle = {
+ textTransform: 'none',
+ color: 'inherit',
+ fontSize: 'inherit',
+ width: '100%',
+ padding: '0'
+};
+
+const linkButtonStyle = {
+ color: 'inherit',
+ borderRadius: '0',
+ minHeight: '36px',
+ height: 'auto',
+ lineHeight: '20px',
+ padding: '12px 0'
+};
+
+const LinkButton = ({ buttonText, href }) => (
+ <div className='link-button'>
+ <FlatButton
+ href={href}
+ containerElement='a'
+ label={buttonText}
+ labelStyle={labelStyle}
+ hoverColor={'#ff9c00'}
+ style={linkButtonStyle}
+ />
+ </div>
+);
+
+LinkButton.propTypes = {
+ buttonText: React.PropTypes.string.isRequired,
+ href: React.PropTypes.string.isRequired
+};
+
+export default LinkButton;
diff --git a/web-ui/src/common/link_button/link_button.scss b/web-ui/src/common/link_button/link_button.scss
new file mode 100644
index 00000000..3b4a534c
--- /dev/null
+++ b/web-ui/src/common/link_button/link_button.scss
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2017 ThoughtWorks, Inc.
+ *
+ * Pixelated is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Pixelated is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Pixelated. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+@import "~scss/base/colors";
+
+.link-button > a {
+ width: 100%;
+}
+
+.link-button {
+ width: 100%;
+ margin-top: 2em;
+ border: 2px solid $light_orange;
+ border-radius: 2px;
+ font-size: 1em;
+ color: $light_orange;
+ &:hover {
+ color: $white;
+ }
+}
+
+@media only screen and (min-width : 500px) {
+ .link-button {
+ width: 70%;
+ align-self: center;
+ }
+}
+
+@media only screen and (min-width : 960px) {
+ .link-button {
+ width: 300px;
+ margin-bottom: 1em;
+ font-size: 0.8em;
+ }
+}
diff --git a/web-ui/src/common/link_button/link_button.spec.js b/web-ui/src/common/link_button/link_button.spec.js
new file mode 100644
index 00000000..945afffe
--- /dev/null
+++ b/web-ui/src/common/link_button/link_button.spec.js
@@ -0,0 +1,20 @@
+import { shallow } from 'enzyme';
+import expect from 'expect';
+import React from 'react';
+import LinkButton from 'src/common/link_button/link_button';
+
+describe('LinkButton', () => {
+ let linkButton;
+
+ beforeEach(() => {
+ linkButton = shallow(<LinkButton buttonText='Go To Link' href='/some-link' />);
+ });
+
+ it('renders link button with given button text', () => {
+ expect(linkButton.find('FlatButton').props().label).toEqual('Go To Link');
+ });
+
+ it('renders link button with given href', () => {
+ expect(linkButton.find('FlatButton').props().href).toEqual('/some-link');
+ });
+});
diff --git a/web-ui/src/common/snackbar_notification/snackbar_notification.js b/web-ui/src/common/snackbar_notification/snackbar_notification.js
new file mode 100644
index 00000000..8a7e5094
--- /dev/null
+++ b/web-ui/src/common/snackbar_notification/snackbar_notification.js
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2017 ThoughtWorks, Inc.
+ *
+ * Pixelated is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Pixelated is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Pixelated. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+import React from 'react';
+import Snackbar from 'material-ui/Snackbar';
+import { red500, blue500 } from 'material-ui/styles/colors';
+
+import './snackbar_notification.scss';
+
+const notificationStyle = () => ({
+ top: 0,
+ left: 'auto',
+ bottom: 'auto',
+ alignSelf: 'center',
+ transform: 'translate3d(0, 0px, 0)'
+});
+
+const contentStyle = {
+ textAlign: 'center'
+};
+
+const getStyleByType = (isError) => {
+ const style = { height: 'auto' };
+ style.backgroundColor = isError ? red500 : blue500;
+ return style;
+};
+
+const SnackbarNotification = ({ message, isError = false, autoHideDuration = 5000 }) => (
+ <Snackbar
+ id='snackbar'
+ open
+ bodyStyle={getStyleByType(isError)}
+ message={message}
+ autoHideDuration={autoHideDuration}
+ contentStyle={contentStyle}
+ style={notificationStyle()}
+ />
+);
+
+SnackbarNotification.propTypes = {
+ message: React.PropTypes.string.isRequired,
+ isError: React.PropTypes.bool,
+ autoHideDuration: React.PropTypes.number
+};
+
+SnackbarNotification.defaultProps = {
+ isError: false,
+ autoHideDuration: 5000
+};
+
+export default SnackbarNotification;
diff --git a/web-ui/src/common/snackbar_notification/snackbar_notification.scss b/web-ui/src/common/snackbar_notification/snackbar_notification.scss
new file mode 100644
index 00000000..e37ba4ae
--- /dev/null
+++ b/web-ui/src/common/snackbar_notification/snackbar_notification.scss
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2017 ThoughtWorks, Inc.
+ *
+ * Pixelated is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Pixelated is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Pixelated. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+//TODO: Refer to Issue - https://github.com/callemall/material-ui/issues/3860
+#snackbar > div {
+ line-height: 20px !important;
+ padding: 24px !important;
+}
diff --git a/web-ui/src/common/snackbar_notification/snackbar_notification.spec.js b/web-ui/src/common/snackbar_notification/snackbar_notification.spec.js
new file mode 100644
index 00000000..24b79e71
--- /dev/null
+++ b/web-ui/src/common/snackbar_notification/snackbar_notification.spec.js
@@ -0,0 +1,31 @@
+import { shallow } from 'enzyme';
+import expect from 'expect';
+import React from 'react';
+import SnackbarNotification from 'src/common/snackbar_notification/snackbar_notification';
+import Snackbar from 'material-ui/Snackbar';
+import { red500 } from 'material-ui/styles/colors';
+
+describe('SnackbarNotification', () => {
+ let snackbarNotification;
+
+ beforeEach(() => {
+ snackbarNotification = shallow(<SnackbarNotification message={'Error Message'} isError />);
+ });
+
+ it('renders snackbar with error message', () => {
+ expect(snackbarNotification.find(Snackbar).props().message).toEqual('Error Message');
+ });
+
+ it('renders snackbar with open as true', () => {
+ expect(snackbarNotification.find(Snackbar).props().open).toEqual(true);
+ });
+
+ it('renders snackbar with error body style', () => {
+ expect(snackbarNotification.find(Snackbar).props().bodyStyle)
+ .toEqual({ height: 'auto', backgroundColor: red500 });
+ });
+
+ it('renders snackbar with default auto-hide duration', () => {
+ expect(snackbarNotification.find(Snackbar).props().autoHideDuration).toEqual(5000);
+ });
+});
diff --git a/web-ui/src/common/submit_button/submit_button.js b/web-ui/src/common/submit_button/submit_button.js
index 1224c7bd..f77a5596 100644
--- a/web-ui/src/common/submit_button/submit_button.js
+++ b/web-ui/src/common/submit_button/submit_button.js
@@ -30,7 +30,7 @@ const buttonStyle = {
height: '48px'
};
-const SubmitButton = ({ buttonText, disabled = false }) => (
+const SubmitButton = ({ buttonText, disabled = false, ...other }) => (
<div className='submit-button'>
<RaisedButton
type='submit'
@@ -41,6 +41,7 @@ const SubmitButton = ({ buttonText, disabled = false }) => (
overlayStyle={buttonStyle}
fullWidth
primary
+ {...other}
/>
</div>
);
diff --git a/web-ui/src/common/util.js b/web-ui/src/common/util.js
index effb3d9c..c70a8444 100644
--- a/web-ui/src/common/util.js
+++ b/web-ui/src/common/util.js
@@ -1,8 +1,27 @@
+import browser from 'helpers/browser';
+
export const hasQueryParameter = (param) => {
const decodedUri = decodeURIComponent(window.location.search.substring(1));
return !(decodedUri.split('&').indexOf(param) < 0);
};
+export const submitForm = (event, url, body = {}) => {
+ event.preventDefault();
+
+ return fetch(url, {
+ credentials: 'same-origin',
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json'
+ },
+ body: JSON.stringify({
+ csrftoken: [browser.getCookie('XSRF-TOKEN')],
+ ...body
+ })
+ });
+};
+
export default {
- hasQueryParameter
+ hasQueryParameter,
+ submitForm
};
diff --git a/web-ui/src/common/util.spec.js b/web-ui/src/common/util.spec.js
index 805d9dd5..a79859a0 100644
--- a/web-ui/src/common/util.spec.js
+++ b/web-ui/src/common/util.spec.js
@@ -1,4 +1,7 @@
import expect from 'expect';
+import fetchMock from 'fetch-mock';
+
+import browser from 'helpers/browser';
import Util from 'src/common/util';
describe('Utils', () => {
@@ -17,4 +20,36 @@ describe('Utils', () => {
expect(Util.hasQueryParameter('error')).toBe(false);
});
});
+
+ describe('submitForm', () => {
+ const event = {};
+
+ beforeEach(() => {
+ event.preventDefault = expect.createSpy();
+ expect.spyOn(browser, 'getCookie').andReturn('abc123');
+
+ fetchMock.post('/some-url', 200);
+ Util.submitForm(event, '/some-url', { userCode: '123' });
+ });
+
+ it('sends csrftoken as content', () => {
+ expect(fetchMock.lastOptions('/some-url').body).toContain('"csrftoken":["abc123"]');
+ });
+
+ it('sends body as content', () => {
+ expect(fetchMock.lastOptions('/some-url').body).toContain('"userCode":"123"');
+ });
+
+ it('sends content-type header', () => {
+ expect(fetchMock.lastOptions('/some-url').headers['Content-Type']).toEqual('application/json');
+ });
+
+ it('sends same origin headers', () => {
+ expect(fetchMock.lastOptions('/some-url').credentials).toEqual('same-origin');
+ });
+
+ it('prevents default call to refresh page', () => {
+ expect(event.preventDefault).toHaveBeenCalled();
+ });
+ });
});