diff --git a/assets/css/custom.css b/assets/css/custom.css
index f5b59c908209b13be408864b6fe0780710cacbe9..dd58a6f20a3488b6331047171258937fef54530e 100755
--- a/assets/css/custom.css
+++ b/assets/css/custom.css
@@ -13,13 +13,19 @@
   color:black;
 }
 
+.item-list {
+  word-wrap: break-word;
+  width: 100%;
+}
 
 .ui.card.register{
 background-color: #EEEEEE;
 }
 
 .create-lowongan{
-  margin: 60px 19% 100px;
+padding-bottom: 7%;
+padding-left:15%;
+padding-right:15%;
 }
 
 .ui.segment.form-segment{
@@ -30,7 +36,7 @@ background-color: #EEEEEE;
   background: #fff;
   border: 1px solid #e5e5e5;
   border-radius: 3px;
-  margin: 100px 100px 30px;
+  margin: 80px 100px 30px;
 }
 .tabs__labels {
   margin: 0;
@@ -69,8 +75,8 @@ background-color: #EEEEEE;
 }
 
 .formLogin{
-  margin: 30px auto 0;
-  width: 430px;
+  /*margin: auto;*/
+  /*width: 430px;*/
 }
 
 .registerModal{
@@ -106,18 +112,6 @@ font-size: 32px;
   margin-top:10px;
 }
 
-.coverLetter{
-  margin-top:30px;
-
-}
-
-.linkCV{
-  float: right;
-  margin-top: 30px;
-  margin-bottom: 10px;
-}
-
-
 .registerForm{
   margin: 0 auto;
   /*padding:50px;*/
@@ -165,6 +159,8 @@ card .formRegis{
 
 .ui.pointing.secondary.menu{
   background-color: #ffffff;
+  margin-bottom: 10px;
+  margin-top: 0px;
 }
 
 .extra.extra-company h3{
@@ -192,6 +188,34 @@ card .formRegis{
   margin-top:4%;
 }
 
+.profilePage {
+  margin-bottom: 40px;
+  margin-left: 5%;
+  margin-right: 5%;
+}
+
+#react-app{
+ position: relative; /* needed for footer positioning*/
+ height: auto !important; /* real browsers */
+ min-height: 100%; /* real browsers */
+ background-color: #EEEEEE;
+}
+
+.content{
+  padding-bottom: 5%;
+}
+
+.footer{
+ background-color: #031634;
+ position: absolute;
+ bottom: 0;
+ width: 100%;
+ padding: 1%;
+}
+
+.footer h5{
+  color:white;
+}
 .profilePage{
   margin-bottom:40px;
   margin-left:5%;
@@ -220,3 +244,12 @@ card .formRegis{
   margin-right: 10%;
 }
 
+.admin-bar{
+  margin: 0;
+  padding: 0 10px 0 0;
+  width: 100%;
+  text-align: right;
+  background-color: #304D8A;
+  color: white;
+}
+
diff --git a/assets/js/ApplicantPage.jsx b/assets/js/ApplicantPage.jsx
index 51334b1d73700944632bff36164b92e0c7e7e650..761fad8d8ab3716e3045dcdb4f5d210884becd11 100644
--- a/assets/js/ApplicantPage.jsx
+++ b/assets/js/ApplicantPage.jsx
@@ -1,10 +1,14 @@
 import React from 'react';
 import Tabs from './components/Tabs';
-import Pane from './components/Pane';
-import Storage from './lib/Storage';
-import VacancyList from './components/VacancyList';
+import ApplicantList from './components/ApplicantList';
+import Applicant from './components/Applicant';
+import Pagination from './components/Pagination';
 
-export default class VacancyPage extends React.Component {
+export default class ApplicantPage extends React.Component {
+
+  static propTypes = {
+    user: React.PropTypes.object.isRequired,
+  };
 
   constructor(props) {
     super(props);
@@ -13,31 +17,58 @@ export default class VacancyPage extends React.Component {
       email: '',
       password: '',
       errorFlag: false,
-      vacancies: [],
+      company: { id: 1 },
     };
-    this.handleItemClick = this.handleItemClick.bind(this);
   }
 
-  handleItemClick = (e, { name }) => this.setState({ activeItem: name });
-
   render() {
-    const student = Storage.get('user-data').student;
+    const company = this.props.user.data.company;
     return (
-  <div className="halamanPendaftar">
       <Tabs selected={0}>
-        <Pane label="Lamaran Baru" >
-          <VacancyList key={1} studentId={student.id}  url="/vacancies/" />
-        </Pane>
-        <Pane label="Bintangi" >
-          <VacancyList key={2} status="Batal" studentId={student.id} url={`/students/${student.id}/applied-vacancies/`} />
-        </Pane>
-        <Pane label="Semua Lamaran" >
-          <VacancyList key={3} studentId={student.id}  url={`/students/${student.id}/bookmarked-vacancies/`} />
-        </Pane>
+        <Pagination
+          key={1}
+          url={`/companies/${company.id}/applications/?status=${Applicant.APPLICATION_STATUS.NEW}`}
+          label="Lamaran Baru"
+          child={
+            <ApplicantList companyId={company.id} status={Applicant.APPLICATION_STATUS.NEW} />
+          }
+        />
+        <Pagination
+          key={2}
+          url={`/companies/${company.id}/applications/?status=${Applicant.APPLICATION_STATUS.READ}`}
+          label="Lamaran Dibaca"
+          child={
+            <ApplicantList companyId={company.id} status={Applicant.APPLICATION_STATUS.READ} />
+          }
+        />
+        <Pagination
+          key={3}
+          url={`/companies/${company.id}/applications/?status=${Applicant.APPLICATION_STATUS.BOOKMARKED}`}
+          label="Lamaran Ditandai"
+          child={
+            <ApplicantList
+              companyId={company.id}
+              status={Applicant.APPLICATION_STATUS.BOOKMARKED}
+            />
+          }
+        />
+        <Pagination
+          key={4}
+          url={`/companies/${company.id}/applications/?status=${Applicant.APPLICATION_STATUS.ACCEPTED}`}
+          label="Lamaran Diterima"
+          child={
+            <ApplicantList companyId={company.id} status={Applicant.APPLICATION_STATUS.ACCEPTED} />
+          }
+        />
+        <Pagination
+          key={5}
+          url={`/companies/${company.id}/applications/?status=${Applicant.APPLICATION_STATUS.REJECTED}`}
+          label="Lamaran Ditolak"
+          child={
+            <ApplicantList companyId={company.id} status={Applicant.APPLICATION_STATUS.REJECTED} />
+          }
+        />
       </Tabs>
-
-  </div>
-
     );
   }
 }
diff --git a/assets/js/CompanyPage.jsx b/assets/js/CompanyPage.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..f84648e8a271500e97b6051dcfff4aa1cdeaf1a0
--- /dev/null
+++ b/assets/js/CompanyPage.jsx
@@ -0,0 +1,65 @@
+import React from 'react';
+import { Button } from 'semantic-ui-react';
+import Tabs from './components/Tabs';
+import CompanyList from './components/CompanyList';
+import Company from './components/Company';
+import Pagination from './components/Pagination';
+
+export default class CompanyPage extends React.Component {
+
+  static propTypes = {
+    user: React.PropTypes.object.isRequired,
+  };
+
+  handleClick = () => window.open('/admin/');
+  handleVacancy = () => window.open('/lowongan');
+
+  render() {
+    return (
+      <div>
+        <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}
+            url={`/companies/?status=${Company.COMPANY_STATUS.NEW}`}
+            label="Baru"
+            child={
+              <CompanyList status={Company.COMPANY_STATUS.NEW} />
+            }
+          />
+          <Pagination
+            key={2}
+            url={`/companies/?status=${Company.COMPANY_STATUS.VERIFIED}`}
+            label="Terverifikasi"
+            child={
+              <CompanyList status={Company.COMPANY_STATUS.VERIFIED} />
+            }
+          />
+          <Pagination
+            key={3}
+            url={`/companies/?status=${Company.COMPANY_STATUS.UNVERIFIED}`}
+            label="Ditolak"
+            child={
+              <CompanyList status={Company.COMPANY_STATUS.UNVERIFIED} />
+            }
+          />
+          <Pagination
+            key={4}
+            url={'/companies/'}
+            label="Semua Perusahaan"
+            child={
+              <CompanyList status={Company.COMPANY_STATUS.ALL} />
+            }
+          />
+        </Tabs>
+      </div>
+    );
+  }
+}
diff --git a/assets/js/CreateVacancy.jsx b/assets/js/CreateVacancy.jsx
index e5015d6ff56edaa2b97e3b7ab0ab69f6b590368d..7fbf853fbc6abfee5999bfb9c9896dbbbb8c377f 100644
--- a/assets/js/CreateVacancy.jsx
+++ b/assets/js/CreateVacancy.jsx
@@ -5,13 +5,13 @@ import DatePicker from 'react-datepicker';
 import moment from 'moment';
 import ModalAlert from './components/ModalAlert';
 import Server from './lib/Server';
-import Storage from './lib/Storage';
 import Dumper from './lib/Dumper';
 
 export default class CreateVacancy extends React.Component {
 
   static propTypes = {
     params: React.PropTypes.object.isRequired,
+    user: React.PropTypes.object.isRequired,
   };
 
   constructor(props) {
@@ -19,10 +19,12 @@ export default class CreateVacancy extends React.Component {
     /* istanbul ignore next */
     this.handleChange = this.handleChange.bind(this);
     this.handleSubmit = this.handleSubmit.bind(this);
+    this.setCloseTime = this.setCloseTime.bind(this);
+    this.setOpenTime = this.setOpenTime.bind(this);
 
     this.state = {
       formLoading: false,
-      company: Storage.get('user-data').company,
+      company: this.props.user.data.company,
       vacancyId: this.props.params.id,
       open_time: moment(),
       close_time: moment(),
@@ -40,6 +42,14 @@ export default class CreateVacancy extends React.Component {
     });
   }
 
+  setOpenTime(date) {
+    this.setState({ open_time: date });
+  }
+
+  setCloseTime(date) {
+    this.setState({ close_time: date });
+  }
+
   handleChange = (e) => {
     this.setState({ [e.target.name]: e.target.value });
   };
@@ -59,7 +69,7 @@ export default class CreateVacancy extends React.Component {
     Server.sendRequest(url, method, data).then(() => {
       browserHistory.push('/lowongan');
     }, error => error.then((r) => {
-      this.modalAlert.open('Gagal Membuat Lowongan', Dumper.dump(r, '    '));
+      this.modalAlert.open('Gagal Membuat Lowongan', r.detail);
       this.setState({ formLoading: false });
     }));
   };
@@ -89,7 +99,7 @@ export default class CreateVacancy extends React.Component {
               control={DatePicker}
               label="Waktu Buka Lowongan"
               selected={this.state.open_time}
-              onChange={date => this.setState({ open_time: date })}
+              onChange={this.setOpenTime}
               required
             />
             <Form.Field
@@ -97,7 +107,7 @@ export default class CreateVacancy extends React.Component {
               control={DatePicker}
               label="Waktu Tutup Lowongan"
               selected={this.state.close_time}
-              onChange={date => this.setState({ close_time: date })}
+              onChange={this.setCloseTime}
               required
             />
           </Form.Group>
diff --git a/assets/js/Dashboard.jsx b/assets/js/Dashboard.jsx
index 79da3a19515e7c794cd9e7dca00c550d2e14cdad..3b8eb83ec352cbfb3fae57b8cba39d2ecdd024bc 100755
--- a/assets/js/Dashboard.jsx
+++ b/assets/js/Dashboard.jsx
@@ -1,9 +1,7 @@
 import React from 'react';
 import TopMenu from './components/TopMenu';
 import Server from './lib/Server';
-
-
-const defaultPicture = 'http://semantic-ui.com/images/avatar/small/elliot.jpg';
+import Footer from './components/Footer';
 
 export default class Dashboard extends React.Component {
   static propTypes = {
@@ -14,44 +12,19 @@ export default class Dashboard extends React.Component {
       React.PropTypes.arrayOf(React.PropTypes.node),
       React.PropTypes.node,
     ]).isRequired,
+    user: React.PropTypes.object.isRequired,
   };
 
   constructor(props) {
     super(props);
     /* istanbul ignore next */
-    this.state = {
-      id: '',
-      name: '',
-      email: '',
-      photo: '',
-    };
-    this.getProfile = this.getProfile.bind(this);
-    this.getProfile();
   }
 
-  getProfile() {
-    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,
-        email: data.user.email,
-        photo: data.photo,
-      });
-    }, error => error.then(() => {
-        // this.modalAlert.open('Gagal Mengambil ', r.error);
-      this.state.name = 'Gagal mendapatkan informasi';
-    }));
-  }
-
-
   render = () => (
     <div>
-      <TopMenu
-        name={this.state.name} email={this.state.email}
-        photo={this.state.photo ? this.state.photo : defaultPicture}
-      />
-      {this.props.children}
+      <TopMenu user={this.props.user} />
+      <div className="content"> {this.props.children} </div>
+      <Footer />
     </div>
   )
 }
diff --git a/assets/js/Login.jsx b/assets/js/Login.jsx
index 0065df988f8b5d93448959b78db5714a2e522a5f..badba59f85f55c8d1dc649af136186fe71b33d44 100644
--- a/assets/js/Login.jsx
+++ b/assets/js/Login.jsx
@@ -2,6 +2,7 @@ import React from 'react';
 import { Grid, Segment, Header, Card, Image } from 'semantic-ui-react';
 import LoginForm from './components/LoginForm';
 import CompanyRegisterModal from './components/CompanyRegisterModal';
+import Footer from './components/Footer';
 
 export default class Login extends React.Component {
 
@@ -27,8 +28,15 @@ export default class Login extends React.Component {
         </Header>
       </div>
 
-      <Grid stackable columns={2} relaxed>
-        <Grid.Column>
+      <Grid stackable={true} columns={2} padded style={{ display: 'flex', justifyContent: 'center' }}>
+        <Grid.Column width="seven">
+          <Segment basic>
+            <LoginForm type="sso-ui" header="SSO Login" imgSrc="UI.png" imgSize="tiny" />
+            {this.props.children}
+          </Segment>
+        </Grid.Column>
+
+        <Grid.Column width="seven">
           <Segment basic>
             <LoginForm type="company" header="Company Login" imgSrc="logo.png" imgSize="small" />
             {this.props.children}
@@ -49,14 +57,8 @@ export default class Login extends React.Component {
             </Card>
           </div>
         </Grid.Column>
-
-        <Grid.Column>
-          <Segment basic>
-            <LoginForm type="sso-ui" header="SSO Login" imgSrc="UI.png" imgSize="tiny" />
-            {this.props.children}
-          </Segment>
-        </Grid.Column>
       </Grid>
+      <Footer />
     </div>
   )
 }
diff --git a/assets/js/ProfilePage.jsx b/assets/js/ProfilePage.jsx
index 721c6cb9fb898d262d7f531a5ccd6d348da23701..fb1fe596bcbc8ef9ec429d7b502f25dac1b9f0d8 100644
--- a/assets/js/ProfilePage.jsx
+++ b/assets/js/ProfilePage.jsx
@@ -72,13 +72,11 @@ export default class ProfilePage extends React.Component {
     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) => {
@@ -91,7 +89,7 @@ export default class ProfilePage extends React.Component {
     const form = this.state.form;
     form[e.target.name] = e.target.files[0];
     this.setState({ form });
-  }
+  };
 
   handleChange = (e) => {
     const form = this.state.form;
diff --git a/assets/js/TranscriptPage.jsx b/assets/js/TranscriptPage.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..eeacde8a6a3474fecbec47ebee506f0e394d4708
--- /dev/null
+++ b/assets/js/TranscriptPage.jsx
@@ -0,0 +1,22 @@
+import React from 'react';
+import CourseList from './components/CourseList';
+import Server from './lib/Server';
+
+export default class TranscriptPage extends React.Component {
+  static propTypes = {
+    params: React.PropTypes.object.isRequired,
+  };
+
+  constructor(props) {
+    super(props);
+    /* istanbul ignore next */
+    this.state = {};
+    Server.get(`/applications/${this.props.params.id}/`).then(response => this.setState({ data: response }));
+  }
+
+  render() {
+    return (
+      this.state.data ? <CourseList data={this.state.data} /> : <h5 style={{ textAlign: 'center' }}> Mohon Tunggu.. </h5>
+    );
+  }
+}
diff --git a/assets/js/VacancyPage.jsx b/assets/js/VacancyPage.jsx
index be611e968189bd7ee1c3f4e4ddb7bc01087e746c..1110c966de08c3041a6e16e3d684ef7019c3afc4 100644
--- a/assets/js/VacancyPage.jsx
+++ b/assets/js/VacancyPage.jsx
@@ -4,6 +4,7 @@ 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') {
+    } 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,46 +34,95 @@ export default class VacancyPage extends React.Component {
     };
   }
 
+
   generateVacancies() {
     if (this.props.user.role === 'student') {
       return (
         <Tabs selected={0}>
           <Pane label="Semua Lowongan" >
-            <VacancyList
+            <Pagination
               key={1}
-              userId={this.state.id}
               url="/vacancies/"
+              child={
+                <VacancyList
+                  user={this.props.user}
+                  key={1}
+                  userId={this.state.id}
+                />
+              }
             />
           </Pane>
           <Pane label="Lamaran saya" >
-            <VacancyList
+            <Pagination
               key={2}
-              userId={this.state.id}
               url={`/students/${this.state.id}/applied-vacancies/`}
+              child={
+                <VacancyList
+                  user={this.props.user}
+                  key={2}
+                  userId={this.state.id}
+                />
+              }
             />
           </Pane>
           <Pane label="Lamaran Ditandai" >
-            <VacancyList
+            <Pagination
               key={3}
-              userId={this.state.id}
               url={`/students/${this.state.id}/bookmarked-vacancies/`}
+              child={
+                <VacancyList
+                  key={3}
+                  user={this.props.user}
+                  userId={this.state.id}
+                />
+              }
             />
           </Pane>
         </Tabs>
       );
     } else if (this.props.user.role === 'company') {
       return (
-        <VacancyList key={1} userId={this.state.id} url={`/companies/${this.state.id}/vacancies/`} type="company" />
+        <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"
+        />
       );
-    } else if (this.props.user.role === 'supervisor') {
+    } else if (this.props.user.role === 'admin' || this.props.user.role === 'supervisor') {
       return (
         <Tabs selected={0}>
-          <Pane label="Lowongan Belum Terferivikasi" >
-            <Item.Group>
-              <AdminVacancy />
-            </Item.Group>
+          <Pane label="Lowongan Belum Terverifikasi" >
+            <Pagination
+              key={1}
+              url="/vacancies/"
+              child={
+                <VacancyList
+                  user={this.props.user}
+                  key={1}
+                  userId={this.state.id}
+                />
+              }
+            />
+          </Pane>
+          <Pane label="Lowongan Terverifikasi" >
+            <Pagination
+              key={2}
+              url={`/vacancies/`}
+              child={
+                <VacancyList
+                  user={this.props.user}
+                  key={2}
+                  userId={this.state.id}
+                />
+              }
+            />
           </Pane>
-          <Pane label=" Semua Lamaran" />
         </Tabs>
       );
     }
diff --git a/assets/js/__test__/ApplicantPage-test.jsx b/assets/js/__test__/ApplicantPage-test.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..d8d03185cf80da8327500226d6887327caca49e8
--- /dev/null
+++ b/assets/js/__test__/ApplicantPage-test.jsx
@@ -0,0 +1,42 @@
+import React from 'react';
+import ReactTestUtils from 'react-addons-test-utils';
+import fetchMock from 'fetch-mock';
+import ApplicantPage from '../ApplicantPage';
+
+describe('ApplicantPage', () => {
+  fetchMock.get('*', { data: 'value' });
+
+  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,
+    },
+  };
+
+  it('renders for companies without problem', () => {
+    const applicantPage = ReactTestUtils.renderIntoDocument(
+      <ApplicantPage user={companyUser} />);
+    expect(applicantPage).to.exist;
+  });
+});
diff --git a/assets/js/__test__/CompanyPage-test.jsx b/assets/js/__test__/CompanyPage-test.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..04dfdcaa8c24bab3b7be2c0aa5f5bf13df59c004
--- /dev/null
+++ b/assets/js/__test__/CompanyPage-test.jsx
@@ -0,0 +1,51 @@
+import React from 'react';
+import ReactTestUtils from 'react-addons-test-utils';
+import fetchMock from 'fetch-mock';
+import CompanyPage from '../CompanyPage';
+
+describe('CompanyPage', () => {
+  fetchMock.get('*', { data: 'value' });
+
+  const adminUser = {
+    role: 'admin',
+    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,
+    },
+  };
+
+  it('renders for admin without problem', () => {
+    const companyPage = ReactTestUtils.renderIntoDocument(
+      <CompanyPage user={adminUser} />);
+    expect(companyPage).to.exist;
+  });
+
+  it('click dashboard button problem', () => {
+    const companyPage = ReactTestUtils.renderIntoDocument(
+      <CompanyPage user={adminUser} />);
+    const dashboardButton = ReactTestUtils.findRenderedDOMComponentWithTag(companyPage, 'Button');
+    ReactTestUtils.Simulate.click(dashboardButton);
+    expect(companyPage).to.exist;
+    expect(dashboardButton).to.exist;
+  });
+});
diff --git a/assets/js/__test__/CreateVacancy-test.jsx b/assets/js/__test__/CreateVacancy-test.jsx
index 82c288168bc8b8a2704876644b4434521b2c53ce..7cdc39c75abcbfd52dbf2d134c2755f92acc724b 100644
--- a/assets/js/__test__/CreateVacancy-test.jsx
+++ b/assets/js/__test__/CreateVacancy-test.jsx
@@ -1,6 +1,7 @@
 import React from 'react';
 import ReactTestUtils from 'react-addons-test-utils';
 import fetchMock from 'fetch-mock';
