Browse Source

https://assistance.opentalent.fr/browse/V8-2613

Olivier Massot 4 years ago
parent
commit
496032d0cb

+ 10 - 0
assets/style/global.css

@@ -38,4 +38,14 @@ table.no-border td {
   border: none;
 }
 
+a.neutral {
+  color: #333333 !important;
+  text-decoration: underline;
+}
+
+a.neutral:hover {
+  color: var(--v-primary-base) !important;
+  text-decoration: underline;
+}
+
 /*# sourceMappingURL=global.css.map */

+ 1 - 1
assets/style/global.css.map

@@ -1 +1 @@
-{"version":3,"sourceRoot":"","sources":["global.scss"],"names":[],"mappings":"AACA;EACE;;;AAGF;EACE;;;AAGF;EACE;;;AAGF;EACE;;;AAGF;EAAgB;;;AAChB;EAAgB;;;AAChB;EAAgB;;;AAChB;EAAgB;;;AAChB;EAAgB;;;AAEhB;EACE","file":"global.css"}
+{"version":3,"sourceRoot":"","sources":["global.scss"],"names":[],"mappings":"AACA;EACE;;;AAGF;EACE;;;AAGF;EACE;;;AAGF;EACE;;;AAGF;EAAgB;;;AAChB;EAAgB;;;AAChB;EAAgB;;;AAChB;EAAgB;;;AAChB;EAAgB;;;AAEhB;EACE;;;AAGF;EACE;EACA;;;AAEF;EACE;EACA","file":"global.css"}

+ 9 - 0
assets/style/global.scss

@@ -24,3 +24,12 @@
 table.no-border td {
   border: none;
 }
+
+a.neutral {
+  color: #333333 !important;
+  text-decoration: underline;
+}
+a.neutral:hover {
+  color: var(--v-primary-base) !important;
+  text-decoration: underline;
+}

+ 1 - 1
components/Ui/Map/Structures.vue

