Browse Source

structures search - filters ok

Olivier Massot 4 years ago
parent
commit
1054b47e64
5 changed files with 169 additions and 56 deletions
  1. 52 14
      components/Ui/Search/Address.vue
  2. 2 2
      enums/departments.js
  3. 42 0
      enums/practices.js
  4. 0 1
      nuxt.config.js
  5. 73 39
      pages/structures_adherentes/index.vue

+ 52 - 14
components/Ui/Search/Address.vue

@@ -1,18 +1,21 @@
 <template>
   <div>
-    <v-text-field
-      v-model="text"
-      type="text"
-      name="search-city"
-      class="search-bar"
-      outlined
+    <v-autocomplete
+      v-model="model"
+      :loading="loading"
+      :items="items"
+      :search-input.sync="search"
+      hide-no-data
+      hide-details
+      return-object
+      auto-select-first
+      clearable
       :label="$t('where') + ' ?'"
-      autocomplete="off"
+      outlined
       append-icon="mdi-crosshairs-gps"
-      @change="$emit('change', $event)"
+      @change="$emit('change', $event ? $event.value : '')"
       @click:append="geolocalizeUser"
     />
-
     <v-snackbar :value="errorMsg !== ''">
       {{ errorMsg }}
       <template #action="{ attrs }">
