Fakultas Ilmu Komputer UI

Commit 5dac8617 authored by M. Reza Qorib's avatar M. Reza Qorib
Browse files

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

Merge branch 'develop' of https://gitlab.com/PPL2017csui/PPLA1 into Features/CompanyVacancyApplicationList
parents adc85050 10054448
......@@ -19,7 +19,9 @@ background-color: #EEEEEE;
}
.create-lowongan{
margin: 60px 19% 100px;
padding-bottom: 7%;
padding-left:15%;
padding-right:15%;
}
.ui.segment.form-segment{
......@@ -106,18 +108,6 @@ font-size: 32px;
margin-top:10px;
}
.coverLetter{
margin-top:30px;
}
.linkCV{
float: right;
margin-top: 30px;
margin-bottom: 10px;
}
.registerForm{
margin: 0 auto;
/*padding:50px;*/
......@@ -175,3 +165,40 @@ card .formRegis{
color: black;
}
.biodata h5{
line-height: 30%;
}
.button-profile{
margin-top:30px;
}
.ui.segment.profile-form{
padding-bottom: 37px;
margin-top:4%;
}
.profilePage {
margin-bottom: 40px;
margin-left: 5%;
margin-right: 5%;
}
#react-app{
position: relative; /* needed for footer positioning*/
height: auto !important; /* real browsers */
min-height: 100%; /* real browsers */
background-color: #EEEEEE;
}
.footer{
background-color: #031634;
position: absolute;
bottom: 0;
width: 100%;
padding:1%;
}
.footer h5{
color:white;
}
\ No newline at end of file
......@@ -2,10 +2,10 @@ import React from 'react';
import Tabs from './components/Tabs';
import Pane from './components/Pane';
import Storage from './lib/Storage';
import VacancyList from './components/VacancyList';
export default class VacancyPage extends React.Component {
import ApplicantList from './components/ApplicantList';
import Applicant from './components/Applicant';
export default class ApplicantPage extends React.Component {
constructor(props) {
super(props);
/* istanbul ignore next */
......@@ -13,7 +13,7 @@ export default class VacancyPage extends React.Component {
email: '',
password: '',
errorFlag: false,
vacancies: [],
company: { id: 1 },
};
this.handleItemClick = this.handleItemClick.bind(this);
}
......@@ -21,23 +21,25 @@ export default class VacancyPage extends React.Component {
handleItemClick = (e, { name }) => this.setState({ activeItem: name });
render() {
const student = Storage.get('user-data').student;
const company = Storage.get('user-data').company;
return (
<div className="halamanPendaftar">
<Tabs selected={0}>
<Pane label="Lamaran Baru" >
<VacancyList key={1} studentId={student.id} url="/vacancies/" />
<ApplicantList key={1} companyId={company.id} url={`/companies/${company.id}/applications/?status=${Applicant.APPLICATION_STATUS.NEW}`} status={Applicant.APPLICATION_STATUS.NEW} />
</Pane>
<Pane label="Lamaran Dibaca" >
<ApplicantList key={2} companyId={company.id} url={`/companies/${company.id}/applications/?status=${Applicant.APPLICATION_STATUS.READ}`} status={Applicant.APPLICATION_STATUS.READ} />
</Pane>
<Pane label="Lamaran Ditandai" >
<ApplicantList key={3} companyId={company.id} url={`/companies/${company.id}/applications/?status=${Applicant.APPLICATION_STATUS.BOOKMARKED}`} status={Applicant.APPLICATION_STATUS.BOOKMARKED} />
</Pane>
<Pane label="Bintangi" >
<VacancyList key={2} status="Batal" studentId={student.id} url={`/students/${student.id}/applied-vacancies/`} />
<Pane label="Lamaran Diterima" >
<ApplicantList key={4} companyId={company.id} url={`/companies/${company.id}/applications/?status=${Applicant.APPLICATION_STATUS.ACCEPTED}`} status={Applicant.APPLICATION_STATUS.ACCEPTED} />
</Pane>
<Pane label="Semua Lamaran" >
<VacancyList key={3} studentId={student.id} url={`/students/${student.id}/bookmarked-vacancies/`} />
<Pane label="Lamaran Ditolak" >
<ApplicantList key={5} companyId={company.id} url={`/companies/${company.id}/applications/?status=${Applicant.APPLICATION_STATUS.REJECTED}`} status={Applicant.APPLICATION_STATUS.REJECTED} />
</Pane>
</Tabs>
</div>
);
}
}
import React from 'react';
import TopMenu from './components/TopMenu';
import Footer from './components/Footer'
export default class Dashboard extends React.Component {
static propTypes = {
......@@ -13,6 +14,7 @@ export default class Dashboard extends React.Component {
<div>
<TopMenu />
{this.props.children}
<Footer/>
</div>
)
}
import React from 'react';
import { Segment, Image, Header, Icon, Container, Button, Form } from 'semantic-ui-react';
import Server from './lib/Server';
export default class ProfilePage extends React.Component {
static propTypes = {
route: React.PropTypes.object.isRequired,
params: React.PropTypes.object.isRequired,
};
constructor(props) {
super(props);
/* istanbul ignore next */
this.state = {
id: '',
npm: '',
name: '',
major: '',
batch: '',
email: '',
cityOfBirth: '',
dateOfBirth: '',
resume: '',
phone: '',
showTranscript: '',
};
this.getProfile = this.getProfile.bind(this);
this.handleChange = this.handleChange.bind(this);
this.getProfile();
}
getProfile() {
if (this.props.route.own) {
// check api format in /api#!/login
this.state = {
id: this.props.route.data.student.id,
npm: this.props.route.data.student.npm,
name: this.props.route.data.student.name,
major: this.props.route.data.student.major,
batch: this.props.route.data.student.batch,
email: this.props.route.data.student.user.email,
cityOfBirth: this.props.route.data.student.birth_place,
dateOfBirth: this.props.route.data.student.birth_date,
resume: this.props.route.data.student.resume,
phone: this.props.route.data.student.phone_number,
showTranscript: this.props.route.data.student.show_transcript,
};
return Promise.resolve(this.state);
} else {
return Server.get(`/students/${this.props.params.id}/`).then((data) => {
this.setState({
id: data.id,
name: data.name,
npm: data.npm,
resume: data.resume,
major: data.major,
batch: data.batch,
email: data.user.email,
cityOfBirth: data.birth_place,
dateOfBirth: data.birth_date,
phone: data.phone_number,
showTranscript: data.show_transcript,
});
}, error => error.then(() => {
// this.modalAlert.open('Gagal Mengambil ', r.error);
this.state.name = 'Gagal mendapatkan informasi';
}));
}
}
handleChange = (e) => {
this.setState({ [e.target.name]: e.target.value });
};
updateForm(show) {
if (show) {
return (
<Segment className="profile-form">
<Header as="h3" textAlign="center">
<Icon name="edit" />
<Header.Content>
Edit Profile Page
</Header.Content>
</Header>
<Form size="small" onSubmit={this.handleSubmit}>
<Form.Field>
<label htmlFor="photo">Profile Picture</label>
<input onChange={this.handleChange} placeholder="Profile Photo.jpg" name="photo" type="File" />
</Form.Field>
<Form.Field>
<label htmlFor="email">Email</label>
<input onChange={this.handleChange} placeholder="jojon@email.com" name="email" />
</Form.Field>
<Form.Field>
<label htmlFor="phone">No. Hp</label>
<input onChange={this.handleChange} placeholder="08123456789" name="phone" />
</Form.Field>
<Form.Field>
<label htmlFor="resume">Resume</label>
<input onChange={this.handleChange} placeholder="Resume" name="resume" type="File" />
</Form.Field>
<Button type="submit" size="small" primary floated="right">Submit</Button>
</Form>
</Segment>
);
}
return (<div />);
}
render() {
return (
<div className="profilePage">
<Segment className="biodata-section">
<Header as="h2" icon textAlign="center">
<Image src="http://semantic-ui.com/images/wireframe/square-image.png" size="small" shape="circular" />
</Header>
<Container textAlign="center" className="profile-biodata">
<div className="biodata">
<h3> { this.state.name } </h3>
<h5> { this.state.major }, { this.state.batch } </h5>
<h5> { this.state.email } </h5>
<h5> { this.state.phone } </h5>
<h5> { this.state.cityOfBirth}, { this.state.dateOfBirth } </h5>
</div>
<div className="button-profile">
<Button primary size="small">Resume</Button>
{ this.state.showTranscript ? <Button primary size="small">Transkrip</Button> : <div /> }
</div>
</Container>
</Segment >
{ this.updateForm(this.props.route.own) }
</div>
);
}
}
import React from 'react';
import CourseList from './components/CourseList';
import Server from './lib/Server';
export default class TranscriptPage extends React.Component {
static propTypes = {
params: React.PropTypes.object.isRequired,
};
constructor(props) {
super(props);
/* istanbul ignore next */
this.state = {};
Server.get(`/applications/${this.props.params.id}/`).then(response => this.setState({ data: response }));
}
render() {
return (
this.state.data ? <CourseList data={this.state.data} /> : <h5 style={{ textAlign: 'center' }}> Mohon Tunggu.. </h5>
);
}
}
/* eslint-disable no-unused-expressions */
import React from 'react';
import ReactTestUtils from 'react-addons-test-utils';
import fetchMock from 'fetch-mock';
import ProfilePage from '../ProfilePage';
describe('ProfilePage', () => {
const studentSession = {
url: 'http://localhost:8000/api/users/9/',
username: 'muhammad.reza42',
email: 'muhammad.reza42@ui.ac.id',
is_staff: false,
company: null,
supervisor: null,
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,
],
},
};
const brokenSession = {
url: 'http://localhost:8000/api/users/9/',
username: 'muhammad.reza42',
email: 'muhammad.reza42@ui.ac.id',
is_staff: false,
company: null,
supervisor: null,
student: null,
};
const response = {
id: 3,
name: 'Muhammad R.',
user: {
url: 'http://localhost:8000/api/users/9/',
username: 'muhammad.reza42',
email: 'muhammad.reza42@ui.ac.id',
is_staff: false,
},
npm: 1406543593,
resume: null,
phone_number: null,
birth_place: null,
birth_date: null,
major: null,
batch: null,
show_transcript: false,
};
it('renders without problem', () => {
const profile = ReactTestUtils.renderIntoDocument(
<ProfilePage route={{ own: true, data: studentSession }} params={{}} />);
expect(profile.state.name).to.equal(studentSession.student.name);
});
it('get profile for company without problem', () => {
fetchMock.get('*', response);
const profile = ReactTestUtils.renderIntoDocument(
<ProfilePage route={{ own: false, data: studentSession }} params={{ id: 3 }} />);
profile.getProfile().then(()=> expect(profile.state.name).to.equal(response.name));
fetchMock.restore();
});
it('renders without problem when error getting data', () => {
fetchMock.get('*', 400);
const profile = ReactTestUtils.renderIntoDocument(
<ProfilePage route={{ own: false, data: studentSession }} params={{ id: 3 }} />);
profile.getProfile().then(()=> expect(profile.state.name).to.equal('Gagal mendapatkan informasi'));
});
});
import React from 'react';
import ReactTestUtils from 'react-addons-test-utils';
import Applicant from '../../components/Applicant';
import fetchMock from 'fetch-mock';
describe('Applicant', () => {
const stub = {
data: {
vacancy: { name: 'name' },
student: { major: 'hue' },
status: 2,
},
updateStatus: () => {},
};
const stub2 = {
data: {
vacancy: { name: 'name' },
student: { major: 'hue' },
status: 3,
},
updateStatus: () => {},
};
it('renders without problem', () => {
fetchMock.get('*', stub);
const applicant = ReactTestUtils.renderIntoDocument(
<Applicant data={stub.data} updateStatus={stub.updateStatus} />,
);
expect(applicant).to.exist;
fetchMock.restore();
});
it('bookmarks without problem', () => {
fetchMock.get('*', stub);
fetchMock.patch('*', {});
const applicant = ReactTestUtils.renderIntoDocument(
<Applicant data={stub2.data} updateStatus={stub.updateStatus} />,
);
applicant.bookmark();
expect(applicant).to.exist;
fetchMock.restore();
});
it('bookmarks with problem', () => {
fetchMock.get('*', stub);
fetchMock.patch('*', {});
const applicant = ReactTestUtils.renderIntoDocument(
<Applicant data={stub.data} updateStatus={stub.updateStatus} />,
);
applicant.bookmark();
expect(applicant).to.exist;
fetchMock.restore();
});
// it('test apply without problem', () => {
// const applyModal = ReactTestUtils.renderIntoDocument(
// <Applicant />,
// );
// const response = { student: { id: 1, name: 2 } };
//
// Storage.set('user-data', response);
// fetchMock.post('*', { data: 'value' });
// applyModal.open('Menghubungkan ke Server');
// expect(applyModal.state.header).to.equal('Menghubungkan ke Server');
// fetchMock.restore();
// });
//
// it('test apply with problem', () => {
// const applyModal = ReactTestUtils.renderIntoDocument(
// <Applicant />,
// );
// const response = { student: { id: 1, name: 2 } };
//
// Storage.set('user-data', response);
// fetchMock.post('*', 404);
// applyModal.open('Menghubungkan ke Server', '', '', () => {});
// applyModal.handleYes();
// expect(applyModal.state.header).to.equal('Menghubungkan ke Server');
// fetchMock.restore();
// });
});
/* eslint-disable no-unused-expressions */
import React from 'react';
import ReactTestUtils from 'react-addons-test-utils';
import fetchMock from 'fetch-mock';
import ApproveModal from '../../components/ApproveModal';
describe('ApproveModal', () => {
it('renders without problem', () => {
const modalApproval = ReactTestUtils.renderIntoDocument(
<ApproveModal updateStatus={() => {}} data={{ key: 'value', student: { resume: 'asdasd' } }} />);
expect(modalApproval).to.exist;
});
it('open without problem', () => {
fetchMock.get('*', { student: { resume: 'asdasd' } });
const modalApproval = ReactTestUtils.renderIntoDocument(
<ApproveModal updateStatus={() => {}} data={{ key: 'value', student: { resume: 'asdasd' } }} />);
const modal = ReactTestUtils.findRenderedDOMComponentWithTag(modalApproval, 'Button');
ReactTestUtils.Simulate.click(modal);
fetchMock.restore();
});
it('close without problem', () => {
fetchMock.get('*', { student: { resume: 'asdasd' } });
const modalApproval = ReactTestUtils.renderIntoDocument(
<ApproveModal updateStatus={() => {}} data={{ key: 'value', student: { resume: 'asdasd' } }} />);
modalApproval.handleClose();
expect(modalApproval.state.modalOpen).to.equal(false);
fetchMock.restore();
});
it('reject without problem', () => {
fetchMock.get('*', { student: { resume: 'asdasd' } });
fetchMock.patch('*', { });
const modalApproval = ReactTestUtils.renderIntoDocument(
<ApproveModal updateStatus={() => {}} data={{ key: 'value', student: { resume: 'asdasd' }, cover_letter: 'asdasd' }} />);
modalApproval.modal = { open: () => {} };
modalApproval.reject();
modalApproval.rejectApplication();
modalApproval.gotoLink('link random');
expect(modalApproval.state.rejectLoading).to.equal(true);
fetchMock.restore();
});
it('apply without problem', () => {
fetchMock.get('*', { student: { resume: 'asdasd' } });
fetchMock.patch('*', { });
const modalApproval = ReactTestUtils.renderIntoDocument(
<ApproveModal updateStatus={() => {}} data={{ key: 'value', student: { resume: 'asdasd', show_transcript: true } }} />);
modalApproval.modal = { open: () => {} };
modalApproval.accept();
modalApproval.acceptApplication();
modalApproval.gotoLink('link random');
expect(modalApproval.state.acceptLoading).to.equal(true);
fetchMock.restore();
});
});
import React from 'react';
import { Item, Rating, Grid } from 'semantic-ui-react';
import Server from '../lib/Server';
import ModalAlert from './ModalAlert';
import ApproveModal from './ApproveModal';
const defaultImage = 'http://semantic-ui.com/images/wireframe/image.png';
export default class Applicant extends React.Component {
static propTypes = {
data: React.PropTypes.object.isRequired,
updateStatus: React.PropTypes.func.isRequired,
};
static APPLICATION_STATUS = {
NEW: 0,
READ: 1,
BOOKMARKED: 2,
REJECTED: 3,
ACCEPTED: 4,
};
constructor(props) {
super(props);
/* istanbul ignore next */
this.bookmark = this.bookmark.bind(this);
}
bookmark = () => {
let data = { status: Applicant.APPLICATION_STATUS.BOOKMARKED };
if (this.props.data.status === Applicant.APPLICATION_STATUS.BOOKMARKED) {
data = { status: Applicant.APPLICATION_STATUS.READ };
}
if (this.props.data.status > 2) {
this.modalAlert.open('Gagal Menandai', 'Lamaran yang sudah ditolak atau diterima tidak bisa ditandai');
} else {
Server.patch(`/applications/${this.props.data.id}/`, data).then((status) => {
this.props.updateStatus(this.props.data.id, status.status);