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:
- export CHROME_BIN=/usr/bin/google-chrome
- curl -sL https://deb.nodesource.com/setup_4.x | sudo -E bash -
- sudo apt-get install -y nodejs
- sudo apt-get install -y build-essential
- npm install npm -g
- npm install
- npm run build-production
- service postgresql start
......
......@@ -275,6 +275,7 @@ border-color: transparent;
.ui.segment.biodata-section b{
color: white;
}
.admin-bar{
margin: 0;
padding: 0 10px 0 0;
......@@ -282,4 +283,5 @@ border-color: transparent;
text-align: right;
background-color: #304D8A;
color: white;
}
\ No newline at end of file
}
......@@ -12,6 +12,7 @@ export default class CompanyPage extends React.Component {
};
handleClick = () => window.open('/admin/');
handleVacancy = () => window.open('/lowongan');
render() {
return (
......@@ -19,6 +20,11 @@ export default class CompanyPage extends React.Component {
<div style={{ paddingLeft: '10px' }}>
<Button onClick={this.handleClick} icon="dashboard" labelPosition="left" color="facebook" content="Buka Menu Administrasi" />
</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}>
<Pagination
key={1}
......
......@@ -3,9 +3,9 @@ import { Segment, Button, Form, Header, Icon, Input } from 'semantic-ui-react';
import { browserHistory } from 'react-router';
import DatePicker from 'react-datepicker';
import moment from 'moment';
import CKEditor from 'react-ckeditor-wrapper';
import ModalAlert from './components/ModalAlert';
import Server from './lib/Server';
import Dumper from './lib/Dumper';
export default class CreateVacancy extends React.Component {
......@@ -19,11 +19,14 @@ export default class CreateVacancy extends React.Component {
/* istanbul ignore next */
this.handleChange = this.handleChange.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.setOpenTime = this.setOpenTime.bind(this);
this.state = {
formLoading: false,
loading: !!this.props.params.id,
company: this.props.user.data.company,
vacancyId: this.props.params.id,
open_time: moment(),
......@@ -32,14 +35,17 @@ export default class CreateVacancy extends React.Component {
description: '',
};
this.state.vacancyId && Server.get(`/vacancies/${this.state.vacancyId}/`).then((r) => {
this.setState({
description: r.description,
name: r.name,
open_time: moment(r.open_time),
close_time: moment(r.close_time),
if (this.state.vacancyId) {
Server.get(`/vacancies/${this.state.vacancyId}/`).then((r) => {
this.setState({
description: r.description,
name: r.name,
open_time: moment(r.open_time),
close_time: moment(r.close_time),
loading: false,
});
});
});
}
}
setOpenTime(date) {
......@@ -54,14 +60,29 @@ export default class CreateVacancy extends React.Component {
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) => {
e.preventDefault();
console.log(this.state);
this.setState({ formLoading: true });
const data = Object.assign({}, this.state);
data.open_time = data.open_time.format();
data.close_time = data.close_time.format();
data.company = this.state.company.id;
const data = {};
data.name = this.state.name;
data.description = this.state.description;
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 method = this.state.vacancyId ? 'PATCH' : 'POST';
......@@ -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 = () => (
<div className="create-lowongan" >
<ModalAlert ref={(modal) => { this.modalAlert = modal; }} />
......@@ -86,13 +122,23 @@ export default class CreateVacancy extends React.Component {
</Header>
<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.TextArea
name="description"
label="Deskripsi"
placeholder="Deskripsi Lowongan..."
onChange={this.handleChange}
value={this.state.description} required
/>
{ !this.state.loading && <CKEditor value={this.state.description} onChange={this.handleEditor} /> }
{/*<TinyMCE*/}
{/*content={this.state.description}*/}
{/*config={{*/}
{/*plugins: 'link image code',*/}
{/*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.Field
className="open-time-field"
......
import React from 'react';
import TopMenu from './components/TopMenu';
import Server from './lib/Server';
import Footer from './components/Footer';
export default class Dashboard extends React.Component {
......@@ -13,6 +14,11 @@ export default class Dashboard extends React.Component {
]).isRequired,
};
constructor(props) {
super(props);
/* istanbul ignore next */
}
render = () => (
<div>
<TopMenu user={this.props.user} />
......
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 Storage from './lib/Storage';
import ModalAlert from './components/ModalAlert';
export default class ProfilePage extends React.Component {
......@@ -35,12 +36,15 @@ export default class ProfilePage extends React.Component {
show_transcript: '',
},
bagikanTranskrip: '',
acceptedNo: 0,
refresh: 1,
};
this.getProfile = this.getProfile.bind(this);
this.handleChange = this.handleChange.bind(this);
this.handleCheckbox = this.handleCheckbox.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
this.handleFile = this.handleFile.bind(this);
this.gotoLink = this.gotoLink.bind(this);
this.getProfile();
}
......@@ -60,10 +64,17 @@ export default class ProfilePage extends React.Component {
phone_number: data.phone_number,
photo: data.photo,
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(() => {
// this.modalAlert.open('Gagal Mengambil ', r.error);
this.state.name = 'Gagal mendapatkan informasi';
}));
}
......@@ -78,9 +89,9 @@ export default class ProfilePage extends React.Component {
}
});
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) => {
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 {
this.setState({ form, show_transcript: d.checked });
};
gotoLink = (url) => {
const win = window.open(url);
win.focus();
};
updateForm(show) {
if (show) {
return (
......@@ -114,7 +130,7 @@ export default class ProfilePage extends React.Component {
</Header.Content>
</Header>
<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>
<label htmlFor="photo">Profile Picture</label>
<input onChange={this.handleFile} placeholder="Profile Photo.jpg" name="photo" type="File" />
......@@ -164,77 +180,70 @@ export default class ProfilePage extends React.Component {
<Grid.Column width={6}>
<Container textAlign="left" className="profile-biodata">
<div className="biodata">
<Segment basic textAlign="center">
<h1> { this.state.name } </h1>
</Segment>
<Segment basic vertical>
<Grid>
<Grid.Column width={2}>
<Icon name="university" size="big" />
</Grid.Column>
<Grid.Column width={13}>
<h3> { this.state.major }, { this.state.batch } </h3>
</Grid.Column>
</Grid>
</Segment>
<Segment basic vertical>
<Grid>
<Grid.Column width={2}>
<Icon name="mail" size="big" />
</Grid.Column>
<Grid.Column width={13}>
<h3> { this.state.email } </h3>
</Grid.Column>
</Grid>
</Segment>
<Segment basic vertical>
<Grid>
<Grid.Column width={2}>
<Icon name="phone" size="big" />
</Grid.Column>
<Grid.Column width={13}>
<h3> { this.state.phone_number }</h3>
</Grid.Column>
</Grid>
</Segment>
<Segment basic vertical>
<Grid>
<Grid.Column width={2}>
<Icon name="gift" size="big" />
</Grid.Column>
<Grid.Column width={13}>
<h3> { this.state.cityOfBirth}, { this.state.dateOfBirth } </h3>
</Grid.Column>
</Grid>
</Segment>
<Segment basic textAlign="center">
<h1> { this.state.name } </h1>
</Segment>
<Segment basic vertical>
<Grid>
<Grid.Column width={2}>
<Icon name="university" size="big" />
</Grid.Column>
<Grid.Column width={13}>
<h3> { this.state.major }, { this.state.batch } </h3>
</Grid.Column>
</Grid>
</Segment>
<Segment basic vertical>
<Grid>
<Grid.Column width={2}>
<Icon name="mail" size="big" />
</Grid.Column>
<Grid.Column width={13}>
<h3> { this.state.email } </h3>
</Grid.Column>
</Grid>
</Segment>
<Segment basic vertical>
<Grid>
<Grid.Column width={2}>
<Icon name="phone" size="big" />
</Grid.Column>
<Grid.Column width={13}>
<h3> { this.state.phone_number }</h3>
</Grid.Column>
</Grid>
</Segment>
<Segment basic vertical>
<Grid>
<Grid.Column width={2}>
<Icon name="gift" size="big" />
</Grid.Column>
<Grid.Column width={13}>
<h3> { this.state.cityOfBirth}, { this.state.dateOfBirth } </h3>
</Grid.Column>
</Grid>
</Segment>
</div>
<Container textAlign="center">
<div className="button-profile">
<div className="button-profile">
<a href={this.state.resume || '#'} ><Button primary size="small">Resume</Button></a>
</div>
<div>
<h4> Bagikan Transkrip : { this.state.bagikanTranskrip }</h4>
</div>
</Container>
</Container>
</Grid.Column >
</Grid>
</Segment >
{ this.updateForm(this.props.route.own) }
</div>
);
}
}
import React from 'react';
import { Container } from 'semantic-ui-react';
import Tabs from './components/Tabs';
import Pane from './components/Pane';
import VacancyList from './components/VacancyList';
import Pagination from './components/Pagination';
import Applicants from './SupervisorPage';
export default class VacancyPage extends React.Component {
......@@ -15,8 +15,10 @@ export default class VacancyPage extends React.Component {
const role = user.role;
if (role === 'student') {
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;
} else if (role === 'supervisor' || (role === 'admin' && user.data.supervisor != null)) {
return user.data.supervisor.id;
}
return 0;
......@@ -31,6 +33,7 @@ export default class VacancyPage extends React.Component {
};
}
generateVacancies() {
if (this.props.user.role === 'student') {
return (
......@@ -48,7 +51,7 @@ export default class VacancyPage extends React.Component {
}
/>
</Pane>
<Pane label="Lamaran saya" >
<Pane label="Lamaran Saya" >
<Pagination
key={2}
url={`/students/${this.state.id}/applied-vacancies/`}
......@@ -76,10 +79,12 @@ export default class VacancyPage extends React.Component {
</Pane>
</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 (
<div>
<Container className="vacancies">
<Pagination
key={1}
url={`/companies/${this.state.id}/vacancies/`}
child={
<VacancyList
......@@ -87,17 +92,41 @@ export default class VacancyPage extends React.Component {
user={this.props.user}
userId={this.state.id}
/>
}
}
error="Anda belum diverifikasi. Harap hubungi admin"
/>
</div>
</Container>
);
} else if (this.props.user.role === 'admin') {
} else if (this.props.user.role === 'admin' || this.props.user.role === 'supervisor') {
return (
<div>
<h1> halo </h1>
</div>
<Tabs selected={0}>
<Pane label="Lowongan Belum Terverifikasi" >
<Pagination
key={1}
url="/vacancies/?verified=false"
child={
<VacancyList
user={this.props.user}
key={1}
userId={this.state.id}
/>
}
/>
</Pane>
<Pane label="Lowongan Terverifikasi" >
<Pagination
key={2}
url="/vacancies/?verified=true"
child={
<VacancyList
user={this.props.user}
key={2}
userId={this.state.id}
/>
}
/>
</Pane>
</Tabs>
);
}
......
......@@ -43,7 +43,7 @@ describe('CompanyPage', () => {
it('click dashboard button problem', () => {
const companyPage = ReactTestUtils.renderIntoDocument(
<CompanyPage user={adminUser} />);
const dashboardButton = ReactTestUtils.findRenderedDOMComponentWithTag(companyPage, 'Button');
const dashboardButton = ReactTestUtils.scryRenderedDOMComponentsWithTag(companyPage, 'Button')[0];
ReactTestUtils.Simulate.click(dashboardButton);
expect(companyPage).to.exist;
expect(dashboardButton).to.exist;
......
/* eslint-disable no-unused-expressions */
import React from 'react';
import ReactTestUtils from 'react-addons-test-utils';
import AdminVacancy from '../../components/AdminVacancy';
import Storage from '../../lib/Storage';
describe('AdminVacancy', () => {
it('renders without problem', () => {
const adminVacancy = ReactTestUtils.renderIntoDocument(
<AdminVacancy />);
expect(adminVacancy).to.exist;
const fetchMock = require('fetch-mock');
const response = {
close_time: '2019-03-28T05:55:42Z',
company: {
address: 'kebayoran baru',
id: 1,
logo: null,
name: 'tutup lapak',
},
created: '2017-03-28T07:05:47.128672Z',
description: 'Lorem ipsum dolbh.',
id: 3,
name: 'Software Engineer',
open_time: '2017-03-28T05:55:38Z',
updated: '2017-03-28T07:34:13.122093Z',
verified: true,
};
const response2 = {
close_time: '2019-03-28T05:55:42Z',
company: {
address: 'kebayoran baru',
id: 1,
logo: 'pictures',
name: 'tutup lapak',
},
created: '2017-03-28T07:05:47.128672Z',
description: 'Lorem ipsum dolbh.',
id: 3,
name: 'Software Engineer',
open_time: '2017-03-28T05:55:38Z',
updated: '2017-03-28T07:34:13.122093Z',
verified: false,
};
const supervisorUser = {
role: 'supervisor',
data: {
url: 'http://localhost:8001/api/users/8/',
username: 'Tutuplapak',
email: '',
is_staff: false,
student: {
id: 3,
user: {
url: 'http://localhost:8000/api/users/9/',
username: 'muhammad.reza42',
email: 'muhammad.reza42@ui.ac.id',
is_staff: false,
},
name: 'Muhammad R.',
created: '2017-03-28T13:33:46.147241Z',
updated: '2017-03-28T13:33:46.148248Z',
npm: 1406543593,
resume: null,
phone_number: null,
birth_place: null,
birth_date: null,
major: null,
batch: null,
show_resume: false,
bookmarked_vacancies: [
3,
2,
],
applied_vacancies: [
3,
1,
],
},
},