Fakultas Ilmu Komputer UI

Commit 68b6b6be authored by Farhan Farasdak's avatar Farhan Farasdak
Browse files

[#50][#140653601]resolve confilct verify vacancy for admin and supervisor

parents 533c56fc 87f22a4c
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>
); );
} }
} }
import React from 'react'; import React from 'react';
import { Item } from 'semantic-ui-react'; import { Container, Item } from 'semantic-ui-react';S
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';
...@@ -82,17 +82,20 @@ export default class VacancyPage extends React.Component { ...@@ -82,17 +82,20 @@ export default class VacancyPage extends React.Component {
); );
} else if (this.props.user.role === 'company') { } else if (this.props.user.role === 'company') {
return ( return (
<Pagination <Container className="vacancies">
url={`/companies/${this.state.id}/vacancies/`} <Pagination
child={ key={1}
<VacancyList url={`/companies/${this.state.id}/vacancies/`}
key={1} child={
user={this.props.user} <VacancyList
userId={this.state.id} key={1}
/> user={this.props.user}
} userId={this.state.id}
error="Anda belum diverifikasi. Harap hubungi admin" />
/> }
error="Anda belum diverifikasi. Harap hubungi admin"
/>
</Container>
); );
} else if (this.props.user.role === 'admin' || this.props.user.role === 'supervisor') { } else if (this.props.user.role === 'admin' || this.props.user.role === 'supervisor') {
return ( return (
......
...@@ -370,6 +370,7 @@ describe('VacancyList', () => { ...@@ -370,6 +370,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 { 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';
...@@ -68,7 +68,15 @@ export default class ApplyModal extends React.Component { ...@@ -68,7 +68,15 @@ export default class ApplyModal extends React.Component {
<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>)
: (
<Message
error
icon="warning sign"
header="CV Tidak Ditemukan"
content="Anda belum mengunggah CV. Harap ubah profil anda terlebih dahulu pada halaman Profil."
/>)
}
</div> </div>
<br /> <br />
<div> <div>
...@@ -82,7 +90,7 @@ export default class ApplyModal extends React.Component { ...@@ -82,7 +90,7 @@ export default class ApplyModal extends React.Component {
</Modal.Content> </Modal.Content>
<Modal.Actions> <Modal.Actions>
<Button loading={this.state.load} color="blue" disabled={!this.props.active} onClick={this.handleApply}> <Button loading={this.state.load} color="blue" disabled={!this.props.active || this.props.resume == null} onClick={this.handleApply}>
{ this.props.active ? 'Daftar' : 'Sudah Terdaftar' } <Icon name="right chevron" /> { this.props.active ? 'Daftar' : 'Sudah Terdaftar' } <Icon name="right chevron" />
</Button> </Button>
</Modal.Actions> </Modal.Actions>
......
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 />
<div>
<b>
{this.props.data.student.resume ? <a onClick={this.gotoStudentResume} href="#" >CV Pelamar </a> : 'Pelamar tidak memiliki CV'}
<br />
{this.props.data.student.show_transcript ? <a onClick={this.gotoStudentTranscript} href="#" >Transkrip Pelamar</a> : 'Pelamar tidak mengijinkan transktip dilihat'}
<br />
</b>
</div> </div>
</Modal.Content> </Modal.Content>
<Modal.Actions> <Modal.Actions>
<Button color="facebook" onClick={this.gotoStudentProfile} floated="left" >
<Icon name="user outline" /> Lihat Profil
</Button>
<Button.Group> <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 disabled={this.props.data.status === Applicant.APPLICATION_STATUS.REJECTED} loading={this.state.rejectLoading} color="red" onClick={this.reject}>Tolak Lamaran</Button>
<Button.Or /> <Button.Or />
......
...@@ -2,6 +2,7 @@ import React from 'react'; ...@@ -2,6 +2,7 @@ import React from 'react';
import moment from 'moment'; import moment from 'moment';
import { Button, Icon, Item, Grid } from 'semantic-ui-react'; import { Button, Icon, Item, Grid } from 'semantic-ui-react';
import { Link } from 'react-router'; import { Link } from 'react-router';
import Server from '../lib/Server';
const defaultImage = 'http://semantic-ui.com/images/wireframe/image.png'; const defaultImage = 'http://semantic-ui.com/images/wireframe/image.png';
...@@ -15,8 +16,12 @@ export default class CompanyVacancy extends React.Component { ...@@ -15,8 +16,12 @@ export default class CompanyVacancy extends React.Component {
constructor(props) { constructor(props) {
super(props); super(props);
/* istanbul ignore next */
moment.locale('id'); moment.locale('id');
this.state = { deleteLoading: false }; this.state = { deleteLoading: false, count: 0, countNew: 0 };
Server.get(`/vacancies/${this.props.data.id}/count/`, false).then((data) => {
this.setState({ count: data.count, countNew: data.count_new });
});
} }
getLink = `/buat-lowongan/${this.props.data.id}`; getLink = `/buat-lowongan/${this.props.data.id}`;
...@@ -25,12 +30,13 @@ export default class CompanyVacancy extends React.Component { ...@@ -25,12 +30,13 @@ export default class CompanyVacancy extends React.Component {
return ( return (
<Item className="applicantItems"> <Item className="applicantItems">
<Item.Image src={this.props.data.company.logo ? this.props.data.company.logo : defaultImage} size="small" /> <Item.Image src={this.props.data.company.logo ? this.props.data.company.logo : defaultImage} size="small" />
<Item.Content> <Item.Content verticalAlign="middle" style={{ wordWrap: 'break-word', width: '100%' }} >
<Item.Header as="a">{this.props.data.name}</Item.Header> <Item.Header as="a">{this.props.data.name}</Item.Header>
<Grid.Row> <Grid.Row>
<Grid.Column floated="left"> <Grid.Column floated="left">
<h5> 105 Pendaftar </h5> <p>{ this.state.count } Pendaftar<br/>
Ditutup {moment(moment(this.props.data.close_time)).fromNow()} { this.state.countNew } Pendaftar Baru<br/><br/>
Ditutup {moment(moment(this.props.data.close_time)).fromNow()}</p>
</Grid.Column> </Grid.Column>
<Grid.Column floated="right"> <Grid.Column floated="right">
{this.props.data.verified ? {this.props.data.verified ?
......
...@@ -2,7 +2,7 @@ from django.contrib.auth.models import User ...@@ -2,7 +2,7 @@ from django.contrib.auth.models import User
from rest_framework import serializers from rest_framework import serializers
from core.models.accounts import Supervisor, Company, Student from core.models.accounts import Supervisor, Company, Student
from core.models.vacancies import Application
class BasicUserSerializer(serializers.HyperlinkedModelSerializer): class BasicUserSerializer(serializers.HyperlinkedModelSerializer):
class Meta: class Meta:
...@@ -13,11 +13,17 @@ class BasicUserSerializer(serializers.HyperlinkedModelSerializer): ...@@ -13,11 +13,17 @@ class BasicUserSerializer(serializers.HyperlinkedModelSerializer):
class StudentSerializer(serializers.ModelSerializer): class StudentSerializer(serializers.ModelSerializer):
user = BasicUserSerializer() user = BasicUserSerializer()
name = serializers.ReadOnlyField() name = serializers.ReadOnlyField()
accepted_no = serializers.SerializerMethodField()
class Meta: class Meta:
model = Student model = Student
fields = ['id', 'name', 'user', 'npm', 'resume', 'phone_number', 'birth_place', 'birth_date', 'major', 'batch', \ fields = ['id', 'name', 'user', 'npm', 'resume', 'phone_number', 'birth_place', 'birth_date', 'major', 'batch', \
'show_transcript', 'photo'] 'show_transcript', 'photo', 'accepted_no']
def get_accepted_no(self, obj):
apps = Application.objects.filter(student=obj, status=4)
companies = apps.values('vacancy__company').distinct()
return companies.count()
class StudentUpdateSerializer(serializers.ModelSerializer): class StudentUpdateSerializer(serializers.ModelSerializer):
......
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