Phyks (Lucas Verney) 2 years ago
parent
commit
11d4917d1e

+ 28
- 2
.eslintrc.js View File

@@ -10,16 +10,42 @@ module.exports = {
10 10
     browser: true,
11 11
   },
12 12
   // https://github.com/standard/standard/blob/master/docs/RULES-en.md
13
-  extends: 'standard',
13
+  extends: 'airbnb-base',
14 14
   // required to lint *.vue files
15 15
   plugins: [
16 16
     'html'
17 17
   ],
18
+  // check if imports actually resolve
19
+  'settings': {
20
+    'import/resolver': {
21
+      'webpack': {
22
+        'config': 'build/webpack.base.conf.js'
23
+      }
24
+    }
25
+  },
18 26
   // add your custom rules here
19 27
   rules: {
20 28
     // allow async-await
21 29
     'generator-star-spacing': 'off',
22 30
     // allow debugger during development
23
-    'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off'
31
+    'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
32
+    // Use 4 spaces indent
33
+    'indent': ['error', 4],
34
+    'import/prefer-default-export': 'off',
35
+    'no-console': 'off',
36
+    // Ignore assignment to state
37
+    'no-param-reassign': [
38
+        "error",
39
+        {
40
+            "props": true,
41
+            "ignorePropertyModificationsFor": ["state"]
42
+        }
43
+    ],
44
+    'no-bitwise': [
45
+        "error",
46
+        {
47
+            "int32Hint": true
48
+        }
49
+    ]
24 50
   }
25 51
 }

+ 1
- 1
config/index.js View File

@@ -23,7 +23,7 @@ module.exports = {
23 23
     // Use Eslint Loader?
24 24
     // If true, your code will be linted during bundling and
25 25
     // linting errors and warnings will be shown in the console.
26
-    useEslint: false,
26
+    useEslint: true,
27 27
     // If true, eslint errors and warnings will also be shown in the error overlay
28 28
     // in the browser.
29 29
     showEslintErrorsInOverlay: false,

+ 2
- 4
package.json View File

@@ -35,14 +35,12 @@
35 35
     "copy-webpack-plugin": "^4.0.1",
36 36
     "css-loader": "^0.28.0",
37 37
     "eslint": "^3.19.0",
38
-    "eslint-config-standard": "^10.2.1",
38
+    "eslint-config-airbnb-base": "^11.1.3",
39 39
     "eslint-friendly-formatter": "^3.0.0",
40
+    "eslint-import-resolver-webpack": "^0.8.1",
40 41
     "eslint-loader": "^1.7.1",
41 42
     "eslint-plugin-html": "^3.0.0",
42 43
     "eslint-plugin-import": "^2.7.0",
43
-    "eslint-plugin-node": "^5.2.0",
44
-    "eslint-plugin-promise": "^3.4.0",
45
-    "eslint-plugin-standard": "^3.0.1",
46 44
     "eventsource-polyfill": "^0.9.6",
47 45
     "extract-text-webpack-plugin": "^3.0.0",
48 46
     "file-loader": "^1.1.4",

+ 11
- 11
src/App.vue View File

@@ -43,21 +43,21 @@
43 43
 </template>
44 44
 
45 45
 <script>
46
-import FlatList from './components/FlatList'
46
+import FlatList from './components/FlatList.vue';
47 47
 
48 48
 export default {
49 49
     components: {
50
-        FlatList
50
+        FlatList,
51 51
     },
52
-        data () {
53
-            return {
54
-                drawer: true,
55
-                menuItems: [
56
-                    { icon: 'bubble_chart', title: 'Inspire' }
57
-                ]
58
-            }
59
-        }
60
-}
52
+    data() {
53
+        return {
54
+            drawer: true,
55
+            menuItems: [
56
+                { icon: 'bubble_chart', title: 'Inspire' },
57
+            ],
58
+        };
59
+    },
60
+};
61 61
 </script>
62 62
 
63 63
 <style>

+ 69
- 71
src/api/index.js View File