@@ -87,7 +87,7 @@ export default Vue.extend({
   },
   mounted () {
     const defaultCenter: L.LatLngTuple = [46.71, 1.94]
-    const defaultZoom: number = 5.75
+    const defaultZoom: number = 5.5
     const layerSource: string = 'http://{s}.tile.osm.org/{z}/{x}/{y}.png'
     const attribution: string = '&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
 

+ 8 - 4
components/Ui/Search/Address.vue

@@ -10,6 +10,7 @@
       return-object
       auto-select-first
       clearable
+      no-filter
       :label="$t('where') + ' ?'"
       outlined
       append-icon="mdi-crosshairs-gps"
@@ -79,7 +80,7 @@ export default Vue.extend({
     limit: {
       type: Number,
       required: false,
-      default: 5
+      default: 10
     },
     autocomplete: {
       type: Boolean,
@@ -117,11 +118,14 @@ export default Vue.extend({
       this.loading = true
 
       // Lazily load input items
-      const apiUrl = 'https://api-adresse.data.gouv.fr/search/' +
+      let apiUrl = 'https://api-adresse.data.gouv.fr/search/' +
                      `?type=${this.type}` +
                      `&autocomplete=${this.autocomplete ? 1 : 0}` +
-                     `&limit=${this.limit}` +
-                     `&q=${val}`
+                     `&q=${encodeURI(val.replace(/\s+/gi, '+'))}`
+
+      if (this.limit > 0) {
+        apiUrl += `&limit=${this.limit}`
+      }
 
       fetch(encodeURI(apiUrl))
         .then(res => res.json())

+ 1 - 0
lang/fr-FR.js

@@ -29,6 +29,7 @@ export default (_context, _locale) => {
     no_results: 'Aucun résultats',
     my_position: 'Ma position',
     close: 'Fermer',
+    others: 'autres',
     geolocation_error: 'Une erreur s\'est produite lors de la géolocalisation',
     geolocation_not_supported: 'La géolocalisation n\'est pas supportée par votre navigateur',
     show_tel: 'Montrer le numéro de téléphone',

+ 1 - 1
layouts/default.vue

@@ -3,7 +3,7 @@
     <v-app dark>
       <v-main>
         <v-container>
-          <Nuxt />
+          <Nuxt keep-alive />
         </v-container>
       </v-main>
 

+ 1 - 0
package.json

@@ -24,6 +24,7 @@
     "@nuxtjs/i18n": "^7.0.3",
     "core-js": "^3.15.1",
     "leaflet": "^1.7.1",
+    "libphonenumber-js": "^1.9.38",
     "nuxt": "^2.15.7",
     "nuxt-fontawesome": "^0.4.0",
     "nuxt-leaflet": "^0.0.25",

+ 37 - 19
pages/structures/_id.vue

@@ -16,7 +16,8 @@
     <v-container class="content">
       <v-layout class="flex-row align-center mb-4">
         <nuxt-img
-          :src="structure.logoId ? 'https://api.opentalent.fr/app.php/_internal/secure/files/' + structure.logoId + '/0x60' : '/images/default.jpg'"
+          v-if="structure.logoId"
+          :src="'https://api.opentalent.fr/app.php/_internal/secure/files/' + structure.logoId + '/0x60'"
           alt="logo"
         />
 
@@ -43,6 +44,7 @@
             v-if="structure.imageId"
             :src="'https://api.opentalent.fr/app.php/_internal/secure/files/' + structure.imageId + '/raw'"
             alt="banner"
+            style="max-height: 300px"
           />
         </v-col>
       </v-row>
@@ -57,6 +59,24 @@
         </v-col>
       </v-row>
 
+      <v-row class="mb-4">
+        <v-col cols="12" class="d-flex flex-row justify-center">
+          <v-btn
+            v-for="article in structure.articles"
+            :key="article.id"
+            :href="(article.link.match(/https?:\/\/.*/) ? '' : 'https://') + article.link "
+            target="_blank"
+            small
+            color="primary"
+            class="ma-2"
+            :title="article.title"
+          >
+            <font-awesome-icon class="icon mr-1" :icon="['fas', 'star']" />
+            {{ $t('spot_on_from') + ' ' + new Date(article.date).toLocaleDateString($i18n.locale) }}
+          </v-btn>
+        </v-col>
+      </v-row>
+
       <v-divider class="my-2" />
 
       <v-row class="my-2 py-2">
@@ -104,7 +124,9 @@
               </td>
               <td class="phone">
                 <div v-if="structure.telphone">
-                  <a v-if="showTel" :href="'tel:' + structure.telphone">{{ structure.telphone }}</a>
+                  <a v-if="showTel" :href="'tel:' + structure.telphone" class="neutral">
+                    {{ formatPhoneNumber(structure.telphone) }}
+                  </a>
                   <v-btn v-else small @click="showTel = 1">
                     {{ $t('show_tel') }}
                   </v-btn>
@@ -118,7 +140,9 @@
               </td>
               <td class="mail">
                 <div v-if="structure.email">
-                  <a v-if="showMail" :href="'mailto:' + structure.email">{{ structure.email }}</a>
+                  <a v-if="showMail" :href="'mailto:' + structure.email" class="neutral">
+                    {{ structure.email }}
+                  </a>
                   <v-btn v-else small @click="showMail = 1">
                     {{ $t('show_email') }}
                   </v-btn>
@@ -131,7 +155,7 @@
                 <font-awesome-icon class="icon" :icon="['fas', 'globe-europe']" />
               </td>
               <td class="website">
-                <a :href="structure.website" target="_blank">{{ structure.website }}</a>
+                <a class="neutral" :href="structure.website" target="_blank">{{ structure.website }}</a>
               </td>
             </tr>
             <tr>
@@ -141,6 +165,7 @@
               <td class="network">
                 <NuxtLink
                   v-if="structure.n1Id !== parent"
+                  class="neutral"
                   :to="{path: '/structures/' + structure.n1Id, query: { parent: parent, view: view, theme: theme }}"
                   nuxt
                 >
@@ -155,21 +180,6 @@
         </v-col>
       </v-row>
 
-      <v-row class="mb-4">
-        <v-col cols="12" >
-          <v-btn
-            v-for="article in structure.articles"
-            :key="article.id"
-            :href="(article.link.match(/https?:\/\/.*/) ? '' : 'https://') + article.link "
-            small
-            target="_blank"
-            class="ma-2"
-          >
-            {{ $t('spot_on_from') + ' ' + new Date(article.date).toLocaleDateString($i18n.locale) }}
-          </v-btn>
-        </v-col>
-      </v-row>
-
       <v-row v-if="structure.latitude && structure.longitude">
         <v-col cols="12">
           <v-responsive width="100%" height="450px">
@@ -205,6 +215,8 @@
 
 <script lang="ts">
 import Vue from 'vue'
+// eslint-disable-next-line import/no-named-as-default
+import parsePhoneNumber from 'libphonenumber-js'
 import StructuresProvider from '~/services/data/StructuresProvider'
 
 export default Vue.extend({
@@ -231,6 +243,12 @@ export default Vue.extend({
       showTel: false,
       showMail: false
     }
+  },
+  methods: {
+    formatPhoneNumber (number: string): string {
+      const parsed = parsePhoneNumber(number)
+      return parsed ? parsed.formatNational() : ''
+    }
   }
 })
 </script>

+ 65 - 22
pages/structures/index.vue

@@ -77,7 +77,7 @@
                 <v-col :cols="(listview && $vuetify.breakpoint.mdAndUp) ? 8 : 12">
                   <v-row class="filters">
                     <v-col lg="3" :md="listview ? 3 : 6" sm="6" cols="12" class="py-2 px-1">
-                      <v-select
+                      <v-autocomplete
                         v-model="practicesFilter"
                         :label="$t('type')"
                         :items="translatedPractices"
@@ -85,11 +85,12 @@
                         item-text="label"
                         filled
                         hide-details
+                        hide-no-data
                         @change="search"
                       />
                     </v-col>
                     <v-col lg="3" :md="listview ? 3 : 6" sm="6" cols="12" class="py-2 px-1">
-                      <v-select
+                      <v-autocomplete
                         v-model="departmentFilter"
                         :items="departments"
                         item-value="code"
@@ -97,11 +98,12 @@
                         :label="$t('department')"
                         filled
                         hide-details
+                        hide-no-data
                         @change="search"
                       />
                     </v-col>
                     <v-col lg="3" :md="listview ? 3 : 6" sm="6" cols="12" class="py-2 px-1">
-                      <v-select
+                      <v-autocomplete
                         v-model="federationFilter"
                         :items="federations"
                         item-value="id"
@@ -109,6 +111,7 @@
                         :label="$t('federation')"
                         filled
                         hide-details
+                        hide-no-data
                         @change="search"
                       />
                     </v-col>
@@ -189,25 +192,21 @@
                     outlined
                     :class="'structure-card pa-3 d-flex ' + ((mapview || $vuetify.breakpoint.smAndDown) ? 'flex-column' : 'flex-row align-items-center')"
                   >
-                    <div class="d-flex justify-center">
+                    <div class="d-flex justify-center max-w100">
                       <v-img
-                        :src="structure.logoId ? ('https://api.opentalent.fr/app.php/_internal/secure/files/' + structure.logoId) : '/images/default.jpg'"
+                        v-if="structure.logoId"
+                        :src="'https://api.opentalent.fr/app.php/_internal/secure/files/' + structure.logoId"
                         alt="poster"
                         height="80px"
-                        min-width="160px"
-                        max-width="80%"
+                        width="240px"
                         max-height="100%"
                         :contain="true"
                         style="margin: 12px;"
                       />
+                      <div v-else style="height: 104px; width: 264px"></div>
                     </div>
 
                     <div class="d-flex flex-column">
-                      <v-chip-group v-if="structure.practices" active-class="primary--text">
-                        <v-chip v-for="practice in structure.practices" :key="practice" outlined small pill>
-                          {{ $t(practice) }}
-                        </v-chip>
-                      </v-chip-group>
 
                       <v-card-title class="title">
                         {{ structure.name }}
@@ -216,26 +215,41 @@
                       <v-card-text class="infos">
                         <table>
                           <tr>
-                            <td class="py-1 pr-2">
+                            <td>
                               <font-awesome-icon class="icon" :icon="['fas', 'map-marker-alt']" />
                             </td>
-                            <td class="py-1">
+                            <td>
                               <span v-if="structure.streetAddress">{{ structure.streetAddress }}<br></span>
                               <span v-if="structure.postalCode" class="postalCode">{{ structure.postalCode }} </span>
                               {{ structure.addressCity }}
                             </td>
                           </tr>
                           <tr>
-                            <td class="py-1 pr-2">
+                            <td>
                               <font-awesome-icon class="icon" :icon="['fas', 'project-diagram']" />
                             </td>
-                            <td class="py-1">
-                              {{ structure.n1Name }}
+                            <td>
+                              <NuxtLink
+                                v-if="structure.n1Id !== parent"
+                                class="neutral"
+                                :to="{path: '/structures/' + structure.n1Id, query: { parent: parent, view: view, theme: theme }}"
+                                nuxt
+                              >
+                                {{ structure.n1Name }}
+                              </NuxtLink>
+                              <div v-else>
+                                {{ structure.n1Name }}
+                              </div>
                             </td>
                           </tr>
                         </table>
                       </v-card-text>
                     </div>
+                    <v-chip-group v-if="structure.practices" column active-class="primary--text">
+                      <v-chip v-for="practice in structure.practices" :key="practice" outlined small pill>
+                        {{ $t(practice) }}
+                      </v-chip>
+                    </v-chip-group>
                     <span class="flex-fill" />
 
                     <v-card-actions :class="listview ? 'align-self-end' : ''">
@@ -276,6 +290,8 @@ import practices from '@/enums/practices'
 import sphericDistance from '@/services/utils/geo'
 import StructuresProvider from '~/services/data/StructuresProvider'
 
+const CMF_ID = 12097
+
 export default Vue.extend({
   validate ({ query }) {
     if (!/^\d+$/.test(query.parent as string ?? '')) {
@@ -329,11 +345,16 @@ export default Vue.extend({
             this.federations.push(f)
           }
         }
+
+        // zoom on map markers (except if the parent structure is the CMF)
+        if (this.parent !== CMF_ID) {
+          this.fitMapToResults()
+        }
       })
   },
   computed: {
     onMapFilteredStructures (): Array<Structure> {
-      if (this.mapBoundsFilterStarted) {
+      if (this.mapview && this.mapBoundsFilterStarted) {
         return this.filteredStructures.filter((s) => {
           return this.matchMapBounds(s)
         })
@@ -364,6 +385,9 @@ export default Vue.extend({
   methods: {
     viewChanged (e: number) {
       this.view = (e === 0) ? 'map' : 'list'
+      if (this.mapview) {
+        this.fitMapToResults()
+      }
     },
     textFilterChanged (newVal: string) {
       this.textFilter = newVal
@@ -375,6 +399,14 @@ export default Vue.extend({
       }
       this.search()
     },
+    resetMap (): void {
+      const map = this.$refs.map as any
+      map.resetBounds()
+      if (this.parent !== CMF_ID) {
+        this.fitMapToResults()
+      }
+      this.mapBoundsFilterStarted = false
+    },
     fitMapToResults (): void {
       (this.$refs.map as any).zoomOnResults()
     },
@@ -392,8 +424,7 @@ export default Vue.extend({
       this.mapBoundsFilter = null
       const addressSearch = this.$refs.addressSearch as any
       addressSearch.clear()
-      const map = this.$refs.map as any
-      map.resetBounds()
+      this.resetMap()
       this.filteredStructures = this.structures
     },
     /**
@@ -437,7 +468,11 @@ export default Vue.extend({
      */
     matchDepartmentFilter (structure: Structure): boolean {
       if (!this.departmentFilter) { return true }
-      return structure.postalCode !== null && structure.postalCode.startsWith(this.departmentFilter)
+      return structure.postalCode !== null &&
+        (
+          structure.postalCode.startsWith(this.departmentFilter) ||
+          (['2A', '2B'].includes(this.departmentFilter) && structure.postalCode.startsWith('20'))
+        )
     },
     /**
      * Does the structure match the current federationFilter
@@ -472,7 +507,6 @@ export default Vue.extend({
         this.matchPracticesFilter(structure) &&
         this.matchDepartmentFilter(structure) &&
         this.matchFederationFilter(structure)
-        // this.matchMapBounds(structure)
     },
     /**
      * Update the filteredStructures array
@@ -501,6 +535,15 @@ export default Vue.extend({
     padding: 6px 12px;
   }
 
+  .infos td {
+    padding: 4px;
+    vertical-align: top;
+  }
+  .infos td:first-child {
+    padding-top: 6px;
+    text-align: center;
+  }
+
   .title {
     word-break: normal;
     color: var(--v-primary-base);

+ 5 - 0
yarn.lock

@@ -7857,6 +7857,11 @@ levn@~0.3.0:
     prelude-ls "~1.1.2"
     type-check "~0.3.2"
 
+libphonenumber-js@^1.9.38:
+  version "1.9.38"
+  resolved "https://registry.yarnpkg.com/libphonenumber-js/-/libphonenumber-js-1.9.38.tgz#d0388deebc95a8691382313d2f7dac2de2219387"
+  integrity sha512-7CCl9NZPYtX4JNXdvV5RnrQqrXp7LsLOTpYSUfEJBiySEnC5hysdwouXAuWgPDB55D/fpKm4RjM2/tUUh8kuoA==
+
 lines-and-columns@^1.1.6:
   version "1.1.6"
   resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00"