From 6299bee8ddeedd8649a3c27f7d92c6bd1e204183 Mon Sep 17 00:00:00 2001
From: Zamil Majdy <z.majdy1996@gmail.com>
Date: Mon, 24 Apr 2017 20:35:52 +0700
Subject: [PATCH] [#140652771] [#21] [Refactor] fix update vacancy bug + add
 testcases

---
 assets/css/custom.css                     | 25 +++-------
 assets/js/CreateVacancy.jsx               | 34 +++++++++++--
 assets/js/VacancyPage.jsx                 |  2 +-
 assets/js/__test__/CreateVacancy-test.jsx | 61 +++++++++++++++++++++--
 assets/js/components/CompanyVacancy.jsx   | 19 +++++--
 assets/js/components/VacancyList.jsx      | 16 +++---
 assets/js/index.jsx                       |  1 +
 assets/js/lib/Server.jsx                  |  2 +-
 core/views/vacancies.py                   |  4 +-
 9 files changed, 121 insertions(+), 43 deletions(-)

diff --git a/assets/css/custom.css b/assets/css/custom.css
index 706d9ddf..395990f1 100755
--- a/assets/css/custom.css
+++ b/assets/css/custom.css
@@ -1,5 +1,3 @@
-
-
 .center{
   text-align: center;
 }
@@ -26,10 +24,7 @@ background-color: #EEEEEE;
 }
 
 .create-lowongan{
-  margin-top: 60px;
-  margin-left: 19%;
-  margin-right: 19%;
-  margin-bottom: 100px;
+  margin: 60px 19% 100px;
 }
 
 .ui.segment.form-segment{
@@ -37,13 +32,10 @@ background-color: #EEEEEE;
 }
 
 .tabs {
-  margin-top: 100px;
-  margin-left:  100px;
-  margin-right: 100px;
   background: #fff;
   border: 1px solid #e5e5e5;
   border-radius: 3px;
-  margin-bottom: 30px;
+  margin: 100px 100px 30px;
 }
 .tabs__labels {
   margin: 0;
@@ -67,10 +59,10 @@ background-color: #EEEEEE;
 }
 
 .halamanLogin{
-  background-image: url("../img/bw-blur.png");
+  width: 1000px;
+  height: 646px;
   background-size: cover;
-  background-position: center;
-  background-attachment: fixed;
+  background: url("../img/bw-blur.png") fixed center;
   padding-bottom: 80px;
 }
 