@@ -1,29 +1,30 @@
1
-import moment from 'moment'
1
+import moment from 'moment';
2 2
 
3
-import * as CONSTANTS from '@/constants'
3
+import * as CONSTANTS from '@/constants';
4 4
 
5
-require('es6-promise').polyfill()
6
-require('isomorphic-fetch')
5
+require('es6-promise').polyfill();
6
+require('isomorphic-fetch');
7 7
 
8
-const postProcessAPIResults = function (flat) {
8
+const postProcessAPIResults = (flatFromAPI) => {
9
+    const flat = Object.assign({}, flatFromAPI);
9 10
     /* eslint-disable camelcase */
10 11
     if (flat.date) {
11
-        flat.date = moment.utc(flat.date)
12
+        flat.date = moment.utc(flat.date);
12 13
     }
13 14
     if (flat.visit_date) {
14
-        flat.visit_date = moment.utc(flat.visit_date)
15
+        flat.visit_date = moment.utc(flat.visit_date);
15 16
     }
16 17
     if (flat.flatisfy_time_to) {
17
-        const momentifiedTimeTo = {}
18
-        Object.keys(flat.flatisfy_time_to).forEach(key => {
19
-            const value = flat.flatisfy_time_to[key]
18
+        const momentifiedTimeTo = {};
19
+        Object.keys(flat.flatisfy_time_to).forEach((key) => {
20
+            const value = flat.flatisfy_time_to[key];
20 21
             momentifiedTimeTo[key] = Object.assign(
21 22
                 {},
22 23
                 value,
23
-                { time: moment.duration(value.time, 'seconds') }
24
-            )
25
-        })
26
-        flat.flatisfy_time_to = momentifiedTimeTo
24
+                { time: moment.duration(value.time, 'seconds') },
25
+            );
26
+        });
27
+        flat.flatisfy_time_to = momentifiedTimeTo;
27 28
     }
28 29
 
29 30
     // TODO
@@ -36,84 +37,81 @@ const postProcessAPIResults = function (flat) {
36 37
     }
37 38
 
38 39
     // Fill cost per square meter.
39
-    flat.price_per_meter = Math.round(flat.cost * 100 / flat.area) / 100 | 0
40
+    flat.price_per_meter = Math.round((flat.cost / flat.area) * 100) / 100 | 0;
40 41
 
41 42
     /* eslint-enable camelcase */
42
-    return flat
43
-}
43
+    return flat;
44
+};
44 45
 
45
-export const getFlats = function (callback) {
46
-    fetch(`${CONSTANTS.BASE_API_URL}/api/v1/flats`, { credentials: 'same-origin' })
47
-        .then(function (response) {
48
-            return response.json()
49
-        }).then(function (json) {
50
-            const flats = json.data
51
-            flats.map(postProcessAPIResults)
52
-            callback(flats)
53
-        }).catch(function (ex) {
54
-            console.error('Unable to parse flats: ' + ex)
55
-        })
56
-}
46
+export const getFlats = (callback) => {
47
+    fetch(`${CONSTANTS.BASE_API_URL}/api/v1/flats`)
48
+        .then(response => response.json())
49
+        .then((json) => {
50
+            const flats = json.data;
51
+            flats.map(postProcessAPIResults);
52
+            callback(flats);
53
+        }).catch((ex) => {
54
+            console.error(`Unable to parse flats: ${ex}.`);
55
+        });
56
+};
57 57
 
58
-export const getFlat = function (flatId, callback) {
58
+export const getFlat = (flatId, callback) => {
59 59
     fetch(
60 60
         `${CONSTANTS.BASE_API_URL}/api/v1/flats/${encodeURIComponent(flatId)}`,
61
-        { credentials: 'same-origin' }
62
-    ).then(function (response) {
63
-        return response.json()
64
-    }).then(function (json) {
65
-        const flat = postProcessAPIResults(json.data)
66
-        callback(flat)
67
-    }).catch(function (ex) {
68
-        console.error('Unable to parse flats: ' + ex)
69
-    })
70
-}
61
+    )
62
+        .then(response => response.json())
63
+        .then((json) => {
64
+            const flat = postProcessAPIResults(json.data);
65
+            callback(flat);
66
+        }).catch((ex) => {
67
+            console.error(`Unable to parse flats: ${ex}.`);
68
+        });
69
+};
71 70
 
