Fakultas Ilmu Komputer UI

Commit 4b65b513 authored by Reza Qorib's avatar Reza Qorib
Browse files

Merge branch 'Features/VerifyVacancyForAdmin' into 'develop'

Verify vacancy for admin and supervisor

See merge request !20
parents 1ce99a41 34b38d89
......@@ -244,7 +244,6 @@ card .formRegis{
margin-right: 10%;
}
.admin-bar{
margin: 0;
padding: 0 10px 0 0;
......@@ -252,4 +251,5 @@ card .formRegis{
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}
......
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 {
static propTypes = {
user: React.PropTypes.object.isRequired,
route: React.PropTypes.object.isRequired,
params: React.PropTypes.object.isRequired,
children: React.PropTypes.oneOfType([
React.PropTypes.arrayOf(React.PropTypes.node),
React.PropTypes.node,
......@@ -11,6 +15,11 @@ export default class Dashboard extends React.Component {
user: React.PropTypes.object.isRequired,
};
constructor(props) {
super(props);
/* istanbul ignore next */
}
render = () => (
<div>
<TopMenu user={this.props.user} />
......
import React from 'react';
import { Container } from 'semantic-ui-react';
import { Container, Item } from 'semantic-ui-react';
import Tabs from './components/Tabs';
import Pane from './components/Pane';
import VacancyList from './components/VacancyList';
import AdminVacancy from './components/AdminVacancy';
import Pagination from './components/Pagination';
export default class VacancyPage extends React.Component {
......@@ -15,8 +16,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 +34,7 @@ export default class VacancyPage extends React.Component {
};
}
generateVacancies() {
if (this.props.user.role === 'student') {
return (
......@@ -76,7 +80,7 @@ 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 === 'company') {
return (
<Container className="vacancies">
<Pagination
......@@ -93,6 +97,37 @@ export default class VacancyPage extends React.Component {
/>
</Container>
);
} else if (this.props.user.role === 'admin' || this.props.user.role === 'supervisor') {
return (
<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>
);
}
return (
......
......@@ -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('Vacancy', () => {
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,
],
},
},
};
it('renders for verified without problem', () => {
const lowongan = ReactTestUtils.renderIntoDocument(
<AdminVacancy status={4} data={response} />);
expect(lowongan).to.exist;
});
it('renders for unverified without problem', () => {
const lowongan = ReactTestUtils.renderIntoDocument(
<AdminVacancy status={3} data={response2} />);
expect(lowongan).to.exist;
});
it('generate button without problem', () => {
const lowongan = ReactTestUtils.renderIntoDocument(
<AdminVacancy status={3} data={response2} />);
expect(lowongan.generateButton()).to.exist;
});
});
......@@ -34,6 +34,46 @@ describe('VacancyList', () => {
},
};
const supervisorUser = {
role: 'supervisor',
data: {
url: 'http://localhost:8001/api/users/8/',
username: 'Tutuplapak',
email: '',
is_staff: false,
company: null,
supervisor: {
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,
],
},
student: null,
},
};
const studentUser = {
role: 'company',
data: {
......@@ -245,6 +285,20 @@ describe('VacancyList', () => {
expect(vacancyList.generateVacancies()).to.exist;
});
it('renders without problem for supervisor', () => {
const vacancyList = ReactTestUtils.renderIntoDocument(
<VacancyList items={newResponse} userId={3} user={supervisorUser} />);
vacancyList.state.vacancies = newResponse;
expect(vacancyList.generateVacancies()).to.exist;
});
it('update status without problem', () => {
const vacancyList = ReactTestUtils.renderIntoDocument(
<VacancyList items={newResponse} userId={3} user={supervisorUser} />);
vacancyList.state.vacancies = newResponse;
vacancyList.updateStatus(4,1);
});
// it('renders with problem for company', () => {
// const vacancyList = ReactTestUtils.renderIntoDocument(
// <VacancyList type="company" userId={1} url="test" />);
......
import React from 'react';
import ReactTestUtils from 'react-addons-test-utils';
import VerifyAdminModal from '../../components/VerifyAdminModal';
import fetchMock from 'fetch-mock';
import Storage from '../../lib/Storage';
describe('VerifyAdminModal', () => {
it('renders without problem', () => {
const verifyModal = ReactTestUtils.renderIntoDocument(
<VerifyAdminModal />,
);
expect(verifyModal).to.exist;
});
it('open without problem', () => {
const verifyModal = ReactTestUtils.renderIntoDocument(
<VerifyAdminModal id={4} />);
const modal = ReactTestUtils.findRenderedDOMComponentWithTag(verifyModal, 'Button');
ReactTestUtils.Simulate.click(modal);
expect(verifyModal.state.modalOpen).to.equal(true);
});
it('close without problem', () => {
const verifyModal = ReactTestUtils.renderIntoDocument(
<VerifyAdminModal id={4} />);
verifyModal.handleClose();
expect(verifyModal.state.modalOpen).to.equal(false);
});
});
import React from 'react';
import { Item, Grid, Icon, Button } from 'semantic-ui-react';
import VerifyAdminModal from './VerifyAdminModal';
import Server from '../lib/Server';
export default class AdminVacancy extends React.Component {
static propTypes = {
data: React.PropTypes.object.isRequired,
updateStatus : React.PropTypes.func.isRequired,
};
changeVerifiedStatus(){
let data = {};
if(this.props.data.verified){
data = {"verified" : false};
}
else{
data = {"verified" : true};
}
Server.patch(`/vacancies/${this.props.data.id}/verify/`, data).then((status) => {
this.props.updateStatus(this.props.data.id, status.status);
});
}
generateButton(){
const unverifyButton = <Button floated="right" color="red" onClick={this.changeVerifiedStatus.bind(this)}>Batalkan Verifikasi</Button>;
const verifyButton = <Button floated="right" color="blue" onClick={this.changeVerifiedStatus.bind(this)}>Verifikasi</Button>;
if(this.props.data.verified){
return unverifyButton;
}
return verifyButton;
}
render() {
return (
<Item className="adminItems">
<Item.Image src="http://semantic-ui.com/images/wireframe/image.png" size="small" />
<Item.Content>
<Item.Header as="a">{this.props.data.name}</Item.Header>
<Grid.Row>
<Grid.Column floated="left">
<h4>{this.props.data.company.name} </h4>
{this.props.data.company.address}
</Grid.Column>
<Grid.Column floated="right">
{this.generateButton()}
</Grid.Column>
</Grid.Row>
</Item.Content>
</Item>
);
}
}
import React from 'react';
import { Menu, Image } from 'semantic-ui-react';
import { Menu, Image, Popup, Button, Card } from 'semantic-ui-react';
import { Link, browserHistory } from 'react-router';
import Server from '../lib/Server';
import Storage from '../lib/Storage';
const defaultPicture = 'http://semantic-ui.com/images/avatar/small/elliot.jpg';
export default class TopMenu extends React.Component {
static propTypes = {
......@@ -14,6 +16,7 @@ export default class TopMenu extends React.Component {
constructor(props) {
super(props);
/* istanbul ignore next */
console.log(this.props.user);
this.state = { activeItem: 'home' };
this.logout = this.logout.bind(this);
this.logoutCompany = this.logoutCompany.bind(this);
......@@ -39,6 +42,7 @@ export default class TopMenu extends React.Component {
render() {
const { activeItem } = this.state;
return (
<div>
{ this.props.user.data.is_staff && this.props.user.data.company && (
......@@ -48,13 +52,30 @@ export default class TopMenu extends React.Component {
</div>
)}
<Menu color="blue" pointing secondary>
<Image as="a" size="small" src="/assets/img/logo.png" href="/" />
<Menu.Menu position="right">
<Menu.Item as={Link} to="/home" name="home" active={activeItem === 'home'} onClick={this.handleItemClick} />
<Menu.Item as={Link} to="/profile" name="profil" active={activeItem === 'profil'} onClick={this.handleItemClick} />
<Menu.Item as={Link} onClick={this.logout} name="logout" />
</Menu.Menu>
</Menu>
<Image as="a" size="small" src="/assets/img/logo.png" href="/" />
<Menu.Menu position="right">
<Menu.Item as={Link} to="/home" name="home" active={activeItem === 'home'} onClick={this.handleItemClick} />
<Menu.Item>
<Popup
trigger={<Image
as={Link} to="/profil" src={this.props.user.data.photo || defaultPicture} avatar
onClick={this.handleItemClick}
/>}
flowing
hoverable
>
<Card
header={this.props.user.data.name}
description={this.props.user.data.email}
/>
<Button as={Link} onClick={this.logout} name="logout" color="blue" size="tiny">Logout</Button>
</Popup>
</Menu.Item>
</Menu.Menu>
</Menu>
</div>
);
}
......
......@@ -3,6 +3,7 @@ import { Item, Button, Grid } from 'semantic-ui-react';
import { Link } from 'react-router';
import Vacancy from './Vacancy';
import CompanyVacancy from './CompanyVacancy';
import AdminVacancy from './AdminVacancy';
import Server from '../lib/Server';
export default class VacancyList extends React.Component {
......@@ -17,6 +18,15 @@ export default class VacancyList extends React.Component {
items: [],
};
updateStatus(id, status) {
const obj = [];
this.state.vacancies.map((vacancy) => {
if (vacancy.id !== id) return obj.push(vacancy);
return null;
});
this.setState({ vacancies: obj });
}
constructor(props) {
super(props);
/* istanbul ignore next */
......@@ -27,6 +37,7 @@ export default class VacancyList extends React.Component {
loading: true,
};
this.generateVacancies = this.generateVacancies.bind(this);
this.updateStatus = this.updateStatus.bind(this);
}
deleteVacancy = id => Server.delete(`/vacancies/${id}/`, this.state).then(() => {
......@@ -53,7 +64,15 @@ export default class VacancyList extends React.Component {
),
);
}
if (this.props.user.role === 'admin' || this.props.user.role === 'supervisor'){
return this.state.vacancies.map(vacancy => (<AdminVacancy
key={vacancy.id}
data={vacancy}
updateStatus={this.updateStatus}
/>),
);
}
return this.state.vacancies.map(vacancy => (<CompanyVacancy
key={vacancy.id}
data={vacancy}
......
import React from 'react';
import { Button, Header, Modal } from 'semantic-ui-react';
export default class VerifyAdminModal extends React.Component {
state = { modalOpen: false }
handleOpen = () => this.setState({
modalOpen: true,
});
handleClose = () => this.setState({
modalOpen: false,
});
render() {
return (
<Modal
trigger={
<Button color="blue" icon="right chevron" labelPosition="right" floated="right" content="ubah" onClick={this.handleOpen} />
}
closeIcon="close"
open={this.state.modalOpen}
onClose={this.handleClose}
>
<Modal.Header>Software Engineer</Modal.Header>
<Modal.Content >
<Modal.Description>
<Header>Deskripsi Lowongan</Header>
Lorem ipsum dolor sit amet, consectetur adipiscing elit,
sed do eiusmod tempor incididunt ut labore et dolore
magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco
laboris nisi ut aliquip ex ea commodo consequat.
</Modal.Description>
</Modal.Content>
<Modal.Actions>
<Button color="green" floated="right" onClick={this.handleClose}>Verifikasi</Button>
</Modal.Actions>
</Modal>
);
}
}
......@@ -76,7 +76,10 @@ export default class App extends React.Component {
replace({ pathname: '/lowongan' }); cb();
} else if (App.getRole() === 'admin') {
replace({ pathname: '/perusahaan' }); cb();
} else if (App.getRole() === 'supervisor'){
replace({ pathname:'/lowongan'}); cb();
}
}
replace({ pathname: '/login' }); cb();
};
......@@ -84,28 +87,32 @@ export default class App extends React.Component {
render() {
const staff = this.authorization(['admin']);
const student = this.authorization(['admin', 'student']);
// const supervisor = this.authorization(['admin', 'supervisor']);
const supervisor = this.authorization(['admin', 'supervisor']);
const company = this.authorization(['admin', 'company']);
const commonUser = this.authorization(['admin', 'student', 'company']);
const grownups = this.authorization(['admin', 'company', 'supervisor']);
const facultyMember = this.authorization(['admin', 'student', 'supervisor']);
const all = this.authorization(['admin', 'company', 'supervisor', 'student']);
return (
<Router history={browserHistory}>
<Route path="/login" component={Login} />