diff --git a/.eslintrc b/.eslintrc index c6197154ba3f78d5acfaa6285d5920c82cf34c06..3832227820fa2ff722a19b1f54c1c2d83047074c 100644 --- a/.eslintrc +++ b/.eslintrc @@ -10,6 +10,7 @@ "rules": { "func-names": ["error", "never"], "react/prefer-stateless-function": [0, { "ignorePureComponents": true }], + "react/forbid-prop-types": [0], "import/extensions": ["off", "never"], "import/no-unresolved": 0, "no-underscore-dangle" : 0, diff --git a/assets/js/Login.jsx b/assets/js/Login.jsx index df26050fa6bba2fc1c8be0f876585a0d3202b8b0..32b47246649c23687ca791a214df781a9c015776 100644 --- a/assets/js/Login.jsx +++ b/assets/js/Login.jsx @@ -19,14 +19,14 @@ export default class Login extends React.Component { <Grid columns={2} relaxed> <Grid.Column> <Segment basic> - <LoginForm url="/login/company" imgSrc="logo.png" imgSize="small" /> + <LoginForm type="company" header="Company Login" imgSrc="logo.png" imgSize="small" /> {this.props.children} </Segment> </Grid.Column> <Grid.Column> <Segment basic> - <LoginForm url="/login/sso" imgSrc="UI.png" imgSize="tiny" /> + <LoginForm type="sso-ui" header="SSO Login" imgSrc="UI.png" imgSize="tiny" /> {this.props.children} </Segment> </Grid.Column> diff --git a/assets/js/__test__/components/VacancyList-test.jsx b/assets/js/__test__/components/VacancyList-test.jsx index 709bcb256471c63a0e413712c2aa131ca2e402b7..46add0967aa13393a9dad70bfed2e1fab84cd692 100644 --- a/assets/js/__test__/components/VacancyList-test.jsx +++ b/assets/js/__test__/components/VacancyList-test.jsx @@ -2,7 +2,7 @@ import React from 'react'; import ReactTestUtils from 'react-addons-test-utils'; import VacancyList from '../../components/VacancyList'; -import ModalPendaftaran from '../../components/ModalPendaftaran'; +import Lowongan from '../../components/Lowongan'; describe('VacancyList', () => { it('created without problem', () => { @@ -12,11 +12,11 @@ describe('VacancyList', () => { it('renders without problem', () => { const vacancyList = ReactTestUtils.renderIntoDocument( - <VacancyList header="header" content="content" buttonTitle="submit" />); + <VacancyList vacancies={[{ key: 'value' }, { key2: 'value2' }]} />); expect(vacancyList).to.exist; React.Children.forEach(vacancyList.props.children, (child) => { - expect(child).to.be.an.instanceof(ModalPendaftaran); + expect(child).to.be.an.instanceof(Lowongan); }); }); }); diff --git a/assets/js/components/LoginForm.jsx b/assets/js/components/LoginForm.jsx index f40605c8493a6ff851620e8f99e4af30d8ba085d..8e36ddff56b382c0fc6c5e8ebbc26a3505a318a8 100644 --- a/assets/js/components/LoginForm.jsx +++ b/assets/js/components/LoginForm.jsx @@ -1,56 +1,74 @@ import React from 'react'; -import { Form, Input, Button, Image } from 'semantic-ui-react'; +import { Form, Input, Button, Message, Image } from 'semantic-ui-react'; +import { browserHistory } from 'react-router'; import Server from '../lib/server'; export default class LoginForm extends React.Component { static propTypes = { - url: React.PropTypes.string.isRequired, + type: React.PropTypes.string.isRequired, imgSrc: React.PropTypes.string, imgSize: React.PropTypes.string, + header: React.PropTypes.string, }; static defaultProps = { imgSrc: '', imgSize: 'small', + header: 'Login', }; constructor(props) { super(props); /* istanbul ignore next */ - this.state = { email: '', password: '' }; + this.state = { email: '', password: '', errorFlag: false }; + this.handleChange = this.handleChange.bind(this); this.handleSubmit = this.handleSubmit.bind(this); } - handleChange(name, event) { + handleChange(event, name) { this.setState({ [name]: event.target.value }); } - handleSubmit() { - Server.post(this.props.url, this.state); + handleSubmit(event) { + event.preventDefault(); + const data = { + type: this.props.type, + email: this.state.email, + password: this.state.password + } + Server.post('api/login/', data).then(() => { + browserHistory.push('/home'); + }, () => { + this.setState({ errorFlag: true }); + }); } render = () => ( <div className="formLogin" > - - <Image src={`./assets/img/${this.props.imgSrc}`} size={this.props.imgSize} verticalAlign="middle" /> <span>Company Login</span> - - <Form onSubmit={this.handleSubmit}> + <Form onSubmit={(e) => this.handleSubmit(e)} error={this.state.errorFlag}> + <div className="formHeader"> + <Image src={`./assets/img/${this.props.imgSrc}`} size={this.props.imgSize} verticalAlign="middle" /> <span>{ this.props.header }</span> + </div> <Form.Group widths="equal"> - <Form.Field> + <Form.Field required> <label htmlFor="id"> Email </label> - <Input type="text" id="email" icon="user" iconPosition="left" placeholder="email" onChange={this.handleChange.bind(this, 'email')} /> + <Input type="text" id="email" icon="user" iconPosition="left" placeholder="email" onChange={(e) => this.handleChange(e, 'email')} required /> </Form.Field> </Form.Group> <Form.Group widths="equal"> - <Form.Field> + <Form.Field required> <label htmlFor="password"> Password </label> - <Input type="password" id="password" icon="key" iconPosition="left" placeholder="password" onChange={this.handleChange.bind(this, 'password')} /> + <Input type="password" id="password" icon="key" iconPosition="left" placeholder="password" onChange={(e) => this.handleChange(e, 'password')} required /> </Form.Field> </Form.Group> <Button type="submit" fluid color="blue">Login</Button> + <Message + error + content="Login gagal: email atau password salah." + /> </Form> </div> diff --git a/assets/js/components/Lowongan.jsx b/assets/js/components/Lowongan.jsx index 900df337894b114514945b4c02163b0816e7a3e7..087d9ea0ae796646f4b63032cafd5855d6452811 100644 --- a/assets/js/components/Lowongan.jsx +++ b/assets/js/components/Lowongan.jsx @@ -21,7 +21,7 @@ export default class Lowongan extends React.Component { <Item.Description>{this.props.content}</Item.Description> <Item.Extra> <div className="daftar"> - <ModalPendaftaran content={{ tes: 'dor' }} header="Pendaftaran Lowongan" buttontTitle="Daftar" /> + <ModalPendaftaran data={{ tes: 'dor' }} buttonTitle="Daftar" /> </div> </Item.Extra> </Item.Content> diff --git a/assets/js/components/ModalPendaftaran.jsx b/assets/js/components/ModalPendaftaran.jsx index 3a4d6f9c5cee6f5c2d29b322a8bcfdaace42ba93..33055db10230dbd93435785345aa75ff7b72e4eb 100644 --- a/assets/js/components/ModalPendaftaran.jsx +++ b/assets/js/components/ModalPendaftaran.jsx @@ -1,29 +1,49 @@ import React from 'react'; import { Modal, Button, Icon, TextArea, Form } from 'semantic-ui-react'; import ModalAlert from './ModalAlert'; - +import Server from '../lib/Server'; export default class ModalPendaftaran extends React.Component { static propTypes = { - header: React.PropTypes.oneOfType([ - React.PropTypes.node, - React.PropTypes.string, - ]).isRequired, - content: React.PropTypes.oneOfType([ - React.PropTypes.node, - React.PropTypes.string, - ]).isRequired, - buttontTitle: React.PropTypes.oneOfType([ - React.PropTypes.node, - React.PropTypes.string, - ]).isRequired, + data: React.PropTypes.object.isRequired, + id: React.PropTypes.number.isRequired, + buttonTitle: React.PropTypes.string.isRequired, }; - state = { modalOpen: false }; + static successResponse = 'Pendaftaran anda berhasil direkam. Harap menunggu kabar selanjutnya dari pihak yang terkait\n'; + static failedResponse = 'Maaf pendaftaran yang anda lakukan gagal. Harap ulangi pendaftaran atau hubungi administrator\n'; - handleOpen = () => this.setState({ - modalOpen: true, - }); + constructor(props) { + super(props); + /* istanbul ignore next */ + this.state = { + modalOpen: false, + responseHeader: 'Menghubungkan ke Server', + responseText: 'Terima kasih sudah mendaftar!', + coverLetter: '', + }; + this.handleChange = this.handleChange.bind(this); + } + + handleChange(event) { + this.setState({ coverLetter: event.target.value }); + } + + handleOpen() { + const data = { coverLetter: this.state.coverLetter }; + Server.post(`/students/${this.props.id}/application`, data).then((data) => { + this.setState({ + responseHeader: 'Pendaftaran Berhasil', + responseText: this.successResponse + JSON.stringify(data), + }); + }, (error) => { + this.setState({ + responseHeader: 'Pendaftaran Gagal', + responseText: this.failedResponse + JSON.stringify(error), + }); + }); + this.setState({ modalOpen: true }); + } handleClose = () => this.setState({ modalOpen: false, @@ -31,20 +51,20 @@ export default class ModalPendaftaran extends React.Component { render = () => ( <Modal - trigger={<Button onClick={this.handleOpen} >{this.props.buttontTitle}</Button>} + trigger={<Button onClick={this.handleOpen} >{this.props.buttonTitle}</Button>} closeIcon="close" open={this.state.modalOpen} onClose={this.handleClose} > - <Modal.Header>{this.props.header}</Modal.Header> + <Modal.Header>{this.props.data}</Modal.Header> <Modal.Content image> <div className="image"> <Icon name="right arrow" /> </div> <Modal.Description> <Modal.Header> <h3> Deskripsi Lowongan </h3></Modal.Header> - {this.props.content} + {this.props.data} <div className="linkCV"> <a> your latest CV </a> @@ -53,14 +73,18 @@ export default class ModalPendaftaran extends React.Component { <div className="coverLetter"> <h5> Write your Cover Letter </h5> <Form> - <TextArea placeholder="Tell us more" /> + <TextArea placeholder="Tell us more" onChange={this.handleChange} /> </Form> </div> </Modal.Description> </Modal.Content> <Modal.Actions> - <ModalAlert onChangeValue={this.handleClose} header="Pendaftaran" content="Terima kasih sudah mendaftar!" /> + <ModalAlert + onChangeValue={this.handleClose} + header={this.state.responseHeader} + content={this.state.responseText} + /> </Modal.Actions> </Modal> ) diff --git a/assets/js/components/VacancyList.jsx b/assets/js/components/VacancyList.jsx index 6cea70a2210d3256fa609147b262546338eb0def..49ac6d5ac8c6ee961812cdd392a11a3fc965d63a 100644 --- a/assets/js/components/VacancyList.jsx +++ b/assets/js/components/VacancyList.jsx @@ -4,22 +4,17 @@ import Lowongan from './Lowongan'; export default class VacancyList extends React.Component { static propTypes = { - vacancies: React.PropTypes.array + vacancies: React.PropTypes.array.isRequired, }; - static defaultProps = { - vacancies: [], - }; - - generateVacancies(){ - return( - this.props.vacancies.map((vacancyData) => - <Lowongan data={vacancyData}/>) + generateVacancies() { + return this.props.vacancies.map((vacancy) => + <Lowongan data={vacancy} />, ); } render = () => ( - <div className="vscancyList" >{ this.generateVacancies() } + <div className="vacancyList" >{ this.generateVacancies() } </div> ) } \ No newline at end of file