72
-export const updateFlat = function (flatId, updatedFields, callback) {
71
+export const updateFlat = (flatId, updatedFields, callback) => {
73 72
     fetch(
74 73
         `${CONSTANTS.BASE_API_URL}/api/v1/flats/${encodeURIComponent(flatId)}`,
75 74
         {
76
-            credentials: 'same-origin',
77 75
             method: 'PATCH',
78 76
             headers: {
79
-                'Content-Type': 'application/json'
77
+                'Content-Type': 'application/json',
80 78
             },
81
-            body: JSON.stringify(updatedFields)
82
-        }
83
-    ).then(callback).catch(function (ex) {
84
-        console.error('Unable to update flat status: ' + ex)
85
-    })
86
-}
79
+            body: JSON.stringify(updatedFields),
80
+        },
81
+    )
82
+        .then(callback)
83
+        .catch((ex) => {
84
+            console.error(`Unable to update flat status: ${ex}.`);
85
+        });
86
+};
87 87
 
88
-export const getTimeToPlaces = function (callback) {
88
+export const getTimeToPlaces = (callback) => {
89 89
     fetch(
90 90
         `${CONSTANTS.BASE_API_URL}/api/v1/time_to_places`,
91
-        { credentials: 'same-origin' }
92
-    ).then(function (response) {
93
-        return response.json()
94
-    }).then(function (json) {
95
-        callback(json.data)
96
-    }).catch(function (ex) {
97
-        console.error('Unable to fetch time to places: ' + ex)
98
-    })
99
-}
91
+    )
92
+        .then(response => response.json())
93
+        .then(json => callback(json.data))
94
+        .catch((ex) => {
95
+            console.error(`Unable to fetch time to places: ${ex}.`);
96
+        });
97
+};
100 98
 
101
-export const doSearch = function (query, callback) {
99
+export const doSearch = (query, callback) => {
102 100
     fetch(
103 101
         '/api/v1/search',
104 102
         {
105
-            credentials: 'same-origin',
106 103
             method: 'POST',
107 104
             headers: {
108
-                'Content-Type': 'application/json'
105
+                'Content-Type': 'application/json',
109 106
             },
110 107
             body: JSON.stringify({
111
-                query: query
112
-            })
113
-        }
114
-    ).then(response => response.json()).then(json => {
115
-        callback(json.data)
116
-    }).catch(function (ex) {
117
-        console.error('Unable to perform search: ' + ex)
118
-    })
119
-}
108
+                query,
109
+            }),
110
+        },
111
+    )
112
+        .then(response => response.json())
113
+        .then(json => callback(json.data))
114
+        .catch((ex) => {
115
+            console.error(`Unable to perform search: ${ex}.`);
116
+        });
117
+};

+ 75
- 75
src/components/FlatEntry.vue View File

@@ -1,70 +1,70 @@
1 1
 <template>
