From f7534d5570be20160177b161ca79ce755bd147d3 Mon Sep 17 00:00:00 2001 From: Zamil Majdy <z.majdy1996@gmail.com> Date: Wed, 22 Mar 2017 20:13:03 +0700 Subject: [PATCH] [#140382397] #5 Heavy refactor js to follow coding convention --- .eslintrc | 7 +- assets/js/__test__/coba-test.js | 25 --- assets/js/__test__/lib/logger-test.js | 25 +++ assets/js/component.js | 3 - assets/js/components/FormLogin.jsx | 30 +++ assets/js/components/ModalAlert.jsx | 44 ++++ assets/js/components/Pane.jsx | 15 ++ assets/js/components/SSOLogin.jsx | 32 +++ assets/js/components/Tabs.jsx | 67 ++++++ assets/js/components/TopMenu.jsx | 24 ++ assets/js/dashboard.jsx | 49 ++-- assets/js/index.js | 310 -------------------------- assets/js/index.jsx | 137 ++++++++++++ assets/js/lib/logger.jsx | 54 ++--- assets/js/lib/server.jsx | 149 +++++++------ assets/js/lib/storage.jsx | 31 +-- assets/js/login.jsx | 122 +++------- assets/js/root.js | 42 ---- core/views/accounts.py | 1 + npm-debug.log.1735884061 | 0 package.json | 4 +- webpack.config.js | 34 +-- 22 files changed, 568 insertions(+), 637 deletions(-) delete mode 100755 assets/js/__test__/coba-test.js create mode 100644 assets/js/__test__/lib/logger-test.js delete mode 100755 assets/js/component.js create mode 100644 assets/js/components/FormLogin.jsx create mode 100644 assets/js/components/ModalAlert.jsx create mode 100644 assets/js/components/Pane.jsx create mode 100644 assets/js/components/SSOLogin.jsx create mode 100644 assets/js/components/Tabs.jsx create mode 100644 assets/js/components/TopMenu.jsx delete mode 100755 assets/js/index.js create mode 100644 assets/js/index.jsx delete mode 100755 assets/js/root.js create mode 100644 npm-debug.log.1735884061 diff --git a/.eslintrc b/.eslintrc index 1ee944f9..c6197154 100644 --- a/.eslintrc +++ b/.eslintrc @@ -9,7 +9,12 @@ }, "rules": { "func-names": ["error", "never"], - "react/prefer-stateless-function": [0, { "ignorePureComponents": true }] + "react/prefer-stateless-function": [0, { "ignorePureComponents": true }], + "import/extensions": ["off", "never"], + "import/no-unresolved": 0, + "no-underscore-dangle" : 0, + "linebreak-style" : 0, + "no-extra-bind" : 0 }, "parser": "babel-eslint", "parserOptions": { diff --git a/assets/js/__test__/coba-test.js b/assets/js/__test__/coba-test.js deleted file mode 100755 index 432d9c75..00000000 --- a/assets/js/__test__/coba-test.js +++ /dev/null @@ -1,25 +0,0 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; -import ReactTestUtils from 'react-addons-test-utils' // ES6 -import expect from 'expect'; -import Root from '../root'; - -describe('root', function () { - it('renders without problems', function () { - let root = ReactTestUtils.renderIntoDocument(<Root/>); - expect(root).toExist(); - }); - - it('changes without problems', function () { - let root = ReactTestUtils.renderIntoDocument(<Root/>); - - const inputNode = ReactDOM.findDOMNode(root.refs.input); - - const newValue = 'some text'; - inputNode.value = newValue; - ReactTestUtils.Simulate.change(inputNode); - - const nameNode = ReactDOM.findDOMNode(root.refs.name); - expect(nameNode.textContent).toEqual(newValue); - }); -}); \ No newline at end of file diff --git a/assets/js/__test__/lib/logger-test.js b/assets/js/__test__/lib/logger-test.js new file mode 100644 index 00000000..ac3c13fc --- /dev/null +++ b/assets/js/__test__/lib/logger-test.js @@ -0,0 +1,25 @@ +import expect from "expect"; +import Logger from "../../lib/logger"; +import {describe, beforeEach, it} from "mocha"; + +describe('logger log', function () { + beforeEach(function() { + expect(Logger, 'log'); + Logger.log("testing log"); + }); + + it('Logger sent log properly', function () { + expect(console.log).toHaveBeenCalled(); + }); +}); + +describe('logger error', function () { + beforeEach(function() { + expect(Logger, 'error'); + Logger.error("testing error"); + }); + + it('Logger sent error properly', function () { + expect(console.log).toHaveBeenCalled(); + }); +}); \ No newline at end of file diff --git a/assets/js/component.js b/assets/js/component.js deleted file mode 100755 index 8420d7a4..00000000 --- a/assets/js/component.js +++ /dev/null @@ -1,3 +0,0 @@ -var component = TestUtils.renderIntoDocument( - <MyComponent /> -); \ No newline at end of file diff --git a/assets/js/components/FormLogin.jsx b/assets/js/components/FormLogin.jsx new file mode 100644 index 00000000..a47a452d --- /dev/null +++ b/assets/js/components/FormLogin.jsx @@ -0,0 +1,30 @@ +import React from 'react'; +import { Form, Input, Button, Image } from 'semantic-ui-react'; + +export default class FormLogin extends React.Component { + render = () => ( + <div className="formLogin" > + + <Image src="/assets/img/logo.png" size="small" verticalAlign="middle" /> <span>Company Login</span> + + <Form> + <Form.Group widths="equal"> + <Form.Field> + <label htmlFor="id"> Email </label> + <Input id="email" icon="user" iconPosition="left" placeholder="email" /> + </Form.Field> + </Form.Group> + + <Form.Group widths="equal"> + <Form.Field> + <label htmlFor="password"> Password </label> + <Input id="password" icon="key" iconPosition="left" placeholder="password" /> + </Form.Field> + </Form.Group> + + <Button fluid color="blue">Login</Button> + + </Form> + </div> + ) +} diff --git a/assets/js/components/ModalAlert.jsx b/assets/js/components/ModalAlert.jsx new file mode 100644 index 00000000..ac9d1703 --- /dev/null +++ b/assets/js/components/ModalAlert.jsx @@ -0,0 +1,44 @@ +import React from 'react'; +import { Modal, Button, Icon } from 'semantic-ui-react'; + +export default class ModalAlert extends React.Component { + static propTypes = { + onChangeValue: React.PropTypes.func.isRequired, + header: React.PropTypes.oneOfType([ + React.PropTypes.node, + React.PropTypes.string, + ]).isRequired, + content: React.PropTypes.oneOfType([ + React.PropTypes.node, + React.PropTypes.string, + ]).isRequired, + }; + + state = { open: false }; + + open = () => this.setState({ open: true }); + close = () => this.setState({ open: false }); + + render() { + const { open } = this.state; + + return ( + <Modal + dimmer={false} + open={open} + onOpen={this.open} + onClose={this.close} + size="small" + trigger={<Button > Proceed <Icon name="right chevron" /></Button>} + > + <Modal.Header>{this.props.header}</Modal.Header> + <Modal.Content> + <p>{this.props.content}</p> + </Modal.Content> + <Modal.Actions> + <Button icon="check" content="All Done" onClick={this.props.onChangeValue} /> + </Modal.Actions> + </Modal> + ); + } +} \ No newline at end of file diff --git a/assets/js/components/Pane.jsx b/assets/js/components/Pane.jsx new file mode 100644 index 00000000..ae57febc --- /dev/null +++ b/assets/js/components/Pane.jsx @@ -0,0 +1,15 @@ +import React from 'react'; + +export default class Pane extends React.Component { + static displayName = 'Pane'; + + static propTypes = { + children: React.PropTypes.element.isRequired, + }; + + render = () => ( + <div> + {this.props.children} + </div> + ) +} diff --git a/assets/js/components/SSOLogin.jsx b/assets/js/components/SSOLogin.jsx new file mode 100644 index 00000000..fd2b9438 --- /dev/null +++ b/assets/js/components/SSOLogin.jsx @@ -0,0 +1,32 @@ +import React from 'react'; +import { Form, Input, Button, Image } from 'semantic-ui-react'; + +export default class SsoLogin extends React.Component { + render = () => ( + <div className="formLogin" > + + <Image src="/assets/img/UI.png" size="tiny" verticalAlign="middle" /> <span> SSO Login</span> + + <div className="input"> + <Form> + <Form.Group widths="equal"> + <Form.Field> + <label htmlFor="email">Email</label> + <Input id="email" icon="user" iconPosition="left" placeholder="email" /> + </Form.Field> + </Form.Group> + + <Form.Group widths="equal"> + <Form.Field> + <label htmlFor="password">Password</label> + <Input id="password" icon="key" iconPosition="left" placeholder="password" /> + </Form.Field> + </Form.Group> + <Button fluid color="blue" >Login</Button> + + </Form> + </div> + + </div> + ) +} diff --git a/assets/js/components/Tabs.jsx b/assets/js/components/Tabs.jsx new file mode 100644 index 00000000..a6317bc4 --- /dev/null +++ b/assets/js/components/Tabs.jsx @@ -0,0 +1,67 @@ +import React from 'react'; + +export default class Tabs extends React.Component { + static displayName = 'Tabs'; + + static propTypes = { + selected: React.PropTypes.number.isRequired, + children: React.PropTypes.oneOfType([ + React.PropTypes.array, + React.PropTypes.element, + ]).isRequired, + }; + + static defaultProps = () => ({ + selected: 0, + }); + + constructor(props) { + super(props); + this.state = { + selected: this.props.selected, + }; + } + + shouldComponentUpdate = (nextProps, nextState) => ( + this.props !== nextProps || this.state !== nextState + ); + + handleClick = (index, event) => { + event.preventDefault(); + this.setState({ + selected: index, + }); + }; + + _renderTitles = () => { + function labels(child, index) { + const activeClass = (this.state.selected === index ? 'active' : ''); + return ( + <li key={index}> + <button className={activeClass} onClick={this.handleClick.bind(this, index)}> + {child.props.label} + </button> + </li> + ); + } + return ( + <ul className="tabs__labels"> + {this.props.children.map(labels.bind(this))} + </ul> + ); + }; + + _renderContent = () => ( + <div className="tabs__content"> + {this.props.children[this.state.selected]} + </div> + ); + + + render = () => ( + <div className="tabs"> + {this._renderTitles()} + {this._renderContent()} + </div> + ); +} diff --git a/assets/js/components/TopMenu.jsx b/assets/js/components/TopMenu.jsx new file mode 100644 index 00000000..ed754c0b --- /dev/null +++ b/assets/js/components/TopMenu.jsx @@ -0,0 +1,24 @@ +import React from 'react'; +import { Menu, Image } from 'semantic-ui-react'; +import { Link } from 'react-router'; +import Server from './../lib/server'; + +export default class TopMenu extends React.Component { + state = { activeItem: 'home' }; + + render() { + return ( + <Menu pointing secondary> + <Image as="a" size="small" src="/assets/img/logo.png" href="/" /> + <Menu.Menu position="right"> + <Menu.Item as={Link} to="/home" name="home" /> + <Menu.Item as={Link} to="/profile" name="profil" /> + {Server.isLoggedIn() ? + <Menu.Item as={Link} href="/api/api-auth/logout/?next=/" name="logout" /> : + <Menu.Item as={Link} to="/login" name="login" /> + } + </Menu.Menu> + </Menu> + ); + } +} diff --git a/assets/js/dashboard.jsx b/assets/js/dashboard.jsx index 77790d3b..634fdefa 100755 --- a/assets/js/dashboard.jsx +++ b/assets/js/dashboard.jsx @@ -1,37 +1,18 @@ -import React, { Component } from "react"; -import {Menu, Segment, Image} from "semantic-ui-react"; -import {Link,Button, Header, Icon, Modal} from "react-router"; -import Server from "./lib/server"; +import React from 'react'; +import TopMenu from './components/TopMenu'; -export class TopMenu extends React.Component { - state = { activeItem: 'home' }; +export default class Dashboard extends React.Component { + static propTypes = { + children: React.PropTypes.oneOfType([ + React.PropTypes.arrayOf(React.PropTypes.node), + React.PropTypes.node, + ]).isRequired, + }; - render() { - return ( - <Menu pointing secondary> - <Image as='a' size='small' src='/assets/img/logo.png' href='/'/> - <Menu.Menu position='right'> - <Menu.Item as={Link} to="/home" name='home' /> - <Menu.Item as={Link} to="/profile" name='profil' /> - {Server.isLoggedIn() ? - <Menu.Item as={Link} href="/api/api-auth/logout/?next=/" name='logout' /> : - <Menu.Item as={Link} to="/login" name='login' /> - } - </Menu.Menu> - </Menu> - ) - } + render = () => ( + <div> + <TopMenu /> + {this.props.children} + </div> + ) } - - - -export default class Dashboard extends React.Component { - render = () => { - return ( - <div> - <TopMenu/> - {this.props.children} - </div> - ) - } -} \ No newline at end of file diff --git a/assets/js/index.js b/assets/js/index.js deleted file mode 100755 index a133f406..00000000 --- a/assets/js/index.js +++ /dev/null @@ -1,310 +0,0 @@ -import React from "react"; -import Dashboard from "./dashboard"; -import Login from './login'; -import ReactDOM from "react-dom"; -import {Router, Route, browserHistory} from "react-router"; -import {Segment, Modal, Button, Icon,Input,Menu,Image as ImageComponent, Item , Header,Grid, Divider,TextArea, Form } from "semantic-ui-react"; - -import Server from "./lib/server" - -export const Profile = () => ( - <Segment> - <img src='http://semantic-ui.com/images/wireframe/media-paragraph.png' /> - </Segment> -); - -class Greeting extends React.Component { - state = { - username : "unknown-user", - modalOpen : true - }; - - closeModal = () => {this.setState({modalOpen: false})}; - - componentWillMount() { - Server.get("/users/me/") - .then(results => { - results.username && this.setState({username : results.username}); - }, error => { - // console.log(error); - }); - } - - render () { - return ( - <Modal open={this.state.modalOpen} basic size='small' onClose={this.closeModal}> - <Modal.Content> - <h1 style={{textAlign : 'center'}}> - <Icon loading name='like outline' size='large'/> - Hi {this.state.username} - <Icon loading name='like outline' size='large'/> - </h1> - </Modal.Content> - <Modal.Actions> - <Button color='green' inverted onClick={this.closeModal} > - <Icon name='checkmark' /> Hi - </Button> - </Modal.Actions> - </Modal> - ); - } -} - - - -var Tabs = React.createClass({ - displayName: 'Tabs', - propTypes: { - selected: React.PropTypes.number, - children: React.PropTypes.oneOfType([ - React.PropTypes.array, - React.PropTypes.element - ]).isRequired - }, - getDefaultProps: function () { - return { - selected: 0 - }; - }, - getInitialState: function () { - return { - selected: this.props.selected - }; - }, - shouldComponentUpdate(nextProps, nextState) { - return this.props !== nextProps || this.state !== nextState; - }, - handleClick: function (index, event) { - event.preventDefault(); - this.setState({ - selected: index - }); - }, - _renderTitles: function () { - function labels(child, index) { - var activeClass = (this.state.selected === index ? 'active' : ''); - return ( - <li key={index}> - <a href="#" - className={activeClass} - onClick={this.handleClick.bind(this, index)}> - {child.props.label} - </a> - </li> - ); - } - return ( - <ul className="tabs__labels"> - {this.props.children.map(labels.bind(this))} - </ul> - ); - }, - _renderContent: function () { - return ( - <div className="tabs__content"> - {this.props.children[this.state.selected]} - </div> - ); - }, - render: function () { - return ( - <div className="tabs"> - {this._renderTitles()} - {this._renderContent()} - </div> - ); - } -}); - -var Pane = React.createClass({ - displayName: 'Pane', - propTypes: { - label: React.PropTypes.string.isRequired, - children: React.PropTypes.element.isRequired - }, - render: function () { - return ( - <div> - {this.props.children} - </div> - ); - } -}); - -export const Home = () => ( - <div> - <Tabs selected={0}> - <Pane label="Semua Lowongan"> - <ItemExampleFloated/> - </Pane> - <Pane label="Lamaran saya"> - <div>This is my tab 2 contents!</div> - </Pane> - </Tabs> - </div> -); - -export const App = () => ( - <Router history={browserHistory}> - <Route path="/login" component={Login} /> - <Route component={Dashboard}> - <Route path="/" component={Greeting} /> - <Route path="profile" component={Profile} /> - <Route path="home" component={Home} /> - <Route path="users" component={Profile} /> - </Route> - </Router> -); - - - -const paragraph = <ImageComponent src='http://semantic-ui.com/images/wireframe/short-paragraph.png' />; - -export class ItemExampleFloated extends React.Component { - - render() { - return ( - <Item.Group relaxed> - <Item> - - <Item.Image size='small' src='http://semantic-ui.com/images/wireframe/image.png' /> - <Item.Content verticalAlign='middle'> - <Item.Header>Lowongan 1</Item.Header> - <Item.Description>{paragraph}</Item.Description> - <Item.Extra> - <div className="daftar"> - <ModalExampleMultiple /> - </div> - </Item.Extra> - </Item.Content> - - - </Item> - - <Item> - - <Item.Image size='small' src='http://semantic-ui.com/images/wireframe/image.png' /> - <Item.Content verticalAlign='middle'> - <Item.Header>Lowongan 2</Item.Header> - <Item.Description>{paragraph}</Item.Description> - <Item.Extra> - <div className="daftar"> - <ModalExampleMultiple /> - </div> - </Item.Extra> - </Item.Content> - - - </Item> - - <Item> - - <Item.Image size='small' src='http://semantic-ui.com/images/wireframe/image.png' /> - <Item.Content verticalAlign='middle'> - <Item.Header>Lowongan 3</Item.Header> - <Item.Description>{paragraph}</Item.Description> - <Item.Extra> - <div className="daftar"> - <ModalExampleMultiple /> - </div> - </Item.Extra> - </Item.Content> - - - </Item> - - - </Item.Group> - ) - } -} - -export class NestedModal extends React.Component { - state = { open: false } - - open = () => this.setState({ open: true }) - close = () => this.setState({ open: false }) - - render() { - const { open } = this.state - - return ( - <Modal - dimmer={false} - open={open} - onOpen={this.open} - onClose={this.close} - size='small' - trigger={<Button > Proceed <Icon name='right chevron' /></Button>} - > - <Modal.Header>Pendaftaran</Modal.Header> - <Modal.Content> - <p>Terima kasih sudah mendaftar!</p> - </Modal.Content> - <Modal.Actions> - <Button icon='check' content='All Done' onClick={this.props.onChangeValue} /> - </Modal.Actions> - </Modal> - ) - } -} - - - -export class ModalExampleMultiple extends React.Component { - - - state = { modalOpen: false } - - handleOpen = (e) => this.setState({ - modalOpen: true, - }) - - handleClose = (e) => this.setState({ - modalOpen: false, - }) - - render() { - return ( - <Modal - trigger={<Button onClick={this.handleOpen} >Daftar</Button>} - closeIcon='close' - open={this.state.modalOpen} - onClose={this.handleClose} - > - - <Modal.Header>Pendaftaran Lowongan</Modal.Header> - <Modal.Content image> - <div className='image'> - <Icon name='right arrow' /> - </div> - <Modal.Description> - <Modal.Header> <h3> Deskripsi Lowongan </h3></Modal.Header> - {paragraph} - - <div className='linkCV'> - <a> your latest CV </a> - </div> - - <div className='coverLetter'> - <h5> Write your Cover Letter </h5> - <TextAreaExample /> - </div> - - </Modal.Description> - </Modal.Content> - <Modal.Actions> - <NestedModal onChangeValue={ this.handleClose } /> - </Modal.Actions> - </Modal> - ) - } -} - -export const TextAreaExample = () => ( - <Form> - <TextArea placeholder='Tell us more' /> - </Form> -); - -ReactDOM.render( <App />, document.getElementById('react-app')); diff --git a/assets/js/index.jsx b/assets/js/index.jsx new file mode 100644 index 00000000..8cce53ea --- /dev/null +++ b/assets/js/index.jsx @@ -0,0 +1,137 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import { Router, Route, browserHistory } from 'react-router'; +import { Segment, Modal, Button, Icon, Image as ImageComponent, Item, TextArea, Form } from 'semantic-ui-react'; +import Dashboard from './dashboard'; +import Login from './login'; +import Pane from './components/Pane'; +import Tabs from './components/Tabs'; +import ModalAlert from './components/ModalAlert'; + +export const Profile = () => ( + <Segment> + <img src="http://semantic-ui.com/images/wireframe/media-paragraph.png" alt="wire-frame" /> + </Segment> +); + +export const Home = () => ( + <div> + <Tabs selected={0}> + <Pane label="Semua Lowongan"> + <ItemExampleFloated /> + </Pane> + <Pane label="Lamaran saya"> + <div>This is my tab 2 contents!</div> + </Pane> + </Tabs> + </div> +); + +export const App = () => ( + <Router history={browserHistory}> + <Route path="/login" component={Login} /> + <Route component={Dashboard}> + <Route path="/" component={Profile} /> + <Route path="profile" component={Profile} /> + <Route path="home" component={Home} /> + <Route path="users" component={Profile} /> + </Route> + </Router> +); + +const paragraph = <ImageComponent src="http://semantic-ui.com/images/wireframe/short-paragraph.png" />; +const imageWireFrame = <Item.Image size="small" src="http://semantic-ui.com/images/wireframe/image.png" />; + +export const ItemExampleFloated = () => ( + <Item.Group relaxed> + <Item> + {imageWireFrame} + <Item.Content verticalAlign="middle"> + <Item.Header>Lowongan 1</Item.Header> + <Item.Description>{paragraph}</Item.Description> + <Item.Extra> + <div className="daftar"> + <ModalExampleMultiple /> + </div> + </Item.Extra> + </Item.Content> + </Item> + + <Item> + {imageWireFrame} + <Item.Content verticalAlign="middle"> + <Item.Header>Lowongan 2</Item.Header> + <Item.Description>{paragraph}</Item.Description> + <Item.Extra> + <div className="daftar"> + <ModalExampleMultiple /> + </div> + </Item.Extra> + </Item.Content> + </Item> + <Item> + {imageWireFrame} + <Item.Content verticalAlign="middle"> + <Item.Header>Lowongan 3</Item.Header> + <Item.Description>{paragraph}</Item.Description> + <Item.Extra> + <div className="daftar"> + <ModalExampleMultiple /> + </div> + </Item.Extra> + </Item.Content> + </Item> + </Item.Group> + ); + + +export class ModalExampleMultiple extends React.Component { + + state = { modalOpen: false }; + + handleOpen = () => this.setState({ + modalOpen: true, + }); + + handleClose = () => this.setState({ + modalOpen: false, + }); + + render = () => ( + <Modal + trigger={<Button onClick={this.handleOpen} >Daftar</Button>} + closeIcon="close" + open={this.state.modalOpen} + onClose={this.handleClose} + > + + <Modal.Header>Pendaftaran Lowongan</Modal.Header> + <Modal.Content image> + <div className="image"> + <Icon name="right arrow" /> + </div> + <Modal.Description> + <Modal.Header> <h3> Deskripsi Lowongan </h3></Modal.Header> + {paragraph} + + <div className="linkCV"> + <a> your latest CV </a> + </div> + + <div className="coverLetter"> + <h5> Write your Cover Letter </h5> + <Form> + <TextArea placeholder="Tell us more" /> + </Form> + </div> + + </Modal.Description> + </Modal.Content> + <Modal.Actions> + <ModalAlert onChangeValue={this.handleClose} header="Pendaftaran" content="Terima kasih sudah mendaftar!" /> + </Modal.Actions> + </Modal> + ) +} + +ReactDOM.render(<App />, document.getElementById('react-app')); diff --git a/assets/js/lib/logger.jsx b/assets/js/lib/logger.jsx index d55489a1..6118bd0f 100755 --- a/assets/js/lib/logger.jsx +++ b/assets/js/lib/logger.jsx @@ -1,42 +1,42 @@ /* eslint-disable no-console */ -let DEV = (process.env.NODE_ENV !== "production"); +// noinspection ES6ModulesDependencies,JSUnresolvedVariable +const DEV = process.env.NODE_ENV !== 'production'; export default class Logger { - static log(...args) { - if (DEV) { - console.log(...args); - } + static log(...args) { + if (DEV) { + console.log(...args); } + } - static warn(...args) { - if (DEV) { - console.warn(...args); - } + static warn(...args) { + if (DEV) { + console.warn(...args); } + } - static error(...args) { - if (DEV) { - console.error(...args); - } + static error(...args) { + if (DEV) { + console.error(...args); } + } - static serverError(error, callback) { - if (error.json) { - error.json().then(errorText => { - Logger.error(`Error ${errorText}`); - if (callback !== undefined) { - callback(errorText); - } - }); - } - else { - Logger.error(`Error ${error}`); - if (callback !== undefined) { - callback(error); - } + static serverError(error, callback) { + if (error.json) { + error.json().then((errorText) => { + Logger.error(`Error ${errorText}`); + if (callback !== undefined) { + callback(errorText); } + }); + } else { + Logger.error(`Error ${error}`); + if (callback !== undefined) { + callback(error); + } } + } } global.Logger = Logger; diff --git a/assets/js/lib/server.jsx b/assets/js/lib/server.jsx index 437a8637..6796153c 100755 --- a/assets/js/lib/server.jsx +++ b/assets/js/lib/server.jsx @@ -1,88 +1,89 @@ -import Logger from "./logger"; -import Storage from "./storage"; +import Logger from './logger'; +import Storage from './storage'; export default class Server { - static getCookie(name) { - let cookieValue = null; - if (document.cookie && document.cookie !== "") { - let cookies = document.cookie.split(";"); - for (let i = 0; i < cookies.length; i++) { - let cookie = cookies[i].trim(); - // Does this cookie string begin with the name we want? - if (cookie.substring(0, name.length + 1) === (name + "=")) { - cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); - break; - } - } + static getCookie(name) { + let cookieValue = null; + if (document.cookie && document.cookie !== '') { + const cookies = document.cookie.split(';'); + for (let i = 0; i < cookies.length; i += 1) { + const cookie = cookies[i].trim(); + // Does this cookie string begin with the name we want? + if (cookie.substring(0, name.length + 1) === (`${name}`)) { + cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); + break; } - return cookieValue; + } } + return cookieValue; + } - static _request(path, method, data, useCache = false) { + static sendRequest(path, method, data, useCache = false) { + const url = `/api${path}`; + const csrftoken = this.getCookie('csrftoken'); + const headers = { + 'content-type': 'application/json', + Accept: 'application/json', + 'X-CSRFToken': csrftoken, + }; + const requestData = { + headers, + method, + body: data !== null ? JSON.stringify(data) : undefined, + credentials: 'same-origin', + }; - let url = "/api" + path; - let csrftoken = this.getCookie("csrftoken"); - let headers = { - "content-type": "application/json", - "Accept": "application/json", - "X-CSRFToken": csrftoken - }; - let requestData = { - headers: headers, - method: method, - body: data !== null ? JSON.stringify(data) : undefined, - credentials: "same-origin", - }; - - let request = fetch(url, requestData); - let promise = request.then((response) => { + // noinspection JSUnresolvedFunction + const request = fetch(url, requestData); + const promise = request.then((response) => { // Logger.log("[Server] Calling", url, response); - if (response.status < 200 || response.status > 399) { - throw response; - } - if (response.status === 204) { - return response; - } - return response.json(); - }); + if (response.status < 200 || response.status > 399) { + throw response; + } + if (response.status === 204) { + return response; + } + return response.json(); + }); - return useCache ? promise.then((response) => { - Logger.log("[Server] Response from", url, response); - Storage.set(path, response); - return response; - }) : promise.then((response) => { - Logger.log("[Server] Response from", url, response); - return response; - }) - } + return useCache ? promise.then((response) => { + Logger.log('[Server] Response from', url, response); + Storage.set(path, response); + return response; + }) : promise.then((response) => { + Logger.log('[Server] Response from', url, response); + return response; + }); + } - static get(path, useCache = true) { - return (useCache && Storage.get(path)) ? - Promise.resolve(Storage.get(path)) : this._request(path, "GET", null, useCache); - } + static get(path, useCache = true) { + return (useCache && Storage.get(path)) ? + Promise.resolve(Storage.get(path)) : this.sendRequest(path, 'GET', null, useCache); + } - static post(path, data) { - return this._request(path, "POST", data); - } + static post(path, data) { + return this.sendRequest(path, 'POST', data); + } - static patch(path, data) { - return this._request(path, "PATCH", data); - } + static patch(path, data) { + return this.sendRequest(path, 'PATCH', data); + } - static delete(path) { - return this._request(path, "DELETE", {}); - } + // noinspection ReservedWordAsName + static delete(path) { + return this.sendRequest(path, 'DELETE', {}); + } - static request(url, method, payload, success, error) { - let request = new XMLHttpRequest(); - request.open(method, url, true); - request.onload = success; - request.onerror = error; - request.setRequestHeader('Content-Type', 'text/plain'); - return request.send(payload); - } + static request(url, method, payload, success, error) { + const request = new XMLHttpRequest(); + request.open(method, url, true); + request.onload = success; + request.onerror = error; + request.setRequestHeader('Content-Type', 'text/plain'); + return request.send(payload); + } - static isLoggedIn() { - return this.getCookie("sessionid"); - } -} \ No newline at end of file + static isLoggedIn() { + return this.getCookie('sessionid'); + } +} diff --git a/assets/js/lib/storage.jsx b/assets/js/lib/storage.jsx index 79e2ca81..be269055 100644 --- a/assets/js/lib/storage.jsx +++ b/assets/js/lib/storage.jsx @@ -1,10 +1,12 @@ /** Session Storage Polyfill */ + +/* eslint-disable */ var isStorageAvailable = function (storage) { - if (typeof storage == 'undefined') return false; + if (typeof storage === 'undefined') return false; try { // hack for safari incognito - storage.setItem("storage", ""); - storage.getItem("storage"); - storage.removeItem("storage"); + storage.setItem('storage', ''); + storage.getItem('storage'); + storage.removeItem('storage'); return true; } catch (err) { @@ -108,17 +110,18 @@ if (!isStorageAvailable(window.localStorage)) window.localStorage = new Storage( if (!isStorageAvailable(window.sessionStorage)) window.sessionStorage = new Storage('session'); })(); +/*eslint-enable */ export default class Storage { - static get(key) { - return JSON.parse(sessionStorage.getItem(key)) - } + static get(key) { + return JSON.parse(sessionStorage.getItem(key)); + } - static set(key ,value) { - sessionStorage.setItem(key, JSON.stringify(value)); - } + static set(key, value) { + sessionStorage.setItem(key, JSON.stringify(value)); + } - static clear() { - sessionStorage.clear(); - } -} \ No newline at end of file + static clear() { + sessionStorage.clear(); + } +} diff --git a/assets/js/login.jsx b/assets/js/login.jsx index 7a1016f2..1a8a1c4d 100644 --- a/assets/js/login.jsx +++ b/assets/js/login.jsx @@ -1,94 +1,38 @@ -import React from 'react' -import { Form, Input, Icon, Button, Grid, Segment, Divider, Image,Card } from 'semantic-ui-react' - - -export class FormLogin extends React.Component { - render = () => { - return ( - <div className="formLogin" > - - <Image src='/assets/img/logo.png' size='small' verticalAlign='middle' /> <span>Company Login</span> - - <Form> - <Form.Group widths='equal'> - <Form.Field> - <label>Email</label> - <Input icon='user' iconPosition='left' placeholder='email'/> - </Form.Field> - </Form.Group> - - <Form.Group widths='equal'> - <Form.Field> - <label>Password</label> - <Input icon='key' iconPosition='left' placeholder='password' /> - </Form.Field> - </Form.Group> - - <Button fluid color='blue'>Login</Button> - - </Form> - </div> - ) - } -} - - -export class SsoLogin extends React.Component { - render = () => { - return ( - <div className="formLogin" > - - <Image src='/assets/img/UI.png' size='tiny' verticalAlign='middle' /> <span> SSO Login</span> - - <div className="input"> - <Form> - <Form.Group widths='equal'> - <Form.Field> - <label>Email</label> - <Input icon='user' iconPosition='left' placeholder='email'/> - </Form.Field> - </Form.Group> - - <Form.Group widths='equal'> - <Form.Field> - <label>Password</label> - <Input icon='key' iconPosition='left' placeholder='password' /> - </Form.Field> - </Form.Group> - <Button fluid color='blue' >Login</Button> - - </Form> - </div> - - </div> - ) - } -} - - +import React from 'react'; +import { Grid, Segment } from 'semantic-ui-react'; +import FormLogin from './components/FormLogin'; +import SSOLogin from './components/SSOLogin'; export default class Login extends React.Component { - render = () => { - return ( - <Grid columns={2} relaxed> - <Grid.Column> - <Segment basic> - <FormLogin/> - {this.props.children} - </Segment> - </Grid.Column> - - <Grid.Column> - <Segment basic> - <SsoLogin/> - {this.props.children} - </Segment> - </Grid.Column> - - </Grid> + + static defaultProps = { + children: null, + }; + + static propTypes = { + children: React.PropTypes.oneOfType([ + React.PropTypes.arrayOf(React.PropTypes.node), + React.PropTypes.node, + ]), + }; + + render = () => ( + <Grid columns={2} relaxed> + <Grid.Column> + <Segment basic> + <FormLogin /> + {this.props.children} + </Segment> + </Grid.Column> + + <Grid.Column> + <Segment basic> + <SSOLogin /> + {this.props.children} + </Segment> + </Grid.Column> + + </Grid> ) - } } - - diff --git a/assets/js/root.js b/assets/js/root.js deleted file mode 100755 index fd9d6323..00000000 --- a/assets/js/root.js +++ /dev/null @@ -1,42 +0,0 @@ -/** - * Created by M. Reza Qorib on 3/11/2017. - */ -import React from 'react'; - -class Root extends React.Component { - constructor(props) { - super(props); - - this.state = { - name: '' - }; - - this.handleChange = (e) => { - var newName = e.target.value; - - this.setState({ - name: newName - }); - } - } - - render() { - return ( - <div> - <h1>Hello World!!</h1> - - <p> - Please input your name here: - <input ref="input" - onChange={this.handleChange} - value={this.state.name} - /> - </p> - - <p>Hello, <span ref="name">{this.state.name}</span> </p> - </div> - ); - } -} - -export default Root; \ No newline at end of file diff --git a/core/views/accounts.py b/core/views/accounts.py index 07d8ef88..33bb4bb2 100644 --- a/core/views/accounts.py +++ b/core/views/accounts.py @@ -6,6 +6,7 @@ from rest_framework.response import Response from core.models.accounts import Student, Company, Supervisor from core.serializers.accounts import UserSerializer, StudentSerializer, CompanySerializer, SupervisorSerializer + class UserViewSet(viewsets.ModelViewSet): queryset = User.objects.all() serializer_class = UserSerializer diff --git a/npm-debug.log.1735884061 b/npm-debug.log.1735884061 new file mode 100644 index 00000000..e69de29b diff --git a/package.json b/package.json index 19b005b5..60cbd095 100755 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "license": "ISC", "devDependencies": { "babel": "^6.5.2", + "babel-eslint": "^7.2.0", "babel-loader": "^6.2.5", "babel-preset-es2015": "^6.22.0", "babel-preset-stage-1": "^6.16.0", @@ -23,6 +24,7 @@ "eslint-plugin-import": "^2.2.0", "eslint-plugin-jsx-a11y": "^4.0.0", "eslint-plugin-react": "^6.10.3", + "eslint-watch": "^3.0.1", "expect": "^1.20.2", "expect.js": "^0.3.1", "istanbul-instrumenter-loader": "^2.0.0", @@ -34,7 +36,6 @@ "karma-sourcemap-loader": "^0.3.7", "karma-webpack": "^2.0.2", "mocha": "^3.2.0", - "react": "^15.4.0", "react-addons-test-utils": "^15.4.2", "react-hot-loader": "^3.0.0-beta.5", "react-test-utils": "0.0.1", @@ -43,6 +44,7 @@ "webpack-dev-server": "^1.16.2" }, "dependencies": { + "react": "^15.4.0", "axios": "^0.14.0", "babel-core": "^6.17.0", "babel-preset-react": "^6.16.0", diff --git a/webpack.config.js b/webpack.config.js index b07c2c85..cb176d4a 100755 --- a/webpack.config.js +++ b/webpack.config.js @@ -1,6 +1,6 @@ -var path = require("path") -var webpack = require('webpack') -var BundleTracker = require('webpack-bundle-tracker') +const path = require('path'); +const webpack = require('webpack'); +const BundleTracker = require('webpack-bundle-tracker'); module.exports = { context: __dirname, @@ -8,34 +8,34 @@ module.exports = { entry: './assets/js/index', // entry point of our app. assets/js/index.js should require other js modules and dependencies it needs output: { - path: path.resolve('./assets/bundles/'), - filename: "[name]-[hash].js", + path: path.resolve('./assets/bundles/'), + filename: '[name]-[hash].js', }, plugins: [ new webpack.HotModuleReplacementPlugin(), - new BundleTracker({filename: './webpack-stats.json'}) + new BundleTracker({ filename: './webpack-stats.json' }), ], module: { loaders: [ - { test: /\.jsx?$/, - exclude: /node_modules/, + { test: /\.jsx?$/, + exclude: /node_modules/, loader: 'babel-loader', // to transform JSX into JS query: { - presets:['react', 'es2015', 'stage-1'] - } - } + presets: ['react', 'es2015', 'stage-1'], + }, + }, ], - postLoaders: [ { //delays coverage til after tests are run, fixing transpiled source coverage error - test: /\.js$/, - exclude: /(test|node_modules|bower_components)\//, - loader: 'istanbul-instrumenter' } ] + postLoaders: [{ + test: /\.js$/, + exclude: /(test|node_modules|bower_components)\//, + loader: 'istanbul-instrumenter' }], }, resolve: { modulesDirectories: ['node_modules', 'bower_components'], - extensions: ['', '.js', '.jsx'] + extensions: ['', '.js', '.jsx'], }, -} +}; -- GitLab