diff --git a/assets/js/ProfilePage.jsx b/assets/js/ProfilePage.jsx index fb1fe596bcbc8ef9ec429d7b502f25dac1b9f0d8..be46addf666836b00f3494855ed3d2ebc4b1bba2 100644 --- a/assets/js/ProfilePage.jsx +++ b/assets/js/ProfilePage.jsx @@ -1,6 +1,7 @@ import React from 'react'; import { Segment, Image, Header, Icon, Checkbox, Container, Button, Form } from 'semantic-ui-react'; import Server from './lib/Server'; +import Storage from './lib/Storage'; import ModalAlert from './components/ModalAlert'; export default class ProfilePage extends React.Component { @@ -35,12 +36,14 @@ export default class ProfilePage extends React.Component { show_transcript: '', }, bagikanTranskrip: '', + refresh: 1, }; 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.gotoLink = this.gotoLink.bind(this); this.getProfile(); } @@ -60,10 +63,16 @@ export default class ProfilePage extends React.Component { phone_number: data.phone_number, photo: data.photo, show_transcript: data.show_transcript, - bagikanTranskrip: (data.show_transcript ? 'Ya' : 'Tidak'), + 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(() => { - // this.modalAlert.open('Gagal Mengambil ', r.error); this.state.name = 'Gagal mendapatkan informasi'; })); } @@ -78,9 +87,9 @@ export default class ProfilePage extends React.Component { } }); 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) => { - this.modalAlert.open('Pembaharuan profil gagal', r.error); + this.modalAlert.open('Pembaharuan profil gagal', r.detail); })); }; @@ -103,6 +112,11 @@ export default class ProfilePage extends React.Component { this.setState({ form, show_transcript: d.checked }); }; + gotoLink = (url) => { + const win = window.open(url); + win.focus(); + }; + updateForm(show) { if (show) { return ( @@ -114,7 +128,7 @@ export default class ProfilePage extends React.Component { </Header.Content> </Header> <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> <label htmlFor="photo">Profile Picture</label> <input onChange={this.handleFile} placeholder="Profile Photo.jpg" name="photo" type="File" /> @@ -134,7 +148,7 @@ export default class ProfilePage extends React.Component { <Form.Field> <Checkbox 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" name="show_transcript" /> @@ -165,19 +179,18 @@ export default class ProfilePage extends React.Component { <h5> { this.state.cityOfBirth}, { this.state.dateOfBirth } </h5> </div> <div className="button-profile"> - <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> - } + <a target="_blank" rel="noopener noreferrer" href={this.state.resume ? this.state.resume : '#'} > + <Button primary size="small">Resume</Button> + </a> </div> <div> - Bagikan Transkrip: <b>{ this.state.bagikanTranskrip }</b> + <br /> + Bagikan Transkrip: <b>{ this.state.bagikanTranskrip ? 'Ya' : 'Tidak'}</b> </div> </Container> </Segment > { this.updateForm(this.props.route.own) } </div> - ); } } diff --git a/assets/js/VacancyPage.jsx b/assets/js/VacancyPage.jsx index 3163bc8e9901d9a60de96d70d1e89f90ef81eb09..8cf923da52323fc65c4f53262ed4aa63a0ba9e4c 100644 --- a/assets/js/VacancyPage.jsx +++ b/assets/js/VacancyPage.jsx @@ -1,4 +1,5 @@ import React from 'react'; +import { Container } from 'semantic-ui-react'; import Tabs from './components/Tabs'; import Pane from './components/Pane'; import VacancyList from './components/VacancyList'; @@ -77,17 +78,20 @@ export default class VacancyPage extends React.Component { ); } else if (this.props.user.role === 'company' || this.props.user.role === 'admin') { return ( - <Pagination - url={`/companies/${this.state.id}/vacancies/`} - child={ - <VacancyList - key={1} - user={this.props.user} - userId={this.state.id} - /> - } - error="Anda belum diverifikasi. Harap hubungi admin" - /> + <Container className="vacancies"> + <Pagination + key={1} + url={`/companies/${this.state.id}/vacancies/`} + child={ + <VacancyList + key={1} + user={this.props.user} + userId={this.state.id} + /> + } + error="Anda belum diverifikasi. Harap hubungi admin" + /> + </Container> ); } diff --git a/assets/js/__test__/components/VacancyList-test.jsx b/assets/js/__test__/components/VacancyList-test.jsx index ee03b113fff1b6f9ef3e9a037a87f8c6c0ab2118..a3fdb795594a595e2e3b1bc61d53f06b2fa5360a 100644 --- a/assets/js/__test__/components/VacancyList-test.jsx +++ b/assets/js/__test__/components/VacancyList-test.jsx @@ -316,6 +316,7 @@ describe('VacancyList', () => { it('fails delete vacancy', () => { fetchMock.restore(); fetchMock.delete('*', 404); + fetchMock.get('*', response2); const vacancyList = ReactTestUtils.renderIntoDocument( <VacancyList userId={1} items={newResponse} user={companyUser} deleteCallback={() => {}} />, ); diff --git a/assets/js/components/ApplyModal.jsx b/assets/js/components/ApplyModal.jsx index 68ad74796e32ca3012f2db4a15280dbdfecbe569..0fb1af1126d9caa8317b2aec2e7c8848821c21b2 100644 --- a/assets/js/components/ApplyModal.jsx +++ b/assets/js/components/ApplyModal.jsx @@ -1,5 +1,5 @@ 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 Server from './../lib/Server'; @@ -49,7 +49,7 @@ export default class ApplyModal extends React.Component { ); }; - render(){ + render() { return ( <Modal trigger={<Button primary onClick={this.handleOpen} floated="right">{this.props.buttonTitle}</Button>} @@ -62,13 +62,21 @@ export default class ApplyModal extends React.Component { <ModalAlert ref={(modal) => { this.modalAlert = modal; }} /> <Modal.Description> <Modal.Header> <h3> Deskripsi Lowongan </h3></Modal.Header> - { <div dangerouslySetInnerHTML={{__html: this.props.data.description }} /> } + { <div dangerouslySetInnerHTML={{ __html: this.props.data.description }} /> } </Modal.Description> {this.props.active && ( <div className="coverLetter"> <br /> <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> <br /> <div> @@ -78,8 +86,7 @@ export default class ApplyModal extends React.Component { </Form> </div> </div> - )} - + )} </Modal.Content> <Modal.Actions> <Button loading={this.state.load} color="blue" disabled={!this.props.active} onClick={this.handleApply}> diff --git a/assets/js/components/ApproveModal.jsx b/assets/js/components/ApproveModal.jsx index 132083a6b9dcaa27338a0b8c8e95b4af37f310a4..fa04bed2af8c90b015b45b1f7e0fdcf7780b5bea 100644 --- a/assets/js/components/ApproveModal.jsx +++ b/assets/js/components/ApproveModal.jsx @@ -1,5 +1,5 @@ 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 ConfirmationModal from './../components/ConfirmationModal'; import Applicant from './../components/Applicant'; @@ -21,6 +21,7 @@ export default class ApproveModal extends React.Component { this.handleOpen = this.handleOpen.bind(this); this.reject = this.reject.bind(this); this.accept = this.accept.bind(this); + this.gotoStudentProfile = this.gotoStudentProfile.bind(this); this.gotoStudentResume = this.gotoStudentResume.bind(this); this.gotoStudentTranscript = this.gotoStudentTranscript.bind(this); } @@ -69,6 +70,8 @@ export default class ApproveModal extends React.Component { gotoStudentTranscript = () => this.gotoLink(`/transcript/${this.props.data.id}`); + gotoStudentProfile = () => this.gotoLink(`/mahasiswa/${this.props.data.student.id}`); + accept = () => { this.modal.open( 'Terima Lamaran?', @@ -89,15 +92,25 @@ export default class ApproveModal extends React.Component { <Modal.Header>Data Lamaran</Modal.Header> <Modal.Content> <h4> Cover Letter </h4> - { this.props.data.cover_letter ? this.props.data.cover_letter : 'Kosong' } - <div style={{ float: 'right', textAlign: 'right' }}> - {this.props.data.student.resume ? <a onClick={this.gotoStudentResume} href="#" >CV Pelamar </a> : ''} - <br /> - {this.props.data.student.show_transcript ? <a onClick={this.gotoStudentTranscript} href="#" >Transkrip Pelamar</a> : ''} - <br /> + <Segment> + <p> + { this.props.data.cover_letter ? this.props.data.cover_letter : 'Kosong' } + </p> + </Segment> + <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> </Modal.Content> <Modal.Actions> + <Button color="facebook" onClick={this.gotoStudentProfile} floated="left" > + <Icon name="user outline" /> Lihat Profil + </Button> <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 /> diff --git a/assets/js/components/CompanyVacancy.jsx b/assets/js/components/CompanyVacancy.jsx index 8ff71d10692b46767974fb15ae97d2c61abdb424..d935ff7f095833e41d76aa6b9319edd30bab50d0 100644 --- a/assets/js/components/CompanyVacancy.jsx +++ b/assets/js/components/CompanyVacancy.jsx @@ -2,6 +2,7 @@ import React from 'react'; import moment from 'moment'; import { Button, Icon, Item, Grid } from 'semantic-ui-react'; import { Link } from 'react-router'; +import Server from '../lib/Server'; const defaultImage = 'http://semantic-ui.com/images/wireframe/image.png'; @@ -15,8 +16,12 @@ export default class CompanyVacancy extends React.Component { constructor(props) { super(props); + /* istanbul ignore next */ 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}`; @@ -25,12 +30,13 @@ export default class CompanyVacancy extends React.Component { return ( <Item className="applicantItems"> <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> <Grid.Row> <Grid.Column floated="left"> - <h5> 105 Pendaftar </h5> - Ditutup {moment(moment(this.props.data.close_time)).fromNow()} + <p>{ this.state.count } Pendaftar<br/> + { this.state.countNew } Pendaftar Baru<br/><br/> + Ditutup {moment(moment(this.props.data.close_time)).fromNow()}</p> </Grid.Column> <Grid.Column floated="right"> {this.props.data.verified ?