2
-<v-card class="flat-entry">
3
-    <v-card-text>
4
-        <v-container grid-list-sm>
5
-            <v-layout row align-center>
6
-                <v-flex xs4 text-xs-center md2>
7
-                    <v-layout column>
8
-                        <v-flex d-flex xs12>
9
-                          <Avatar :thumbnail="thumbnail" />
10
-                        </v-flex>
11
-                        <v-flex d-flex xs12>
12
-                            <span class="body-2">{{ formattedPrice }}</span>
13
-                        </v-flex>
14
-                    </v-layout>
15
-                </v-flex>
16
-                <v-flex xs7 offset-xs1 md6>
17
-                    <v-layout column>
18
-                        <v-flex xs12 d-flex>
19
-                            <h2 class="title">{{ title }}</h2>
20
-                        </v-flex>
21
-                        <v-flex xs12 d-flex>
22
-                            <v-layout row>
23
-                                <v-flex xs4 class="flex-icon">
24
-                                    <v-icon>aspect_ratio</v-icon> <span v-html="formattedArea"></span>
25
-                                </v-flex>
26
-                                <v-flex xs4 class="flex-icon">
27
-                                    <v-icon>home</v-icon> {{ $tc('flatEntry.rooms', nRooms, { count: nRooms }) }}
28
-                                </v-flex>
29
-                            </v-layout>
30
-                        </v-flex>
31
-                        <v-flex xs12 d-flex>
32
-                            <v-icon class="flex-icon">location_on</v-icon> {{ location }}
33
-                        </v-flex>
34
-                    </v-layout>
35
-                </v-flex>
36
-                <v-flex xs1 hidden-sm-and-down>
37
-                    <v-btn flat icon v-on:click.stop="starFlat">
38
-                        <v-icon>star</v-icon>
39
-                    </v-btn>
40
-                </v-flex>
41
-                <v-flex xs1 hidden-sm-and-down>
42
-                    <v-btn flat icon v-on:click.stop="deleteFlat">
43
-                        <v-icon>delete</v-icon>
44
-                    </v-btn>
45
-                </v-flex>
46
-                <v-flex xs1 hidden-sm-and-down>
47
-                    <a :href="urls[0]" target="_blank">
48
-                      <v-btn flat icon>
49
-                          <v-icon class="fa-icon">fa-external-link</v-icon>
50
-                      </v-btn>
51
-                    </a>
52
-                </v-flex>
53
-            </v-layout>
54
-        </v-container>
55
-    </v-card-text>
56
-</v-card>
2
+    <v-card class="flat-entry">
3
+        <v-card-text>
4
+            <v-container grid-list-sm>
5
+                <v-layout row align-center>
6
+                    <v-flex xs4 text-xs-center md2>
7
+                        <v-layout column>
8
+                            <v-flex d-flex xs12>
9
+                                <Avatar :thumbnail="thumbnail"></Avatar>
10
+                            </v-flex>
11
+                            <v-flex d-flex xs12>
12
+                                <span class="body-2">{{ formattedPrice }}</span>
13
+                            </v-flex>
14
+                        </v-layout>
15
+                    </v-flex>
16
+                    <v-flex xs7 offset-xs1 md6>
17
+                        <v-layout column>
18
+                            <v-flex xs12 d-flex>
19
+                                <h2 class="title">{{ title }}</h2>
20
+                            </v-flex>
21
+                            <v-flex xs12 d-flex>
22
+                                <v-layout row>
23
+                                    <v-flex xs4 class="flex-icon">
24
+                                        <v-icon>aspect_ratio</v-icon> <span v-html="formattedArea"></span>
25
+                                    </v-flex>
26
+                                    <v-flex xs4 class="flex-icon">
27
+                                        <v-icon>home</v-icon> {{ $tc('flatEntry.rooms', nRooms, { count: nRooms }) }}
28
+                                    </v-flex>
29
+                                </v-layout>
30
+                            </v-flex>
31
+                            <v-flex xs12 d-flex>
32
+                                <v-icon class="flex-icon">location_on</v-icon> {{ location }}
33
+                            </v-flex>
34
+                        </v-layout>
35
+                    </v-flex>
36
+                    <v-flex xs1 hidden-sm-and-down>
37
+                        <v-btn flat icon v-on:click.stop="starFlat">
38
+                            <v-icon>star</v-icon>
39
+                        </v-btn>
40
+                    </v-flex>
41
+                    <v-flex xs1 hidden-sm-and-down>
42
+                        <v-btn flat icon v-on:click.stop="deleteFlat">
43
+                            <v-icon>delete</v-icon>
44
+                        </v-btn>
45
+                    </v-flex>
46
+                    <v-flex xs1 hidden-sm-and-down>
47
+                        <a :href="urls[0]" target="_blank">
48
+                            <v-btn flat icon>
49
+                                <v-icon class="fa-icon">fa-external-link</v-icon>
50
+                            </v-btn>
51
+                        </a>
52
+                    </v-flex>
53
+                </v-layout>
54
+            </v-container>
55
+        </v-card-text>
56
+    </v-card>
57 57
 </template>
