Fakultas Ilmu Komputer UI

Commit d502a5a4 authored by Zamil Majdy's avatar Zamil Majdy
Browse files

[#140656091] [#33] [Green] Add applicant and approve implementations

parent e51ee2c8
......@@ -3,9 +3,9 @@ import Tabs from './components/Tabs';
import Pane from './components/Pane';
import Storage from './lib/Storage';
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 ApplicantPage extends React.Component {
email: '',
password: '',
errorFlag: false,
company: {id:1},
company: { id: 1 },
};
this.handleItemClick = this.handleItemClick.bind(this);
}
......@@ -23,18 +23,23 @@ export default class ApplicantPage extends React.Component {
render() {
const company = Storage.get('user-data').company;
return (
<div className="halamanPendaftar">
<Tabs selected={0}>
<Pane label="Semua Lamaran" >
<ApplicantList key={1} companyId={company.id} url={`/students/${company.id}/bookmarked-vacancies/`} />
<Pane label="Lamaran Baru" >
<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" >
<ApplicantList key={2} status="Bookmarked" companyId={company.id} url={`/students/${company.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="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 { Item, Rating } from 'semantic-ui-react';
import ApproveModal from './ApproveModal';
import Storage from '../lib/Storage';
import { Item, Rating, Grid } from 'semantic-ui-react';
import Server from '../lib/Server';
import CancelModal from './CancelModal';
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,
bookmarked: React.PropTypes.number,
status: React.PropTypes.string.isRequired,
updateStatus: React.PropTypes.func.isRequired,
};
static defaultProps = {
bookmarked: 0,
static APPLICATION_STATUS = {
NEW: 0,
READ: 1,
BOOKMARKED: 2,
REJECTED: 3,
ACCEPTED: 4,
};
constructor(props) {
super(props);
/* istanbul ignore next */
this.state = { bookmarked: this.props.bookmarked };
this.bookmark = this.bookmark.bind(this);
this.generateAction = this.generateAction.bind(this);
}
bookmark() {
/* still under construction */
const companyId = Storage.get('user-data').company.id;
const data = { application_id: this.props.data.id };
if (this.state.bookmarked < 1) {
Server.post(`/company/${companyId}/bookmarked-applications/`, data);
} else {
Server.delete(`/company/${companyId}/bookmarked-applications/${this.props.data.id}/`);
bookmark = () => {
let data = { status: Applicant.APPLICATION_STATUS.BOOKMARKED };
if (this.props.data.status === Applicant.APPLICATION_STATUS.BOOKMARKED) {
data = { status: Applicant.APPLICATION_STATUS.READ };
}
this.state.bookmarked = 1 - this.state.bookmarked;
}
generateAction() {
const approveModal = (<ApproveModal
id={this.props.data.id} data={{ header: this.props.data.name,
description: this.props.data.description }} buttonTitle="Detail"
/>);
return approveModal;
}
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);
});
}
};
render() {
return (
<Item >
<ModalAlert ref={(modal) => { this.modalAlert = modal; }} />
<Item.Image size="small" src={defaultImage} />
<Item.Content verticalAlign="middle">
<Item.Extra>
<h3>{this.props.data.name}</h3>
<div className="bookmark">
<Rating icon="star" onRate={this.bookmark} size="massive" defaultRating={this.props.bookmarked ? this.props.bookmarked : 0} maxRating={1} />
</div>
<h5>{this.props.data.jurusan}</h5>
<h4>{this.props.data.application}</h4>
{ this.generateAction() }
<Grid.Row>
<Grid.Column floated="left">
<h4> {this.props.data.student.name} </h4>
{this.props.data.vacancy.name} <br />
{this.props.data.student.major}
</Grid.Column>
<Grid.Column floated="right" textAlign="center">
<Grid.Row>
<Rating
icon="star" size="massive"
defaultRating={this.props.data.status === Applicant.APPLICATION_STATUS.BOOKMARKED ? 1 : 0}
onRate={this.bookmark}
maxRating={1}
/>
</Grid.Row>
<ApproveModal updateStatus={this.props.updateStatus} data={this.props.data} />
</Grid.Column>
</Grid.Row>
</Item.Extra>
</Item.Content>
</Item>
......
import React from 'react';
import { Item } from 'semantic-ui-react';
import { Item, Grid } from 'semantic-ui-react';
import Applicant from './Applicant';
import Server from '../lib/Server';
......@@ -7,41 +7,47 @@ export default class ApplicantList extends React.Component {
static propTypes = {
url: React.PropTypes.string.isRequired,
companyId: React.PropTypes.number.isRequired,
status: React.PropTypes.string,
status: React.PropTypes.number.isRequired,
};
static defaultProps = {
status: 'Unbookmarked',
};
constructor(props) {
super(props);
/* istanbul ignore next */
/*
this.state = { applications: [] };
Server.get(this.props.url, false).then((data) => {
this.setState({ applications: data });
});
*/
this.state = { applications: [{id:1, name:"Farasdak", description:"huehuehuehue", bookmarked:0, jurusan:"Ilmu Komputer", application:"Software Engineer"}], bookmarkList: [] };
this.generateApplicants = this.generateApplicants.bind(this);
this.updateStatus = this.updateStatus.bind(this);
}
updateStatus(id, status) {
const obj = [];
this.state.applications.map((application) => {
const clonedObj = {};
Object.assign(clonedObj, application);
if (application.id === id) clonedObj.status = status;
return obj.push(clonedObj);
});
this.setState({ applications: obj });
}
generateApplicants() {
console.log(this.state.applications)
return this.state.applications.map(application =>
<Applicant
key={application.id}
status={this.props.status}
data={application}
/>,
application.status === this.props.status && (<Applicant
key={application.id} data={application}
updateStatus={this.updateStatus}
/>),
);
}
render = () => (
<Item.Group relaxed>
{ this.generateApplicants() }
</Item.Group>
<Grid container doubling>
<Item.Group relaxed style={{ width: '100%' }}>
{ this.generateApplicants() }
</Item.Group>
</Grid>
);
}
import React from 'react';
import { Modal, Button, Icon, TextArea, Form } from 'semantic-ui-react';
import ModalAlert from './ModalAlert';
import { Modal, Button } from 'semantic-ui-react';
import Server from './../lib/Server';
import ConfirmationModal from './../components/ConfirmationModal';
import Applicant from './../components/Applicant';
export default class ApproveModal extends React.Component {
static propTypes = {
data: React.PropTypes.object.isRequired,
id: React.PropTypes.number.isRequired,
buttonTitle: React.PropTypes.string.isRequired,
updateStatus: React.PropTypes.func.isRequired,
};
constructor(props) {
......@@ -14,50 +15,73 @@ export default class ApproveModal extends React.Component {
/* istanbul ignore next */
this.state = {
modalOpen: false,
rejectLoading: false,
acceptLoading: false,
};
this.handleOpen = this.handleOpen.bind(this);
this.reject = this.reject.bind(this);
this.accept = this.accept.bind(this);
}
handleOpen = () => this.setState({ modalOpen: true });
handleClose = () => this.setState({ modalOpen: false });
handleOpen() {
this.setState({ modalOpen: true });
}
rejectApplication = () => {
const data = { status: Applicant.APPLICATION_STATUS.REJECTED };
this.setState({ rejectLoading: true });
Server.patch(`/applications/${this.props.data.id}/`, data).then((status) => {
this.props.updateStatus(this.props.data.id, status.status);
});
};
reject = () => {
this.modal.open(
'Tolak Lamaran?',
'Apakah anda yakin untuk menolak lamaran ini?',
'trash',
this.rejectApplication,
);
};
handleClose = () => this.setState({
modalOpen: false,
});
acceptApplication = () => {
const data = { status: Applicant.APPLICATION_STATUS.ACCEPTED };
this.setState({ acceptLoading: true });
Server.patch(`/applications/${this.props.data.id}/`, data).then((status) => {
this.props.updateStatus(this.props.data.id, status.status);
});
};
accept = () => {
this.modal.open(
'Terima Lamaran?',
'Apakah anda yakin untuk menerima lamaran ini?',
'checkmark',
this.acceptApplication,
);
};
render = () => (
<Modal
trigger={<Button primary onClick={this.handleOpen} floated="right">{this.props.buttonTitle}</Button>}
trigger={<Button primary onClick={this.handleOpen} floated="right">Detail</Button>}
closeIcon="close"
open={this.state.modalOpen}
onClose={this.handleClose}
>
<Modal.Header>{this.props.data.header}</Modal.Header>
<ConfirmationModal ref={(modal) => { this.modal = modal; }} />
<Modal.Header>Data Lamaran</Modal.Header>
<Modal.Content>
<div className="coverLetter">
<div className="linkCV">
<a> Applicant's CV </a>
</div>
<h4> Cover Letter </h4>
<h5>{this.props.data.description}</h5>
</div>
<h4> Cover Letter </h4>
{ this.props.data.cover_letter }
<div style={{ float: 'right' }}>
<a href={this.props.data.resume} >CV Pelamar </a>
</div>
</Modal.Content>
<Modal.Actions>
<ModalAlert
id={this.props.id}
onChangeValue={this.handleClose}
status="Terima"
/>
<Button.Group>
<Button disabled={this.props.data.status === Applicant.APPLICATION_STATUS.REJECTED} loading={this.state.rejectLoading} color="red" onClick={this.reject}>Tolak Lamaran</Button>
<Button.Or />
<Button disabled={this.props.data.status === Applicant.APPLICATION_STATUS.ACCEPTED} loading={this.state.acceptLoading} color="green" onClick={this.accept}>Terima Lamaran</Button>
</Button.Group>
</Modal.Actions>
</Modal>
)
......
import React from 'react';
import { Item, Rating, Button } from 'semantic-ui-react';
import { Item, Rating, Button, Grid } from 'semantic-ui-react';
import ApplyModal from './ApplyModal';
import Server from '../lib/Server';
import ConfirmationModal from './ConfirmationModal';
......@@ -92,16 +92,21 @@ export default class Vacancy extends React.Component {
<Item.Image size="small" src={this.props.data.company.logo ? this.props.data.company.logo : defaultImage} />
<Item.Content verticalAlign="middle">
<Item.Extra>
<h3>{ this.props.data.name }</h3>
<div className="bookmark">
<Rating icon="star" onRate={this.bookmark} size="massive" defaultRating={this.props.bookmarked} maxRating={1} />
</div>
<h4>{ this.props.data.company.name }</h4>
<h5>{ this.props.data.company.address }</h5>
{ this.generateAction() }
<Grid.Row>
<Grid.Column floated="left">
<h4>{ this.props.data.name }</h4>
{ this.props.data.company.name }<br />
{ this.props.data.company.address }
</Grid.Column>
<Grid.Column floated="right" >
<Grid.Row textAlign="center">
<Rating icon="star" onRate={this.bookmark} size="massive" defaultRating={this.props.bookmarked} maxRating={1} />
</Grid.Row>
<Grid.Row>
{ this.generateAction() }
</Grid.Row>
</Grid.Column>
</Grid.Row>
</Item.Extra>
</Item.Content>
</Item>
......
......@@ -105,7 +105,7 @@ export default class VacancyList extends React.Component {
}
render = () => (
<Segment>
<div>
<ModalAlert ref={(modal) => { this.modalAlert = modal; }} />
<Grid container columns="eleven" doubling>
{ this.companyHeader() }
......@@ -113,6 +113,6 @@ export default class VacancyList extends React.Component {
{ this.generateVacancies() }
</Item.Group>
</Grid>
</Segment>
</div>
);
}
......@@ -92,8 +92,10 @@ class CompanyApplicationViewSet(viewsets.GenericViewSet):
---
"""
company = get_object_or_404(Company.objects.all(), pk=company_id)
vacancies = Vacancy.objects.filter(company = company)
applications = Application.objects.filter(vacancy__in = vacancies)
vacancies = Vacancy.objects.filter(company=company)
applications = Application.objects.filter(vacancy__in=vacancies)
if 'status' in request.query_params:
applications = applications.filter(status=request.query_params['status'])
return Response(ApplicationSerializer(applications, many=True, context={'request': request}).data)
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment