Fakultas Ilmu Komputer UI

Commit 307ae0a3 authored by sirinbaisa's avatar sirinbaisa
Browse files

Merge branch 'Features/CompanyBrowseByVacancy' of...

Merge branch 'Features/CompanyBrowseByVacancy' of https://gitlab.com/PPL2017csui/PPLA1 into Features/CompanyBrowseByVacancy
parents 2f773a13 2190b7f5
...@@ -10,6 +10,8 @@ test: ...@@ -10,6 +10,8 @@ test:
- export CHROME_BIN=/usr/bin/google-chrome - export CHROME_BIN=/usr/bin/google-chrome
- curl -sL https://deb.nodesource.com/setup_4.x | sudo -E bash - - curl -sL https://deb.nodesource.com/setup_4.x | sudo -E bash -
- sudo apt-get install -y nodejs - sudo apt-get install -y nodejs
- sudo apt-get install -y build-essential
- npm install npm -g
- npm install - npm install
- npm run build-production - npm run build-production
- service postgresql start - service postgresql start
......
...@@ -3,9 +3,9 @@ import { Segment, Button, Form, Header, Icon, Input } from 'semantic-ui-react'; ...@@ -3,9 +3,9 @@ import { Segment, Button, Form, Header, Icon, Input } from 'semantic-ui-react';
import { browserHistory } from 'react-router'; import { browserHistory } from 'react-router';
import DatePicker from 'react-datepicker'; import DatePicker from 'react-datepicker';
import moment from 'moment'; import moment from 'moment';
import CKEditor from 'react-ckeditor-wrapper';
import ModalAlert from './components/ModalAlert'; import ModalAlert from './components/ModalAlert';
import Server from './lib/Server'; import Server from './lib/Server';
import Dumper from './lib/Dumper';
export default class CreateVacancy extends React.Component { export default class CreateVacancy extends React.Component {
...@@ -19,11 +19,14 @@ export default class CreateVacancy extends React.Component { ...@@ -19,11 +19,14 @@ export default class CreateVacancy extends React.Component {
/* istanbul ignore next */ /* istanbul ignore next */
this.handleChange = this.handleChange.bind(this); this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this); this.handleSubmit = this.handleSubmit.bind(this);
this.handleEditorChange = this.handleEditorChange.bind(this);
this.handleEditor = this.handleEditor.bind(this);
this.setCloseTime = this.setCloseTime.bind(this); this.setCloseTime = this.setCloseTime.bind(this);
this.setOpenTime = this.setOpenTime.bind(this); this.setOpenTime = this.setOpenTime.bind(this);
this.state = { this.state = {
formLoading: false, formLoading: false,
loading: !!this.props.params.id,
company: this.props.user.data.company, company: this.props.user.data.company,
vacancyId: this.props.params.id, vacancyId: this.props.params.id,
open_time: moment(), open_time: moment(),
...@@ -32,14 +35,17 @@ export default class CreateVacancy extends React.Component { ...@@ -32,14 +35,17 @@ export default class CreateVacancy extends React.Component {
description: '', description: '',
}; };
this.state.vacancyId && Server.get(`/vacancies/${this.state.vacancyId}/`).then((r) => { if (this.state.vacancyId) {
this.setState({ Server.get(`/vacancies/${this.state.vacancyId}/`).then((r) => {
description: r.description, this.setState({
name: r.name, description: r.description,
open_time: moment(r.open_time), name: r.name,
close_time: moment(r.close_time), open_time: moment(r.open_time),
close_time: moment(r.close_time),
loading: false,
});
}); });
}); }
} }
setOpenTime(date) { setOpenTime(date) {
...@@ -54,14 +60,29 @@ export default class CreateVacancy extends React.Component { ...@@ -54,14 +60,29 @@ export default class CreateVacancy extends React.Component {
this.setState({ [e.target.name]: e.target.value }); this.setState({ [e.target.name]: e.target.value });
}; };
handleEditor(value) {
this.setState({ description: value });
console.log('dor');
}
handleEditorChange = (e) => {
this.setState({ description: e.target.getContent() });
console.log('Content was updated:', this.state.description);
};
handleSubmit = (e) => { handleSubmit = (e) => {
e.preventDefault(); e.preventDefault();
console.log(this.state);
this.setState({ formLoading: true }); this.setState({ formLoading: true });
const data = Object.assign({}, this.state); const data = {};
data.open_time = data.open_time.format(); data.name = this.state.name;
data.close_time = data.close_time.format(); data.description = this.state.description;
data.company = this.state.company.id; data.open_time = this.state.open_time.format();
data.close_time = this.state.close_time.format();
if (!this.state.vacancyId) {
data.company = this.state.company.id;
}
const url = this.state.vacancyId ? `/vacancies/${this.state.vacancyId}/` : '/vacancies/'; const url = this.state.vacancyId ? `/vacancies/${this.state.vacancyId}/` : '/vacancies/';
const method = this.state.vacancyId ? 'PATCH' : 'POST'; const method = this.state.vacancyId ? 'PATCH' : 'POST';
...@@ -74,6 +95,21 @@ export default class CreateVacancy extends React.Component { ...@@ -74,6 +95,21 @@ export default class CreateVacancy extends React.Component {
})); }));
}; };
modules = {
toolbar: [
[{ header: [1, 2, false] }],
['bold', 'italic', 'underline', 'strike', 'blockquote'],
[{ list: 'ordered' }, { list: 'bullet' }, { indent: '-1' }, { indent: '+1' }],
['link', 'image'],
['clean'],
],
};
formats = ['header', 'bold', 'italic', 'underline', 'strike', 'blockquote',
'list', 'bullet', 'indent',
'link', 'image',
];
render = () => ( render = () => (
<div className="create-lowongan" > <div className="create-lowongan" >
<ModalAlert ref={(modal) => { this.modalAlert = modal; }} /> <ModalAlert ref={(modal) => { this.modalAlert = modal; }} />
...@@ -86,13 +122,23 @@ export default class CreateVacancy extends React.Component { ...@@ -86,13 +122,23 @@ export default class CreateVacancy extends React.Component {
</Header> </Header>
<Form loading={this.state.formLoading} onSubmit={this.handleSubmit}> <Form loading={this.state.formLoading} onSubmit={this.handleSubmit}>
<Form.Field label="Posisi" name="name" control={Input} onChange={this.handleChange} value={this.state.name} required /> <Form.Field label="Posisi" name="name" control={Input} onChange={this.handleChange} value={this.state.name} required />
<Form.TextArea { !this.state.loading && <CKEditor value={this.state.description} onChange={this.handleEditor} /> }
name="description" {/*<TinyMCE*/}
label="Deskripsi" {/*content={this.state.description}*/}
placeholder="Deskripsi Lowongan..." {/*config={{*/}
onChange={this.handleChange} {/*plugins: 'link image code',*/}
value={this.state.description} required {/*toolbar: 'undo redo | bold italic | alignleft aligncenter alignright | code image',*/}
/> {/*}}*/}
{/*onChange={this.handleEditorChange}*/}
{/*/>*/}
{/*<Form.TextArea*/}
{/*name="description"*/}
{/*label="Deskripsi"*/}
{/*placeholder="Deskripsi Lowongan..."*/}
{/*onChange={this.handleChange}*/}
{/*value={this.state.description} required*/}
{/*/>*/}
<script>CKEDITOR.replace( 'description' );</script>
<Form.Group widths="equal"> <Form.Group widths="equal">
<Form.Field <Form.Field
className="open-time-field" className="open-time-field"
......
import React from 'react'; import React from 'react';
import { Segment, Image, Header, Icon, Checkbox, Container, Button, Form } from 'semantic-ui-react'; import { Segment, Image, Header, Icon, Checkbox, Container, Button, Form } from 'semantic-ui-react';
import Server from './lib/Server'; import Server from './lib/Server';
import Storage from './lib/Storage';
import ModalAlert from './components/ModalAlert'; import ModalAlert from './components/ModalAlert';
export default class ProfilePage extends React.Component { export default class ProfilePage extends React.Component {
...@@ -35,12 +36,15 @@ export default class ProfilePage extends React.Component { ...@@ -35,12 +36,15 @@ export default class ProfilePage extends React.Component {
show_transcript: '', show_transcript: '',
}, },
bagikanTranskrip: '', bagikanTranskrip: '',
acceptedNo: 0,
refresh: 1,
}; };
this.getProfile = this.getProfile.bind(this); this.getProfile = this.getProfile.bind(this);
this.handleChange = this.handleChange.bind(this); this.handleChange = this.handleChange.bind(this);
this.handleCheckbox = this.handleCheckbox.bind(this); this.handleCheckbox = this.handleCheckbox.bind(this);
this.handleSubmit = this.handleSubmit.bind(this); this.handleSubmit = this.handleSubmit.bind(this);
this.handleFile = this.handleFile.bind(this); this.handleFile = this.handleFile.bind(this);
this.gotoLink = this.gotoLink.bind(this);
this.getProfile(); this.getProfile();
} }
...@@ -60,10 +64,17 @@ export default class ProfilePage extends React.Component { ...@@ -60,10 +64,17 @@ export default class ProfilePage extends React.Component {
phone_number: data.phone_number, phone_number: data.phone_number,
photo: data.photo, photo: data.photo,
show_transcript: data.show_transcript, show_transcript: data.show_transcript,
bagikanTranskrip: (data.show_transcript ? 'Ya' : 'Tidak'), acceptedNo: data.accepted_no,
bagikanTranskrip: data.show_transcript,
refresh: this.state.refresh + 1,
}); });
if (this.props.route.own) {
const newSession = this.props.user.data;
newSession.student = data;
Storage.set('user-data', newSession);
window.scrollTo(0, 0);
}
}, error => error.then(() => { }, error => error.then(() => {
// this.modalAlert.open('Gagal Mengambil ', r.error);
this.state.name = 'Gagal mendapatkan informasi'; this.state.name = 'Gagal mendapatkan informasi';
})); }));
} }
...@@ -78,9 +89,9 @@ export default class ProfilePage extends React.Component { ...@@ -78,9 +89,9 @@ export default class ProfilePage extends React.Component {
} }
}); });
Server.submit(`/profiles/students/${this.state.id}/`, submitForm, 'PATCH').then(() => { Server.submit(`/profiles/students/${this.state.id}/`, submitForm, 'PATCH').then(() => {
this.modalAlert.open('Profil berhasil diperbaharui', 'Silakan periksa kembali profil anda' ); this.modalAlert.open('Profil berhasil diperbaharui', 'Silakan periksa kembali profil anda', this.getProfile);
}, error => error.then((r) => { }, error => error.then((r) => {
this.modalAlert.open('Pembaharuan profil gagal', r.error); this.modalAlert.open('Pembaharuan profil gagal', r.detail);
})); }));
}; };
...@@ -103,6 +114,11 @@ export default class ProfilePage extends React.Component { ...@@ -103,6 +114,11 @@ export default class ProfilePage extends React.Component {
this.setState({ form, show_transcript: d.checked }); this.setState({ form, show_transcript: d.checked });
}; };
gotoLink = (url) => {
const win = window.open(url);
win.focus();
};
updateForm(show) { updateForm(show) {
if (show) { if (show) {
return ( return (
...@@ -114,7 +130,7 @@ export default class ProfilePage extends React.Component { ...@@ -114,7 +130,7 @@ export default class ProfilePage extends React.Component {
</Header.Content> </Header.Content>
</Header> </Header>
<ModalAlert ref={(modal) => { this.modalAlert = modal; }} /> <ModalAlert ref={(modal) => { this.modalAlert = modal; }} />
<Form size="small" onSubmit={this.handleSubmit}> <Form ref={(input) => { this.form = input; }} key={this.state.refresh} size="small" onSubmit={this.handleSubmit}>
<Form.Field> <Form.Field>
<label htmlFor="photo">Profile Picture</label> <label htmlFor="photo">Profile Picture</label>
<input onChange={this.handleFile} placeholder="Profile Photo.jpg" name="photo" type="File" /> <input onChange={this.handleFile} placeholder="Profile Photo.jpg" name="photo" type="File" />
...@@ -134,7 +150,7 @@ export default class ProfilePage extends React.Component { ...@@ -134,7 +150,7 @@ export default class ProfilePage extends React.Component {
<Form.Field> <Form.Field>
<Checkbox <Checkbox
onChange={this.handleCheckbox} onChange={this.handleCheckbox}
checked={ this.state.show_transcript ? true : false } checked={!!this.state.show_transcript}
label="Ijinkan perusahaan tempat saya mendaftar untuk melihat transkrip akademik saya" label="Ijinkan perusahaan tempat saya mendaftar untuk melihat transkrip akademik saya"
name="show_transcript" name="show_transcript"
/> />
...@@ -163,21 +179,21 @@ export default class ProfilePage extends React.Component { ...@@ -163,21 +179,21 @@ export default class ProfilePage extends React.Component {
<h5> { this.state.email } </h5> <h5> { this.state.email } </h5>
<h5> { this.state.phone_number } </h5> <h5> { this.state.phone_number } </h5>
<h5> { this.state.cityOfBirth}, { this.state.dateOfBirth } </h5> <h5> { this.state.cityOfBirth}, { this.state.dateOfBirth } </h5>
<p>Sudah diterima di { this.state.acceptedNo } perusahaan</p>
</div> </div>
<div className="button-profile"> <div className="button-profile">
<a href={this.state.resume ? this.state.resume : '#'} ><Button primary size="small">Resume</Button></a> <a target="_blank" rel="noopener noreferrer" href={this.state.resume ? this.state.resume : '#'} >
{ this.state.show_transcript && <Button primary size="small">Resume</Button>
<Button primary size="small">Transkrip</Button> </a>
}
</div> </div>
<div> <div>
Bagikan Transkrip: <b>{ this.state.bagikanTranskrip }</b> <br />
Bagikan Transkrip: <b>{ this.state.bagikanTranskrip ? 'Ya' : 'Tidak'}</b>
</div> </div>
</Container> </Container>
</Segment > </Segment >
{ this.updateForm(this.props.route.own) } { this.updateForm(this.props.route.own) }
</div> </div>
); );
} }
} }
...@@ -48,7 +48,7 @@ export default class VacancyPage extends React.Component { ...@@ -48,7 +48,7 @@ export default class VacancyPage extends React.Component {
} }
/> />
</Pane> </Pane>
<Pane label="Lamaran saya" > <Pane label="Lamaran Saya" >
<Pagination <Pagination
key={2} key={2}
url={`/students/${this.state.id}/applied-vacancies/`} url={`/students/${this.state.id}/applied-vacancies/`}
...@@ -80,6 +80,7 @@ export default class VacancyPage extends React.Component { ...@@ -80,6 +80,7 @@ export default class VacancyPage extends React.Component {
return ( return (
<Segment className="paginationCompany"> <Segment className="paginationCompany">
<Pagination <Pagination
key={1}
url={`/companies/${this.state.id}/vacancies/`} url={`/companies/${this.state.id}/vacancies/`}
child={ child={
<VacancyList <VacancyList
...@@ -87,7 +88,7 @@ export default class VacancyPage extends React.Component { ...@@ -87,7 +88,7 @@ export default class VacancyPage extends React.Component {
user={this.props.user} user={this.props.user}
userId={this.state.id} userId={this.state.id}
/> />
} }
error="Anda belum diverifikasi. Harap hubungi admin" error="Anda belum diverifikasi. Harap hubungi admin"
/> />
</Segment> </Segment>
......
...@@ -316,6 +316,7 @@ describe('VacancyList', () => { ...@@ -316,6 +316,7 @@ describe('VacancyList', () => {
it('fails delete vacancy', () => { it('fails delete vacancy', () => {
fetchMock.restore(); fetchMock.restore();
fetchMock.delete('*', 404); fetchMock.delete('*', 404);
fetchMock.get('*', response2);
const vacancyList = ReactTestUtils.renderIntoDocument( const vacancyList = ReactTestUtils.renderIntoDocument(
<VacancyList userId={1} items={newResponse} user={companyUser} deleteCallback={() => {}} />, <VacancyList userId={1} items={newResponse} user={companyUser} deleteCallback={() => {}} />,
); );
......
import React from 'react'; import React from 'react';
import { Item, Grid } from 'semantic-ui-react'; import { Item, Grid, Container } from 'semantic-ui-react';
import Applicant from './Applicant'; import Applicant from './Applicant';
export default class ApplicantList extends React.Component { export default class ApplicantList extends React.Component {
...@@ -33,6 +33,17 @@ export default class ApplicantList extends React.Component { ...@@ -33,6 +33,17 @@ export default class ApplicantList extends React.Component {
} }
generateApplicants() { generateApplicants() {
if (this.state.applications.length == 0){
return (
<Item className="applicantItems">
<Grid.Row>
<Container textAlign="center">
<p>Tidak ada pelamar<br /></p>
</Container>
</Grid.Row>
</Item>
);
}
return this.state.applications.map(application => return this.state.applications.map(application =>
application.status === this.props.status && (<Applicant application.status === this.props.status && (<Applicant
key={application.id} data={application} key={application.id} data={application}
......
import React from 'react'; import React from 'react';
import { Icon, Modal, Button, TextArea, Form } from 'semantic-ui-react'; import { Icon, Modal, Button, TextArea, Form, Message } from 'semantic-ui-react';
import ModalAlert from './../components/ModalAlert'; import ModalAlert from './../components/ModalAlert';
import Server from './../lib/Server'; import Server from './../lib/Server';
...@@ -49,43 +49,51 @@ export default class ApplyModal extends React.Component { ...@@ -49,43 +49,51 @@ export default class ApplyModal extends React.Component {
); );
}; };
render = () => ( render() {
<Modal return (
trigger={<Button primary onClick={this.handleOpen} floated="right">{this.props.buttonTitle}</Button>} <Modal
closeIcon="close" trigger={<Button primary onClick={this.handleOpen} floated="right">{this.props.buttonTitle}</Button>}
open={this.state.modalOpen} closeIcon="close"
onClose={this.handleClose} open={this.state.modalOpen}
> onClose={this.handleClose}
<Modal.Header>{this.props.data.header}</Modal.Header> >
<Modal.Content> <Modal.Header>{this.props.data.header}</Modal.Header>
<ModalAlert ref={(modal) => { this.modalAlert = modal; }} /> <Modal.Content>
<Modal.Description> <ModalAlert ref={(modal) => { this.modalAlert = modal; }} />
<Modal.Header> <h3> Deskripsi Lowongan </h3></Modal.Header> <Modal.Description>
{this.props.data.description} <Modal.Header> <h3> Deskripsi Lowongan </h3></Modal.Header>
{ <div dangerouslySetInnerHTML={{ __html: this.props.data.description }} /> }
</Modal.Description> </Modal.Description>
{this.props.active && ( {this.props.active && (
<div className="coverLetter"> <div className="coverLetter">
<br /> <br />
<div className="linkCV"> <div className="linkCV">
<a href={this.props.resume} target="_blank" rel="noopener noreferrer"> Klik untuk lihat CV terakhirmu</a> { this.props.resume ? (<a href={this.props.resume} target="_blank" rel="noopener noreferrer"> Klik untuk lihat CV terakhirmu</a>)
</div> : (
<br /> <Message
<div> error
<h5>Cover Letter </h5> icon="warning sign"
<Form > header="CV Tidak Ditemukan"
<TextArea placeholder="Tell us more" size="big" onChange={this.handleChange} /> content="Anda belum mengunggah CV. Harap ubah profil anda terlebih dahulu pada halaman Profil."
</Form> />)
}
</div>
<br />
<div>
<h5>Cover Letter </h5>
<Form >
<TextArea placeholder="Tell us more" size="big" onChange={this.handleChange} />
</Form>
</div>
</div> </div>
</div> )}
)} </Modal.Content>
<Modal.Actions>
</Modal.Content> <Button loading={this.state.load} color="blue" disabled={!this.props.active} onClick={this.handleApply}>
<Modal.Actions> { this.props.active ? 'Daftar' : 'Sudah Terdaftar' } <Icon name="right chevron" />
<Button loading={this.state.load} color="blue" disabled={!this.props.active} onClick={this.handleApply}> </Button>
{ this.props.active ? 'Daftar' : 'Sudah Terdaftar' } <Icon name="right chevron" /> </Modal.Actions>
</Button> </Modal>
</Modal.Actions> );
</Modal> }
)
} }
import React from 'react'; import React from 'react';
import { Modal, Button } from 'semantic-ui-react'; import { Modal, Button, Icon, Segment } from 'semantic-ui-react';
import Server from './../lib/Server'; import Server from './../lib/Server';
import ConfirmationModal from './../components/ConfirmationModal'; import ConfirmationModal from './../components/ConfirmationModal';
import Applicant from './../components/Applicant'; import Applicant from './../components/Applicant';
...@@ -21,6 +21,7 @@ export default class ApproveModal extends React.Component { ...@@ -21,6 +21,7 @@ export default class ApproveModal extends React.Component {
this.handleOpen = this.handleOpen.bind(this); this.handleOpen = this.handleOpen.bind(this);
this.reject = this.reject.bind(this); this.reject = this.reject.bind(this);
this.accept = this.accept.bind(this); this.accept = this.accept.bind(this);
this.gotoStudentProfile = this.gotoStudentProfile.bind(this);
this.gotoStudentResume = this.gotoStudentResume.bind(this); this.gotoStudentResume = this.gotoStudentResume.bind(this);
this.gotoStudentTranscript = this.gotoStudentTranscript.bind(this); this.gotoStudentTranscript = this.gotoStudentTranscript.bind(this);
} }
...@@ -69,6 +70,8 @@ export default class ApproveModal extends React.Component { ...@@ -69,6 +70,8 @@ export default class ApproveModal extends React.Component {
gotoStudentTranscript = () => this.gotoLink(`/transcript/${this.props.data.id}`); gotoStudentTranscript = () => this.gotoLink(`/transcript/${this.props.data.id}`);
gotoStudentProfile = () => this.gotoLink(`/mahasiswa/${this.props.data.student.id}`);
accept = () => { accept = () => {
this.modal.open( this.modal.open(
'Terima Lamaran?', 'Terima Lamaran?',
...@@ -89,15 +92,25 @@ export default class ApproveModal extends React.Component { ...@@ -89,15 +92,25 @@ export default class ApproveModal extends React.Component {
<Modal.Header>Data Lamaran</Modal.Header> <Modal.Header>Data Lamaran</Modal.Header>
<Modal.Content> <Modal.Content>
<h4> Cover Letter </h4> <h4> Cover Letter </h4>
{ this.props.data.cover_letter ? this.props.data.cover_letter : 'Kosong' } <Segment>
<div style={{ float: 'right', textAlign: 'right' }}> <p>
{this.props.data.student.resume ? <a onClick={this.gotoStudentResume} href="#" >CV Pelamar </a> : ''} { this.props.data.cover_letter ? this.props.data.cover_letter : 'Kosong' }
<br /> </p>
{this.props.data.student.show_transcript ? <a onClick={this.gotoStudentTranscript} href="#" >Transkrip Pelamar</a> : ''} </Segment>
<br /> <br />