58 58
 
59 59
 <script>
60
-import currencyFormatter from 'currency-formatter'
60
+import currencyFormatter from 'currency-formatter';
61 61
 
62
-import Avatar from '@/components/ui/Avatar';
62
+import Avatar from '@/components/ui/Avatar.vue';
63 63
 
64 64
 export default {
65
-  components: {
66
-    Avatar
67
-  },
65
+    components: {
66
+        Avatar,
67
+    },
68 68
     props: {
69 69
         title: String,
70 70
         thumbnail: String,
@@ -74,29 +74,29 @@ export default {
74 74
         currency: String,
75 75
         nRooms: Number,
76 76
         location: String,
77
-        urls: Array
77
+        urls: Array,
78 78
     },
79 79
     computed: {
80 80
         formattedPrice() {
81
-            return currencyFormatter.format(this.price, { code: this.currency, precision: 0 })
81
+            return currencyFormatter.format(this.price, { code: this.currency, precision: 0 });
82 82
         },
83 83
         formattedArea() {
84
-            if (this.areaUnits == 'm^2') {
85
-                return `${this.area}&nbsp;m<sup>2</sup>`
84
+            if (this.areaUnits === 'm^2') {
85
+                return `${this.area}&nbsp;m<sup>2</sup>`;
86 86
             }
87
-            return this.area
88
-        }
87
+            return this.area;
88
+        },
89 89
     },
90 90
     methods: {
91
-      deleteFlat() {
92
-        // TODO
93
-        alert('Delete')
94
-      },
95
-      starFlat() {
96
-        // TODO
97
-        alert('Star')
98
-      },
99
-    }
91
+        deleteFlat() {
92
+            // TODO
93
+            console.log('Delete');
94
+        },
95
+        starFlat() {
96
+            // TODO
97
+            console.log('Star');
98
+        },
99
+    },
100 100
 };
101 101
 </script>
102 102
 

+ 10
- 29
src/components/FlatList.vue View File

@@ -1,47 +1,28 @@
1 1
 <template>
2 2
     <div>
3 3
         <template v-for="flat in flats">
4
-        <FlatEntry v-bind="flat"/>
4
+            <FlatEntry v-bind="flat"></FlatEntry>
5 5
         </template>
6 6
     </div>
7 7
 </template>
8 8
 
9 9
 <script>
10
-import * as api from '../api'
11
-import FlatEntry from './FlatEntry'
10
+import * as api from '../api';
11
+import FlatEntry from './FlatEntry.vue';
12 12
 
13 13
 export default {
14 14
     components: {
15
-        FlatEntry
15
+        FlatEntry,
16 16
     },
17 17
     data() {
18 18
         return {
19
-            flats: [
20
-                /*{
21
-                    title: "Studio 33m2 - Paris 17e",
22
-                    thumbnail: "https://static.pap.fr/photos/B88/B88A1053.thumb.jpg",
23
-                    area: 33,
24
-                    areaUnits: "m2",
25
-                    nRooms: 1,
26
-                    location: "Paris 17e",
27
-                    price: 825,
28
-                    currency: "EUR"
29
-                },
30
-                {
31
-                    title: "Appartement 50m2 - Paris 20e",
32
-                    thumbnail: "https://static.pap.fr/photos/B88/B88A1053.thumb.jpg",
33
-                    area: 50,
34
-                    areaUnits: "m2",
35
-                    nRooms: 2,
36
-                    location: "Paris 20e",
37
-                    price: 1200,
38
-                    currency: "EUR"
39
-                }*/
40
-            ]
41
-        }
19
+            flats: [],
20
+        };
42 21
     },