+import moment from 'moment';
 import CreateVacancy from '../CreateVacancy';
 import Storage from '../lib/Storage';
 
@@ -44,7 +45,7 @@ describe('CreateVacancy', () => {
     fetchMock.get('*', {});
     Storage.set('user-data', companySession);
     const createVacancy = ReactTestUtils.renderIntoDocument(
-      <CreateVacancy params={{ id: 1 }} />,
+      <CreateVacancy params={{ id: 1 }} user={{ data: { company: {} } }} />,
     );
     expect(createVacancy).to.exist;
     fetchMock.restore();
@@ -55,7 +56,7 @@ describe('CreateVacancy', () => {
     fetchMock.get('*', {});
     Storage.set('user-data', errorSession);
     const createVacancy = ReactTestUtils.renderIntoDocument(
-      <CreateVacancy params={{ id: 1 }} />,
+      <CreateVacancy params={{ id: 1 }} user={{ data: { company: {} } }} />,
     );
     expect(createVacancy).to.exist;
     fetchMock.restore();
@@ -65,7 +66,7 @@ describe('CreateVacancy', () => {
     fetchMock.get('*', {});
     Storage.set('user-data', companySession);
     const createVacancy = ReactTestUtils.renderIntoDocument(
-      <CreateVacancy params={{ id: 1 }} />,
+      <CreateVacancy params={{ id: 1 }} user={{ data: { company: {} } }} />,
     );
     createVacancy.setState({
       name: 'stub',
@@ -81,7 +82,7 @@ describe('CreateVacancy', () => {
     fetchMock.get('*', {});
     Storage.set('user-data', companySession);
     const createVacancy = ReactTestUtils.renderIntoDocument(
-      <CreateVacancy params={{ id: undefined }} />,
+      <CreateVacancy params={{ id: undefined }} user={{ data: { company: {} } }} />,
     );
     createVacancy.setState({
       name: 'stub',
@@ -106,7 +107,7 @@ describe('CreateVacancy', () => {
     fetchMock.get('*', {});
     Storage.set('user-data', companySession);
     const createVacancy = ReactTestUtils.renderIntoDocument(
-      <CreateVacancy params={{ id: undefined }} />,
+      <CreateVacancy params={{ id: undefined }} user={{ data: { company: {} } }} />,
     );
     createVacancy.setState({
       name: 'stub',
@@ -124,7 +125,7 @@ describe('CreateVacancy', () => {
     fetchMock.get('*', {});
     Storage.set('user-data', companySession);
     const createVacancy = ReactTestUtils.renderIntoDocument(
-      <CreateVacancy params={{ id: 1 }} />,
+      <CreateVacancy params={{ id: 1 }} user={{ data: { company: {} } }} />,
     );
     createVacancy.setState({
       name: 'stub',
@@ -137,6 +138,8 @@ describe('CreateVacancy', () => {
     ReactTestUtils.Simulate.keyDown(openField, { key: 'Enter', keyCode: 13, which: 13 });
     ReactTestUtils.Simulate.click(closeField);
     ReactTestUtils.Simulate.keyDown(closeField, { key: 'Enter', keyCode: 13, which: 13 });
+    createVacancy.setOpenTime(moment());
+    createVacancy.setCloseTime(moment());
 
     expect(createVacancy.state.formLoading).to.equal(false);
     createVacancy.handleSubmit(new Event('click'));
@@ -149,7 +152,7 @@ describe('CreateVacancy', () => {
     fetchMock.get('*', {});
     Storage.set('user-data', companySession);
     const createVacancy = ReactTestUtils.renderIntoDocument(
-      <CreateVacancy params={{ id: 1 }} />,
+      <CreateVacancy params={{ id: 1 }} user={{ data: { company: {} } }} />,
     );
     createVacancy.setState({
       name: 'stub',
diff --git a/assets/js/__test__/Dashboard-test.jsx b/assets/js/__test__/Dashboard-test.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..892fbabf98466949ad103034a99a90d3deff1a90
--- /dev/null
+++ b/assets/js/__test__/Dashboard-test.jsx
@@ -0,0 +1,149 @@
+/* eslint-disable no-unused-expressions */
+import React from 'react';
+import ReactTestUtils from 'react-addons-test-utils';
+import fetchMock from 'fetch-mock';
+import Dashboard from '../Dashboard';
+
+describe('Dashboard', () => {
+  fetchMock.get('*', { data: 'value' });
+
+  const studentUser = {
+    role: 'student',
+    data: {
+      url: 'http://localhost:8000/api/users/9/',
+      username: 'muhammad.reza42',
+      email: 'muhammad.reza42@ui.ac.id',
+      is_staff: false,
+      company: null,
+      supervisor: null,
+      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,
+        bookmarked_vacancies: [
+          3,
+        ],
+        applied_vacancies: [
+          3,
+          1,
+        ],
+      },
+    },
+  };
+
+  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 adminUser = {
+    role: 'admin',
+    data: {
+      url: 'http://localhost:8001/api/users/8/',
+      username: 'Tutuplapak',
+      email: '',
+      is_staff: false,
+      company: null,
+      supervisor: null,
+      student: null,
+    },
+  };
+
+  const supervisorUser = {
+    role: 'supervisor',
+    data: {
+      url: 'http://localhost:8001/api/users/8/',
+      username: 'Tutuplapak',
+      email: '',
+      is_staff: false,
+      company: null,
+      supervisor: null,
+      student: null,
+    },
+  };
+
+  const errorUser = {
+    role: 'error',
+    data: {
+      url: 'http://localhost:8001/api/users/8/',
+      username: 'Tutuplapak',
+      email: '',
+      is_staff: false,
+      company: null,
+      supervisor: null,
+      student: null,
+    },
+  };
+
+  it('renders for company without problem', () => {
+    const dashboard = ReactTestUtils.renderIntoDocument(
+      <Dashboard user={companyUser} />);
+    expect(dashboard).to.exist;
+  });
+
+  it('renders for supervisor without problem', () => {
+    const dashboard = ReactTestUtils.renderIntoDocument(
+      <Dashboard user={supervisorUser}>
+        <div> test </div>
+      </Dashboard>);
+    expect(dashboard).to.exist;
+  });
+
+  it('renders for admin without problem', () => {
+    const dashboard = ReactTestUtils.renderIntoDocument(
+      <Dashboard user={adminUser}>
+        <div> test </div>
+      </Dashboard>);
+    expect(dashboard).to.exist;
+  });
+
+  it('renders for student without problem', () => {
+    const dashboard = ReactTestUtils.renderIntoDocument(
+      <Dashboard user={studentUser}>
+        <div> test </div>
+      </Dashboard>);
+    expect(dashboard).to.exist;
+  });
+
+  it('renders for error without problem', () => {
+    const dashboard = ReactTestUtils.renderIntoDocument(
+      <Dashboard user={errorUser}>
+        <div> test </div>
+      </Dashboard>);
+    expect(dashboard).to.exist;
+  });
+});
+
diff --git a/assets/js/__test__/Login.jsx b/assets/js/__test__/Login.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..b562c29070ef12b17468e801f2b152aa0a26beac
--- /dev/null
+++ b/assets/js/__test__/Login.jsx
@@ -0,0 +1,11 @@
+import React from 'react';
+import ReactTestUtils from 'react-addons-test-utils';
+import Login from '../Login';
+
+describe('Login', () => {
+  it('renders for login without problem', () => {
+    const login = ReactTestUtils.renderIntoDocument(<Login><div>test</div></Login>);
+    expect(login).to.exist;
+  });
+});
+
diff --git a/assets/js/__test__/TranscriptPage-test.jsx b/assets/js/__test__/TranscriptPage-test.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..00eb2b2064940845245076b771aa3060d7b96617
--- /dev/null
+++ b/assets/js/__test__/TranscriptPage-test.jsx
@@ -0,0 +1,24 @@
+import React from 'react';
+import ReactTestUtils from 'react-addons-test-utils';
+import fetchMock from 'fetch-mock';
+import TranscriptPage from '../TranscriptPage';
+
+describe('TranscriptPage', () => {
+  const data = {
+    transcript: [
+      { kelas: { nm_kls: 'kelas1' }, nilai: 'A' },
+      { kelas: { nm_kls: 'kelas2' }, nilai: 'B' },
+      { nilai: 'B' },
+    ],
+    name: 'Badak Terbang',
+  };
+
+  fetchMock.get('*', data);
+
+  it('renders for admin without problem', () => {
+    const transcriptPage = ReactTestUtils.renderIntoDocument(
+      <TranscriptPage params={{ id: 1 }} />);
+    transcriptPage.setState({data})
+    expect(transcriptPage).to.exist;
+  });
+});
diff --git a/assets/js/__test__/VacancyPage-test.jsx b/assets/js/__test__/VacancyPage-test.jsx
index fd2d07c2b726c4c37a3e8a493e540a7de93145b2..dcccff16e1a09c5f74f18bfdc43281185bbb13ea 100644
--- a/assets/js/__test__/VacancyPage-test.jsx
+++ b/assets/js/__test__/VacancyPage-test.jsx
@@ -3,7 +3,6 @@ import React from 'react';
 import ReactTestUtils from 'react-addons-test-utils';
 import fetchMock from 'fetch-mock';
 import VacancyPage from '../VacancyPage';
-import Storage from '../lib/Storage';
 
 describe('VacancyPage', () => {
   fetchMock.get('*', { data: 'value' });
diff --git a/assets/js/__test__/components/Applicant-test.jsx b/assets/js/__test__/components/Applicant-test.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..d9db8170b088fb87a80b90795feb1049b08f1944
--- /dev/null
+++ b/assets/js/__test__/components/Applicant-test.jsx
@@ -0,0 +1,55 @@
+import React from 'react';
+import ReactTestUtils from 'react-addons-test-utils';
+import Applicant from '../../components/Applicant';
+import fetchMock from 'fetch-mock';
+
+describe('Applicant', () => {
+  const stub = {
+    data: {
+      vacancy: { name: 'name' },
+      student: { major: 'hue' },
+      status: 2,
+    },
+    updateStatus: () => {},
+  };
+
+  const stub2 = {
+    data: {
+      vacancy: { name: 'name' },
+      student: { major: 'hue' },
+      status: 3,
+    },
+    updateStatus: () => {},
+  };
+
+  it('renders without problem', () => {
+    fetchMock.get('*', stub);
+    const applicant = ReactTestUtils.renderIntoDocument(
+      <Applicant data={stub.data} updateStatus={stub.updateStatus} />,
+    );
+    expect(applicant).to.exist;
+    fetchMock.restore();
+  });
+
+  it('bookmarks without problem', () => {
+    fetchMock.get('*', stub);
+    fetchMock.patch('*', {});
+    const applicant = ReactTestUtils.renderIntoDocument(
+      <Applicant data={stub2.data} updateStatus={stub.updateStatus} />,
+    );
+    applicant.bookmark();
+    expect(applicant).to.exist;
+    fetchMock.restore();
+  });
+
+  it('bookmarks with problem', () => {
+    fetchMock.get('*', stub);
+    fetchMock.patch('*', {});
+    const applicant = ReactTestUtils.renderIntoDocument(
+      <Applicant data={stub.data} updateStatus={stub.updateStatus} />,
+    );
+    applicant.bookmark();
+    expect(applicant).to.exist;
+    fetchMock.restore();
+  });
+});
diff --git a/assets/js/__test__/components/ApplicantList-test.jsx b/assets/js/__test__/components/ApplicantList-test.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..0a907611d4bb5a7738ee5382dd141aca3da3b43a
--- /dev/null
+++ b/assets/js/__test__/components/ApplicantList-test.jsx
@@ -0,0 +1,86 @@
+import React from 'react';
+import ReactTestUtils from 'react-addons-test-utils';
+import fetchMock from 'fetch-mock';
+import ApplicantList from '../../components/ApplicantList';
+import Applicant from '../../components/Applicant';
+
+describe('ApplicantList', () => {
+
+  const vacancy = {
+    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: 1,
+    name: 'Software Engineer',
+    open_time: '2017-03-28T05:55:38Z',
+    updated: '2017-03-28T07:34:13.122093Z',
+    verified: true,
+  }
+
+  const student = {
+    role: 'student',
+    data: {
+      url: 'http://localhost:8000/api/users/9/',
+      username: 'muhammad.reza42',
+      email: 'muhammad.reza42@ui.ac.id',
+      is_staff: false,
+      company: null,
+      supervisor: null,
+      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,
+        bookmarked_vacancies: [
+          3,
+        ],
+        applied_vacancies: [
+          3,
+          1,
+        ],
+      },
+    },
+  };
+
+  const response = [
+    { id: 1, status: Applicant.APPLICATION_STATUS.ACCEPTED, student, vacancy },
+    { id: 2, status: Applicant.APPLICATION_STATUS.BOOKMARKED, student, vacancy },
+    { id: 3, status: Applicant.APPLICATION_STATUS.NEW, student, vacancy },
+    { id: 4, status: Applicant.APPLICATION_STATUS.REJECTED, student, vacancy },
+  ];
+
+  fetchMock.restore();
+  fetchMock.get('*', response);
+
+  it('renders without problem', () => {
+    const applicantList = ReactTestUtils.renderIntoDocument(
+      <ApplicantList status={Applicant.APPLICATION_STATUS.ACCEPTED} />);
+    expect(applicantList).to.exist;
+  });
+
+  it('can update status', () => {
+    const applicantList = ReactTestUtils.renderIntoDocument(
+      <ApplicantList status={Applicant.APPLICATION_STATUS.ACCEPTED} />);
+    applicantList.setState({applications: response });
+
+    expect(applicantList.state).to.not.equal(response);
+    applicantList.updateStatus(1, Applicant.APPLICATION_STATUS.BOOKMARKED);
+    expect(applicantList.state).to.not.equal(response);
+  });
+});
+
diff --git a/assets/js/__test__/components/ApplyModal-test.jsx b/assets/js/__test__/components/ApplyModal-test.jsx
index f06675e173670ac571d3b40a5f81e99f731c6584..1119ff7caf68e2043b4803570fb7d64bdd3f3a76 100644
--- a/assets/js/__test__/components/ApplyModal-test.jsx
+++ b/assets/js/__test__/components/ApplyModal-test.jsx
@@ -2,6 +2,7 @@
 import React from 'react';
 import ReactTestUtils from 'react-addons-test-utils';
 import ApplyModal from '../../components/ApplyModal';
+import fetchMock from 'fetch-mock';
 
 describe('ApplyModal', () => {
   it('renders without problem', () => {
@@ -11,12 +12,25 @@ describe('ApplyModal', () => {
   });
 
   it('open without problem', () => {
+    fetchMock.post('*', {});
     const modalPendaftaran = ReactTestUtils.renderIntoDocument(
       <ApplyModal id={4} data={{ key: 'value' }} buttonTitle="submit" apply={() => {}}/>);
     const modal = ReactTestUtils.findRenderedDOMComponentWithTag(modalPendaftaran, 'Button');
     modalPendaftaran.handleApply();
     ReactTestUtils.Simulate.click(modal);
     expect(modalPendaftaran).to.exist;
+    fetchMock.restore();
+  });
+
+  it('open with problem', () => {
+    fetchMock.post('*', 404);
+    const modalPendaftaran = ReactTestUtils.renderIntoDocument(
+      <ApplyModal id={4} data={{ key: 'value' }} buttonTitle="submit" apply={() => {}}/>);
+    const modal = ReactTestUtils.findRenderedDOMComponentWithTag(modalPendaftaran, 'Button');
+    modalPendaftaran.handleApply();
+    ReactTestUtils.Simulate.click(modal);
+    expect(modalPendaftaran).to.exist;
+    fetchMock.restore();
   });
 
   it('change without problem', () => {
diff --git a/assets/js/__test__/components/ApproveModal-test.jsx b/assets/js/__test__/components/ApproveModal-test.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..2f0a3bf025769cd70c5cdf2159939e661b759209
--- /dev/null
+++ b/assets/js/__test__/components/ApproveModal-test.jsx
@@ -0,0 +1,77 @@
+/* eslint-disable no-unused-expressions */
+import React from 'react';
+import ReactTestUtils from 'react-addons-test-utils';
+import fetchMock from 'fetch-mock';
+import ApproveModal from '../../components/ApproveModal';
+import Applicant from '../../components/Applicant';
+
+describe('ApproveModal', () => {
+  it('renders without problem', () => {
+    const modalApproval = ReactTestUtils.renderIntoDocument(
+      <ApproveModal updateStatus={() => {}} data={{ key: 'value', student: { resume: 'asdasd' } }} />);
+    expect(modalApproval).to.exist;
+  });
+
+  it('open without problem', () => {
+    fetchMock.get('*', { student: { resume: 'asdasd' } });
+    const modalApproval = ReactTestUtils.renderIntoDocument(
+      <ApproveModal updateStatus={() => {}} data={{ key: 'value', student: { resume: 'asdasd' }, status: Applicant.APPLICATION_STATUS.NEW }} />);
+
+    const modal = ReactTestUtils.findRenderedDOMComponentWithTag(modalApproval, 'Button');
+    ReactTestUtils.Simulate.click(modal);
+    fetchMock.restore();
+  });
+
+  it('open resume without problem', () => {
+    fetchMock.get('*', { student: { resume: 'asdasd' } });
+    const modalApproval = ReactTestUtils.renderIntoDocument(
+      <ApproveModal updateStatus={() => {}} data={{ key: 'value', student: { resume: 'asdasd' }, status: Applicant.APPLICATION_STATUS.NEW, show_transcript: true }} />);
+    modalApproval.gotoStudentResume();
+    fetchMock.restore();
+  });
+
+  it('open transcript without problem', () => {
+    fetchMock.get('*', { student: { resume: 'asdasd' } });
+    const modalApproval = ReactTestUtils.renderIntoDocument(
+      <ApproveModal updateStatus={() => {}} data={{ key: 'value', student: { resume: 'asdasd' }, status: Applicant.APPLICATION_STATUS.NEW, show_transcript: true }} />);
+    modalApproval.gotoStudentTranscript();
+    fetchMock.restore();
+  });
+
+  it('close without problem', () => {
+    fetchMock.get('*', { student: { resume: 'asdasd' } });
+    fetchMock.patch('*', { student: { resume: 'asdasd' } });
+    const modalApproval = ReactTestUtils.renderIntoDocument(
+      <ApproveModal updateStatus={() => {}} data={{ key: 'value', student: { resume: 'asdasd' }, status: Applicant.APPLICATION_STATUS.NEW  }} />);
+
+    modalApproval.handleClose();
+    expect(modalApproval.state.modalOpen).to.equal(false);
+    fetchMock.restore();
+  });
+
+  it('reject without problem', () => {
+    fetchMock.get('*', { student: { resume: 'asdasd' } });
+    fetchMock.patch('*', { });
+    const modalApproval = ReactTestUtils.renderIntoDocument(
+      <ApproveModal updateStatus={() => {}} data={{ key: 'value', student: { resume: 'asdasd' }, cover_letter: 'asdasd' }} />);
+    modalApproval.modal = { open: () => {} };
+    modalApproval.reject();
+    modalApproval.rejectApplication();
+    modalApproval.gotoLink('link random');
+    expect(modalApproval.state.rejectLoading).to.equal(true);
+    fetchMock.restore();
+  });
+
+  it('apply without problem', () => {
+    fetchMock.get('*', { student: { resume: 'asdasd' } });
+    fetchMock.patch('*', { });
+    const modalApproval = ReactTestUtils.renderIntoDocument(
+      <ApproveModal updateStatus={() => {}} data={{ key: 'value', student: { resume: 'asdasd', show_transcript: true  } }} />);
+    modalApproval.modal = { open: () => {} };
+    modalApproval.accept();
+    modalApproval.acceptApplication();
+    modalApproval.gotoLink('link random');
+    expect(modalApproval.state.acceptLoading).to.equal(true);
+    fetchMock.restore();
+  });
+});
diff --git a/assets/js/__test__/components/Company-test.jsx b/assets/js/__test__/components/Company-test.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..640fb2d51b43ff35c0b628c350a2f228cac96b82
--- /dev/null
+++ b/assets/js/__test__/components/Company-test.jsx
@@ -0,0 +1,93 @@
+import React from 'react';
+import ReactTestUtils from 'react-addons-test-utils';
+import Company from '../../components/Company';
+import fetchMock from 'fetch-mock';
+
+describe('Company', () => {
+  const stub = {
+    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.',
+    logo: 'http://localhost:8001/files/company-logo/8a258a48-3bce-4873-b5d1-538b360d0059.png',
+    address: 'Jl. Kebayoran Baru nomor 13, Jakarta Barat',
+  };
+
+  const company1 = {};
+  const company2 = {};
+  Object.assign(company1, stub);
+  Object.assign(company2, stub);
+  company1.status = Company.COMPANY_STATUS.NEW;
+  company2.status = Company.COMPANY_STATUS.VERIFIED;
+  company2.logo = null;
+
+  it('renders without problem', () => {
+    fetchMock.get('*', company1);
+    const company = ReactTestUtils.renderIntoDocument(
+      <Company data={company1} updateStatus={() => {}} />,
+    );
+    expect(company).to.exist;
+    fetchMock.restore();
+  });
+
+  it('accept without problem', () => {
+    fetchMock.get('*', company1);
+    fetchMock.patch('*', {});
+    const company = ReactTestUtils.renderIntoDocument(
+      <Company data={company2} updateStatus={() => {}} />,
+    );
+    company.accept();
+    expect(company).to.exist;
+    fetchMock.restore();
+  });
+
+  it('accept with problem', () => {
+    fetchMock.get('*', company1);
+    fetchMock.patch('*', 404);
+    const company = ReactTestUtils.renderIntoDocument(
+      <Company data={company1} updateStatus={() => {}} />,
+    );
+    company.accept();
+    expect(company).to.exist;
+    fetchMock.restore();
+  });
+
+  it('reject without problem', () => {
+    fetchMock.get('*', company1);
+    fetchMock.patch('*', {});
+    const company = ReactTestUtils.renderIntoDocument(
+      <Company data={company2} updateStatus={() => {}} />,
+    );
+    company.reject();
+    expect(company).to.exist;
+    fetchMock.restore();
+  });
+
+  it('reject with problem', () => {
+    fetchMock.get('*', company1);
+    fetchMock.patch('*', 404);
+    const company = ReactTestUtils.renderIntoDocument(
+      <Company data={company1} updateStatus={() => {}} />,
+    );
+    company.reject();
+    expect(company).to.exist;
+    fetchMock.restore();
+  });
+
+  it('go to company home click with problem', () => {
+    fetchMock.get('*', company1);
+    fetchMock.patch('*', 404);
+    const company = ReactTestUtils.renderIntoDocument(
+      <Company data={company1} updateStatus={() => {}} />,
+    );
+    company.goToCompanyHome();
+    fetchMock.restore();
+  });
+});
diff --git a/assets/js/__test__/components/CompanyList-test.jsx b/assets/js/__test__/components/CompanyList-test.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..dd9ec0bab313dcc3002c399854104868984174a5
--- /dev/null
+++ b/assets/js/__test__/components/CompanyList-test.jsx
@@ -0,0 +1,56 @@
+import React from 'react';
+import ReactTestUtils from 'react-addons-test-utils';
+import fetchMock from 'fetch-mock';
+import CompanyList from '../../components/CompanyList';
+import Company from '../../components/Company';
+
+describe('CompanyList', () => {
+  const 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.',
+    logo: 'http://localhost:8001/files/company-logo/8a258a48-3bce-4873-b5d1-538b360d0059.png',
+    address: 'Jl. Kebayoran Baru nomor 13, Jakarta Barat',
+  };
+
+  const company1 = {};
+  const company2 = {};
+  const company3 = {};
+  Object.assign(company1, company);
+  Object.assign(company2, company);
+  Object.assign(company3, company);
+  company1.status = Company.COMPANY_STATUS.NEW;
+  company2.status = Company.COMPANY_STATUS.VERIFIED;
+  company3.status = Company.COMPANY_STATUS.ALL;
+
+  const response = [company1, company2, company3];
+
+  fetchMock.restore();
+  fetchMock.get('*', response);
+
+  it('renders without problem', () => {
+    const companyList = ReactTestUtils.renderIntoDocument(
+      <CompanyList status={Company.COMPANY_STATUS.VERIFIED} items={response} />);
+    expect(companyList).to.exist;
+  });
+
+  it('can update status', () => {
+    const companyList = ReactTestUtils.renderIntoDocument(
+      <CompanyList status={Company.COMPANY_STATUS.VERIFIED} items={response} />);
+    companyList.setState({ companies: response });
+    companyList.generateCompanies();
+
+    expect(companyList.state).to.not.equal(response);
+    companyList.updateStatus(3, Company.COMPANY_STATUS.ALL);
+    expect(companyList.state).to.not.equal(response);
+  });
+});
+
diff --git a/assets/js/__test__/components/Pagination-test.jsx b/assets/js/__test__/components/Pagination-test.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..c822d2ce9ee6c82d77d2f60cf582c2f9e751ac97
--- /dev/null
+++ b/assets/js/__test__/components/Pagination-test.jsx
@@ -0,0 +1,171 @@
+/* eslint-disable no-unused-expressions */
+import React from 'react';
+import ReactTestUtils from 'react-addons-test-utils';
+import fetchMock from 'fetch-mock';
+import Pagination from '../../components/Pagination';
+import Logger from '../../lib/Logger';
+
+describe('Pagination', () => {
+  const response = {
+    count: 4,
+    next: 'next',
+    previous: 'prev',
+    results: [{
+      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: 1,
+      name: 'Software Engineer',
+      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 = {
+    count: 4,
+    next: null,
+    previous: null,
+    results: [{
+      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: 1,
+      name: 'Software Engineer',
+      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,
+    },
+    ],
+  };
+
+  it('renders without problem', () => {
+    fetchMock.get('*', response);
+    const pagination = ReactTestUtils.renderIntoDocument(
+      <Pagination child={<div />} url="test" />);
+    expect(pagination).to.exist;
+    fetchMock.restore();
+  });
+
+  it('renders without problem when it is the first or last page', () => {
+    fetchMock.get('*', response2);
+    const pagination = ReactTestUtils.renderIntoDocument(
+      <Pagination child={<div />} url="test" />);
+    expect(pagination).to.exist;
+    fetchMock.restore();
+  });
+
+  it('get items without problem', () => {
+    fetchMock.get('*', response);
+    const pagination = ReactTestUtils.renderIntoDocument(
+      <Pagination child={<div />} url="test" />);
+    pagination.getItemsData().then(() => {
+      expect(JSON.stringify(pagination.state.items)).to.equal(JSON.stringify(response.items));
+    });
+    fetchMock.restore();
+  });
+
+  it('renders without problem when failed getting data', () => {
+    fetchMock.get('*', 404);
+    const pagination = ReactTestUtils.renderIntoDocument(
+      <Pagination child={<div />} url="test" />);
+    expect(pagination).to.exist;
+    fetchMock.restore();
+  });
+
+  it('can go prev without problem', () => {
+    fetchMock.restore();
+    fetchMock.get('*', response);
+    const pagination = ReactTestUtils.renderIntoDocument(
+      <Pagination child={<div />} url="test" />);
+    pagination.getItemsData().then(() => {
+      const prev = ReactTestUtils.scryRenderedDOMComponentsWithTag(pagination, 'Menu.Item')[0];
+      ReactTestUtils.Simulate.click(prev);
+    });
+    pagination.handlePrev();
+    fetchMock.restore();
+  });
+
+  it('can refresh without problem', () => {
+    fetchMock.get('*', response);
+    const pagination = ReactTestUtils.renderIntoDocument(
+      <Pagination child={<div />} url="test" />);
+    pagination.getItemsData().then(() => {
+      const next = ReactTestUtils.scryRenderedDOMComponentsWithTag(pagination, 'Menu.Item')[1];
+      ReactTestUtils.Simulate.click(next);
+    });
+    pagination.refresh();
+    fetchMock.restore();
+  });
+
+  it('can go next without problem', () => {
+    fetchMock.get('*', response);
+    const pagination = ReactTestUtils.renderIntoDocument(
+      <Pagination child={<div />} url="test" />);
+    pagination.getItemsData().then(() => {
+      const next = ReactTestUtils.scryRenderedDOMComponentsWithTag(pagination, 'Menu.Item')[2];
+      ReactTestUtils.Simulate.click(next);
+    });
+    pagination.handleNext();
+    fetchMock.restore();
+  });
+
+  it('cannot go next or prev without problem', () => {
+    fetchMock.get('*', response2);
+    const pagination = ReactTestUtils.renderIntoDocument(
+      <Pagination child={<div />} url="test" />);
+    pagination.getItemsData().then(() => {
+      const next = ReactTestUtils.scryRenderedDOMComponentsWithTag(pagination, 'Menu.Item')[2];
+      ReactTestUtils.Simulate.click(next);
+    });
+    pagination.state.first = true;
+    pagination.state.last = true;
+    pagination.handleNext();
+    pagination.handlePrev();
+    fetchMock.restore();
+  });
+});
+
diff --git a/assets/js/__test__/components/TopMenu-test.jsx b/assets/js/__test__/components/TopMenu-test.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..7f841e107bb7c79274fbd1312fbe4d5e1116d399
--- /dev/null
+++ b/assets/js/__test__/components/TopMenu-test.jsx
@@ -0,0 +1,197 @@
+/* eslint-disable no-unused-expressions */
+import React from 'react';
+import ReactTestUtils from 'react-addons-test-utils';
+import fetchMock from 'fetch-mock';
+import TopMenu from '../../components/TopMenu';
+
+describe('TopMenu', () => {
+  fetchMock.restore();
+  fetchMock.get('*', { data: 'value' });
+
+  const studentUser = {
+    role: 'student',
+    data: {
+      url: 'http://localhost:8000/api/users/9/',
+      username: 'muhammad.reza42',
+      email: 'muhammad.reza42@ui.ac.id',
+      is_staff: false,
+      company: null,
+      supervisor: null,
+      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,
+        bookmarked_vacancies: [
+          3,
+        ],
+        applied_vacancies: [
+          3,
+          1,
+        ],
+      },
+    },
+  };
+
+  const companyUser = {
+    role: 'company',
+    data: {
+      url: 'http://localhost:8001/api/users/8/',
+      username: 'Tutuplapak',
+      email: '',
+      is_staff: true,
+      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 adminUser1 = {
+    role: 'admin',
+    data: {
+      url: 'http://localhost:8001/api/users/8/',
+      username: 'Tutuplapak',
+      email: '',
+      is_staff: true,
+      supervisor: null,
+      student: null,
+      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',
+      },
+    },
+  };
+
+  const adminUser2 = {
+    role: 'admin',
+    data: {
+      url: 'http://localhost:8001/api/users/8/',
+      username: 'Tutuplapak',
+      email: '',
+      is_staff: false,
+      company: null,
+      supervisor: null,
+      student: null,
+    },
+  };
+
+  const supervisorUser = {
+    role: 'supervisor',
+    data: {
+      url: 'http://localhost:8001/api/users/8/',
+      username: 'Tutuplapak',
+      email: '',
+      is_staff: false,
+      company: null,
+      supervisor: null,
+      student: null,
+    },
+  };
+
+  const errorUser = {
+    role: 'error',
+    data: {
+      url: 'http://localhost:8001/api/users/8/',
+      username: 'Tutuplapak',
+      email: '',
+      is_staff: false,
+      company: null,
+      supervisor: null,
+      student: null,
+    },
+  };
+
+  it('renders for company without problem', () => {
+    const topmenu = ReactTestUtils.renderIntoDocument(
+      <TopMenu user={companyUser} />);
+    expect(topmenu).to.exist;
+  });
+
+  it('renders for supervisor without problem', () => {
+    const topmenu = ReactTestUtils.renderIntoDocument(
+      <TopMenu user={supervisorUser}>
+        <div> test </div>
+      </TopMenu>);
+    expect(topmenu).to.exist;
+  });
+
+  it('renders for admin without problem', () => {
+    const topmenu = ReactTestUtils.renderIntoDocument(
+      <TopMenu user={adminUser1}>
+        <div> test </div>
+      </TopMenu>);
+    expect(topmenu).to.exist;
+  });
+
+  it('renders for student without problem', () => {
+    const topmenu = ReactTestUtils.renderIntoDocument(
+      <TopMenu user={studentUser}>
+        <div> test </div>
+      </TopMenu>);
+    expect(topmenu).to.exist;
+  });
+
+  it('renders for error without problem', () => {
+    const topmenu = ReactTestUtils.renderIntoDocument(
+      <TopMenu user={errorUser}>
+        <div> test </div>
+      </TopMenu>);
+    expect(topmenu).to.exist;
+  });
+
+  it('renders for user to logout without problem', () => {
+    fetchMock.get('*', { data: 'value' });
+    const topmenu = ReactTestUtils.renderIntoDocument(
+      <TopMenu user={adminUser1}>
+        <div> test </div>
+      </TopMenu>);
+    topmenu.logout(new Event('click'));
+    expect(topmenu).to.exist;
+  });
+
+  it('changes the activeItem when item is clicked', () => {
+    const topmenu = ReactTestUtils.renderIntoDocument(
+      <TopMenu user={adminUser2}>
+        <div> test </div>
+      </TopMenu>);
+    topmenu.handleItemClick(new Event('click'), 'undefined');
+    expect(topmenu.state.activeItem).to.equal(undefined);
+  });
+});
+
diff --git a/assets/js/__test__/components/Vacancy-test.jsx b/assets/js/__test__/components/Vacancy-test.jsx
index 7d99368d8b6d03d53cd547a1fe5c31d58512ed27..9f1e253be4d99c08928d497fd48ffa00f183b6c3 100644
--- a/assets/js/__test__/components/Vacancy-test.jsx
+++ b/assets/js/__test__/components/Vacancy-test.jsx
@@ -6,7 +6,7 @@ import Storage from '../../lib/Storage';
 
 describe('Vacancy', () => {
   const fetchMock = require('fetch-mock');
-  const response ={
+  const response = {
     close_time: '2019-03-28T05:55:42Z',
     company: {
       address: 'kebayoran baru',
@@ -15,12 +15,12 @@ describe('Vacancy', () => {
       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,
+    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 = {
@@ -40,34 +40,85 @@ describe('Vacancy', () => {
     verified: true,
   };
 
+  const studentUser = {
+    role: 'company',
+    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 with null picture and apply button without problem', () => {
     const lowongan = ReactTestUtils.renderIntoDocument(
-      <Vacancy status="Daftar" data={response} />);
+      <Vacancy status={0} user={studentUser} data={response} />);
     expect(lowongan).to.exist;
   });
 
   it('renders with null picture and cancel button without problem', () => {
     const lowongan = ReactTestUtils.renderIntoDocument(
-      <Vacancy status="Batal" data={response} />);
+      <Vacancy status={1} user={studentUser} data={response} />);
     expect(lowongan).to.exist;
   });
 
   it('renders with picture and apply button without problem', () => {
     const lowongan = ReactTestUtils.renderIntoDocument(
-      <Vacancy status="Daftar" data={response2} />);
+      <Vacancy status={0} user={studentUser} data={response2} />);
     expect(lowongan).to.exist;
   });
 
   it('renders with picture and cancel button without problem', () => {
     const lowongan = ReactTestUtils.renderIntoDocument(
-      <Vacancy status="Batal" data={response2} />);
+      <Vacancy status={2} user={studentUser} data={response2} />);
+    expect(lowongan).to.exist;
+  });
+
+  it('renders for accepted without problem', () => {
+    const lowongan = ReactTestUtils.renderIntoDocument(
+      <Vacancy status={4} user={studentUser} data={response2} />);
+    expect(lowongan).to.exist;
+  });
+
+  it('renders for rejected without problem', () => {
+    const lowongan = ReactTestUtils.renderIntoDocument(
+      <Vacancy status={3} user={studentUser} data={response2} />);
     expect(lowongan).to.exist;
   });
 
   it('bookmarks without problem', () => {
     fetchMock.post('*', response);
     const lowongan = ReactTestUtils.renderIntoDocument(
-      <Vacancy status="Daftar" data={response2} />);
+      <Vacancy status="Daftar" user={studentUser} data={response2} />);
     const response3 = { student: { id: 1, name: 2 } };
     expect(lowongan.props.data.id).to.equal(3);
     Storage.set('user-data', response3);
@@ -78,10 +129,11 @@ describe('Vacancy', () => {
   it('cancel bookmarks without problem', () => {
     fetchMock.delete('*', { data: 'value' });
     const lowongan = ReactTestUtils.renderIntoDocument(
-      <Vacancy status="Daftar" data={response2} bookmarked={1}/>);
+      <Vacancy status="Daftar" user={studentUser} data={response2} bookmarked={1} />);
     const response3 = { student: { id: 1, name: 2 } };
     lowongan.removeVacancyApplication();
     lowongan.openConfirmationModal();
+    lowongan.updateStatus();
     expect(lowongan.props.data.id).to.equal(3);
     Storage.set('user-data', response3);
     expect(lowongan.bookmark()).to.be.undefined;
@@ -91,37 +143,12 @@ describe('Vacancy', () => {
   it('cancel bookmarks with problem', () => {
     fetchMock.delete('*', 404);
     const lowongan = ReactTestUtils.renderIntoDocument(
-      <Vacancy status="Daftar" data={response2} bookmarked={1}/>);
+      <Vacancy status="Daftar" user={studentUser} data={response2} bookmarked={1} />);
     const response3 = { student: { id: 1, name: 2 } };
     lowongan.removeVacancyApplication();
     expect(lowongan.props.data.id).to.equal(3);
     Storage.set('user-data', response3);
-    expect(lowongan.bookmark()).to.be.undefined;
-    fetchMock.restore();
-  });
-
-  it('apply without problem', () => {
-    fetchMock.post('*', response);
-    fetchMock.delete('*', response);
-    const lowongan = ReactTestUtils.renderIntoDocument(
-      <Vacancy status="Daftar" data={response2} bookmarked={1}/>);
-    const response3 = { student: { id: 1, name: 2 } };
-    lowongan.apply(1);
-    expect(lowongan.props.data.id).to.equal(3);
-    Storage.set('user-data', response3);
-    expect(lowongan.bookmark()).to.be.undefined;
-    fetchMock.restore();
-  });
-
-  it('apply with problem', () => {
-    fetchMock.post('*', 404);
-    fetchMock.delete('*', response);
-    const lowongan = ReactTestUtils.renderIntoDocument(
-      <Vacancy status="Daftar" data={response2} bookmarked={1}/>);
-    const response3 = { student: { id: 1, name: 2 } };
-    lowongan.apply(1);
-    expect(lowongan.props.data.id).to.equal(3);
-    Storage.set('user-data', response3);
+    lowongan.updateStatus('failed');
     expect(lowongan.bookmark()).to.be.undefined;
     fetchMock.restore();
   });
diff --git a/assets/js/__test__/components/VacancyList-test.jsx b/assets/js/__test__/components/VacancyList-test.jsx
index 0fcfc8f3e83d889eec72ec1a5f7d4a11347422ff..ee03b113fff1b6f9ef3e9a037a87f8c6c0ab2118 100644
--- a/assets/js/__test__/components/VacancyList-test.jsx
+++ b/assets/js/__test__/components/VacancyList-test.jsx
@@ -5,37 +5,215 @@ import fetchMock from 'fetch-mock';
 import VacancyList from '../../components/VacancyList';
 
 describe('VacancyList', () => {
-  const response = [{
-    close_time: '2019-03-28T05:55:42Z',
-    company: {
-      address: 'kebayoran baru',
-      id: 1,
-      logo: null,
-      name: 'tutup lapak',
+
+  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,
     },
-    created: '2017-03-28T07:05:47.128672Z',
-    description: 'Lorem ipsum dolbh.',
-    id: 1,
-    name: 'Software Engineer',
-    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',
+  };
+
+  const studentUser = {
+    role: 'company',
+    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,
+        ],
+      },
     },
-    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 newResponse = [
+    {
+      company: {
+        id: 3,
+        user: {
+          url: 'http://localhost:8000/api/users/8/',
+          username: 'Tutuplapak',
+          email: '',
+          is_staff: false,
+        },
+        name: 'Tutuplapak',
+        created: '2017-03-28T07:30:10.535240Z',
+        updated: '2017-05-07T13:22:19.175033Z',
+        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.',
+        registeredStatus: 1,
+        logo: null,
+        address: 'Jl. Kebayoran Baru nomor 13, Jakarta Barat',
+      },
+      verified: true,
+      open_time: '2017-04-26T03:39:11Z',
+      description: 'deskripsi',
+      close_time: '2017-04-30T03:39:11Z',
+      created: '2017-04-26T03:39:39.916758Z',
+      updated: '2017-04-26T03:41:07.157634Z',
+      name: 'Kepala Sekolah',
+      status: 0,
+      bookmarked: false,
+      id: 4,
+    },
+    {
+      company: {
+        id: 3,
+        user: {
+          url: 'http://localhost:8000/api/users/8/',
+          username: 'Tutuplapak',
+          email: '',
+          is_staff: false,
+        },
+        name: 'Tutuplapak',
+        created: '2017-03-28T07:30:10.535240Z',
+        updated: '2017-05-07T13:22:19.175033Z',
+        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.',
+        registeredStatus: 1,
+        logo: 'http://localhost:8000/files/company-logo/8a258a48-3bce-4873-b5d1-538b360d0059.png',
+        address: 'Jl. Kebayoran Baru nomor 13, Jakarta Barat',
+      },
+      verified: true,
+      open_time: '2017-04-26T03:39:11Z',
+      description: 'deskripsi',
+      close_time: '2017-04-30T03:39:11Z',
+      created: '2017-04-26T03:39:39.916758Z',
+      updated: '2017-04-26T03:41:07.157634Z',
+      name: 'Kepala Sekolah',
+      status: 1,
+      bookmarked: false,
+      id: 4,
+    },
+    {
+      company: {
+        id: 3,
+        user: {
+          url: 'http://localhost:8000/api/users/8/',
+          username: 'Tutuplapak',
+          email: '',
+          is_staff: false,
+        },
+        name: 'Tutuplapak',
+        created: '2017-03-28T07:30:10.535240Z',
+        updated: '2017-05-07T13:22:19.175033Z',
+        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.',
+        registeredStatus: 1,
+        logo: null,
+        address: 'Jl. Kebayoran Baru nomor 13, Jakarta Barat',
+      },
+      verified: true,
+      open_time: '2017-04-26T03:39:11Z',
+      description: 'deskripsi',
+      close_time: '2017-04-30T03:39:11Z',
+      created: '2017-04-26T03:39:39.916758Z',
+      updated: '2017-04-26T03:41:07.157634Z',
+      name: 'Kepala Sekolah',
+      status: 2,
+      bookmarked: true,
+      id: 4,
+    },
+    {
+      company: {
+        id: 3,
+        user: {
+          url: 'http://localhost:8000/api/users/8/',
+          username: 'Tutuplapak',
+          email: '',
+          is_staff: false,
+        },
+        name: 'Tutuplapak',
+        created: '2017-03-28T07:30:10.535240Z',
+        updated: '2017-05-07T13:22:19.175033Z',
+        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.',
+        registeredStatus: 1,
+        logo: null,
+        address: 'Jl. Kebayoran Baru nomor 13, Jakarta Barat',
+      },
+      verified: true,
+      open_time: '2017-04-26T03:39:11Z',
+      description: 'deskripsi',
+      close_time: '2017-04-30T03:39:11Z',
+      created: '2017-04-26T03:39:39.916758Z',
+      updated: '2017-04-26T03:41:07.157634Z',
+      name: 'Kepala Sekolah',
+      status: 3,
+      bookmarked: true,
+      id: 4,
+    },
+    {
+      company: {
+        id: 3,
+        user: {
+          url: 'http://localhost:8000/api/users/8/',
+          username: 'Tutuplapak',
+          email: '',
+          is_staff: false,
+        },
+        name: 'Tutuplapak',
+        created: '2017-03-28T07:30:10.535240Z',
+        updated: '2017-05-07T13:22:19.175033Z',
+        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.',
+        registeredStatus: 1,
+        logo: null,
+        address: 'Jl. Kebayoran Baru nomor 13, Jakarta Barat',
+      },
+      verified: true,
+      open_time: '2017-04-26T03:39:11Z',
+      description: 'deskripsi',
+      close_time: '2017-04-30T03:39:11Z',
+      created: '2017-04-26T03:39:39.916758Z',
+      updated: '2017-04-26T03:41:07.157634Z',
+      name: 'Kepala Sekolah',
+      status: 4,
+      bookmarked: true,
+      id: 4,
+    },
+  ];
 
   const response2 = [{
     close_time: '2019-03-28T05:55:42Z',
@@ -55,99 +233,98 @@ describe('VacancyList', () => {
   }];
 
   it('renders without problem', () => {
-    fetchMock.get('*', response);
     const vacancyList = ReactTestUtils.renderIntoDocument(
-      <VacancyList userId={1} url="test" />);
+      <VacancyList items={newResponse} userId={1} user={studentUser} />);
     expect(vacancyList).to.exist;
-    fetchMock.restore();
   });
 
   it('renders without problem for company', () => {
-    fetchMock.get('*', response);
-    const vacancyList = ReactTestUtils.renderIntoDocument(
-      <VacancyList type="company" userId={1} url="test" />);
-    vacancyList.state.vacancies = response;
-    expect(vacancyList.generateVacancies()).to.exist;
-    fetchMock.restore();
-  });
-
-  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" />);
-    vacancyList.updateStatusList();
-    expect(JSON.stringify(vacancyList.state.bookmarkList)).to.be.defined;
-    fetchMock.restore();
-  });
-
-  it('renders marked bookmarked vacancies without problem', () => {
-    fetchMock.get('*', response);
     const vacancyList = ReactTestUtils.renderIntoDocument(
-      <VacancyList userId={1} url="test" />);
-    vacancyList.state.vacancies = response;
-    vacancyList.state.bookmarkList = [{ id: 5 }, { id: 3 }, { id: 1 }];
-    vacancyList.updateStatusList();
+      <VacancyList items={newResponse} userId={1} user={companyUser} />);
+    vacancyList.state.vacancies = newResponse;
     expect(vacancyList.generateVacancies()).to.exist;
-    fetchMock.restore();
   });
 
-  it('renders not marked vacancies without problem', () => {
-    fetchMock.get('*', response);
-    const vacancyList = ReactTestUtils.renderIntoDocument(
-      <VacancyList userId={1} url="test" />);
-    vacancyList.state.vacancies = response;
-    vacancyList.state.bookmarkList = [{ id: 6 }, { id: 4 }, { id: 2 }];
-    expect(vacancyList.generateVacancies()).to.exist;
+  // it('renders with problem for company', () => {
+  //   const vacancyList = ReactTestUtils.renderIntoDocument(
+  //     <VacancyList type="company" userId={1} url="test" />);
+  //   vacancyList.state.vacancies = response;
+  //   expect(vacancyList.generateVacancies()).to.exist;
+  // });
+  //
+  // it('update bookmarks without problem', () => {
+  //   const vacancyList = ReactTestUtils.renderIntoDocument(
+  //     <VacancyList userId={1} url="test" />);
+  //   vacancyList.state.appliedList = [{ id: 1 }, { id: 3 }];
+  //   vacancyList.updateStatusList().then(() => {
+  //     expect(JSON.stringify(vacancyList.state.bookmarkList)).to.be.defined;
+  //   });
+  // });
+  //
+  // it('check applied vacancies without problem', () => {
+  //   const vacancyList = ReactTestUtils.renderIntoDocument(
+  //     <VacancyList userId={1} url="test" />);
+  //   vacancyList.updateStatusList().then(() => {
+  //     expect(JSON.stringify(vacancyList.state.bookmarkList)).to.be.defined;
+  //   });
+  // });
+  //
+  // it('renders marked bookmarked vacancies without problem', (done) => {
+  //   const vacancyList = ReactTestUtils.renderIntoDocument(
+  //     <VacancyList userId={1} url="test" />);
+  //   vacancyList.state.vacancies = response;
+  //   vacancyList.state.bookmarkList = [{ id: 5 }, { id: 3 }, { id: 1 }];
+  //   vacancyList.updateStatusList().then(() => {
+  //     expect(vacancyList.generateVacancies()).to.exist;
+  //     done();
+  //   }, () => done());
+  // });
+  //
+  // it('renders not marked vacancies without problem', () => {
+  //   fetchMock.get('*', response);
+  //   const vacancyList = ReactTestUtils.renderIntoDocument(
+  //     <VacancyList userId={1} url="test" />);
+  //   vacancyList.state.vacancies = response;
+  //   vacancyList.state.bookmarkList = [{ id: 6 }, { id: 4 }, { id: 2 }];
+  //   expect(vacancyList.generateVacancies()).to.exist;
+  //   fetchMock.restore();
+  // });
+  //
+  // it('success calling API', () => {
+  //   fetchMock.get('*', response);
+  //   const vacancyList = ReactTestUtils.renderIntoDocument(
+  //     <VacancyList userId={1} url="test" />);
+  //   vacancyList.state.vacancies = response;
+  //   expect(JSON.stringify(vacancyList.state.vacancies)).to.equal(JSON.stringify(response));
+  //   fetchMock.restore();
+  // });
+  //
+  it('success delete vacancy', () => {
     fetchMock.restore();
-  });
-
-  it('success calling API', () => {
-    fetchMock.get('*', response);
-    const vacancyList = ReactTestUtils.renderIntoDocument(
-      <VacancyList userId={1} url="test" />);
-    vacancyList.state.vacancies = response;
-    expect(JSON.stringify(vacancyList.state.vacancies)).to.equal(JSON.stringify(response));
-    fetchMock.restore();
-  });
-
-  it('success delete vacancy', (done) => {
     fetchMock.delete('*', response2);
-    fetchMock.get('*', response);
     const vacancyList = ReactTestUtils.renderIntoDocument(
-      <VacancyList userId={1} url="test" deleteCallback={() => {}} />);
-    vacancyList.state.vacancies = response;
+      <VacancyList userId={1} url="test" deleteCallback={() => {}} user={companyUser} />);
+    vacancyList.state.vacancies = newResponse;
     vacancyList.deleteVacancy(1).then(() => {
       expect(JSON.stringify(vacancyList.state.vacancies)).to.equal(JSON.stringify(response));
       fetchMock.restore();
-      done();
     }, () => {
       fetchMock.restore();
-      done();
     });
   });
 
-  it('fails delete vacancy', (done) => {
+  it('fails delete vacancy', () => {
+    fetchMock.restore();
     fetchMock.delete('*', 404);
-    fetchMock.get('*', response);
     const vacancyList = ReactTestUtils.renderIntoDocument(
-      <VacancyList userId={1} url="test" deleteCallback={() => {}} />
+      <VacancyList userId={1} items={newResponse} user={companyUser} deleteCallback={() => {}} />,
     );
-    vacancyList.state.vacancies = response;
+    vacancyList.state.vacancies = newResponse;
     vacancyList.deleteVacancy(1).then(() => {
       fetchMock.restore();
       done();
     }, () => {
-      expect(JSON.stringify(vacancyList.state.vacancies)).to.equal(JSON.stringify(response));
+      expect(JSON.stringify(vacancyList.state.vacancies)).to.equal(JSON.stringify(newResponse));
       fetchMock.restore();
       done();
     });
diff --git a/assets/js/__test__/components/VerifyAdminModal-test b/assets/js/__test__/components/VerifyAdminModal-test.jsx
similarity index 100%
rename from assets/js/__test__/components/VerifyAdminModal-test
rename to assets/js/__test__/components/VerifyAdminModal-test.jsx
diff --git a/assets/js/components/AdminVacancy.jsx b/assets/js/components/AdminVacancy.jsx
index df12d6f8bd881a01510a6cf97944a034f33c1f7d..d8b164752a33b891b3527a0e54cc1bc61295c320 100644
--- a/assets/js/components/AdminVacancy.jsx
+++ b/assets/js/components/AdminVacancy.jsx
@@ -1,23 +1,43 @@
 import React from 'react';
-import { Item, Grid, Icon } from 'semantic-ui-react';
+import { Item, Grid, Icon, Button } from 'semantic-ui-react';
 import VerifyAdminModal from './VerifyAdminModal';
 
 export default class AdminVacancy extends React.Component {
+  static propTypes = {
+    data: React.PropTypes.object.isRequired,
+  };
+
+
+  verifyVacancy(){
+    //define here
+  }
+   unverifyVacancy(){
+    //define here
+  }
+
+  generateButton(){
+    const unverifyButton = <Button floated="right" color="red" onClick='{this.unverifyVacancy}'>Batalkan Verifikasi</Button>;
+    const verifyButton = <Button floated="right" color="blue" onClick='{this.unverifyVacancy}'>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">Software Engineer</Item.Header>
+          <Item.Header as="a">{this.props.data.name}</Item.Header>
           <Grid.Row>
             <Grid.Column floated="left">
-              <h4>Jalanloka </h4>
-                Jakarta Barat, DKI Jakarta
+              <h4>{this.props.data.company.name} </h4>
+                {this.props.data.company.address}
             </Grid.Column>
             <Grid.Column floated="right">
-              <h4> <Icon name="remove circle" size="large" color="red" /> Belum Terverifikasi </h4>
-              <VerifyAdminModal />
+              {this.generateButton()}
             </Grid.Column>
           </Grid.Row>
         </Item.Content>
diff --git a/assets/js/components/Applicant.jsx b/assets/js/components/Applicant.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..ca999696d421f28421afbfa9f49e92cc3131f42d
--- /dev/null
+++ b/assets/js/components/Applicant.jsx
@@ -0,0 +1,76 @@
+import React from 'react';
+import { Item, Rating, Grid } from 'semantic-ui-react';
+import Server from '../lib/Server';
+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,
+    updateStatus: React.PropTypes.func.isRequired,
+  };
+
+  static APPLICATION_STATUS = {
+    NEW: 0,
+    READ: 1,
+    BOOKMARKED: 2,
+    REJECTED: 3,
+    ACCEPTED: 4,
+  };
+
+  static APPLICATION_STATUS_TEXT = ['Baru', 'Sudah Dibaca', 'Ditandai', 'Diterima', 'Ditolak'];
+
+  constructor(props) {
+    super(props);
+    /* istanbul ignore next */
+    this.bookmark = this.bookmark.bind(this);
+  }
+
+  bookmark = () => {
+    let data = { status: Applicant.APPLICATION_STATUS.BOOKMARKED };
+    if (this.props.data.status === Applicant.APPLICATION_STATUS.BOOKMARKED) {
+      data = { status: Applicant.APPLICATION_STATUS.READ };
+    }
+
+    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" style={{ wordWrap: 'break-word', width: '100%' }}>
+          <Item.Extra>
+            <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>
+    );
+  }
+}
diff --git a/assets/js/components/ApplicantList.jsx b/assets/js/components/ApplicantList.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..ad542fc63cf811a403fac4c02eb0d6517a7ae49a
--- /dev/null
+++ b/assets/js/components/ApplicantList.jsx
@@ -0,0 +1,51 @@
+import React from 'react';
+import { Item, Grid } from 'semantic-ui-react';
+import Applicant from './Applicant';
+
+export default class ApplicantList extends React.Component {
+
+  static propTypes = {
+    items: React.PropTypes.array,
+    status: React.PropTypes.number.isRequired,
+  };
+
+  static defaultProps = {
+    items: [],
+  };
+
+  constructor(props) {
+    super(props);
+    /* istanbul ignore next */
+    this.state = { applications: this.props.items };
+    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() {
+    return this.state.applications.map(application =>
+      application.status === this.props.status && (<Applicant
+        key={application.id} data={application}
+        updateStatus={this.updateStatus}
+      />),
+    );
+  }
+
+  render = () => (
+    <Grid container doubling>
+      <Item.Group relaxed style={{ width: '100%' }}>
+        { this.generateApplicants() }
+      </Item.Group>
+    </Grid>
+  );
+}
diff --git a/assets/js/components/ApplyModal.jsx b/assets/js/components/ApplyModal.jsx
index e061da2afeb1a456a3abbe9fa0878d925776b1bb..6a830a8664e2dfbd252cfd0848491783a940b5d1 100644
--- a/assets/js/components/ApplyModal.jsx
+++ b/assets/js/components/ApplyModal.jsx
@@ -1,13 +1,16 @@
 import React from 'react';
 import { Icon, Modal, Button, TextArea, Form } from 'semantic-ui-react';
 import ModalAlert from './../components/ModalAlert';
+import Server from './../lib/Server';
 
 export default class ApplyModal extends React.Component {
   static propTypes = {
     data: React.PropTypes.object.isRequired,
     active: React.PropTypes.bool.isRequired,
     buttonTitle: React.PropTypes.string.isRequired,
-    apply: React.PropTypes.func.isRequired,
+    resume: React.PropTypes.string.isRequired,
+    studentId: React.PropTypes.number.isRequired,
+    updateStatus: React.PropTypes.func.isRequired,
   };
 
   constructor(props) {
@@ -33,15 +36,19 @@ export default class ApplyModal extends React.Component {
 
   handleClose = () => this.setState({
     modalOpen: false,
+    load: false,
   });
 
   handleApply = () => {
-    this.load();
-    this.props.apply();
+    this.setState({ load: true });
+    const requestData = { vacancy_id: this.props.data.id, cover_letter: this.state.coverLetter };
+    Server.post(`/students/${this.props.studentId}/applied-vacancies/`, requestData).then(() => {
+      this.modalAlert.open('Pendaftaran Berhasil', 'Pendaftaran anda berhasil direkam. Harap menunggu kabar selanjutnya dari pihak yang terkait\n', this.handleClose);
+      this.props.updateStatus('registered');
+    }, () => this.modalAlert.open('Pendaftaran Gagal', 'Maaf pendaftaran yang anda lakukan gagal. Harap ulangi pendaftaran atau hubungi administrator\n', this.handleClose),
+    );
   };
 
-  load = () => this.setState({ load: true });
-
   render = () => (
     <Modal
       trigger={<Button primary onClick={this.handleOpen} floated="right">{this.props.buttonTitle}</Button>}
@@ -59,11 +66,13 @@ export default class ApplyModal extends React.Component {
         </Modal.Description>
         {this.props.active && (
           <div className="coverLetter">
+            <br />
             <div className="linkCV">
-              <a> your latest CV </a>
+              <a href={this.props.resume} target="_blank" rel="noopener noreferrer"> Klik untuk lihat CV terakhirmu</a>
             </div>
+            <br />
             <div>
-              <h5> Write your Cover Letter </h5>
+              <h5>Cover Letter </h5>
               <Form >
                 <TextArea placeholder="Tell us more" size="big" onChange={this.handleChange} />
               </Form>
diff --git a/assets/js/components/ApproveModal.jsx b/assets/js/components/ApproveModal.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..132083a6b9dcaa27338a0b8c8e95b4af37f310a4
--- /dev/null
+++ b/assets/js/components/ApproveModal.jsx
@@ -0,0 +1,110 @@
+import React from 'react';
+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,
+    updateStatus: React.PropTypes.func.isRequired,
+  };
+
+  constructor(props) {
+    super(props);
+    /* 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);
+    this.gotoStudentResume = this.gotoStudentResume.bind(this);
+    this.gotoStudentTranscript = this.gotoStudentTranscript.bind(this);
+  }
+
+  handleOpen = () => this.setState({ modalOpen: true });
+  handleClose = () => { this.readApplication(); this.setState({ modalOpen: false }); }
+
+  readApplication = () => {
+    const data = { status: Applicant.APPLICATION_STATUS.READ };
+    return this.props.data.status === Applicant.APPLICATION_STATUS.NEW && Server.patch(`/applications/${this.props.data.id}/`, data).then((status) => {
+      this.props.updateStatus(this.props.data.id, status.status);
+    });
+  };
+
+  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,
+    );
+  };
+
+  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);
+    });
+  };
+
+  gotoLink = (url) => {
+    const win = window.open(url);
+    win.focus();
+  };
+
+  gotoStudentResume = () => this.gotoLink(this.props.data.student.resume);
+
+  gotoStudentTranscript = () => this.gotoLink(`/transcript/${this.props.data.id}`);
+
+  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">Detail</Button>}
+      closeIcon="close"
+      open={this.state.modalOpen}
+      onClose={this.handleClose}
+    >
+      <ConfirmationModal ref={(modal) => { this.modal = modal; }} />
+      <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 />
+        </div>
+      </Modal.Content>
+      <Modal.Actions>
+        <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>
+    )
+}
+
diff --git a/assets/js/components/Company.jsx b/assets/js/components/Company.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..273444a91fb26db772a353e50fa4dc87ccaace51
--- /dev/null
+++ b/assets/js/components/Company.jsx
@@ -0,0 +1,91 @@
+import React from 'react';
+import { Item, Button, Grid, Icon } from 'semantic-ui-react';
+import Server from '../lib/Server';
+import ModalAlert from './ModalAlert';
+import Storage from './../lib/Storage';
+
+const defaultImage = 'http://semantic-ui.com/images/wireframe/image.png';
+
+export default class Company extends React.Component {
+  static propTypes = {
+    data: React.PropTypes.object.isRequired,
+    updateStatus: React.PropTypes.func.isRequired,
+  };
+
+  static COMPANY_STATUS = {
+    NEW: 0,
+    UNVERIFIED: 1,
+    VERIFIED: 2,
+    ALL: 3,
+  };
+
+  constructor(props) {
+    super(props);
+    /* istanbul ignore next */
+    this.state = {
+      rejectLoading: false,
+      acceptLoading: false,
+    };
+    this.accept = this.accept.bind(this);
+    this.reject = this.reject.bind(this);
+    this.goToCompanyHome = this.goToCompanyHome.bind(this);
+  }
+
+  reject = () => {
+    const data = { status: Company.COMPANY_STATUS.UNVERIFIED };
+    this.setState({ rejectLoading: true });
+    Server.patch(`/companies/${this.props.data.id}/`, data).then((response) => {
+      this.setState({ rejectLoading: false });
+      this.props.updateStatus(this.props.data.id, response.status);
+    }, () => this.setState({ rejectLoading: false }));
+  };
+
+  accept = () => {
+    const data = { status: Company.COMPANY_STATUS.VERIFIED };
+    this.setState({ acceptLoading: true });
+    Server.patch(`/companies/${this.props.data.id}/`, data).then((response) => {
+      this.setState({ acceptLoading: false });
+      this.props.updateStatus(this.props.data.id, response.status);
+    }, () => this.setState({ acceptLoading: false }));
+  };
+
+  goToCompanyHome = () => {
+    const userData = Storage.get('user-data');
+    userData.company = this.props.data;
+    Storage.set('user-data', userData);
+    const win = window.open('/lowongan');
+    win.focus();
+  };
+
+  render() {
+    return (
+      <Item >
+        <ModalAlert ref={(modal) => { this.modalAlert = modal; }} />
+        <Item.Image size="small" src={this.props.data.logo ? this.props.data.logo : defaultImage} />
+        <Item.Content verticalAlign="middle" style={{ wordWrap: 'break-word', width: '100%' }} >
+          <Item.Extra>
+            <Grid.Row>
+              <Grid.Column floated="left" style={{ width: '100%' }}>
+                <h4> {this.props.data.name} </h4>
+                {this.props.data.address}
+              </Grid.Column>
+              <Grid.Column floated="right" textAlign="center">
+                <div>
+                  {this.props.data.status === Company.COMPANY_STATUS.VERIFIED || <Button loading={this.state.acceptLoading} onClick={this.accept} floated="right" color="green" >
+                    <Icon name="checkmark" />Terima
+                  </Button>}
+                  {this.props.data.status === Company.COMPANY_STATUS.UNVERIFIED || <Button loading={this.state.rejectLoading} onClick={this.reject} floated="right" color="red" >
+                    <Icon name="remove" />Tolak
+                  </Button>}
+                  <Button onClick={this.goToCompanyHome} floated="right" color="facebook" >
+                    <Icon name="home" />Login
+                  </Button>
+                </div>
+              </Grid.Column>
+            </Grid.Row>
+          </Item.Extra>
+        </Item.Content>
+      </Item>
+    );
+  }
+}
diff --git a/assets/js/components/CompanyList.jsx b/assets/js/components/CompanyList.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..fe99956b1af8a3c34a676c8993f3535a07d0e9bb
--- /dev/null
+++ b/assets/js/components/CompanyList.jsx
@@ -0,0 +1,55 @@
+import React from 'react';
+import { Item, Grid } from 'semantic-ui-react';
+import Company from '../components/Company';
+
+export default class CompanyList extends React.Component {
+
+  static propTypes = {
+    items: React.PropTypes.array,
+    status: React.PropTypes.number.isRequired,
+  };
+
+  static defaultProps = {
+    items: [],
+  };
+
+  constructor(props) {
+    super(props);
+    /* istanbul ignore next */
+    this.state = { companies: this.props.items };
+
+    this.generateCompanies = this.generateCompanies.bind(this);
+    this.updateStatus = this.updateStatus.bind(this);
+  }
+
+  updateStatus(id, status) {
+    const obj = [];
+    this.state.companies.map((company) => {
+      const clonedObj = {};
+      Object.assign(clonedObj, company);
+      if (company.id === id) clonedObj.status = status;
+      return obj.push(clonedObj);
+    });
+    this.setState({ companies: obj });
+  }
+
+  generateCompanies() {
+    return this.state.companies.map(company =>
+      (company.status === this.props.status || Company.COMPANY_STATUS.ALL === this.props.status) &&
+      (<Company
+        key={company.id} data={company}
+        updateStatus={this.updateStatus}
+      />),
+    );
+  }
+
+  render = () => (
+    <div>
+      <Grid container doubling>
+        <Item.Group relaxed style={{ width: '100%' }}>
+          { this.generateCompanies() }
+        </Item.Group>
+      </Grid>
+    </div>
+  );
+}
diff --git a/assets/js/components/CompanyRegisterModal.jsx b/assets/js/components/CompanyRegisterModal.jsx
index 7f1a6b2257a400819382b345c715775d5bb5541e..450c3cd23b544eabc6fc77513fa5153a25292451 100644
--- a/assets/js/components/CompanyRegisterModal.jsx
+++ b/assets/js/components/CompanyRegisterModal.jsx
@@ -10,7 +10,9 @@ export default class CompanyRegisterModal extends React.Component {
   constructor(props) {
     super(props);
     /* istanbul ignore next */
+    this.state = { loading: false };
     this.handleChange = this.handleChange.bind(this);
+    this.handleFile = this.handleFile.bind(this);
     this.handleSubmit = this.handleSubmit.bind(this);
   }
 
@@ -18,6 +20,10 @@ export default class CompanyRegisterModal extends React.Component {
     this.setState({ [e.target.name]: e.target.value });
   };
 
+  handleFile = (e) => {
+    this.setState({ [e.target.name]: e.target.files[0] });
+  };
+
 
   handlePassword = (e) => {
     if (e.target.name === 'password') this.passwordField = e.target; else
@@ -34,11 +40,12 @@ export default class CompanyRegisterModal extends React.Component {
 
   handleSubmit = (e) => {
     e.preventDefault();
-
+    this.setState({ loading: true });
     Server.submit('/register/', this.state).then((response) => {
       Storage.set('user-data', response);
       browserHistory.push('/home');
     }, error => error.then((r) => {
+      this.setState({ loading: false });
       this.modalAlert.open('Gagal Membuat Akun', r.error);
     }));
   };
@@ -81,7 +88,7 @@ export default class CompanyRegisterModal extends React.Component {
           <Form.Field required>
             <label htmlFor="logo">Logo</label>
             <Input
-              onChange={this.handleChange}
+              onChange={this.handleFile}
               name="logo"
               icon={{ name: 'attach', circular: true, link: true }}
               placeholder="attach logo"
@@ -97,12 +104,11 @@ export default class CompanyRegisterModal extends React.Component {
             <label htmlFor="address">Alamat</label>
             <Input onChange={this.handleChange} placeholder="Alamat" name="address" required />
           </Form.Field>
-
+          <Modal.Actions style={{ textAlign: 'right' }}>
+            <Button loading={this.state.loading} type="submit" color="blue"> <Icon name="checkmark" />Submit</Button>
+          </Modal.Actions>
         </Form>
       </Modal.Content>
-      <Modal.Actions>
-        <Button type="submit" onClick={this.handleSubmit} color="blue"> <Icon name="checkmark" />Submit</Button>
-      </Modal.Actions>
     </Modal>
   )
 }
diff --git a/assets/js/components/ConfirmationModal.jsx b/assets/js/components/ConfirmationModal.jsx
index a8a0ee47dfb2a5e0f36694a591a49cbc57233f20..800e30175e6fd8b4cf1858ff6c6f3a7cc97e2767 100644
--- a/assets/js/components/ConfirmationModal.jsx
+++ b/assets/js/components/ConfirmationModal.jsx
@@ -37,7 +37,7 @@ export default class ConfirmationModal extends React.Component {
   handleYes = () => { this.state.callback(); this.handleClose(); }
 
   open = (header = this.state.header, content = this.state.content, icon = this.state.icon, callback = this.state.callback()) => {
-    this.setState({ modalOpen: true, header, content, callback });
+    this.setState({ modalOpen: true, header, content, callback, icon });
   };
 
   render = () => (
diff --git a/assets/js/components/Course.jsx b/assets/js/components/Course.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..03f005047c240a3c51e4b5f89a422243875a01fc
--- /dev/null
+++ b/assets/js/components/Course.jsx
@@ -0,0 +1,16 @@
+import React from 'react';
+import { Table } from 'semantic-ui-react';
+
+export default class Course extends React.Component {
+  static propTypes = {
+    courseName: React.PropTypes.string.isRequired,
+    grade: React.PropTypes.string.isRequired,
+  };
+
+  render = () => (
+    <Table.Row>
+      <Table.Cell>{this.props.courseName}</Table.Cell>
+      <Table.Cell>{this.props.grade}</Table.Cell>
+    </Table.Row>
+  );
+}
diff --git a/assets/js/components/CourseList.jsx b/assets/js/components/CourseList.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..46abb1d1122fcee4b10c3b62208f2d911b6a418b
--- /dev/null
+++ b/assets/js/components/CourseList.jsx
@@ -0,0 +1,44 @@
+import React from 'react';
+import { Grid, Segment, Table } from 'semantic-ui-react';
+import Course from './Course';
+export default class CourseList extends React.Component {
+
+  static propTypes = {
+    data: React.PropTypes.object.isRequired,
+  };
+
+  constructor(props) {
+    super(props);
+    /* istanbul ignore next */
+    this.state = { course: this.props.data.transcript };
+  }
+
+
+  generateCourse() {
+    return this.state.course.map((course, index) => course.kelas ? (<Course
+      key={index}
+      grade={course.nilai}
+      courseName={course.kelas.nm_kls}
+    />) : null);
+  }
+
+  render = () => (
+    <Grid.Column>
+      <Segment>
+        <h2>Nama : {this.props.data.name}</h2>
+        <Table unstackable>
+          <Table.Header>
+            <Table.Row>
+              <Table.HeaderCell>Mata Kuliah</Table.HeaderCell>
+              <Table.HeaderCell>Nilai</Table.HeaderCell>
+            </Table.Row>
+          </Table.Header>
+
+          <Table.Body>
+            { this.generateCourse() }
+          </Table.Body>
+        </Table>
+      </Segment>
+    </Grid.Column>
+  );
+}
diff --git a/assets/js/components/Footer.jsx b/assets/js/components/Footer.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..50a57ae5676d99b2ebc73b3354e20dea949e5aa0
--- /dev/null
+++ b/assets/js/components/Footer.jsx
@@ -0,0 +1,14 @@
+import React from 'react';
+import { Container } from 'semantic-ui-react';
+
+export default class Footer extends React.Component {
+  render() {
+    return (
+      <div className="footer">
+        <Container textAlign="center">
+          <h5>All Rights Reserved © 2017</h5>
+        </Container>
+      </div>
+    );
+  }
+}
diff --git a/assets/js/components/LoginForm.jsx b/assets/js/components/LoginForm.jsx
index eb120ba307153ce00471fc2616cbaf2b42f88e73..360cb2f486f586ca88be43683e470fe2c47a31c6 100644
--- a/assets/js/components/LoginForm.jsx
+++ b/assets/js/components/LoginForm.jsx
@@ -9,7 +9,6 @@ export default class LoginForm extends React.Component {
   static propTypes = {
     type: React.PropTypes.string.isRequired,
     imgSrc: React.PropTypes.string,
-    imgSize: React.PropTypes.string,
     header: React.PropTypes.string,
   };
 
@@ -53,14 +52,14 @@ export default class LoginForm extends React.Component {
 
       <Segment.Group>
         <Segment>
-          <Image src={`./assets/img/${this.props.imgSrc}`} size={this.props.imgSize} verticalAlign="middle" /> <span>{ this.props.header }</span>
+          <Image src={`./assets/img/${this.props.imgSrc}`} verticalAlign="middle" /> <span>{ this.props.header }</span>
         </Segment>
 
         <Segment inverted className="header" >
           <Form loading={this.state.loading} onSubmit={e => this.handleSubmit(e)} error={this.state.errorFlag}>
             <Form.Group widths="equal">
               <Form.Field>
-                <label htmlFor="id"> Username </label>
+                <label htmlFor="id"> Email </label>
                 <Input type="text" id="username" icon="user" iconPosition="left" placeholder="username" onChange={e => this.handleChange(e, 'username')} required />
               </Form.Field>
             </Form.Group>
diff --git a/assets/js/components/Pagination.jsx b/assets/js/components/Pagination.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..5fad6a064eda6b742243b9bbcbbe432898f09037
--- /dev/null
+++ b/assets/js/components/Pagination.jsx
@@ -0,0 +1,119 @@
+import React from 'react';
+import { Menu, Container, Icon, Loader } from 'semantic-ui-react';
+import Server from '../lib/Server';
+import ModalAlert from '../components/ModalAlert';
+
+
+export default class Pagination extends React.Component {
+
+  static propTypes = {
+    url: React.PropTypes.string.isRequired,
+    child: React.PropTypes.node.isRequired,
+    error: React.PropTypes.string,
+  };
+
+  static defaultProps = {
+    error: 'Gagal Mengambil Data',
+  };
+
+  constructor(props) {
+    super(props);
+    /* istanbul ignore next */
+    this.state = {
+      items: [],
+      current: 1,
+      next: '',
+      prev: '',
+      url: this.props.url,
+      loading: true,
+      dir: 0,
+      start: true,
+      finish: false,
+    };
+    this.handleNext = this.handleNext.bind(this);
+    this.handlePrev = this.handlePrev.bind(this);
+    this.getItemsData = this.getItemsData.bind(this);
+    this.handleMovement = this.handleMovement.bind(this);
+    this.refresh = this.refresh.bind(this);
+    this.content = this.content.bind(this);
+    this.pageMenu = this.pageMenu.bind(this);
+    this.getItemsData();
+  }
+
+  getItemsData = () => Server.get(this.state.url, false).then((data) => {
+    this.setState({ current: this.state.current + this.state.dir });
+    this.setState(
+      { items: data.results,
+        next: `${this.props.url}?page=${this.state.current + 1}`,
+        prev: `${this.props.url}?page=${this.state.current - 1}`,
+        loading: false,
+      });
+    let first = true;
+    let last = true;
+    if (data.previous) {
+      first = false;
+    }
+    if (data.next) {
+      last = false;
+    }
+    this.setState({ first, last });
+  }, error => error.then((r) => {
+    this.modalAlert.open(this.props.error, r.detail);
+  }));
+
+  refresh() {
+    this.forceUpdate();
+  }
+
+  handleMovement(dir) {
+    const newUrl = this.state[dir];
+    this.setState({ url: newUrl, loading: true }, function () {
+      this.getItemsData();
+    });
+  }
+
+  handlePrev() {
+    if (!this.state.first) {
+      this.setState({ dir: -1 }, function () {
+        this.handleMovement('prev');
+      });
+    }
+  }
+
+  handleNext = () => {
+    if (!this.state.last) {
+      this.setState({ dir: 1 }, function () {
+        this.handleMovement('next');
+      });
+    }
+  };
+
+  pageMenu() {
+    return (<Container textAlign="right">
+      <Menu pagination icon="labeled" className="vacancyList">
+        <Menu.Item name="prev" disabled={this.state.first} onClick={this.handlePrev}>
+          <span><Icon disabled={this.state.first} name="angle left" /></span>
+        </Menu.Item>
+        <Menu.Item name="current" active onClick={this.refresh}>
+          {this.state.current}
+        </Menu.Item>
+        <Menu.Item name="next" disabled={this.state.last} onClick={this.handleNext}>
+          <span><Icon disabled={this.state.last} name="angle right" /></span>
+        </Menu.Item>
+      </Menu>
+    </Container>);
+  }
+
+  content() {
+    return React.cloneElement(this.props.child, { items: this.state.items });
+  }
+
+  render = () => (
+    <div>
+      <Loader active={this.state.loading} />
+      <ModalAlert ref={(modal) => { this.modalAlert = modal; }} />
+      {!this.state.loading && this.content()}
+      {!this.state.loading && this.pageMenu()}
+    </div>
+  );
+}
diff --git a/assets/js/components/TopMenu.jsx b/assets/js/components/TopMenu.jsx
index de83a3cdcfcc095ae92df3227ffd1342e528df09..2d19743456354ffccb046c44725d658ace89e3cd 100644
--- a/assets/js/components/TopMenu.jsx
+++ b/assets/js/components/TopMenu.jsx
@@ -4,13 +4,13 @@ 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 = {
     user: React.PropTypes.object.isRequired,
-    name: React.PropTypes.string.isRequired,
-    email: React.PropTypes.string.isRequired,
-    photo: React.PropTypes.any.isRequired,
   };
 
   constructor(props) {
@@ -19,29 +19,46 @@ export default class TopMenu extends React.Component {
     console.log(this.props.user);
     this.state = { activeItem: 'home' };
     this.logout = this.logout.bind(this);
+    this.logoutCompany = this.logoutCompany.bind(this);
   }
 
   handleItemClick = (e, { name }) => this.setState({ activeItem: name });
 
-  logout = () => {
+  logout = (e) => {
+    e.preventDefault();
     Server.get('/api-auth/logout/?next=/', true).then(() => {
       Storage.clear();
       browserHistory.push('/login');
     });
   };
 
+  logoutCompany = /* istanbul ignore next */ (e) => {
+    e.preventDefault();
+    const userData = Storage.get('user-data');
+    userData.company = null;
+    Storage.set('user-data', userData);
+    window.location.replace('/home');
+  };
+
   render() {
     const { activeItem } = this.state;
 
     return (
-      <Menu color="blue" pointing secondary>
+      <div>
+        { this.props.user.data.is_staff && this.props.user.data.company && (
+          <div className="admin-bar">
+            Anda login sebagai perusahaan: {this.props.user.data.company.name} (#{this.props.user.data.company.id}).
+            Untuk keluar, silahkan klik <a href="#" onClick={this.logoutCompany}> link ini</a>
+          </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>
             <Popup
               trigger={<Image
-                as={Link} to="/profil" src={this.props.photo} avatar
+                as={Link} to="/profil" src={this.props.user.data.photo || defaultPicture} avatar
                 onClick={this.handleItemClick}
               />}
               flowing
@@ -49,8 +66,8 @@ export default class TopMenu extends React.Component {
             >
 
               <Card
-                header={this.props.name}
-                description={this.props.email}
+                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>
 
@@ -59,6 +76,7 @@ export default class TopMenu extends React.Component {
           </Menu.Item>
         </Menu.Menu>
       </Menu>
+      </div>
     );
   }
 }
diff --git a/assets/js/components/Vacancy.jsx b/assets/js/components/Vacancy.jsx
index 80069414adf64f8b7e48199ca05bf4ee409efd77..23b5f62b9e61e4f798cfad8581aab3807985c8d8 100644
--- a/assets/js/components/Vacancy.jsx
+++ b/assets/js/components/Vacancy.jsx
@@ -1,5 +1,6 @@
 import React from 'react';
-import { Item, Rating, Button } from 'semantic-ui-react';
+import { Item, Rating, Button, Grid } from 'semantic-ui-react';
+import moment from 'moment';
 import ApplyModal from './ApplyModal';
 import Server from '../lib/Server';
 import ConfirmationModal from './ConfirmationModal';
@@ -9,14 +10,26 @@ const defaultImage = 'http://semantic-ui.com/images/wireframe/image.png';
 
 export default class Vacancy extends React.Component {
   static propTypes = {
-    studentId: React.PropTypes.number.isRequired,
+    user: React.PropTypes.object.isRequired,
+    // studentId: React.PropTypes.number.isRequired,
     data: React.PropTypes.object.isRequired,
     bookmarked: React.PropTypes.number,
-    status: React.PropTypes.string.isRequired,
+    status: React.PropTypes.number,
   };
 
   static defaultProps = {
     bookmarked: 0,
+    status: 0,
+  };
+
+  static APPLICATION_STATUS_TEXT = ['Dikirim', 'Dibaca', 'Dibaca', 'Ditolak', 'Diterima'];
+
+  static APPLICATION_STATUS = {
+    NEW: 0,
+    READ: 1,
+    BOOKMARKED: 2,
+    REJECTED: 3,
+    ACCEPTED: 4,
   };
 
   constructor(props) {
@@ -24,10 +37,12 @@ export default class Vacancy extends React.Component {
     /* istanbul ignore next */
     this.state = {
       bookmarked: this.props.bookmarked,
-      status: this.props.status,
-      deleteLoading: false
+      registeredStatus: this.props.status ? 'registered' : 'new',
+      deleteLoading: false,
     };
+    moment.locale('id');
     this.bookmark = this.bookmark.bind(this);
+    this.updateStatus = this.updateStatus.bind(this);
     this.generateAction = this.generateAction.bind(this);
     this.openConfirmationModal = this.openConfirmationModal.bind(this);
     this.removeVacancyApplication = this.removeVacancyApplication.bind(this);
@@ -36,20 +51,23 @@ export default class Vacancy extends React.Component {
   bookmark() {
     const data = { vacancy_id: this.props.data.id };
     if (this.state.bookmarked < 1) {
-      Server.post(`/students/${this.props.studentId}/bookmarked-vacancies/`, data);
+      Server.post(`/students/${this.props.user.data.student.id}/bookmarked-vacancies/`, data);
     } else {
-      Server.delete(`/students/${this.props.studentId}/bookmarked-vacancies/${this.props.data.id}/`);
+      Server.delete(`/students/${this.props.user.data.student.id}/bookmarked-vacancies/${this.props.data.id}/`);
     }
     this.state.bookmarked = 1 - this.state.bookmarked;
   }
 
+  updateStatus = (registeredStatus = 'registered') => this.setState({ registeredStatus });
+
   removeVacancyApplication() {
     this.setState({ deleteLoading: true });
-    Server.delete(`/students/${this.props.studentId}/applied-vacancies/${this.props.data.id}/`).then(() => {
+    Server.delete(`/students/${this.props.user.data.student.id}/applied-vacancies/${this.props.data.id}/`).then(() => {
       this.modalAlert.open('Pendaftaran Berhasil Dibatalkan', 'Pendaftaran anda berhasil dihapus dari sistem\n');
-      this.setState({ status: 'new' });
+      this.setState({ registeredStatus: 'new', deleteLoading: false });
     }, () => {
       this.modalAlert.open('Permintaan Gagal', 'Maaf permintaan anda gagal diproses sistem. Harap ulangi pendaftaran atau hubungi administrator\n');
+      this.setState({ deleteLoading: false });
     });
   }
 
@@ -62,26 +80,36 @@ export default class Vacancy extends React.Component {
     );
   }
 
-  apply = () => {
-    const requestData = { vacancy_id: this.props.data.id, cover_letter: this.state.coverLetter };
-
-    Server.post(`/students/${this.props.studentId}/applied-vacancies/`, requestData).then(() => {
-      this.modalAlert.open('Pendaftaran Berhasil', 'Pendaftaran anda berhasil direkam. Harap menunggu kabar selanjutnya dari pihak yang terkait\n', this.handleClose);
-      this.setState({ status: 'registered' });
-    }, () => this.modalAlert.open('Pendaftaran Gagal', 'Maaf pendaftaran yang anda lakukan gagal. Harap ulangi pendaftaran atau hubungi administrator\n', this.handleClose),
-    );
-  };
-
   generateAction() {
-    const applyModal = (<ApplyModal
-      active={this.state.status === 'new'}
-      data={{ header: this.props.data.name, description: this.props.data.description }}
-      buttonTitle="Detail"
-      apply={ this.apply }
-    />);
+    const applyModal = (
+      <ApplyModal
+        updateStatus={this.updateStatus}
+        active={this.state.registeredStatus === 'new'}
+        data={{
+          header: this.props.data.name,
+          description: this.props.data.description,
+          id: this.props.data.id,
+        }}
+        resume={this.props.user.data.student.resume}
+        buttonTitle="Detail"
+        studentId={this.props.user.data.student.id}
+      />
+    );
 
     const cancelButton = <Button loading={this.state.deleteLoading} floated="right" color="red" onClick={this.openConfirmationModal}>Batal</Button>;
-    return this.state.status === 'new' ? applyModal : cancelButton;
+    const rejectedButton =
+      <Button floated="right" color="red" disabled>{Vacancy.APPLICATION_STATUS_TEXT[this.props.status]}</Button>;
+    const acceptedButton =
+      <Button floated="right" color="blue" disabled>{Vacancy.APPLICATION_STATUS_TEXT[this.props.status]}</Button>;
+
+    if (this.props.status == null) {
+      return applyModal;
+    } else if (this.props.status === Vacancy.APPLICATION_STATUS.REJECTED) {
+      return rejectedButton;
+    } else if (this.props.status === Vacancy.APPLICATION_STATUS.ACCEPTED) {
+      return acceptedButton;
+    }
+    return cancelButton;
   }
 
   render() {
@@ -90,18 +118,24 @@ export default class Vacancy extends React.Component {
         <ConfirmationModal ref={(modal) => { this.confirmationModal = modal; }} />
         <ModalAlert ref={(modal) => { this.modalAlert = modal; }} />
         <Item.Image size="small" src={this.props.data.company.logo ? this.props.data.company.logo : defaultImage} />
-        <Item.Content verticalAlign="middle">
+        <Item.Content verticalAlign="middle" style={{ wordWrap: 'break-word', width: '100%' }} >
           <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 }<br /><br />
+                <b>{`Ditutup ${moment(moment(this.props.data.close_time)).fromNow()}`}</b>
+              </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>
diff --git a/assets/js/components/VacancyList.jsx b/assets/js/components/VacancyList.jsx
index e6fdad2ae3ff05387549b60a7e5cd3c7e1ac9714..78db463011fed46cac129959aa0b2bf912106f4a 100644
--- a/assets/js/components/VacancyList.jsx
+++ b/assets/js/components/VacancyList.jsx
@@ -1,62 +1,33 @@
 import React from 'react';
-import { Item, Button, Grid, Segment } from 'semantic-ui-react';
+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';
-import ModalAlert from '../components/ModalAlert';
-
 
 export default class VacancyList extends React.Component {
 
   static propTypes = {
-    url: React.PropTypes.string.isRequired,
+    user: React.PropTypes.object.isRequired,
     userId: React.PropTypes.number.isRequired,
-    type: React.PropTypes.string,
+    items: React.PropTypes.array,
   };
 
   static defaultProps = {
-    type: 'student',
+    items: [],
   };
 
   constructor(props) {
     super(props);
     /* istanbul ignore next */
-    this.state = { vacancies: [], bookmarkList: [], appliedList: [] };
-    if (this.props.type === 'student') {
-      this.updateStatusList();
-    }
-    Server.get(this.props.url, false).then((data) => {
-      this.setState({ vacancies: data });
-    });
-    this.updateStatusList = this.updateStatusList.bind(this);
+    this.state = {
+      vacancies: this.props.items,
+      bookmarkList: [],
+      appliedList: [],
+      loading: true,
+    };
     this.generateVacancies = this.generateVacancies.bind(this);
-    this.checkBookmark = this.checkBookmark.bind(this);
-    this.checkApplied = this.checkApplied.bind(this);
-    this.companyHeader = this.companyHeader.bind(this);
-  }
-
-  checkBookmark(id) {
-    for (let i = 0; i < this.state.bookmarkList.length; i += 1) {
-      if (id === this.state.bookmarkList[i].id) { return 1; }
-    }
-    return 0;
-  }
-
-  checkApplied(id) {
-    for (let i = 0; i < this.state.appliedList.length; i += 1) {
-      if (id === this.state.appliedList[i].id) { return 'registered'; }
-    }
-    return 'new';
-  }
-
-  updateStatusList() {
-    Server.get(`/students/${this.props.userId}/bookmarked-vacancies/`, false).then((data) => {
-      this.setState({ bookmarkList: data });
-    });
-    Server.get(`/students/${this.props.userId}/applied-vacancies/`, false).then((data) => {
-      this.setState({ appliedList: data });
-    });
   }
 
   deleteVacancy = id => Server.delete(`/vacancies/${id}/`, this.state).then(() => {
@@ -69,20 +40,28 @@ export default class VacancyList extends React.Component {
   }));
 
   generateVacancies() {
-    if (this.props.type === 'student') {
+    if (this.props.user.role === 'student') {
       return this.state.vacancies.map(vacancy =>
         (
           <Vacancy
             key={vacancy.id}
-            status={this.checkApplied(vacancy.id)}
-            bookmarked={this.checkBookmark(vacancy.id)}
+            status={vacancy.status}
+            user={this.props.user}
+            bookmarked={vacancy.bookmarked ? 1 : 0}
             data={vacancy}
             studentId={this.props.userId}
           />
         ),
       );
     }
-
+    if (this.props.user.role === 'admin' || this.props.user.role === 'supervisor'){
+      return this.state.vacancies.map(vacancy => (<AdminVacancy
+        key={vacancy.id}
+        data={vacancy}
+      />),
+      );  
+    }
+    
     return this.state.vacancies.map(vacancy => (<CompanyVacancy
       key={vacancy.id}
       data={vacancy}
@@ -92,10 +71,10 @@ export default class VacancyList extends React.Component {
   }
 
   companyHeader() {
-    if (this.props.type === 'company') {
+    if (this.props.user.role === 'company') {
       return (
-        <Grid textAlign="center">
-          <Button size="tiny" icon="eye" labelPosition="left" color="facebook" content="Lihat Semua Pendaftar" />
+        <Grid textAlign="center" style={{ paddingTop: '10px' }}>
+          <Button size="tiny" as={Link} to="/pelamar" icon="eye" labelPosition="left" color="facebook" content="Lihat Semua Pendaftar" />
           <Button size="tiny" as={Link} to="/buat-lowongan" icon="add" labelPosition="left" content="Tambah Lowongan Baru" color="teal" />
         </Grid>
       );
@@ -105,14 +84,13 @@ export default class VacancyList extends React.Component {
   }
 
   render = () => (
-    <Segment padded className="vacancyList-company">
-      <ModalAlert ref={(modal) => { this.modalAlert = modal; }} />
+    <div>
       <Grid container columns="eleven" doubling>
         { this.companyHeader() }
         <Item.Group relaxed style={{ width: '100%' }}>
           { this.generateVacancies() }
         </Item.Group>
       </Grid>
-    </Segment>
+    </div>
   );
 }
diff --git a/assets/js/index.jsx b/assets/js/index.jsx
index c2a082babb8b4241ecc9270ce86e8034dca54d49..9a3851a80838833f6d789c9673933815dd9ee347 100644
--- a/assets/js/index.jsx
+++ b/assets/js/index.jsx
@@ -5,11 +5,13 @@ import Dashboard from './Dashboard';
 import Login from './Login';
 import VacancyPage from './VacancyPage';
 import ProfilePage from './ProfilePage';
+import CompanyPage from './CompanyPage';
 import CompanyProfile from './CompanyProfile';
 import CreateVacancy from './CreateVacancy';
 import Server from './lib/Server';
 import Storage from './lib/Storage';
 import ApplicantPage from './ApplicantPage';
+import TranscriptPage from './TranscriptPage';
 
 export default class App extends React.Component {
 
@@ -67,41 +69,47 @@ export default class App extends React.Component {
   };
 
   handleHome= (nextState, replace, cb) => {
-    console.log(Server.isLoggedIn());
     if (Server.isLoggedIn()) {
-      console.log('masuk');
       if (App.getRole() === 'student') {
-        console.log('masuk3');
         replace({ pathname: '/lowongan' }); cb();
       } else if (App.getRole() === 'company') {
         replace({ pathname: '/lowongan' }); cb();
+      } else if (App.getRole() === 'admin') {
+        replace({ pathname: '/perusahaan' }); cb();
       }
     }
     replace({ pathname: '/login' }); cb();
   };
 
   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} />
-        <Route component={App.getRole() === 'student' ? student(Dashboard) : company(Dashboard)} onEnter={this.handleAuth} own>
-          <Route path="/lowongan" component={commonUser(VacancyPage)} />
+        <Route component={all(Dashboard)} onEnter={this.handleAuth}>
+          <Route path="/transcript/:id" component={company(TranscriptPage)} />
+          <Route path="/lowongan" component={all(VacancyPage)} />
           <Route path="/buat-lowongan" component={company(CreateVacancy)} />
           <Route path="/buat-lowongan/:id" component={company(CreateVacancy)} />
           <Route path="/pelamar" component={company(ApplicantPage)} />
           <Route path="/profil" component={App.getRole() === 'student' ? student(ProfilePage) : company(CompanyProfile)} own />
           <Route path="/mahasiswa/:id" component={grownups(ProfilePage)} />
-          <Route path="/perusahaan/:id" component={facultyMember(CompanyProfile)} />
+          <Route path="/perusahaan/:id" component={facultyMember(CompanyProfile)} 
+
+          />
+          <Route path="/perusahaan" component={supervisor(CompanyPage)} />
           <Route path="/transkrip/:id" component={facultyMember(CompanyProfile)} />
         </Route>
         <Route path="/home" onEnter={this.handleHome} />
+        <Route path="/admin-vacancy" component={VacancyPage} />
         <Redirect from="*" to="/home" />
       </Router>
     );
diff --git a/core/lib/mixins.py b/core/lib/mixins.py
new file mode 100644
index 0000000000000000000000000000000000000000..69555547426abc1a78ba865c4f691a819933b1df
--- /dev/null
+++ b/core/lib/mixins.py
@@ -0,0 +1,6 @@
+class MultiSerializerViewSetMixin(object):
+    def get_serializer_class(self):
+        try:
+            return self.serializer_action_classes[self.action]
+        except (KeyError, AttributeError):
+            return super(MultiSerializerViewSetMixin, self).get_serializer_class()
\ No newline at end of file
diff --git a/core/lib/permissions.py b/core/lib/permissions.py
index 71e53560835927daabb86b521fca31a8fee0559f..78091c84eef10e28d0119a2b0868bf810f53805b 100644
--- a/core/lib/permissions.py
+++ b/core/lib/permissions.py
@@ -1,32 +1,39 @@
 from rest_framework import permissions
-from rest_framework.exceptions import APIException
+from rest_framework.exceptions import PermissionDenied
 
 from core.models import Company
 from core.models import Student
 from core.models import Supervisor
+from core.models import Application
 
 
 def is_admin_or_student(user):
-    return user.is_superuser or hasattr(user, "student")
+    return user.is_superuser or user.is_staff or hasattr(user, "student")
 
 
 def is_admin_or_company(user):
-    return user.is_superuser or hasattr(user, "company")
+    if user.is_superuser or user.is_staff:
+        return True
+
+    if not hasattr(user, "company") or user.company.status != Company.VERIFIED :
+        raise PermissionDenied("This account is not valid company account or has not been verified")
+
+    return True
 
 
 def is_admin_or_supervisor(user):
-    return user.is_superuser or hasattr(user, "supervisor")
+    return user.is_superuser or user.is_staff or hasattr(user, "supervisor")
 
 
 def is_admin_or_supervisor_or_company(user):
-    return user.is_superuser or hasattr(user, "supervisor") or hasattr(user, "company")
+    return user.is_superuser or user.is_staff or hasattr(user, "supervisor") or hasattr(user, "company")
 
 
 class IsAdminOrSelfOrReadOnly(permissions.BasePermission):
     def has_object_permission(self, request, view, obj):
         if request.method in permissions.SAFE_METHODS:
             return True
-        if request.user.is_superuser:
+        if request.user.is_superuser or request.user.is_staff:
             return True
         # Instance must have an attribute named `user` or be `user`
         if hasattr(obj, "user"):
@@ -40,7 +47,7 @@ class IsAdminOrStudent(permissions.BasePermission):
 
     def has_object_permission(self, request, view, obj):
         user = request.user
-        if user.is_superuser:
+        if user.is_superuser or user.is_staff:
             return True
         student = None
         if isinstance(obj, Student):
@@ -48,7 +55,7 @@ class IsAdminOrStudent(permissions.BasePermission):
         elif hasattr(obj, "student"):
             student = obj.student
         else:
-            raise APIException(
+            raise PermissionDenied(
                 "Checking student permission on object {} not associated with Student"
                     .format(type(obj.__name__))
             )
@@ -62,7 +69,7 @@ class IsAdminOrSupervisor(permissions.BasePermission):
 
     def has_object_permission(self, request, view, obj):
         user = request.user
-        if user.is_superuser:
+        if user.is_superuser or user.is_staff:
             return True
         supervisor = None
         if isinstance(obj, Supervisor):
@@ -70,7 +77,7 @@ class IsAdminOrSupervisor(permissions.BasePermission):
         elif hasattr(obj, "supervisor"):
             supervisor = obj.supervisor
         else:
-            raise APIException(
+            raise PermissionDenied(
                 "Checking supervisor permission on object {} not associated with Supervisor"
                     .format(type(obj.__name__))
             )
@@ -84,7 +91,7 @@ class IsAdminOrCompany(permissions.BasePermission):
 
     def has_object_permission(self, request, view, obj):
         user = request.user
-        if user.is_superuser:
+        if user.is_superuser or user.is_staff:
             return True
         company = None
         if isinstance(obj, Company):
@@ -92,7 +99,7 @@ class IsAdminOrCompany(permissions.BasePermission):
         elif hasattr(obj, "company"):
             company = obj.company
         else:
-            raise APIException(
+            raise PermissionDenied(
                 "Checking company permission on object {} not associated with Company"
                     .format(type(obj.__name__))
             )
@@ -108,7 +115,7 @@ class IsAdminOrSupervisorOrCompany(permissions.BasePermission):
 class IsAdminOrSupervisorOrCompanyOrSelf(permissions.IsAuthenticated):
     def has_object_permission(self, request, view, obj):
         user = request.user
-        if user.is_superuser or hasattr(user, "company") or hasattr(user, "supervisor"):
+        if user.is_superuser or user.is_staff or hasattr(user, "company") or hasattr(user, "supervisor"):
             return True
         if hasattr(user, "student"):
             if isinstance(obj, Student):
@@ -116,9 +123,25 @@ class IsAdminOrSupervisorOrCompanyOrSelf(permissions.IsAuthenticated):
             elif hasattr(obj, "student"):
                 student = obj.student
             else:
-                raise APIException(
+                raise PermissionDenied(
                     "Checking student permission on object {} not associated with Student"
                         .format(type(obj.__name__))
                 )
             return hasattr(user, "student") and user.student == student
         return False
+
+
+class IsAdminOrVacancyOwner(permissions.BasePermission):
+    def has_permission(self, request, view):
+        return is_admin_or_company(request.user)
+
+    def has_object_permission(self, request, view, obj):
+        user = request.user
+        if user.is_superuser or user.is_staff:
+            return True
+        if isinstance(obj, Application):
+            return user.company == obj.vacancy.company
+        else:
+            raise PermissionDenied(
+                "Checking owner permission on non-application object"
+            )
diff --git a/core/migrations/0007_auto_20170425_1550.py b/core/migrations/0007_auto_20170425_1550.py
new file mode 100644
index 0000000000000000000000000000000000000000..ce925a3660d2ec0cbfe24dfe1d646afeef47ea00
--- /dev/null
+++ b/core/migrations/0007_auto_20170425_1550.py
@@ -0,0 +1,24 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.5 on 2017-04-25 15:50
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('core', '0006_auto_20170328_1950'),
+    ]
+
+    operations = [
+        migrations.RemoveField(
+            model_name='application',
+            name='allow_transcript',
+        ),
+        migrations.AddField(
+            model_name='application',
+            name='status',
+            field=models.IntegerField(default=0),
+        ),
+    ]
diff --git a/core/migrations/0011_merge_20170425_2214.py b/core/migrations/0011_merge_20170425_2214.py
new file mode 100644
index 0000000000000000000000000000000000000000..c255ca51038829cd59f9ae8d8131e5a74ed516be
--- /dev/null
+++ b/core/migrations/0011_merge_20170425_2214.py
@@ -0,0 +1,16 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.5 on 2017-04-25 22:14
+from __future__ import unicode_literals
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('core', '0010_student_photo'),
+        ('core', '0007_auto_20170425_1550'),
+    ]
+
+    operations = [
+    ]
diff --git a/core/migrations/0012_auto_20170502_0925.py b/core/migrations/0012_auto_20170502_0925.py
new file mode 100644
index 0000000000000000000000000000000000000000..692e227970e80fba34415889ffc542d6309c3846
--- /dev/null
+++ b/core/migrations/0012_auto_20170502_0925.py
@@ -0,0 +1,40 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.5 on 2017-05-02 02:25
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('core', '0011_merge_20170425_2214'),
+    ]
+
+    operations = [
+        migrations.AlterModelOptions(
+            name='company',
+            options={'ordering': ['-updated']},
+        ),
+        migrations.AlterModelOptions(
+            name='student',
+            options={'ordering': ['-updated']},
+        ),
+        migrations.AlterModelOptions(
+            name='supervisor',
+            options={'ordering': ['-updated']},
+        ),
+        migrations.AlterModelOptions(
+            name='vacancy',
+            options={'ordering': ['-updated']},
+        ),
+        migrations.RemoveField(
+            model_name='company',
+            name='verified',
+        ),
+        migrations.AddField(
+            model_name='company',
+            name='status',
+            field=models.IntegerField(default=0),
+        ),
+    ]
diff --git a/core/models/accounts.py b/core/models/accounts.py
index 607a4550387bca27204c0d323c5e5d2f66df9123..7fe9aaa98006861559f4a3a62ec196cbc8bf4b99 100644
--- a/core/models/accounts.py
+++ b/core/models/accounts.py
@@ -68,19 +68,30 @@ class Student(models.Model):
     def name(self):
         return get_display_name(self.user)
 
+    @property
+    def full_name(self):
+        return get_display_name(self.user, full_name=True)
+
     def __unicode__(self):
         return u"Student {}".format(get_display_name(self.user))
 
+    class Meta:
+        ordering = ['-updated']
+
 
 class Company(models.Model):
     """
     A user subclass
     """
+    NEW = 0
+    UNVERIFIED = 1
+    VERIFIED = 2
+
     created = models.DateTimeField(auto_now_add=True)
     updated = models.DateTimeField(auto_now=True)
     user = models.OneToOneField(User)
     description = models.TextField()
-    verified = models.BooleanField(default=False)
+    status = models.IntegerField(default=NEW)
     logo = models.FileField(upload_to=get_company_logo_file_path, null=True, blank=True)
     address = models.CharField(max_length=1000, blank=True, null=True)
 
@@ -91,6 +102,9 @@ class Company(models.Model):
     def __unicode__(self):
         return u"Company {}".format(get_display_name(self.user))
 
+    class Meta:
+        ordering = ['-updated']
+
 
 class Supervisor(models.Model):
     """
@@ -107,3 +121,6 @@ class Supervisor(models.Model):
 
     def __unicode__(self):
         return u"Supervisor {}".format(get_display_name(self.user))
+
+    class Meta:
+        ordering = ['-updated']
diff --git a/core/models/vacancies.py b/core/models/vacancies.py
index f165a2b562545ef8feddf717ffda2f1db3063f7f..f2b5dc4956206082a74c1e656b05a698d8c01d18 100644
--- a/core/models/vacancies.py
+++ b/core/models/vacancies.py
@@ -13,12 +13,21 @@ class Vacancy(models.Model):
     updated = models.DateTimeField(auto_now=True)
     name = models.CharField(max_length=100, null=False)
 
+    class Meta:
+        ordering = ['-updated']
+
 
 class Application(models.Model):
+    NEW = 0
+    READ = 1
+    BOOKMARKED = 2
+    REJECTED = 3
+    ACCEPTED = 4
+
     cover_letter = models.TextField(null=True, blank=True)
-    allow_transcript = models.BooleanField(null=False, default=True)
     student = models.ForeignKey(Student, on_delete=models.CASCADE)
     vacancy = models.ForeignKey(Vacancy, on_delete=models.CASCADE)
+    status = models.IntegerField(default=NEW)
 
     class Meta:
         unique_together = (("student", "vacancy"),)
diff --git a/core/serializers/vacancies.py b/core/serializers/vacancies.py
index 3926965db88f6265a4b99def6c14d3da21c3026d..1b4f15dd69bc02e42d009f32064312a6ddf2a36b 100644
--- a/core/serializers/vacancies.py
+++ b/core/serializers/vacancies.py
@@ -2,13 +2,42 @@ from rest_framework import serializers
 
 from core.models import Company
 from core.models.vacancies import Vacancy, Application
-from core.serializers.accounts import StudentSerializer
+from core.serializers.accounts import StudentSerializer, CompanySerializer
 
 
 class VacancySerializer(serializers.ModelSerializer):
-    company = serializers.PrimaryKeyRelatedField(
-        queryset=Company.objects.all()
-    )
+    company = CompanySerializer()
+    status = serializers.SerializerMethodField('_get_app_status')
+    bookmarked = serializers.SerializerMethodField('_get_bookmarked_status')
+
+    def _get_app_status(self, instance):
+        try:
+            request = self.context.get("request")
+            student = request.user.student
+            app = Application.objects.get(vacancy=instance, student=student)
+            return app.status
+        except:
+            return None
+        return None
+
+    def _get_bookmarked_status(self, instance):
+        try:
+            request = self.context.get("request")
+            if request.user.student.bookmarked_vacancies.filter(pk=instance.id).exists():
+                return True
+            return False
+        except:
+            return None
+        return None
+
+    class Meta:
+        model = Vacancy
+        fields = ['company', 'verified', 'open_time', 'description', 'close_time', 'created', 'updated', 'name', \
+                  'status', 'bookmarked', 'id']
+
+
+class PostVacancySerializer(serializers.ModelSerializer):
+    company = serializers.PrimaryKeyRelatedField(queryset=Company.objects.all())
 
     class Meta:
         model = Vacancy
@@ -24,5 +53,8 @@ class ApplicationSerializer(serializers.ModelSerializer):
         fields = '__all__'
 
 
+class ApplicationStatusSerializer(serializers.ModelSerializer):
 
-
+    class Meta:
+        model = Application
+        fields = ['status']
diff --git a/core/templates/core/index.html b/core/templates/core/index.html
index b15d9a2c9065ff9db99bf69bac81afd41914bbbc..ebdfabf2c40d38ef365e4bb52b22a83a1a45d388 100755
--- a/core/templates/core/index.html
+++ b/core/templates/core/index.html
@@ -5,6 +5,7 @@
 <html>
   <head>
     <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
     <title>Yuk Cari Tempat Kape :)</title>
     <link rel="stylesheet" href="{% static 'css/custom.css' %}"/>
     <link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.2.2/semantic.min.css"/>
diff --git a/core/tests/test_accounts.py b/core/tests/test_accounts.py
index e4889f544f125743816dbbf53186f6e55b88d359..89571e2849bd040bc7b72c2b2e94c1fb40062e06 100644
--- a/core/tests/test_accounts.py
+++ b/core/tests/test_accounts.py
@@ -4,8 +4,8 @@ from rest_framework.test import APIClient, APITestCase
 from django.contrib.auth.models import User
 from core.models.accounts import Company, Supervisor, Student
 
-class LoginTests(APITestCase):
 
+class LoginTests(APITestCase):
     @requests_mock.Mocker()
     def test_succesful_student_login_relogin(self, m):
         m.post('https://api.cs.ui.ac.id/authentication/ldap/v2/', json={
@@ -68,7 +68,7 @@ class LoginTests(APITestCase):
 
     def test_success_company_login(self):
         new_user = User.objects.create_user('dummy.login.company', 'dummy.login.company@company.com', 'lalala123')
-        new_company = Company.objects.create(user=new_user, description="lalalala", verified=True, logo=None, address=None)
+        new_company = Company.objects.create(user=new_user, description="lalalala", status=Company.VERIFIED, logo=None, address=None)
 
         url = '/api/login/'
         response = self.client.post(url, {'username': 'dummy.login.company', 'password': 'lalala123', 'login-type': 'company'}, format='json')
@@ -101,6 +101,7 @@ class RegisterTests(APITestCase):
         response = self.client.post(url, {'username': 'lalala'}, format='multipart')
         self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
 
+
 class ProfileUpdateTests(APITestCase):
 
     @requests_mock.Mocker()
diff --git a/core/tests/test_vacancies.py b/core/tests/test_vacancies.py
index a79106e84bca448cb2d50e828b05dd9475e631a6..82a1b07bb91a566814d9b7eae5ebefae8b50ae52 100644
--- a/core/tests/test_vacancies.py
+++ b/core/tests/test_vacancies.py
@@ -65,7 +65,7 @@ class ApplicationTests(APITestCase):
         student_id = response.data.get('student').get('id')
 
         new_user = User.objects.create_user('dummy.company', 'dummy.company@company.com', 'lalala123')
-        new_company = Company.objects.create(user=new_user, description="lalala",verified=True,logo=None,address=None)
+        new_company = Company.objects.create(user=new_user, description="lalala",status=Company.VERIFIED,logo=None,address=None)
         new_vacancy = Vacancy.objects.create(company=new_company, verified=True, open_time=datetime.fromtimestamp(0), description="lalala", close_time=datetime.today())
 
         url = '/api/students/' + str(student_id) + '/applied-vacancies/'
@@ -133,7 +133,7 @@ class BookmarkApplicationTests(APITestCase):
         student_id = response.data.get('student').get('id')
 
         new_user = User.objects.create_user('dummy.company2', 'dummy.compan2y@company.com', 'lalala123')
-        new_company = Company.objects.create(user=new_user, description="lalala",verified=True,logo=None,address=None)
+        new_company = Company.objects.create(user=new_user, description="lalala",status=Company.VERIFIED,logo=None,address=None)
         new_vacancy = Vacancy.objects.create(company=new_company, verified=True, open_time=datetime.fromtimestamp(0), description="lalala", close_time=datetime.today())
 
         url = '/api/students/' + str(student_id) + '/bookmarked-vacancies/'
@@ -144,6 +144,7 @@ class BookmarkApplicationTests(APITestCase):
         response = self.client.delete(url)
         self.assertEqual(response.status_code, status.HTTP_200_OK)
 
+
 class VacancyTest(APITestCase):
     def test_verified_vacancy_list(self):
         superuser = User.objects.create_superuser('dummy.company', 'dummy.company@company.com', 'lalala123')
@@ -171,7 +172,7 @@ class CompanyListsTests(APITestCase):
 
     def test_company_vacancy_list_exist(self):
         new_user = User.objects.create_user('dummy.company3', 'dummy.company3@company.com', 'lalala123')
-        new_company = Company.objects.create(user=new_user, description="lalala", verified=True, logo=None, address=None)
+        new_company = Company.objects.create(user=new_user, description="lalala", status=Company.VERIFIED, logo=None, address=None)
 
         url = '/api/companies/' + str(new_company.pk) + '/vacancies'
         response = self.client.post(url, format='json')
@@ -179,7 +180,7 @@ class CompanyListsTests(APITestCase):
 
     def test_company_application_list_exist(self):
         new_user = User.objects.create_user('dummy.company4', 'dummy.company4@company.com', 'lalala123')
-        new_company = Company.objects.create(user=new_user, description="lalala", verified=True, logo=None,
+        new_company = Company.objects.create(user=new_user, description="lalala", status=Company.VERIFIED, logo=None,
                                              address=None)
 
         url = '/api/companies/' + str(new_company.pk) + '/applications'
diff --git a/core/views/accounts.py b/core/views/accounts.py
index 225d205b46ce063419a83516533a69843f33a683..a441fc795d1a5b6383f16d4f5d4917ff8fc7286d 100644
--- a/core/views/accounts.py
+++ b/core/views/accounts.py
@@ -2,7 +2,6 @@ import requests
 from django.contrib.auth import authenticate, login
 from django.contrib.auth.models import User
 from rest_framework import viewsets, status
-from rest_framework.generics import get_object_or_404
 from rest_framework.decorators import list_route
 from rest_framework.parsers import FormParser,MultiPartParser
 from rest_framework.permissions import AllowAny
@@ -15,6 +14,7 @@ from core.models.accounts import Student, Company, Supervisor
 from core.serializers.accounts import BasicUserSerializer, UserSerializer, StudentSerializer, CompanySerializer, \
     SupervisorSerializer, RegisterSerializer, StudentUpdateSerializer
 
+
 class UserViewSet(viewsets.ModelViewSet):
     queryset = User.objects.all()
     serializer_class = UserSerializer
@@ -56,6 +56,7 @@ class CompanyViewSet(viewsets.ModelViewSet):
     queryset = Company.objects.all()
     serializer_class = CompanySerializer
     permission_classes = [IsAdminOrSelfOrReadOnly, IsAdminOrCompany]
+    filter_fields = ('status',)
 
 
 class SupervisorViewSet(viewsets.ModelViewSet):
diff --git a/core/views/vacancies.py b/core/views/vacancies.py
index ff761057fe3bf58ac38a1d22db1663739f6c5ee7..354f3a84434689b87a0f4f98150c8d871e942698 100644
--- a/core/views/vacancies.py
+++ b/core/views/vacancies.py
@@ -1,19 +1,28 @@
-from rest_framework import viewsets
+import requests
+from django.conf import settings
+from rest_framework import viewsets, status
+from rest_framework.decorators import detail_route
 from rest_framework.exceptions import ValidationError
 from rest_framework.generics import get_object_or_404
 from rest_framework.permissions import IsAuthenticated
 from rest_framework.response import Response
-
-from core.lib.permissions import IsAdminOrStudent, IsAdminOrCompany
+from rest_framework.pagination import PageNumberPagination
+from core.lib.mixins import MultiSerializerViewSetMixin
+from core.lib.permissions import IsAdminOrStudent, IsAdminOrCompany, IsAdminOrVacancyOwner
 from core.models import Student, Company
 from core.models.vacancies import Vacancy, Application
-from core.serializers.vacancies import VacancySerializer, ApplicationSerializer
+from core.serializers.vacancies import VacancySerializer, ApplicationSerializer, ApplicationStatusSerializer, \
+    PostVacancySerializer
 
 
-class VacancyViewSet(viewsets.ModelViewSet):
+class VacancyViewSet(MultiSerializerViewSetMixin, viewsets.ModelViewSet):
     queryset = Vacancy.objects.all()
     serializer_class = VacancySerializer
+    serializer_action_classes = {
+        'create': PostVacancySerializer
+    }
     permission_classes = [IsAdminOrCompany]
+    pagination_class = PageNumberPagination
 
     def get_permissions(self):
         if self.action in ["retrieve", "list"]:
@@ -25,21 +34,35 @@ class VacancyViewSet(viewsets.ModelViewSet):
         verified = request.query_params['verified'] if 'verified' in request.query_params else "True"
         if verified.lower() in ("yes", "true", "t", "1"):
             vacancies = vacancies.filter(verified=True)
-
+        page = self.paginate_queryset(vacancies)
+        if page is not None:
+            return self.get_paginated_response(VacancySerializer(page, many=True, context={'request': request}).data)
         return Response(VacancySerializer(vacancies, many=True, context={'request': request}).data)
 
+    @detail_route(permission_classes=[IsAdminOrCompany])
+    def count(self, request, pk=None):
+        vacancy = self.get_object()
+        count = Application.objects.filter(vacancy=vacancy).count()
+        count_new = Application.objects.filter(vacancy=vacancy, status=Application.NEW).count()
+        return Response({"count": count, "count_new": count_new}, status=status.HTTP_200_OK)
+
 
 class ApplicationViewSet(viewsets.GenericViewSet):
     serializer_class = ApplicationSerializer
     permission_classes = [IsAdminOrStudent]
+    pagination_class = PageNumberPagination
 
     def list(self, request, student_id):
         """
-        Get list of a student {student_id}'s application
+        Get list of a student {student_id}'s applied vacancies
         ---
         """
         student = get_object_or_404(Student.objects.all(), pk=student_id)
-        vacancies = student.applied_vacancies
+        vacancy_ids = Application.objects.filter(student=student).values('vacancy')
+        vacancies = Vacancy.objects.filter(id__in=vacancy_ids)
+        page = self.paginate_queryset(vacancies)
+        if page is not None:
+            return self.get_paginated_response(VacancySerializer(page, many=True, context={'request': request}).data)
         return Response(VacancySerializer(vacancies, many=True, context={'request': request}).data)
 
     def create(self, request, student_id):
@@ -76,6 +99,8 @@ class ApplicationViewSet(viewsets.GenericViewSet):
 
 class CompanyApplicationViewSet(viewsets.GenericViewSet):
     queryset = Application.objects.all()
+    permission_classes = [IsAdminOrCompany]
+    pagination_class = PageNumberPagination
 
     def list(self, request, company_id):
         """
@@ -83,13 +108,49 @@ 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'])
+        page = self.paginate_queryset(applications)
+        if page is not None:
+            return self.get_paginated_response(ApplicationSerializer(page, many=True, context={'request': request}).data)
         return Response(ApplicationSerializer(applications, many=True, context={'request': request}).data)
 
 
+class CompanyApplicationStatusViewSet(viewsets.GenericViewSet):
+    queryset = Application.objects.all()
+    serializer_class = ApplicationStatusSerializer
+    permission_classes = [IsAdminOrVacancyOwner]
+
+    def partial_update(self, request, pk=None):
+        application = self.get_object()
+        serializer = self.get_serializer_class()(application, data=request.data, partial=True)
+        if serializer.is_valid():
+            serializer.save()
+            return Response(serializer.data, status=status.HTTP_202_ACCEPTED)
+        else:
+            return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
+
+    def retrieve(self, request, pk=None):
+        application = self.get_object()
+        student = application.student
+        if student.show_transcript:
+            s = requests.Session()
+            credentials = settings.API_CS_CREDENTIALS
+            s.get('https://api.cs.ui.ac.id/api-auth/login/')
+            csrf = s.cookies['csrftoken']
+            resp = s.post('https://api.cs.ui.ac.id/api-auth/login/', data={'username' : credentials["user"], 'password' : credentials["password"], 'csrfmiddlewaretoken' : csrf})
+            response = s.get('https://api.cs.ui.ac.id/siakngcs/mahasiswa/' + str(student.npm) + '/riwayat/')
+            return Response({'name' : student.full_name, 'transcript' : response.json()}, status=status.HTTP_200_OK)
+        else:
+            return Response({'name' : student.full_name, 'error' : 'student does not allow transcript to be shown'}, status=status.HTTP_200_OK)
+
+
 class CompanyVacanciesViewSet(viewsets.GenericViewSet):
-    queryset = Vacancy. objects.all()
+    queryset = Vacancy.objects.all()
+    pagination_class = PageNumberPagination
+    permission_classes = [IsAdminOrCompany]
 
     def list(self, request, company_id):
         """
@@ -98,6 +159,9 @@ class CompanyVacanciesViewSet(viewsets.GenericViewSet):
         """
         company = get_object_or_404(Company.objects.all().order_by('-updated'), pk=company_id)
         vacancies = Vacancy.objects.filter(company=company)
+        page = self.paginate_queryset(vacancies)
+        if page is not None:
+            return self.get_paginated_response(VacancySerializer(page, many=True, context={'request': request}).data)
         return Response(VacancySerializer(vacancies, many=True, context={'request': request}).data)
 
 
@@ -111,8 +175,11 @@ class BookmarkedVacancyByStudentViewSet(viewsets.GenericViewSet):
         ---
         """
         student = get_object_or_404(Student.objects.all(), pk=student_id)
-        vacancies = self.serializer_class(student.bookmarked_vacancies, many=True, context={'request': request})
-        return Response(vacancies.data)
+        vacancies = student.bookmarked_vacancies.all()
+        page = self.paginate_queryset(vacancies)
+        if page is not None:
+            return self.get_paginated_response(VacancySerializer(page, many=True, context={'request': request}).data)
+        return Response(VacancySerializer(vacancies, many=True, context={'request': request}).data)
 
     def create(self, request, student_id):
         """
diff --git a/kape/settings.py b/kape/settings.py
index f3a865d1af8bee89cb2f1a0bfc148e6b5479694f..358fd0e13eec7312b22b336d627910cbb4b0af3b 100755
--- a/kape/settings.py
+++ b/kape/settings.py
@@ -37,7 +37,8 @@ INSTALLED_APPS = [
     'rest_framework',
     'django_nose',
     'rest_framework_swagger',
-    'silk'
+    'silk',
+    'django_filters'
 ]
 
 MIDDLEWARE = [
@@ -145,7 +146,10 @@ REST_FRAMEWORK = {
     # or allow read-only access for unauthenticated users.
     'DEFAULT_PERMISSION_CLASSES': [
         'rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly'
-    ]
+    ],
+    'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
+    'PAGE_SIZE': 10,
+    'DEFAULT_FILTER_BACKENDS': ('django_filters.rest_framework.DjangoFilterBackend',)
 }
 
 GZIP_CONTENT_TYPES = (
@@ -158,3 +162,6 @@ GZIP_CONTENT_TYPES = (
 SESSION_COOKIE_HTTPONLY = False
 
 RUNNING_DEVSERVER = (len(sys.argv) > 1 and sys.argv[1] == 'runserver')
+
+API_CS_CREDENTIALS = {'user': 'kape', 'password': 'yukcarikape'}
+
diff --git a/kape/urls.py b/kape/urls.py
index 4b40a29e2a47484b68b61d399225aba958649153..da59e3aa14b08d2ed1e43f55f6f1a985d66cd6e4 100755
--- a/kape/urls.py
+++ b/kape/urls.py
@@ -24,7 +24,8 @@ from rest_framework_swagger.views import get_swagger_view
 from core import apps
 from core.views.accounts import StudentViewSet, CompanyViewSet, SupervisorViewSet, UserViewSet, LoginViewSet, \
     CompanyRegisterViewSet, StudentProfileViewSet
-from core.views.vacancies import VacancyViewSet, BookmarkedVacancyByStudentViewSet, ApplicationViewSet, CompanyApplicationViewSet, CompanyVacanciesViewSet
+from core.views.vacancies import VacancyViewSet, BookmarkedVacancyByStudentViewSet, ApplicationViewSet, \
+    CompanyApplicationViewSet, CompanyVacanciesViewSet, CompanyApplicationStatusViewSet
 
 schema_view = get_swagger_view()
 router = routers.DefaultRouter()
@@ -36,6 +37,7 @@ router.register(r'login', LoginViewSet)
 router.register(r'register', CompanyRegisterViewSet)
 router.register(r'vacancies', VacancyViewSet)
 router.register(r'profiles/students', StudentProfileViewSet)
+router.register(r'applications', CompanyApplicationStatusViewSet)
 router.register(r'students/(?P<student_id>\d+)/bookmarked-vacancies', BookmarkedVacancyByStudentViewSet,
                 base_name='bookmarked-vacancy-list')
 router.register(r'students/(?P<student_id>\d+)/applied-vacancies', ApplicationViewSet,
diff --git a/requirements.txt b/requirements.txt
index 50a48df156233e4ffc530842f046e0d8c9ba01e3..aeac0dc7d6a4d7bdb0f3b35c75025e2f3046e78a 100755
--- a/requirements.txt
+++ b/requirements.txt
@@ -12,4 +12,5 @@ coverage
 django-rest-swagger
 django-silk
 requests
-requests-mock
\ No newline at end of file
+requests-mock
+django-filter
\ No newline at end of file