Fakultas Ilmu Komputer UI

Commit 3f7fc64b authored by M. Reza Qorib's avatar M. Reza Qorib
Browse files

Bismillah :")

Merge branch 'develop' of https://gitlab.com/PPL2017csui/PPLA1 into Features/HomeDosen

# Conflicts:
#	assets/css/custom.css
#	assets/js/ProfilePage.jsx
#	assets/js/VacancyPage.jsx
#	assets/js/__test__/components/AdminVacancy-test.jsx
#	assets/js/__test__/components/VacancyList-test.jsx
#	assets/js/components/AdminVacancy.jsx
#	assets/js/components/TopMenu.jsx
#	assets/js/index.jsx
#	core/lib/permissions.py
#	core/serializers/vacancies.py
#	core/tests/test_vacancies.py
#	core/views/vacancies.py
parents 8a177f53 4b65b513
...@@ -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
......
...@@ -275,6 +275,7 @@ border-color: transparent; ...@@ -275,6 +275,7 @@ border-color: transparent;
.ui.segment.biodata-section b{ .ui.segment.biodata-section b{
color: white; color: white;
} }
.admin-bar{ .admin-bar{
margin: 0; margin: 0;
padding: 0 10px 0 0; padding: 0 10px 0 0;
...@@ -282,4 +283,5 @@ border-color: transparent; ...@@ -282,4 +283,5 @@ border-color: transparent;
text-align: right; text-align: right;
background-color: #304D8A; background-color: #304D8A;
color: white; color: white;
} }
\ No newline at end of file
...@@ -12,6 +12,7 @@ export default class CompanyPage extends React.Component { ...@@ -12,6 +12,7 @@ export default class CompanyPage extends React.Component {
}; };
handleClick = () => window.open('/admin/'); handleClick = () => window.open('/admin/');
handleVacancy = () => window.open('/lowongan');
render() { render() {
return ( return (
...@@ -19,6 +20,11 @@ export default class CompanyPage extends React.Component { ...@@ -19,6 +20,11 @@ export default class CompanyPage extends React.Component {
<div style={{ paddingLeft: '10px' }}> <div style={{ paddingLeft: '10px' }}>
<Button onClick={this.handleClick} icon="dashboard" labelPosition="left" color="facebook" content="Buka Menu Administrasi" /> <Button onClick={this.handleClick} icon="dashboard" labelPosition="left" color="facebook" content="Buka Menu Administrasi" />
</div> </div>
<div style={{ paddingLeft: '10px', paddingTop : '10px'}}>
<Button onClick={this.handleVacancy} icon="dashboard" labelPosition="left" color="facebook" content="Halaman Verifikasi Lowongan" />
</div>
<Tabs selected={0}> <Tabs selected={0}>
<Pagination <Pagination
key={1} key={1}
......
...@@ -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 TopMenu from './components/TopMenu'; import TopMenu from './components/TopMenu';
import Server from './lib/Server';
import Footer from './components/Footer'; import Footer from './components/Footer';
export default class Dashboard extends React.Component { export default class Dashboard extends React.Component {
...@@ -13,6 +14,11 @@ export default class Dashboard extends React.Component { ...@@ -13,6 +14,11 @@ export default class Dashboard extends React.Component {
]).isRequired, ]).isRequired,
}; };
constructor(props) {
super(props);
/* istanbul ignore next */
}
render = () => ( render = () => (
<div> <div>
<TopMenu user={this.props.user} /> <TopMenu user={this.props.user} />
......
import React from 'react'; import React from 'react';
import { Segment, Image, Header, Icon, Checkbox, Container, Button, Form, Grid, Card } from 'semantic-ui-react'; import { Segment, Image, Header, Icon, Checkbox, Container, Button, Form, Grid } 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" />
...@@ -164,77 +180,70 @@ export default class ProfilePage extends React.Component { ...@@ -164,77 +180,70 @@ export default class ProfilePage extends React.Component {
<Grid.Column width={6}> <Grid.Column width={6}>
<Container textAlign="left" className="profile-biodata"> <Container textAlign="left" className="profile-biodata">
<div className="biodata"> <div className="biodata">
<Segment basic textAlign="center">
<h1> { this.state.name } </h1>
<Segment basic textAlign="center"> </Segment>
<h1> { this.state.name } </h1>
</Segment> <Segment basic vertical>
<Grid>
<Segment basic vertical> <Grid.Column width={2}>
<Grid> <Icon name="university" size="big" />
<Grid.Column width={2}> </Grid.Column>
<Icon name="university" size="big" /> <Grid.Column width={13}>
</Grid.Column> <h3> { this.state.major }, { this.state.batch } </h3>
<Grid.Column width={13}> </Grid.Column>
<h3> { this.state.major }, { this.state.batch } </h3> </Grid>
</Grid.Column> </Segment>
</Grid>
</Segment> <Segment basic vertical>
<Segment basic vertical> <Grid>
<Grid.Column width={2}>
<Grid> <Icon name="mail" size="big" />
<Grid.Column width={2}> </Grid.Column>
<Icon name="mail" size="big" /> <Grid.Column width={13}>
</Grid.Column> <h3> { this.state.email } </h3>
<Grid.Column width={13}> </Grid.Column>
<h3> { this.state.email } </h3> </Grid>
</Grid.Column> </Segment>
</Grid>
</Segment> <Segment basic vertical>
<Grid>
<Segment basic vertical> <Grid.Column width={2}>
<Grid> <Icon name="phone" size="big" />
<Grid.Column width={2}> </Grid.Column>
<Icon name="phone" size="big" /> <Grid.Column width={13}>
</Grid.Column> <h3> { this.state.phone_number }</h3>
<Grid.Column width={13}> </Grid.Column>
<h3> { this.state.phone_number }</h3> </Grid>
</Grid.Column> </Segment>
</Grid>
</Segment> <Segment basic vertical>
<Grid>
<Segment basic vertical> <Grid.Column width={2}>
<Grid> <Icon name="gift" size="big" />
<Grid.Column width={2}> </Grid.Column>
<Icon name="gift" size="big" /> <Grid.Column width={13}>
</Grid.Column> <h3> { this.state.cityOfBirth}, { this.state.dateOfBirth } </h3>
<Grid.Column width={13}> </Grid.Column>
<h3> { this.state.cityOfBirth}, { this.state.dateOfBirth } </h3> </Grid>
</Grid.Column> </Segment>
</Grid>
</Segment>
</div> </div>
<Container textAlign="center"> <Container textAlign="center">
<div className="button-profile"> <div className="button-profile">
<a href={this.state.resume || '#'} ><Button primary size="small">Resume</Button></a> <a href={this.state.resume || '#'} ><Button primary size="small">Resume</Button></a>
</div> </div>
<div> <div>
<h4> Bagikan Transkrip : { this.state.bagikanTranskrip }</h4> <h4> Bagikan Transkrip : { this.state.bagikanTranskrip }</h4>
</div> </div>
</Container> </Container>
</Container> </Container>
</Grid.Column > </Grid.Column >
</Grid> </Grid>
</Segment > </Segment >
{ this.updateForm(this.props.route.own) } { this.updateForm(this.props.route.own) }
</div> </div>
); );
} }
} }
import React from 'react'; import React from 'react';
import { Container } from 'semantic-ui-react';
import Tabs from './components/Tabs'; import Tabs from './components/Tabs';
import Pane from './components/Pane'; import Pane from './components/Pane';
import VacancyList from './components/VacancyList'; import VacancyList from './components/VacancyList';
import Pagination from './components/Pagination'; import Pagination from './components/Pagination';
import Applicants from './SupervisorPage';
export default class VacancyPage extends React.Component { export default class VacancyPage extends React.Component {
...@@ -15,8 +15,10 @@ export default class VacancyPage extends React.Component { ...@@ -15,8 +15,10 @@ export default class VacancyPage extends React.Component {
const role = user.role; const role = user.role;
if (role === 'student') { if (role === 'student') {
return user.data.student.id; return user.data.student.id;
} else if (role === 'company' || role === 'admin') { } else if (role === 'company' || (role === 'admin' && user.data.company != null)) {
return user.data.company.id; return user.data.company.id;
} else if (role === 'supervisor' || (role === 'admin' && user.data.supervisor != null)) {
return user.data.supervisor.id;
} }
return 0; return 0;
...@@ -31,6 +33,7 @@ export default class VacancyPage extends React.Component { ...@@ -31,6 +33,7 @@ export default class VacancyPage extends React.Component {
}; };
} }
generateVacancies() { generateVacancies() {
if (this.props.user.role === 'student') { if (this.props.user.role === 'student') {
return ( return (
...@@ -48,7 +51,7 @@ export default class VacancyPage extends React.Component { ...@@ -48,7 +51,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/`}
...@@ -76,10 +79,12 @@ export default class VacancyPage extends React.Component { ...@@ -76,10 +79,12 @@ export default class VacancyPage extends React.Component {
</Pane> </Pane>
</Tabs> </Tabs>
); );
} else if (this.props.user.role === 'company' || this.props.user.role === 'admin') { } else if ((this.props.user.role === 'admin' && this.props.user.data.company != null)
|| this.props.user.role === 'company') {
return ( return (
<div> <Container className="vacancies">
<Pagination <Pagination
key={1}
url={`/companies/${this.state.id}/vacancies/`} url={`/companies/${this.state.id}/vacancies/`}
child={ child={
<VacancyList <VacancyList
...@@ -87,17 +92,41 @@ export default class VacancyPage extends React.Component { ...@@ -87,17 +92,41 @@ export default class VacancyPage extends React.Component {