43 22
     created() {
44
-        api.getFlats(flats => this.flats = flats)
45
-    }
23
+        api.getFlats((flats) => {
24
+            this.flats = flats;
25
+        });
26
+    },
46 27
 };
47 28
 </script>

+ 17
- 0
src/components/ui/Avatar.vue View File

@@ -0,0 +1,17 @@
1
+<template>
2
+    <v-avatar size="100%">
3
+        <img :src="thumbnail" :alt="alt">
4
+    </v-avatar>
5
+</template>
6
+
7
+<script>
8
+export default {
9
+    props: {
10
+        thumbnail: String,
11
+        alt: {
12
+            type: String,
13
+            default: 'Thumbnail',
14
+        },
15
+    },
16
+};
17
+</script>

+ 0
- 17
src/components/ui/Avatar/index.vue View File

@@ -1,17 +0,0 @@
1
-<template>
2
-    <v-avatar size="100%">
3
-      <img :src="thumbnail" :alt="alt">
4
-    </v-avatar>
5
-</template>
6
-
7
-<script>
8
-export default {
9
-    props: {
10
-      thumbnail: String,
11
-      alt: {
12
-        type: String,
13
-        defautl: 'Thumbnail',
14
-      }
15
-    },
16
-}
17
-</script>

+ 1
- 1
src/constants.js View File

@@ -1 +1 @@
1
-export const BASE_API_URL = 'http://localhost:8080'
1
+export const BASE_API_URL = 'http://localhost:8080';

+ 7
- 7
src/i18n/index.js View File

@@ -1,12 +1,12 @@
1 1
 const messages = {
2 2
     fr: {
3
-        flatEntry: {
4
-            'rooms': '1 pièce | {count} pièces'
5
-        }
6
-    }
7
-}
3
+        flatEntry: {
4
+            rooms: '1 pièce | {count} pièces',
5
+        },
6
+    },
7
+};
8 8
 
9 9
 export default {
10 10
     locale: 'fr',
11
-    messages
12
-}
11
+    messages,
12
+};

+ 13
- 13
src/main.js View File

@@ -1,19 +1,19 @@
1
-import Vue from 'vue'
2
-import VueI18n from 'vue-i18n'
3
-import Vuetify from 'vuetify'
1
+import Vue from 'vue';
2
+import VueI18n from 'vue-i18n';
3
+import Vuetify from 'vuetify';
4 4
 
5
-import 'font-awesome/css/font-awesome.css'
6
-import 'material-design-icons/iconfont/material-icons.css'
7
-import 'vuetify/dist/vuetify.css'
5
+import 'font-awesome/css/font-awesome.css';
6
+import 'material-design-icons/iconfont/material-icons.css';
7
+import 'vuetify/dist/vuetify.css';
8 8
 
9
-import App from './App.vue'
10
-import i18n from './i18n'
9
+import App from './App.vue';
10
+import i18n from './i18n';
11 11
 
12
-Vue.use(VueI18n)
13
-Vue.use(Vuetify)
12
+Vue.use(VueI18n);
13
+Vue.use(Vuetify);
14 14
 
15
-new Vue({
15
+const app = new Vue({  // eslint-disable-line no-unused-vars
16 16
     el: '#app',
17 17
     render: h => h(App),
18
-    i18n: new VueI18n(i18n)
19
-})
18
+    i18n: new VueI18n(i18n),
19
+});

+ 7
- 7
src/router/index.js View File

@@ -5,11 +5,11 @@ import HelloWorld from '@/components/HelloWorld'
5 5
 Vue.use(Router)
6 6
 
7 7
 export default new Router({
8
-  routes: [
9
-    {
10
-      path: '/',
11
-      name: 'HelloWorld',
12
-      component: HelloWorld
13
-    }
14
-  ]
8
+    routes: [
9
+        {
10
+            path: '/',
11
+            name: 'HelloWorld',
12
+            component: HelloWorld
13
+        }
14
+    ]
15 15
 })