@@ -80,9 +72,8 @@ background-color: #EEEEEE;
 }
 
 .formLogin{
-margin: 0 auto;
-margin-top: 80px;
-width: 430px;
+  margin: 80px auto 0;
+  width: 430px;
 }
 
 .registerModal{
@@ -171,7 +162,7 @@ card .formRegis{
   margin-top: 100px;
 }
 
-itemLowongan{
+.itemLowongan{
   color: black;
 }
 
diff --git a/assets/js/CreateVacancy.jsx b/assets/js/CreateVacancy.jsx
index 8989c3ba..e5015d6f 100644
--- a/assets/js/CreateVacancy.jsx
+++ b/assets/js/CreateVacancy.jsx
@@ -10,17 +10,34 @@ import Dumper from './lib/Dumper';
 
 export default class CreateVacancy extends React.Component {
 
+  static propTypes = {
+    params: React.PropTypes.object.isRequired,
+  };
+
   constructor(props) {
     super(props);
     /* istanbul ignore next */
     this.handleChange = this.handleChange.bind(this);
     this.handleSubmit = this.handleSubmit.bind(this);
+
     this.state = {
       formLoading: false,
       company: Storage.get('user-data').company,
+      vacancyId: this.props.params.id,
       open_time: moment(),
       close_time: moment(),
+      name: '',
+      description: '',
     };
+
+    this.state.vacancyId && Server.get(`/vacancies/${this.state.vacancyId}/`).then((r) => {
+      this.setState({
+        description: r.description,
+        name: r.name,
+        open_time: moment(r.open_time),
+        close_time: moment(r.close_time),
+      });
+    });
   }
 
   handleChange = (e) => {
@@ -36,10 +53,13 @@ export default class CreateVacancy extends React.Component {
     data.close_time = data.close_time.format();
     data.company = this.state.company.id;
 
-    Server.post('/vacancies/', data).then(() => {
+    const url = this.state.vacancyId ? `/vacancies/${this.state.vacancyId}/` : '/vacancies/';
+    const method = this.state.vacancyId ? 'PATCH' : 'POST';
+
+    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', Dumper.dump(r, '    '));
       this.setState({ formLoading: false });
     }));
   };
@@ -55,8 +75,14 @@ export default class CreateVacancy extends React.Component {
           </Header.Content>
         </Header>
         <Form loading={this.state.formLoading} onSubmit={this.handleSubmit}>
-          <Form.Field label="Posisi" name="name" control={Input} onChange={this.handleChange} required />
-          <Form.TextArea label="Deskripsi" placeholder="Deskripsi Lowongan..." required />
+          <Form.Field label="Posisi" name="name" control={Input} onChange={this.handleChange} value={this.state.name} required />
+          <Form.TextArea
+            name="description"
+            label="Deskripsi"
+            placeholder="Deskripsi Lowongan..."
+            onChange={this.handleChange}
+            value={this.state.description} required
+          />
           <Form.Group widths="equal">
             <Form.Field
               className="open-time-field"
diff --git a/assets/js/VacancyPage.jsx b/assets/js/VacancyPage.jsx
index 1a9383a7..551033a1 100644
--- a/assets/js/VacancyPage.jsx
+++ b/assets/js/VacancyPage.jsx
@@ -59,7 +59,7 @@ export default class VacancyPage extends React.Component {
       );
     } else if (this.state.role === 'company') {
       return (
-        <VacancyList key={1} userId={this.state.id} url="/vacancies/?verified=false" type="company" />
+        <VacancyList key={1} userId={this.state.id} url={`/companies/${this.state.id}/vacancies/`} type="company" />
       );
     }
 
diff --git a/assets/js/__test__/CreateVacancy-test.jsx b/assets/js/__test__/CreateVacancy-test.jsx
index d85e10ee..82c28816 100644
--- a/assets/js/__test__/CreateVacancy-test.jsx
+++ b/assets/js/__test__/CreateVacancy-test.jsx
@@ -41,26 +41,31 @@ describe('CreateVacancy', () => {
   };
 
   it('renders for companies without problem', () => {
+    fetchMock.get('*', {});
     Storage.set('user-data', companySession);
     const createVacancy = ReactTestUtils.renderIntoDocument(
-      <CreateVacancy />,
+      <CreateVacancy params={{ id: 1 }} />,
     );
     expect(createVacancy).to.exist;
+    fetchMock.restore();
   });
 
 
   it('renders without problem for error case', () => {
+    fetchMock.get('*', {});
     Storage.set('user-data', errorSession);
     const createVacancy = ReactTestUtils.renderIntoDocument(
-      <CreateVacancy />,
+      <CreateVacancy params={{ id: 1 }} />,
     );
     expect(createVacancy).to.exist;
+    fetchMock.restore();
   });
 
   it('support handle change', () => {
+    fetchMock.get('*', {});
     Storage.set('user-data', companySession);
     const createVacancy = ReactTestUtils.renderIntoDocument(
-      <CreateVacancy />,
+      <CreateVacancy params={{ id: 1 }} />,
     );
     createVacancy.setState({
       name: 'stub',
@@ -68,13 +73,15 @@ describe('CreateVacancy', () => {
     });
     createVacancy.handleChange({ target: { name: 'test', value: 'hue' } });
     expect(createVacancy.state.test).to.equal('hue');
+    fetchMock.restore();
   });
 
   it('submit vacancy properly (loading)', () => {
     fetchMock.post('*', 404);
+    fetchMock.get('*', {});
     Storage.set('user-data', companySession);
     const createVacancy = ReactTestUtils.renderIntoDocument(
-      <CreateVacancy />,
+      <CreateVacancy params={{ id: undefined }} />,
     );
     createVacancy.setState({
       name: 'stub',
@@ -96,9 +103,53 @@ describe('CreateVacancy', () => {
 
   it('submit vacancy properly (success)', () => {
     fetchMock.post('*', { data: 'value' });
+    fetchMock.get('*', {});
+    Storage.set('user-data', companySession);
+    const createVacancy = ReactTestUtils.renderIntoDocument(
+      <CreateVacancy params={{ id: undefined }} />,
+    );
+    createVacancy.setState({
+      name: 'stub',
+      description: 'stub',
+    });
+
+    expect(createVacancy.state.formLoading).to.equal(false);
+    createVacancy.handleSubmit(new Event('click'));
+    expect(createVacancy.state.formLoading).to.equal(true);
+    fetchMock.restore();
+  });
+
+  it('submit vacancy properly (loading)', () => {
+    fetchMock.patch('*', 404);
+    fetchMock.get('*', {});
+    Storage.set('user-data', companySession);
+    const createVacancy = ReactTestUtils.renderIntoDocument(
+      <CreateVacancy params={{ id: 1 }} />,
+    );
+    createVacancy.setState({
+      name: 'stub',
+      description: 'stub',
+    });
+
+    const openField = ReactTestUtils.findRenderedDOMComponentWithClass(createVacancy, 'open-time-field');
+    const closeField = ReactTestUtils.findRenderedDOMComponentWithClass(createVacancy, 'close-time-field');
+    ReactTestUtils.Simulate.click(openField);
+    ReactTestUtils.Simulate.keyDown(openField, { key: 'Enter', keyCode: 13, which: 13 });
+    ReactTestUtils.Simulate.click(closeField);
+    ReactTestUtils.Simulate.keyDown(closeField, { key: 'Enter', keyCode: 13, which: 13 });
+
+    expect(createVacancy.state.formLoading).to.equal(false);
+    createVacancy.handleSubmit(new Event('click'));
+    expect(createVacancy.state.formLoading).to.equal(true);
+    fetchMock.restore();
+  });
+
+  it('submit vacancy properly (success)', () => {
+    fetchMock.patch('*', { data: 'value' });
+    fetchMock.get('*', {});
     Storage.set('user-data', companySession);
     const createVacancy = ReactTestUtils.renderIntoDocument(
-      <CreateVacancy />,
+      <CreateVacancy params={{ id: 1 }} />,
     );
     createVacancy.setState({
       name: 'stub',
diff --git a/assets/js/components/CompanyVacancy.jsx b/assets/js/components/CompanyVacancy.jsx
index d5be3a71..57b1ad8f 100644
--- a/assets/js/components/CompanyVacancy.jsx
+++ b/assets/js/components/CompanyVacancy.jsx
@@ -1,5 +1,7 @@
 import React from 'react';
-import { Segment, Button, Icon, Item } from 'semantic-ui-react';
+import moment from 'moment';
+import { Button, Icon, Item } from 'semantic-ui-react';
+import { Link } from 'react-router';
 
 const defaultImage = 'http://semantic-ui.com/images/wireframe/image.png';
 
@@ -8,6 +10,13 @@ export default class ApplicantList extends React.Component {
     data: React.PropTypes.object.isRequired,
   };
 
+  constructor(props) {
+    super(props);
+    moment.locale('id');
+  }
+
+  getLink = `/buat-lowongan/${this.props.data.id}`;
+
   render() {
     return (
       <Item className="applicantItems">
@@ -15,13 +24,13 @@ export default class ApplicantList extends React.Component {
 
         <Item.Content>
           <Item.Header as="a">{this.props.data.name}</Item.Header>
-          <Segment padded basic floated="right">
-            <Button primary floated="right" >Ubah<Icon name="right chevron" /></Button>
-            <Segment basic> 5 jam lalu</Segment>
-          </Segment>
+          <Button color="blue" floated="right" as={Link} to={this.getLink}>
+            Ubah <Icon name="right chevron" />
+          </Button>
 
           <Item.Extra>
             <h3> 105 Pendaftar </h3>
+            Ditutup {moment(moment(this.props.data.close_time)).fromNow()}
           </Item.Extra>
 
         </Item.Content>
diff --git a/assets/js/components/VacancyList.jsx b/assets/js/components/VacancyList.jsx
index 5e479049..5f57b217 100644
--- a/assets/js/components/VacancyList.jsx
+++ b/assets/js/components/VacancyList.jsx
@@ -1,5 +1,5 @@
 import React from 'react';
-import { Item, Button } 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';
@@ -73,10 +73,10 @@ export default class VacancyList extends React.Component {
   companyHeader() {
     if (this.props.type === 'company') {
       return (
-        <div>
-          <Button icon="eye" secondary labelPosition="left" content="Lihat Semua Pendaftar" />
-          <Button as={Link} to="/buat-lowongan" icon="add" secondary labelPosition="left" content="Tambah Lowongan Baru" />
-        </div>
+        <Grid style={{ padding: '10px' }}>
+          <Button fluid size="mini" icon="eye" labelPosition="left" color="facebook" content="Lihat Semua Pendaftar" />
+          <Button fluid size="mini" as={Link} to="/buat-lowongan" icon="add" labelPosition="left" content="Tambah Lowongan Baru" color="teal" />
+        </Grid>
       );
     }
 
@@ -84,11 +84,11 @@ export default class VacancyList extends React.Component {
   }
 
   render = () => (
-    <div>
+    <Grid container columns="eleven" doubling>
       { this.companyHeader() }
-      <Item.Group relaxed>
+      <Item.Group relaxed style={{ width: '100%' }}>
         { this.generateVacancies() }
       </Item.Group>
-    </div>
+    </Grid>
   );
 }
diff --git a/assets/js/index.jsx b/assets/js/index.jsx
index 0636c719..127d2917 100644
--- a/assets/js/index.jsx
+++ b/assets/js/index.jsx
@@ -39,6 +39,7 @@ export default class App extends React.Component {
         <Route path="/lowongan" component={VacancyPage} />
         <Route path="/perusahaan" component={HomeCompany} />
         <Route path="/buat-lowongan" component={CreateVacancy} />
+        <Route path="/buat-lowongan/:id" component={CreateVacancy} />
       </Route>
       <Route path="/home" onEnter={this.handleHome} />
       <Redirect from="*" to="/home" />
diff --git a/assets/js/lib/Server.jsx b/assets/js/lib/Server.jsx
index bf53cf6f..030bba1c 100644
--- a/assets/js/lib/Server.jsx
+++ b/assets/js/lib/Server.jsx
@@ -76,7 +76,7 @@ export default class Server {
     });
   }
 
-  static get(path, useCache = true) {
+  static get(path, useCache = false) {
     return (useCache && Storage.get(path)) ?
             Promise.resolve(Storage.get(path)) : this.sendRequest(path, 'GET', null, useCache);
   }
diff --git a/core/views/vacancies.py b/core/views/vacancies.py
index 4a257966..ff761057 100644
--- a/core/views/vacancies.py
+++ b/core/views/vacancies.py
@@ -96,8 +96,8 @@ class CompanyVacanciesViewSet(viewsets.GenericViewSet):
         Get list of company {company_id}'s vacancies
         ---
         """
-        company = get_object_or_404(Company.objects.all(), pk=company_id)
-        vacancies = Vacancy.objects.filter(company = company)
+        company = get_object_or_404(Company.objects.all().order_by('-updated'), pk=company_id)
+        vacancies = Vacancy.objects.filter(company=company)
         return Response(VacancySerializer(vacancies, many=True, context={'request': request}).data)
 
 
-- 
GitLab