@@ -28,19 +31,55 @@
 export default {
   data () {
     return {
-      latitude: null,
-      longitude: null,
-      text: '',
+      model: null,
+      search: null,
+      features: [],
+      loading: false,
       errorMsg: ''
     }
   },
+  computed: {
+    items () {
+      return this.features.map((f) => {
+        return {
+          text: f.properties.name + ' (' + f.properties.postcode + ')',
+          value: { longitude: f.geometry.coordinates[0], latitude: f.geometry.coordinates[1] },
+          disabled: false
+        }
+      })
+    }
+  },
+  watch: {
+    search (val) {
+      if (!val) {
+        this.features = []
+        return
+      }
+
+      this.loading = true
+
+      // Lazily load input items
+      fetch('https://api-adresse.data.gouv.fr/search/?type=municipality&autocomplete=1&limit=5&q=' + val)
+        .then(res => res.json())
+        .then(({ features }) => {
+          this.features = features
+        })
+        .catch((err) => {
+          // eslint-disable-next-line no-console
+          console.error(err)
+        })
+        .finally(() => {
+          this.loading = false
+        })
+    }
+  },
   methods: {
     geolocalizeUser () {
       if (navigator.geolocation) {
         navigator.geolocation.getCurrentPosition(
           (position) => {
             this.latitude = position.coords.latitude
-            this.latitude = position.coords.longitude
+            this.longitude = position.coords.longitude
             this.text = this.$t('my_position')
           },
           () => {
@@ -55,7 +94,6 @@ export default {
 }
 </script>
 
-
 <style>
 .v-input__control {
   height: 56px;

+ 2 - 2
plugins/enums.js → enums/departments.js

@@ -1,4 +1,4 @@
-const departmentsEnum = [
+const departments = [
   {
     code: '01',
     label: '01 - Ain'
@@ -405,4 +405,4 @@ const departmentsEnum = [
   }
 ]
 
-export default departmentsEnum
+export default departments

+ 42 - 0
enums/practices.js

@@ -0,0 +1,42 @@
+
+const practices = [
+  { id: 'BIG_BAND' },
+  { id: 'BRASS_BAND' },
+  { id: 'ORCHESTRA_CLASS' },
+  { id: 'ACCORDION_ORCHESTRA' },
+  { id: 'HARMONY_ORCHESTRA' },
+  { id: 'PHILHARMONIC_ORCHESTRA' },
+  { id: 'SYMPHONY_ORCHESTRA' },
+  { id: 'STRING_ORCHESTRA' },
+  { id: 'PLUCKED_ORCHESTRA' },
+  { id: 'FANFARE_BAND' },
+  { id: 'BAGAD' },
+  { id: 'BANDAS' },
+  { id: 'BATTERY_FANFARE' },
+  { id: 'BATTUCADA' },
+  { id: 'FOLKLORIC_BAND' },
+  { id: 'FIFE_AND_DRUM' },
+  { id: 'MARCHING_BAND' },
+  { id: 'HUNTING_HORNS' },
+  { id: 'CHILDRENS_CHOIR' },
+  { id: 'FEMAL_CHOIR' },
+  { id: 'MENS_CHOIR' },
+  { id: 'MIXED_CHORUS' },
+  { id: 'VOCAL_BAND_UP_16' },
+  { id: 'CLARINET_CHOIR' },
+  { id: 'COPPER_BAND' },
+  { id: 'FLUTE_ENSEMBLE' },
+  { id: 'SAXOPHONES_BAND' },
+  { id: 'VIOLIN_BAND' },
+  { id: 'PERCUSSION_BAND' },
+  { id: 'CURRENT_MUSIC_GROUP' },
+  { id: 'CHAMBER_MUSIC_ENSEMBLE' },
+  { id: 'TRADITIONAL_MUSIC_ENSEMBLE' },
+  { id: 'JAZZ_BAND' },
+  { id: 'EDUCATION' },
+  { id: 'CHEERLEADER' },
+  { id: 'TROOP' },
+  { id: 'OTHER' }
+]
+
+export default practices

+ 0 - 1
nuxt.config.js

@@ -44,7 +44,6 @@ export default {
 
   // Plugins to run before rendering page: https://go.nuxtjs.dev/config-plugins
   plugins: [
-    '~/plugins/enums.js',
     { src: '~/plugins/vue2-leaflet-markercluster.js', mode: 'client' }
   ],
 

+ 73 - 39
pages/structures_adherentes/index.vue

@@ -53,33 +53,37 @@
                 <v-row class="filters">
                   <v-col :cols="3" class="py-2 px-1">
                     <v-select
+                      v-model="typeFilter"
                       :label="$t('type')"
-                      :value="textFilter"
+                      :items="translatedPractices"
+                      item-value="id"
+                      item-text="label"
                       filled
-                      @change="typeFilterChanged"
                     />
                   </v-col>
                   <v-col :cols="3" class="py-2 px-1">
                     <v-select
-                      :items="departmentsEnum"
+                      v-model="departmentFilter"
+                      :items="departments"
                       item-value="code"
                       item-text="label"
                       :label="$t('department')"
-                      :value="departmentFilter"
                       filled
-                      @change="departmentFilterChanged"
                     />
                   </v-col>
                   <v-col :cols="3" class="py-2 px-1">
                     <v-select
+                      v-model="federationFilter"
+                      :items="federations"
+                      item-value="id"
+                      item-text="name"
                       :label="$t('federation')"
-                      :value="federationFilter"
                       filled
-                      @change="federationFilterChanged"
                     />
                   </v-col>
                   <v-col :cols="3" class="py-2 px-1">
                     <v-select
+                      v-model="distanceFilter"
                       :label="$t('distance')"
                       :items="[
                         {distance: 10, label: '10km'},
@@ -89,9 +93,7 @@
                       ]"
                       item-value="distance"
                       item-text="label"
-                      :value="distanceFilter"
                       filled
-                      @change="distanceFilterChanged"
                     />
                   </v-col>
                 </v-row>
@@ -215,7 +217,8 @@
 </template>
 
 <script>
-import departmentsEnum from '~/plugins/enums'
+import departments from '@/enums/departments'
+import practices from '@/enums/practices'
 
 export default {
   data () {
@@ -1799,9 +1802,10 @@ export default {
       page: 1,
       itemsPerPage: 8,
       mapview: true,
-      departmentsEnum,
+      departments,
+      practices,
       textFilter: '',
-      locationFilter: '',
+      locationFilter: null,
       typeFilter: null,
       departmentFilter: null,
       federationFilter: null,
@@ -1821,6 +1825,23 @@ export default {
     },
     listview () {
       return !this.mapview
+    },
+    translatedPractices () {
+      const tPractices = []
+      for (const practice of this.practices) {
+        tPractices.push({ id: practice.id, label: this.$t(practice.id) })
+      }
+      return tPractices
+    },
+    federations () {
+      const federations = []
+      for (const s of this.structures) {
+        const f = { id: s.n1Id, name: s.n1Name }
+        if (!federations.includes(f)) {
+          federations.push(f)
+        }
+      }
+      return federations
     }
   },
   methods: {
@@ -1832,18 +1853,9 @@ export default {
     },
     locationFilterChanged (newVal) {
       this.locationFilter = newVal
-    },
-    typeFilterChanged (newVal) {
-      this.typeFilter = newVal
-    },
-    departmentFilterChanged (newVal) {
-      this.departmentFilter = newVal
-    },
-    federationFilterChanged (newVal) {
-      this.federationFilter = newVal
-    },
-    distanceFilterChanged (newVal) {
-      this.distanceFilter = newVal
+      if (this.distanceFilter === null) {
+        this.distanceFilter = 10
+      }
     },
     mapBoundsFilterChanged (newBounds) {
       this.mapBoundsFilter = newBounds
@@ -1857,6 +1869,23 @@ export default {
       this.distanceFilter = null
       this.mapBoundsFilter = null
     },
+    toRad (val) {
+      // Converts numeric degrees to radians
+      return val * Math.PI / 180
+    },
+    sphericDistance (lat1, lon1, lat2, lon2) {
+      // This function takes in latitude and longitude of two location and returns the distance between them as the crow flies (in km)
+      const R = 6371 // km
+      const dLat = this.toRad(lat2 - lat1)
+      const dLon = this.toRad(lon2 - lon1)
+      lat1 = this.toRad(lat1)
+      lat2 = this.toRad(lat2)
+
+      const a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
+        Math.sin(dLon / 2) * Math.sin(dLon / 2) * Math.cos(lat1) * Math.cos(lat2)
+      const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a))
+      return R * c
+    },
     matchFilters (structure) {
       // Filter by name
       if (this.textFilter && !structure.name.toLowerCase().includes(this.textFilter.toLowerCase())) {
@@ -1864,23 +1893,28 @@ export default {
       }
 
       // filter by geographical position
-      // if (query['lat'] && query['long']) {
-      //   if (!structure.latitude || !structure.longitude) {
-      //     return false;
-      //   }
-      //
-      //   let radius = Number(query['radius']) ?? 0;
-      //
-      //   // radius is increased by 10km to approximate the city radius
-      //   radius += 10;
-      //
-      //   if (sphericDistance(query['lat'], query['long'], structure.latitude, structure.longitude) > radius) {
-      //     return false;
-      //   }
-      // }
+      if (this.locationFilter) {
+        if (!structure.latitude || !structure.longitude) {
+          return false
+        }
+
+        let radius = Number(this.distanceFilter) ?? 0
+
+        // radius is always increased by 10km to approximate the city radius
+        radius += 10
+
+        if (this.sphericDistance(
+          this.locationFilter.latitude,
+          this.locationFilter.longitude,
+          Number.parseFloat(structure.latitude),
+          Number.parseFloat(structure.longitude)) > radius
+        ) {
+          return false
+        }
+      }
 
       // filter by practice
-      if (this.typeFilter && !structure.practices.split(',').includes(this.typeFilter)) {
+      if (this.typeFilter && (!structure.practices || !structure.practices.split(',').includes(this.typeFilter))) {
         return false
       }