Fakultas Ilmu Komputer UI

Commit 2ec7d73c authored by M. Reza Qorib's avatar M. Reza Qorib
Browse files

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

# Conflicts:
#	assets/css/custom.css
#	assets/js/components/VacancyList.jsx
#	assets/js/index.jsx
parents f23f0f80 18f64d25
......@@ -169,6 +169,10 @@ card .formRegis{
line-height: 30%;
}
.biodata-company h4{
color: grey;
}
.button-profile{
margin-top:30px;
}
......@@ -202,4 +206,31 @@ card .formRegis{
.footer h5{
color:white;
}
\ No newline at end of file
}
.profilePage{
margin-bottom:40px;
margin-left:5%;
margin-right:5%;
}
.ui.segment.segment-profile-company{
margin-left: 10%;
margin-right: 10%;
padding: 5%;
}
.ui.segment.profile-form-company{
margin-top:4%;
margin-left: 10%;
margin-right: 10%;
padding-bottom:3%;
}
.company-profile{
padding-bottom:5%;
}
.ui.segment.vacancyList-company{
margin-left: 10%;
margin-right: 10%;
}
import React from 'react';
import { Segment, Header, Image, Container, Form, Button, Icon, TextArea } from 'semantic-ui-react';
export default class CompanyProfile extends React.Component {
render() {
return (
<div className="company-profile">
<Segment className="segment-profile-company" >
<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-company">
<h2>Company</h2>
<h3>Alamat alamat alamat</h3>
<h4>Deskripsi Deskripsi Deskripsi Deskripsi Deskripsi Deskripsi</h4>
</div>
</Container>
</Segment>
<Segment className="profile-form-company">
<Header as="h3" textAlign="center">
<Icon name="edit" />
<Header.Content>
Edit Profile Page
</Header.Content>
</Header>
<Form size="small" >
<Form.Field>
<label htmlFor="photo">Logo Perusahaan</label>
<input placeholder="Profile Photo.jpg" name="photo" type="File" />
</Form.Field>
<Form.Field>
<label htmlFor="email">Nama Perusahaan</label>
<input placeholder="Nama Perusahaan" name="email" />
</Form.Field>
<Form.Field>
<label htmlFor="phone">Deskripsi</label>
<TextArea placeholder='Try adding multiple lines' autoHeight />
</Form.Field>
<Button type="submit" size="small" primary floated="right">Submit</Button>
</Form>
</Segment>
</div>
);
}
}
import React from 'react';
import { Segment, Image, Header, Icon, 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 ModalAlert from './components/ModalAlert';
export default class ProfilePage extends React.Component {
static propTypes = {
route: React.PropTypes.object.isRequired,
params: React.PropTypes.object.isRequired,
user: React.PropTypes.object.isRequired,
};
constructor(props) {
......@@ -22,55 +24,85 @@ export default class ProfilePage extends React.Component {
cityOfBirth: '',
dateOfBirth: '',
resume: '',
phone: '',
showTranscript: '',
phone_number: '',
show_transcript: '',
photo: '',
form: {
picture: '',
email: '',
phone_number: '',
resume: '',
show_transcript: '',
},
bagikanTranskrip: '',
};
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.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(() => {
const id = this.props.route.own ? this.props.user.data.student.id : this.props.params.id;
return Server.get(`/students/${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_number: data.phone_number,
photo: data.photo,
show_transcript: data.show_transcript,
bagikanTranskrip: (data.show_transcript ? 'Ya' : 'Tidak'),
});
}, error => error.then(() => {
// this.modalAlert.open('Gagal Mengambil ', r.error);
this.state.name = 'Gagal mendapatkan informasi';
}));
}
this.state.name = 'Gagal mendapatkan informasi';
}));
}
handleSubmit = (e) => {
e.preventDefault();
const submitForm = {};
console.log(this.state.form);
Object.keys(this.state.form).forEach((key) => {
if (this.state.form[key] !== '') {
submitForm[key] = this.state.form[key];
}
});
console.log(submitForm);
Server.submit(`/profiles/students/${this.state.id}/`, submitForm, 'PATCH').then(() => {
this.modalAlert.open('Profil berhasil diperbaharui', 'Silakan periksa kembali profil anda' );
}, error => error.then((r) => {
this.modalAlert.open('Pembaharuan profil gagal', r.error);
}));
};
handleFile = (e) => {
const form = this.state.form;
form[e.target.name] = e.target.files[0];
this.setState({ form });
}
handleChange = (e) => {
this.setState({ [e.target.name]: e.target.value });
const form = this.state.form;
form[e.target.name] = e.target.value;
this.setState({ form });
};
handleCheckbox = (e, d) => {
const form = this.state.form;
form[d.name] = d.checked;
this.setState({ form, show_transcript: d.checked });
};
updateForm(show) {
......@@ -83,22 +115,31 @@ export default class ProfilePage extends React.Component {
Edit Profile Page
</Header.Content>
</Header>
<ModalAlert ref={(modal) => { this.modalAlert = modal; }} />
<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" />
<input onChange={this.handleFile} 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" />
<label htmlFor="phone_number">No. Hp</label>
<input onChange={this.handleChange} placeholder="08123456789" name="phone_number" />
</Form.Field>
<Form.Field>
<label htmlFor="resume">Resume</label>
<input onChange={this.handleChange} placeholder="Resume" name="resume" type="File" />
<input onChange={this.handleFile} placeholder="Resume" name="resume" type="File" />
</Form.Field>
<Form.Field>
<Checkbox
onChange={this.handleCheckbox}
checked={ this.state.show_transcript ? true : false }
label="Ijinkan perusahaan tempat saya mendaftar untuk melihat transkrip akademik saya"
name="show_transcript"
/>
</Form.Field>
<Button type="submit" size="small" primary floated="right">Submit</Button>
</Form>
......@@ -110,23 +151,29 @@ export default class ProfilePage extends React.Component {
}
render() {
const defaultPicture = 'http://semantic-ui.com/images/wireframe/square-image.png';
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" />
<Image src={this.state.photo ? this.state.photo : defaultPicture} 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.phone_number } </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 /> }
<a href={this.state.resume ? this.state.resume : '#'} ><Button primary size="small">Resume</Button></a>
{ this.state.show_transcript &&
<Button primary size="small">Transkrip</Button>
}
</div>
<div>
Bagikan Transkrip: <b>{ this.state.bagikanTranskrip }</b>
</div>
</Container>
</Segment >
......
import React from 'react';
import ReactTestUtils from 'react-addons-test-utils';
import CompanyProfile from '../CompanyProfile';
describe('CompanyProfile', () => {
it('renders without problem', () => {
const companyProfile = ReactTestUtils.renderIntoDocument(
<CompanyProfile />);
expect(companyProfile).to.exist;
});
});
......@@ -42,14 +42,32 @@ describe('ProfilePage', () => {
},
};
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 companyUser = {
role: 'company',
data: {
url: 'http://localhost:8001/api/users/8/',
username: 'Tutuplapak',
email: '',
is_staff: false,
company: {
id: 3,
user: {
url: 'http://localhost:8001/api/users/8/',
username: 'Tutuplapak',
email: '',
is_staff: false,
},
name: 'Tutuplapak',
created: '2017-03-28T07:30:10.535000Z',
updated: '2017-03-28T07:30:10.535000Z',
description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla aliquet semper neque a fermentum. Duis ac tellus vitae augue iaculis ultrices. Curabitur commodo et neque nec feugiat. Morbi ac diam vel nunc commodo cursus. Phasellus nulla sapien, hendrerit vitae bibendum at, sollicitudin eu ante. Maecenas maximus, ante eu sollicitudin convallis, mauris nunc posuere risus, eu porttitor diam lacus vitae enim. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Suspendisse at lectus a elit sollicitudin tempor. Nullam condimentum, justo nec tincidunt maximus, neque mi vulputate leo, sit amet lacinia massa ex eget sem. Duis ac erat facilisis, fringilla mauris in, consequat neque. In et neque consequat, vehicula magna at, efficitur ante. Mauris ac lacinia nibh.\r\n\r\nProin sagittis, lectus quis maximus varius, libero justo sollicitudin augue, non lacinia risus orci a enim. Curabitur iaculis enim quis ullamcorper commodo. Vivamus id nisi rhoncus, dignissim tellus quis, interdum est. Fusce sollicitudin eu libero ac feugiat. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Maecenas semper posuere ex, sed accumsan libero iaculis faucibus. Fusce laoreet ac ligula ut consectetur. Donec tortor mauris, rutrum at sodales et, viverra in dolor. Sed bibendum elit et maximus volutpat. Phasellus justo ipsum, laoreet sit amet faucibus eu, ultricies suscipit mauris. Nullam aliquam libero eu ante ultrices mattis. Donec non justo hendrerit neque volutpat placerat. Ut euismod est nec sem mollis, sit amet porttitor massa rhoncus. Aenean id erat sit amet nunc ultrices scelerisque non in ipsum. Curabitur sollicitudin nulla id mi accumsan venenatis.',
verified: true,
logo: 'http://localhost:8001/files/company-logo/8a258a48-3bce-4873-b5d1-538b360d0059.png',
address: 'Jl. Kebayoran Baru nomor 13, Jakarta Barat',
},
supervisor: null,
student: null,
},
};
const response = {
......@@ -66,29 +84,133 @@ describe('ProfilePage', () => {
phone_number: null,
birth_place: null,
birth_date: null,
photo: 'dor',
major: null,
batch: null,
show_transcript: false,
};
const response2 = {
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: true,
};
it('renders without problem', () => {
fetchMock.get('*', response);
const profile = ReactTestUtils.renderIntoDocument(
<ProfilePage route={{ own: true, data: studentSession }} params={{}} />);
expect(profile.state.name).to.equal(studentSession.student.name);
<ProfilePage route={{ own: true, data: studentSession }} user={{ data: studentSession }} params={{}} />);
profile.getProfile().then(()=> expect(profile.state.name).to.equal(response.name));
profile.updateForm(true);
fetchMock.restore();
});
it('get profile for company without problem', () => {
fetchMock.get('*', response);
const profile = ReactTestUtils.renderIntoDocument(
<ProfilePage route={{ own: false, data: studentSession }} params={{ id: 3 }} />);
<ProfilePage route={{ own: false, data: studentSession }} user={{ data: companyUser }} params={{ id: 3 }} />);
profile.getProfile().then(()=> expect(profile.state.name).to.equal(response.name));
fetchMock.restore();
});
it('get profile for company without problem', () => {
fetchMock.get('*', response2);
const profile = ReactTestUtils.renderIntoDocument(
<ProfilePage route={{ own: false, data: studentSession }} user={{ data: companyUser }} params={{ id: 3 }} />);
profile.getProfile().then(()=> expect(profile.state.name).to.equal(response2.name));
fetchMock.restore();
});
it('show/hide transcript without problem', () => {
fetchMock.get('*', response2);
const profile = ReactTestUtils.renderIntoDocument(
<ProfilePage route={{ own: true, data: studentSession }} user={{ data: studentSession }} params={{ id: 3 }} />);
const checkboxNode = ReactTestUtils.scryRenderedDOMComponentsWithTag(profile, 'Input')[4];
const checkbox = false;
checkboxNode.value = checkbox;
profile.getProfile().then(()=> expect(profile.state.show_transcript).to.equal(true));
profile.handleCheckbox({name: 'show_transcript', value: checkbox}, {name: 'show_transcript', checked: false});
// ReactTestUtils.Simulate.change(checkboxNode, { target: {name: 'show_transcript', value: checkbox} }, {name: 'show_transcript', checked: false});
expect(profile.state.form.show_transcript).to.equal(false);
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 }} />);
<ProfilePage route={{ own: false, data: studentSession }} user={{ data: studentSession }} params={{ id: 3 }} />);
profile.getProfile().then(()=> expect(profile.state.name).to.equal('Gagal mendapatkan informasi'));
});
it('submit form without problem', () => {
fetchMock.patch('*', { data: 'value' });
const profile = ReactTestUtils.renderIntoDocument(
<ProfilePage route={{ own: true, data: studentSession }} user={{ data: studentSession }} params={{ id: 3 }} />);
profile.state.form = {name: 'abra', email:''};
const submitButton = ReactTestUtils.scryRenderedDOMComponentsWithTag(profile, 'Input')[1];
ReactTestUtils.Simulate.click(submitButton);
const form = ReactTestUtils.findRenderedDOMComponentWithTag(profile, 'Form');
ReactTestUtils.Simulate.submit(form);
fetchMock.restore();
});
it('render without problem when submit file error', () => {
fetchMock.patch('*', 400);
fetchMock.get('*', response);
const profile = ReactTestUtils.renderIntoDocument(
<ProfilePage route={{ own: true, data: studentSession }} user={{ data: studentSession }} params={{ id: 3 }} />);
profile.state.form = {name: 'abra', email:''};
const submitButton = ReactTestUtils.scryRenderedDOMComponentsWithTag(profile, 'Input')[1];
ReactTestUtils.Simulate.click(submitButton);
const form = ReactTestUtils.findRenderedDOMComponentWithTag(profile, 'Form');
ReactTestUtils.Simulate.submit(form);
fetchMock.restore();
});
it('handle email input without problem', () => {
fetchMock.patch('*', { data: 'value' });
fetchMock.get('*', response);
const profile = ReactTestUtils.renderIntoDocument(
<ProfilePage route={{ own: true, data: studentSession }} user={{ data: studentSession }} params={{ id: 3 }} />);
const emailNode = ReactTestUtils.scryRenderedDOMComponentsWithTag(profile, 'Input')[1];
// const passwordNode = ReactDOM.findDOMNode(formLogin.refs.password);
const password = 'passwd';
emailNode.value = password;
expect(profile.state.form.email).to.equal('');
ReactTestUtils.Simulate.change(emailNode, { target: { value: password } });
expect(emailNode.value).to.equal(password);
});
it('handle file input without problem', () => {
fetchMock.patch('*', { data: 'value' });
fetchMock.get('*', response);
const profile = ReactTestUtils.renderIntoDocument(
<ProfilePage route={{ own: true, data: studentSession }} user={{ data: studentSession }} params={{ id: 3 }} />);
const emailNode = ReactTestUtils.scryRenderedDOMComponentsWithTag(profile, 'Input')[0];
// const passwordNode = ReactDOM.findDOMNode(formLogin.refs.password);
profile.handleFile({ target: { name: 'photo', files: ['abc', 'def'] } });
expect(profile.state.form.photo).to.equal('abc');
});
});
......@@ -37,6 +37,23 @@ describe('CompanyVacancy', () => {
verified: true,
};
const response3 = {
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,
};
it('renders with logo without problem', () => {
const companyVacancy = ReactTestUtils.renderIntoDocument(
<CompanyVacancy data={response2} />);
......@@ -49,6 +66,12 @@ describe('CompanyVacancy', () => {
expect(companyVacancy).to.exist;
});
it('renders without logo for unverified company without problem', () => {
const companyVacancy = ReactTestUtils.renderIntoDocument(
<CompanyVacancy data={response3} />);
expect(companyVacancy).to.exist;
});
it('loads when delete button clicked', () => {
const companyVacancy = ReactTestUtils.renderIntoDocument(
<CompanyVacancy data={response} />);
......
......@@ -20,6 +20,21 @@ describe('VacancyList', () => {
open_time: '2017-03-28T05:55:38Z',
updated: '2017-03-28T07:34:13.122093Z',
verified: true,
}, {
close_time: '2019-03-28T05:55:42Z',
company: {
address: 'kebayoran baru',
id: 2,
logo: null,
name: 'tutup lapak',
},
created: '2017-03-28T07:05:47.128672Z',
description: 'Lorem ipsum dolbh.',
id: 2,
name: 'Software Engineer',
open_time: '2017-03-28T05:55:38Z',
updated: '2017-03-28T07:34:13.122093Z',
verified: true,
}];
const response2 = [{
......@@ -57,6 +72,16 @@ describe('VacancyList', () => {
});
it('update bookmarks without problem', () => {
fetchMock.get('*', response);
const vacancyList = ReactTestUtils.renderIntoDocument(
<VacancyList userId={1} url="test" />);
vacancyList.state.appliedList = [{id:1},{id:3}];
vacancyList.updateStatusList();
expect(JSON.stringify(vacancyList.state.bookmarkList)).to.be.defined;
fetchMock.restore();
});
it('check applied vacancies without problem', () => {
fetchMock.get('*', response);
const vacancyList = ReactTestUtils.renderIntoDocument(
<VacancyList userId={1} url="test" />);
......
......@@ -101,7 +101,7 @@ export default class CompanyRegisterModal extends React.Component {
</Form>
</Modal.Content>
<Modal.Actions>
<Button type="submit" color="blue"> <Icon name="checkmark" />Submit</Button>
<Button type="submit" onClick={this.handleSubmit} color="blue"> <Icon name="checkmark" />Submit</Button>
</Modal.Actions>
</Modal>
)
......