From 5b1b7ee164f2387087981e1dbd6fc8c7cac848e8 Mon Sep 17 00:00:00 2001
From: Thomas Citharel <tcit@tcit.fr>
Date: Wed, 9 Oct 2019 16:37:39 +0200
Subject: [PATCH 1/8] Make sure featured events have currently happening events

Signed-off-by: Thomas Citharel <tcit@tcit.fr>
---
 lib/mobilizon/events/events.ex | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/lib/mobilizon/events/events.ex b/lib/mobilizon/events/events.ex
index 41849d9bf..3bae79e1a 100644
--- a/lib/mobilizon/events/events.ex
+++ b/lib/mobilizon/events/events.ex
@@ -1433,9 +1433,12 @@ defmodule Mobilizon.Events do
     from(e in query, where: e.draft == ^is_draft)
   end
 
+  # Currently happening events are also future events
   @spec filter_future_events(Ecto.Query.t(), boolean) :: Ecto.Query.t()
   defp filter_future_events(query, true) do
-    from(q in query, where: q.begins_on > ^DateTime.utc_now())
+    from(q in query,
+      where: q.begins_on > ^DateTime.utc_now() or q.ends_on > ^DateTime.utc_now()
+    )
   end
 
   defp filter_future_events(query, false), do: query

From c565076fac3c597f1b49f70e47c674a7056b0649 Mon Sep 17 00:00:00 2001
From: Thomas Citharel <tcit@tcit.fr>
Date: Wed, 9 Oct 2019 17:03:35 +0200
Subject: [PATCH 2/8] Fix participants panel icons and improve tabs

Close #198

Signed-off-by: Thomas Citharel <tcit@tcit.fr>
---
 js/src/views/Event/Participants.vue | 105 ++++++++++++++++------------
 1 file changed, 60 insertions(+), 45 deletions(-)

diff --git a/js/src/views/Event/Participants.vue b/js/src/views/Event/Participants.vue
index df7342a4e..3e72ccc6b 100644
--- a/js/src/views/Event/Participants.vue
+++ b/js/src/views/Event/Participants.vue
@@ -3,60 +3,66 @@
         <b-tabs type="is-boxed" v-if="event">
             <b-tab-item>
                 <template slot="header">
-                    <b-icon icon="information-outline"></b-icon>
+                    <b-icon icon="account-multiple"></b-icon>
                     <span>{{ $t('Participants')}} <b-tag rounded> {{ participantStats.approved }} </b-tag> </span>
                 </template>
-                <section v-if="participantsAndCreators.length > 0">
-                    <h2 class="title">{{ $t('Participants') }}</h2>
-                    <div class="columns">
-                        <div class="column is-one-quarter-desktop" v-for="participant in participantsAndCreators" :key="participant.actor.id">
-                            <participant-card
-                                :participant="participant"
-                                :accept="acceptParticipant"
-                                :reject="refuseParticipant"
-                                :exclude="refuseParticipant"
-                            />
-                        </div>
-                    </div>
-                </section>
+                <template>
+                  <section v-if="participantsAndCreators.length > 0">
+                      <h2 class="title">{{ $t('Participants') }}</h2>
+                      <div class="columns">
+                          <div class="column is-one-quarter-desktop" v-for="participant in participantsAndCreators" :key="participant.actor.id">
+                              <participant-card
+                                  :participant="participant"
+                                  :accept="acceptParticipant"
+                                  :reject="refuseParticipant"
+                                  :exclude="refuseParticipant"
+                              />
+                          </div>
+                      </div>
+                  </section>
+                </template>
             </b-tab-item>
-            <b-tab-item>
+            <b-tab-item :disabled="participantStats.unapproved === 0">
                 <template slot="header">
-                    <b-icon icon="source-pull"></b-icon>
+                    <b-icon icon="account-multiple-plus"></b-icon>
                     <span>{{ $t('Requests') }} <b-tag rounded> {{ participantStats.unapproved }} </b-tag> </span>
                 </template>
-                <section v-if="queue.length > 0">
-                    <h2 class="title">{{ $t('Waiting list') }}</h2>
-                    <div class="columns">
-                        <div class="column is-one-quarter-desktop" v-for="participant in queue" :key="participant.actor.id">
-                            <participant-card
-                                :participant="participant"
-                                :accept="acceptParticipant"
-                                :reject="refuseParticipant"
-                                :exclude="refuseParticipant"
-                            />
-                        </div>
-                    </div>
-                </section>
+                <template>
+                  <section v-if="queue.length > 0">
+                      <h2 class="title">{{ $t('Waiting list') }}</h2>
+                      <div class="columns">
+                          <div class="column is-one-quarter-desktop" v-for="participant in queue" :key="participant.actor.id">
+                              <participant-card
+                                  :participant="participant"
+                                  :accept="acceptParticipant"
+                                  :reject="refuseParticipant"
+                                  :exclude="refuseParticipant"
+                              />
+                          </div>
+                      </div>
+                  </section>
+                </template>
             </b-tab-item>
-            <b-tab-item>
+            <b-tab-item :disabled="participantStats.rejected === 0">
                 <template slot="header">
-                    <b-icon icon="source-pull"></b-icon>
+                    <b-icon icon="account-multiple-minus"></b-icon>
                     <span>{{ $t('Rejected')}} <b-tag rounded> {{ participantStats.rejected }} </b-tag> </span>
                 </template>
-                <section v-if="rejected.length > 0">
-                    <h2 class="title">{{ $t('Rejected participations') }}</h2>
-                    <div class="columns">
-                        <div class="column is-one-quarter-desktop" v-for="participant in rejected" :key="participant.actor.id">
-                            <participant-card
-                                    :participant="participant"
-                                    :accept="acceptParticipant"
-                                    :reject="refuseParticipant"
-                                    :exclude="refuseParticipant"
-                            />
-                        </div>
-                    </div>
-                </section>
+                <template>
+                  <section v-if="rejected.length > 0">
+                      <h2 class="title">{{ $t('Rejected participations') }}</h2>
+                      <div class="columns">
+                          <div class="column is-one-quarter-desktop" v-for="participant in rejected" :key="participant.actor.id">
+                              <participant-card
+                                      :participant="participant"
+                                      :accept="acceptParticipant"
+                                      :reject="refuseParticipant"
+                                      :exclude="refuseParticipant"
+                              />
+                          </div>
+                      </div>
+                  </section>
+                </template>
             </b-tab-item>
         </b-tabs>
     </main>
@@ -231,6 +237,15 @@ export default class Participants extends Vue {
 <!-- Add "scoped" attribute to limit CSS to this component only -->
 <style lang="scss" scoped>
     section {
-        padding: 3rem 0;
+        padding: 1rem 0;
     }
 </style>
+<style lang="scss">
+  nav.tabs li {
+    margin: 3rem 0 0;
+  }
+
+  .tab-content {
+    background: #fff;
+  }
+</style>

From e1b3c14cbf39a7dfd56138fdfe4b2df8cfc7395a Mon Sep 17 00:00:00 2001
From: Thomas Citharel <tcit@tcit.fr>
Date: Wed, 9 Oct 2019 17:18:27 +0200
Subject: [PATCH 3/8] Prevent route changing when editing with changes

Close #197

Signed-off-by: Thomas Citharel <tcit@tcit.fr>
---
 js/src/views/Event/Edit.vue | 16 +++++++++++++---
 1 file changed, 13 insertions(+), 3 deletions(-)

diff --git a/js/src/views/Event/Edit.vue b/js/src/views/Event/Edit.vue
index 42c52c77f..cc3dd9c3d 100644
--- a/js/src/views/Event/Edit.vue
+++ b/js/src/views/Event/Edit.vue
@@ -266,6 +266,9 @@ import { ICurrentUser } from '@/types/current-user.model';
       query: TAGS,
     },
   },
+  beforeRouteLeave(to, from, next) {
+    this.confirmGoElsewhere(() => next());
+  },
 })
 export default class EditEvent extends Vue {
   @Prop({ type: Boolean, default: false }) isUpdate!: boolean;
@@ -499,9 +502,9 @@ export default class EditEvent extends Vue {
   /**
    * Confirm cancel
    */
-  confirmGoBack() {
+  confirmGoElsewhere(callback) {
     if (!this.isEventModified) {
-      return this.$router.go(-1);
+      return callback();
     }
     const title: string = this.isUpdate ?
             this.$t('Cancel edition') as string :
@@ -519,10 +522,17 @@ export default class EditEvent extends Vue {
       cancelText: this.$t('Continue editing') as string,
       type: 'is-warning',
       hasIcon: true,
-      onConfirm: () => this.$router.go(-1),
+      onConfirm: callback,
     });
   }
 
+  /**
+   * Confirm cancel
+   */
+  confirmGoBack() {
+    this.confirmGoElsewhere(() => this.$router.go(-1));
+  }
+
   get isEventModified(): boolean {
     return JSON.stringify(this.event.toEditJSON()) !== JSON.stringify(this.unmodifiedEvent);
   }

From 9f583b5767e300dff09ae7c1c2e4291f72410a12 Mon Sep 17 00:00:00 2001
From: Thomas Citharel <tcit@tcit.fr>
Date: Wed, 9 Oct 2019 17:25:09 +0200
Subject: [PATCH 4/8] Rename Events to MyEvents

Close #193

Signed-off-by: Thomas Citharel <tcit@tcit.fr>
---
 js/src/components/NavBar.vue | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/js/src/components/NavBar.vue b/js/src/components/NavBar.vue
index 6632a990d..6bdafa0e9 100644
--- a/js/src/components/NavBar.vue
+++ b/js/src/components/NavBar.vue
@@ -5,7 +5,7 @@
     </template>
     <template slot="start">
       <b-navbar-item tag="router-link" :to="{ name: RouteName.EXPLORE }">{{ $t('Explore') }}</b-navbar-item>
-      <b-navbar-item tag="router-link" :to="{ name: RouteName.MY_EVENTS }">{{ $t('Events') }}</b-navbar-item>
+      <b-navbar-item tag="router-link" :to="{ name: RouteName.MY_EVENTS }">{{ $t('My events') }}</b-navbar-item>
       <b-navbar-item tag="span">
         <b-button tag="router-link" :to="{ name: RouteName.CREATE_EVENT }" type="is-success">{{ $t('Create') }}</b-button>
       </b-navbar-item>

From 2a4dbe55cac0e2b25100560c4f70ee3da3cd67ac Mon Sep 17 00:00:00 2001
From: Thomas Citharel <tcit@tcit.fr>
Date: Wed, 9 Oct 2019 17:25:53 +0200
Subject: [PATCH 5/8] Update i18n

Signed-off-by: Thomas Citharel <tcit@tcit.fr>
---
 js/src/i18n/en_US.json |   1 +
 js/src/i18n/fr_FR.json | 547 +++++++++++++++++++++--------------------
 2 files changed, 275 insertions(+), 273 deletions(-)

diff --git a/js/src/i18n/en_US.json b/js/src/i18n/en_US.json
index 14c63e478..2c3b93bbf 100644
--- a/js/src/i18n/en_US.json
+++ b/js/src/i18n/en_US.json
@@ -126,6 +126,7 @@
 	"Legal": "Legal",
 	"Let's create a new common": "Let's create a new common",
 	"License": "License",
+	"Limited number of places": "Limited number of places",
 	"Limited places": "Limited places",
 	"Load more": "Load more",
 	"Loading…": "Loading…",
diff --git a/js/src/i18n/fr_FR.json b/js/src/i18n/fr_FR.json
index e8d9e5987..72a34fb4f 100644
--- a/js/src/i18n/fr_FR.json
+++ b/js/src/i18n/fr_FR.json
@@ -1,275 +1,276 @@
 {
-    "A validation email was sent to {email}": "Un email de validation a été envoyé à {email}",
-    "About this event": "À propos de cet événement",
-    "About this instance": "À propos de cette instance",
-    "About": "À propos",
-    "Add a new profile": "Ajouter un nouveau profil",
-    "Add a tag": "Ajouter un tag",
-    "Add an address": "Ajouter une adresse",
-    "Add to my calendar": "Ajouter à mon agenda",
-    "Add": "Ajouter",
-    "Additional comments": "Commentaires additionnels",
-    "Administration": "Administration",
-    "Allow all comments": "Autoriser tous les commentaires",
-    "Approve": "Approuver",
-    "Are you going to this event?": "Allez-vous à cet événement ?",
-    "Are you sure you want to cancel the event creation? You'll lose all modifications.": "Étes-vous certain⋅e de vouloir annuler la création de l'événement ? Vous allez perdre toutes vos modifications.",
-    "Are you sure you want to cancel the event edition? You'll lose all modifications.": "Étes-vous certain⋅e de vouloir annuler l'édition de l'événement ? Vous allez perdre toutes vos modifications.",
-    "Are you sure you want to cancel your participation at event \"{title}\"?": "Êtes-vous certain⋅e de vouloir annuler votre participation à l'événement « {title} » ?",
-    "Are you sure you want to delete this event? This action cannot be reverted.": "Êtes-vous certain⋅e de vouloir supprimer cet événement ? Cette action ne peut être annulée.",
-    "Before you can login, you need to click on the link inside it to validate your account": "Avant que vous puissiez vous enregistrer, vous devez cliquer sur le lien à l'intérieur pour valider votre compte",
-    "By {name}": "Par {name}",
-    "Cancel creation": "Annuler la création",
-    "Cancel edition": "Annuler l'édition",
-    "Cancel my participation request…": "Cancel my participation request…",
-    "Cancel my participation…": "Annuler ma participation…",
-    "Cancel": "Annuler",
-    "Category": "Catégorie",
-    "Change my identity…": "Changer mon identité…",
-    "Change my password": "Modifier mon mot de passe",
-    "Change password": "Modifier mot de passe",
-    "Change": "Modifier",
-    "Clear": "Effacer",
-    "Click to select": "Cliquez pour sélectionner",
-    "Click to upload": "Cliquez pour uploader",
-    "Close comments for all (except for admins)": "Fermer les commentaires à tout le monde (excepté les administrateurs)",
-    "Comments on the event page": "Commentaires sur la page de l'événement",
-    "Comments": "Commentaires",
-    "Confirm my particpation": "Confirmer ma particpation",
-    "Confirmed: Will happen": "Confirmé : aura lieu",
-    "Continue editing": "Continuer l'édition",
-    "Country": "Pays",
-    "Create a new event": "Créer un nouvel événement",
-    "Create a new group": "Créer un nouveau groupe",
-    "Create a new identity": "Créer une nouvelle identité",
-    "Create group": "Créer un groupe",
-    "Create my event": "Créer mon événement",
-    "Create my group": "Créer mon groupe",
-    "Create my profile": "Créer mon profil",
-    "Create token": "Créer un jeton",
-    "Create your communities and your events": "Créer vos communautés et vos événements",
-    "Create": "Créer",
-    "Creator": "Créateur",
-    "Current": "Actuel",
-    "Delete event": "Supprimer un événement",
-    "Delete this identity": "Supprimer cette identité",
-    "Delete your identity": "Supprimer votre identité",
-    "Delete {eventTitle}": "Supprimer {eventTitle}",
-    "Delete {preferredUsername}": "Supprimer {preferredUsername}",
-    "Delete": "Supprimer",
-    "Description": "Description",
-    "Didn't receive the instructions ?": "Vous n'avez pas reçu les instructions ?",
-    "Disallow promoting on Mobilizon": "Refuser la mise en avant sur Mobilizon",
-    "Display name": "Nom affiché",
-    "Display participation price": "Afficher un prix de participation",
-    "Displayed name": "Nom affiché",
-    "Do you want to participate in {title}?": "Voulez-vous participer à {title} ?",
-    "Draft": "Brouillon",
-    "Drafts": "Brouillons",
-    "Edit": "Éditer",
-    "Either the account is already validated, either the validation token is incorrect.": "Soit le compte est déjà validé, soit le jeton de validation est incorrect.",
-    "Email": "Email",
-    "Ends on…": "Se termine le…",
-    "Enter some tags": "Écrire des tags",
-    "Error while validating account": "Erreur lors de la validation du compte",
-    "Event already passed": "Événement déjà passé",
-    "Event list": "Liste d'événements",
-    "Event {eventTitle} deleted": "Événement {eventTitle} supprimé",
-    "Event {eventTitle} reported": "Événement {eventTitle} signalé",
-    "Event": "Événement",
-    "Events nearby you": "Événements près de chez vous",
-    "Events you're going at": "Événements auxquels vous vous rendez",
-    "Events": "Événements",
-    "Exclude": "Exclure",
-    "Explore": "Explorer",
-    "Features": "Fonctionnalités",
-    "Find an address": "Trouver une adresse",
-    "Forgot your password ?": "Mot de passe oublié ?",
-    "From the {startDate} at {startTime} to the {endDate} at {endTime}": "Du {startDate} à {startTime} au {endDate} à {endTime}",
-    "General information": "Information générales",
-    "Going as {name}": "En tant que {name}",
-    "Group List": "Liste de groupes",
-    "Group full name": "Nom complet du groupe",
-    "Group name": "Nom du groupe",
-    "Group {displayName} created": "Groupe {displayName} créé",
-    "Group": "Groupe",
-    "Groups": "Groupes",
-    "I create an identity": "Je crée une identité",
-    "I participate": "Je participe",
-    "I want to approve every participation request": "Je veux approuver chaque demande de participation",
-    "Identities": "Identités",
-    "Identity {displayName} created": "Identité {displayName} créée",
-    "Identity {displayName} deleted": "Identité {displayName} supprimée",
-    "Identity {displayName} updated": "Identité {displayName} mise à jour",
-    "Identity": "Identité",
-    "If an account with this email exists, we just sent another confirmation email to {email}": "Si un compte avec un tel email existe, nous venons juste d'envoyer un nouvel email de confirmation à {email}",
-    "If this identity is the only administrator of some groups, you need to delete them before being able to delete this identity.": "Si cette identité est la seule administratrice de certains groupes, vous devez les supprimer avant de pouvoir supprimer cette identité.",
-    "Join event {title}": "Rejoindre {title}",
-    "Join": "Rejoindre",
-    "Last published event": "Dernier événement publié",
-    "Last week": "La semaine dernière",
-    "Learn more on {0}": "En apprendre plus sur {0}",
-    "Learn more on": "En apprendre plus sur",
-    "Leave event": "Annuler ma participation à l'événement",
-    "Leave": "Quitter",
-    "Leaving event \"{title}\"": "Annuler ma participation à l'événement",
-    "Legal": "Mentions légales",
-    "License": "Licence",
-    "Limited places": "Places limitées",
-    "Load more": "Voir plus",
-    "Loading…": "Chargement en cours…",
-    "Locality": "Commune",
-    "Log in": "Se connecter",
-    "Log out": "Se déconnecter",
-    "Login": "Se connecter",
-    "Manage participants": "Gérer les participants",
-    "Manage participations": "Gérer les participations",
-    "Members": "Membres",
-    "Moderated comments (shown after approval)": "Commentaires modérés (affichés après validation)",
-    "My account": "Mon compte",
-    "My events": "Mes événements",
-    "My identities": "Mes identités",
-    "Name": "Nom",
-    "New password": "Nouveau mot de passe",
-    "No address defined": "Aucune adresse définie",
-    "No events found": "Aucun événement trouvé",
-    "No group found": "Aucun groupe trouvé",
-    "No groups found": "Aucun groupe trouvé",
-    "No participants yet.": "Pas de participants pour le moment.",
-    "No results for \"{queryText}\"": "Pas de résultats pour « {queryText} »",
-    "Number of places": "Nombre de places",
-    "Old password": "Ancien mot de passe",
-    "One person is going": "Personne n'y va | Une personne y va | {approved} personnes y vont",
-    "Only accessible through link and search (private)": "Uniquement accessibles par lien et la recherche (privé)",
-    "Opened reports": "Signalements ouverts",
-    "Organized by {name}": "Organisé par {name}",
-    "Organized": "Organisés",
-    "Organizer": "Organisateur",
-    "Other stuff…": "Autres trucs…",
-    "Otherwise this identity will just be removed from the group administrators.": "Sinon cette identité sera juste supprimée des administrateurs du groupe.",
-    "Page limited to my group (asks for auth)": "Accès limité à mon groupe (demande authentification)",
-    "Participants": "Participants",
-    "Participate": "Participer",
-    "Participation approval": "Validation des participations",
-    "Participation requested!": "Participation demandée !",
-    "Password (confirmation)": "Mot de passe (confirmation)",
-    "Password change": "Changement de mot de passe",
-    "Password reset": "Réinitialisation du mot de passe",
-    "Password": "Mot de passe",
-    "Past events": "Événements passés",
-    "Pick an identity": "Choisissez une identité",
-    "Please be nice to each other": "Soyez sympas entre vous",
-    "Please check your spam folder if you didn't receive the email.": "Merci de vérifier votre dossier des indésirables si vous n'avez pas reçu l'email.",
-    "Please contact this instance's Mobilizon admin if you think this is a mistake.": "Veuillez contacter l'administrateur de cette instance Mobilizon si vous pensez qu’il s’agit d’une erreur.",
-    "Please make sure the address is correct and that the page hasn't been moved.": "Assurez‐vous que l’adresse est correcte et que la page n’a pas été déplacée.",
-    "Please read the full rules": "Merci de lire les règles complètes",
-    "Please type at least 5 characters": "Merci d'entrer au moins 5 caractères",
-    "Postal Code": "Code postal",
-    "Private event": "Événement privé",
-    "Private feeds": "Flux privés",
-    "Promotion": "Mise en avant",
-    "Public RSS/Atom Feed": "Flux RSS/Atom public",
-    "Public comment moderation": "Modération des commentaires publics",
-    "Public event": "Événement public",
-    "Public feeds": "Flux publics",
-    "Public iCal Feed": "Flux iCal public",
-    "Publish": "Publier",
-    "Published events": "Événements publiés",
-    "RSS/Atom Feed": "Flux RSS/Atom",
-    "Region": "Région",
-    "Register an account on Mobilizon!": "S'inscrire sur Mobilizon !",
-    "Register": "S'inscrire",
-    "Registration is currently closed.": "Les inscriptions sont actuellement fermées.",
-    "Reject": "Rejetter",
-    "Rejected participations": "Participations rejetées",
-    "Rejected": "Rejetés",
-    "Report this event": "Signaler cet événement",
-    "Report": "Signaler",
-    "Requests": "Requêtes",
-    "Resend confirmation email": "Envoyer à nouveau l'email de confirmation",
-    "Reset my password": "Réinitialiser mon mot de passe",
-    "Save draft": "Enregistrer le brouillon",
-    "Save": "Enregistrer",
-    "Search events, groups, etc.": "Rechercher des événements, des groupes, etc.",
-    "Search results: \"{search}\"": "Résultats de recherche: « {search} »",
-    "Search": "Rechercher",
-    "Searching…": "Recherche en cours…",
-    "Send confirmation email again": "Envoyer l'email de confirmation à nouveau",
-    "Send email to reset my password": "Envoyer un email pour réinitialiser mon mot de passe",
-    "Send the report": "Envoyer le signalement",
-    "Share this event": "Partager l'événement",
-    "Show map": "Afficher la carte",
-    "Show remaining number of places": "Afficher le nombre de places restantes",
-    "Sign up": "S'enregistrer",
-    "Starts on…": "Débute le…",
-    "Status": "Statut",
-    "Street": "Rue",
-    "Tentative: Will be confirmed later": "Provisoire : sera confirmé plus tard",
-    "The content came from another server. Transfer an anonymous copy of the report?": "Le contenu provient d'une autre instance. Transférer une copie anonyme du signalement ?",
-    "The event came from another instance. Your participation will be confirmed after we confirm it with the other instance.": "L'événement provient d'une autre instance. Votre participation sera confirmée après que nous ayons la confirmation de l'autre instance.",
-    "The event organizer didn't add any description.": "L'organisateur de l'événement n'a pas ajouté de description.",
-    "The event organizer has chosen to approve manually the participations to this event. You will receive a notification when your participation has been approved": "L'organisateur⋅ice de l'événement a choisi d'approuver manuellement les participations à cet événement. Vous recevrez une notification lorsque votre participation sera approuvée",
-    "The event title will be ellipsed.": "Le titre de l'événement sera ellipsé.",
-    "The page you're looking for doesn't exist.": "La page que vous recherchez n'existe pas.",
-    "The password was successfully changed": "Le mot de passe a été changé avec succès",
-    "The report will be sent to the moderators of your instance. You can explain why you report this content below.": "Le signalement sera envoyé aux modérateur⋅ices de votre instance. Vous pouvez expliquer pourquoi vous signalez ce contenu ci-dessous.",
-    "The {date} at {time}": "Le {date} à {time}",
-    "The {date} from {startTime} to {endTime}": "Le {date} de {startTime} à {endTime}",
-    "There are {participants} participants.": "Il n'y a qu'un⋅e participant⋅e. | Il y a {participants} participants.",
-    "These events may interest you": "Ces événements peuvent vous intéresser",
-    "This instance isn't opened to registrations, but you can register on other instances.": "Cette instance n'autorise pas les inscriptions, mais vous pouvez vous enregistrer sur d'autres instances.",
-    "This will delete / anonymize all content (events, comments, messages, participations…) created from this identity.": "Cela supprimera / anonymisera tout le contenu (événements, commentaires, messages, participations…) créés avec cette identité.",
-    "Title": "Titre",
-    "To confirm, type your event title \"{eventTitle}\"": "Pour confirmer, entrez le titre de l'événement « {eventTitle} »",
-    "To confirm, type your identity username \"{preferredUsername}\"": "Pour confirmer, entrez le nom de l’identité « {preferredUsername} »",
-    "Transfer to {outsideDomain}": "Transférer à {outsideDomain}",
-    "Unfortunately, your participation request was rejected by the organizers.": "Malheureusement, votre demande de participation a été refusée par les organisateur⋅ices.",
-    "Unknown error.": "Erreur inconnue.",
-    "Unsaved changes": "Modifications non enregistrées",
-    "Upcoming": "À venir",
-    "Update event {name}": "Éditer l'événement {name}",
-    "Update my event": "Éditer mon événement",
-    "User logout": "Déconnexion",
-    "Username": "Pseudo",
-    "Users": "Utilisateurs",
-    "View event page": "Voir la page de l'événement",
-    "View everything": "Voir tout",
-    "Visible everywhere on the web (public)": "Visible partout sur le web (public)",
-    "Waiting for organization team approval.": "En attente d'approbation par l'organisation.",
-    "Waiting list": "Liste d'attente",
-    "We just sent an email to {email}": "Nous venons d'envoyer un email à {email}",
-    "Website / URL": "Site web / URL",
-    "Welcome back {username}": "Bon retour {username}",
-    "Welcome back!": "Bon retour !",
-    "Welcome on your administration panel": "Bienvenue sur votre espace d'administration",
-    "Who can view this event and participate": "Qui peut voir cet événement et y participer",
-    "World map": "Carte mondiale",
-    "You and one other person are going to this event": "Vous êtes le ou la seule à vous rendre à cet événement | Vous et une autre personne vous rendez à cet événement | Vous et {approved} autres personnes vous rendez à cet événement.",
-    "You announced that you're going to this event.": "Vous avez annoncé vous rendre à cet événement.",
-    "You are already logged-in.": "Vous êtes déjà connecté.",
-    "You are an organizer.": "Vous êtes un organisateur.",
-    "You have been disconnected": "Vous avez été déconnecté⋅e",
-    "You have one event in {days} days.": "Vous n'avez pas d'événements dans {days} jours | Vous avez un événement dans {days} jours. | Vous avez {count} événements dans {days} jours",
-    "You have one event today.": "Vous n'avez pas d'évenement aujourd'hui | Vous avez un événement aujourd'hui. | Vous avez {count} événements aujourd'hui",
-    "You have one event tomorrow.": "Vous n'avez pas d'événement demain | Vous avez un événement demain. | Vous avez {count} événements demain",
-    "You need to login.": "Vous devez vous connecter.",
-    "You're not going to any event yet": "Vous n'allez à aucun événement pour le moment",
-    "You're organizing this event": "Vous organisez cet événement",
-    "Your account has been validated": "Votre compte a été validé",
-    "Your account is being validated": "Votre compte est en cours de validation",
-    "Your account is nearly ready, {username}": "Votre compte est presque prêt, {username}",
-    "Your local administrator resumed it's policy:": "Votre administrateur local a résumé sa politique ainsi :",
-    "e.g. 10 Rue Jangot": "par exemple : 10 Rue Jangot",
-    "iCal Feed": "Flux iCal",
-    "meditate a bit": "méditez un peu",
-    "with another identity…": "avec une autre identité…",
-    "with {identity}": "avec {identity}",
-    "{actor}'s avatar": "Avatar de {actor}",
-    "{approved} / {total} seats": "{approved} / {total} places",
-    "{count} participants": "Un⋅e participant⋅e|{count} participant⋅e⋅s",
-    "{count} requests waiting": "Un⋅e demande en attente|{count} demandes en attente",
-    "© The Mobilizon Contributors {date} - Made with Elixir, Phoenix, VueJS & with some love and some weeks": "© Les contributeurs de Mobilizon {date} - Fait avec Elixir, Phoenix, VueJS & et de l'amour et des semaines",
-    "Organize and take action, freely": "S'organiser et agir, librement",
-    "Join {instance}, a Mobilizon instance": "Rejoignez {instance}, une instance Mobilizon",
-    "Learn more": "En apprendre plus"
+	"A validation email was sent to {email}": "Un email de validation a été envoyé à {email}",
+	"About this event": "À propos de cet événement",
+	"About this instance": "À propos de cette instance",
+	"About": "À propos",
+	"Add a new profile": "Ajouter un nouveau profil",
+	"Add a tag": "Ajouter un tag",
+	"Add an address": "Ajouter une adresse",
+	"Add to my calendar": "Ajouter à mon agenda",
+	"Add": "Ajouter",
+	"Additional comments": "Commentaires additionnels",
+	"Administration": "Administration",
+	"Allow all comments": "Autoriser tous les commentaires",
+	"Approve": "Approuver",
+	"Are you going to this event?": "Allez-vous à cet événement ?",
+	"Are you sure you want to cancel the event creation? You'll lose all modifications.": "Étes-vous certain⋅e de vouloir annuler la création de l'événement ? Vous allez perdre toutes vos modifications.",
+	"Are you sure you want to cancel the event edition? You'll lose all modifications.": "Étes-vous certain⋅e de vouloir annuler l'édition de l'événement ? Vous allez perdre toutes vos modifications.",
+	"Are you sure you want to cancel your participation at event \"{title}\"?": "Êtes-vous certain⋅e de vouloir annuler votre participation à l'événement « {title} » ?",
+	"Are you sure you want to delete this event? This action cannot be reverted.": "Êtes-vous certain⋅e de vouloir supprimer cet événement ? Cette action ne peut être annulée.",
+	"Before you can login, you need to click on the link inside it to validate your account": "Avant que vous puissiez vous enregistrer, vous devez cliquer sur le lien à l'intérieur pour valider votre compte",
+	"By {name}": "Par {name}",
+	"Cancel creation": "Annuler la création",
+	"Cancel edition": "Annuler l'édition",
+	"Cancel my participation request…": "Cancel my participation request…",
+	"Cancel my participation…": "Annuler ma participation…",
+	"Cancel": "Annuler",
+	"Category": "Catégorie",
+	"Change my identity…": "Changer mon identité…",
+	"Change my password": "Modifier mon mot de passe",
+	"Change password": "Modifier mot de passe",
+	"Change": "Modifier",
+	"Clear": "Effacer",
+	"Click to select": "Cliquez pour sélectionner",
+	"Click to upload": "Cliquez pour uploader",
+	"Close comments for all (except for admins)": "Fermer les commentaires à tout le monde (excepté les administrateurs)",
+	"Comments on the event page": "Commentaires sur la page de l'événement",
+	"Comments": "Commentaires",
+	"Confirm my particpation": "Confirmer ma particpation",
+	"Confirmed: Will happen": "Confirmé : aura lieu",
+	"Continue editing": "Continuer l'édition",
+	"Country": "Pays",
+	"Create a new event": "Créer un nouvel événement",
+	"Create a new group": "Créer un nouveau groupe",
+	"Create a new identity": "Créer une nouvelle identité",
+	"Create group": "Créer un groupe",
+	"Create my event": "Créer mon événement",
+	"Create my group": "Créer mon groupe",
+	"Create my profile": "Créer mon profil",
+	"Create token": "Créer un jeton",
+	"Create your communities and your events": "Créer vos communautés et vos événements",
+	"Create": "Créer",
+	"Creator": "Créateur",
+	"Current": "Actuel",
+	"Delete event": "Supprimer un événement",
+	"Delete this identity": "Supprimer cette identité",
+	"Delete your identity": "Supprimer votre identité",
+	"Delete {eventTitle}": "Supprimer {eventTitle}",
+	"Delete {preferredUsername}": "Supprimer {preferredUsername}",
+	"Delete": "Supprimer",
+	"Description": "Description",
+	"Didn't receive the instructions ?": "Vous n'avez pas reçu les instructions ?",
+	"Disallow promoting on Mobilizon": "Refuser la mise en avant sur Mobilizon",
+	"Display name": "Nom affiché",
+	"Display participation price": "Afficher un prix de participation",
+	"Displayed name": "Nom affiché",
+	"Do you want to participate in {title}?": "Voulez-vous participer à {title} ?",
+	"Draft": "Brouillon",
+	"Drafts": "Brouillons",
+	"Edit": "Éditer",
+	"Either the account is already validated, either the validation token is incorrect.": "Soit le compte est déjà validé, soit le jeton de validation est incorrect.",
+	"Email": "Email",
+	"Ends on…": "Se termine le…",
+	"Enter some tags": "Écrire des tags",
+	"Error while validating account": "Erreur lors de la validation du compte",
+	"Event already passed": "Événement déjà passé",
+	"Event list": "Liste d'événements",
+	"Event {eventTitle} deleted": "Événement {eventTitle} supprimé",
+	"Event {eventTitle} reported": "Événement {eventTitle} signalé",
+	"Event": "Événement",
+	"Events nearby you": "Événements près de chez vous",
+	"Events you're going at": "Événements auxquels vous vous rendez",
+	"Events": "Événements",
+	"Exclude": "Exclure",
+	"Explore": "Explorer",
+	"Features": "Fonctionnalités",
+	"Find an address": "Trouver une adresse",
+	"Forgot your password ?": "Mot de passe oublié ?",
+	"From the {startDate} at {startTime} to the {endDate} at {endTime}": "Du {startDate} à {startTime} au {endDate} à {endTime}",
+	"General information": "Information générales",
+	"Going as {name}": "En tant que {name}",
+	"Group List": "Liste de groupes",
+	"Group full name": "Nom complet du groupe",
+	"Group name": "Nom du groupe",
+	"Group {displayName} created": "Groupe {displayName} créé",
+	"Group": "Groupe",
+	"Groups": "Groupes",
+	"I create an identity": "Je crée une identité",
+	"I participate": "Je participe",
+	"I want to approve every participation request": "Je veux approuver chaque demande de participation",
+	"Identities": "Identités",
+	"Identity {displayName} created": "Identité {displayName} créée",
+	"Identity {displayName} deleted": "Identité {displayName} supprimée",
+	"Identity {displayName} updated": "Identité {displayName} mise à jour",
+	"Identity": "Identité",
+	"If an account with this email exists, we just sent another confirmation email to {email}": "Si un compte avec un tel email existe, nous venons juste d'envoyer un nouvel email de confirmation à {email}",
+	"If this identity is the only administrator of some groups, you need to delete them before being able to delete this identity.": "Si cette identité est la seule administratrice de certains groupes, vous devez les supprimer avant de pouvoir supprimer cette identité.",
+	"Join event {title}": "Rejoindre {title}",
+	"Join {instance}, a Mobilizon instance": "Rejoignez {instance}, une instance Mobilizon",
+	"Join": "Rejoindre",
+	"Last published event": "Dernier événement publié",
+	"Last week": "La semaine dernière",
+	"Learn more on {0}": "En apprendre plus sur {0}",
+	"Learn more on": "En apprendre plus sur",
+	"Learn more": "En apprendre plus",
+	"Leave event": "Annuler ma participation à l'événement",
+	"Leave": "Quitter",
+	"Leaving event \"{title}\"": "Annuler ma participation à l'événement",
+	"Legal": "Mentions légales",
+	"License": "Licence",
+	"Limited number of places": "Nombre de places limité",
+	"Limited places": "Places limitées",
+	"Load more": "Voir plus",
+	"Loading…": "Chargement en cours…",
+	"Locality": "Commune",
+	"Log in": "Se connecter",
+	"Log out": "Se déconnecter",
+	"Login": "Se connecter",
+	"Manage participants": "Gérer les participants",
+	"Manage participations": "Gérer les participations",
+	"Members": "Membres",
+	"Moderated comments (shown after approval)": "Commentaires modérés (affichés après validation)",
+	"My account": "Mon compte",
+	"My events": "Mes événements",
+	"My identities": "Mes identités",
+	"Name": "Nom",
+	"New password": "Nouveau mot de passe",
+	"No address defined": "Aucune adresse définie",
+	"No events found": "Aucun événement trouvé",
+	"No group found": "Aucun groupe trouvé",
+	"No groups found": "Aucun groupe trouvé",
+	"No participants yet.": "Pas de participants pour le moment.",
+	"No results for \"{queryText}\"": "Pas de résultats pour « {queryText} »",
+	"Number of places": "Nombre de places",
+	"Old password": "Ancien mot de passe",
+	"One person is going": "Personne n'y va | Une personne y va | {approved} personnes y vont",
+	"Only accessible through link and search (private)": "Uniquement accessibles par lien et la recherche (privé)",
+	"Opened reports": "Signalements ouverts",
+	"Organize and take action, freely": "S'organiser et agir, librement",
+	"Organized by {name}": "Organisé par {name}",
+	"Organized": "Organisés",
+	"Organizer": "Organisateur",
+	"Other stuff…": "Autres trucs…",
+	"Otherwise this identity will just be removed from the group administrators.": "Sinon cette identité sera juste supprimée des administrateurs du groupe.",
+	"Page limited to my group (asks for auth)": "Accès limité à mon groupe (demande authentification)",
+	"Participants": "Participants",
+	"Participate": "Participer",
+	"Participation approval": "Validation des participations",
+	"Participation requested!": "Participation demandée !",
+	"Password (confirmation)": "Mot de passe (confirmation)",
+	"Password change": "Changement de mot de passe",
+	"Password reset": "Réinitialisation du mot de passe",
+	"Password": "Mot de passe",
+	"Past events": "Événements passés",
+	"Pick an identity": "Choisissez une identité",
+	"Please be nice to each other": "Soyez sympas entre vous",
+	"Please check your spam folder if you didn't receive the email.": "Merci de vérifier votre dossier des indésirables si vous n'avez pas reçu l'email.",
+	"Please contact this instance's Mobilizon admin if you think this is a mistake.": "Veuillez contacter l'administrateur de cette instance Mobilizon si vous pensez qu’il s’agit d’une erreur.",
+	"Please make sure the address is correct and that the page hasn't been moved.": "Assurez‐vous que l’adresse est correcte et que la page n’a pas été déplacée.",
+	"Please read the full rules": "Merci de lire les règles complètes",
+	"Please type at least 5 characters": "Merci d'entrer au moins 5 caractères",
+	"Postal Code": "Code postal",
+	"Private event": "Événement privé",
+	"Private feeds": "Flux privés",
+	"Promotion": "Mise en avant",
+	"Public RSS/Atom Feed": "Flux RSS/Atom public",
+	"Public comment moderation": "Modération des commentaires publics",
+	"Public event": "Événement public",
+	"Public feeds": "Flux publics",
+	"Public iCal Feed": "Flux iCal public",
+	"Publish": "Publier",
+	"Published events": "Événements publiés",
+	"RSS/Atom Feed": "Flux RSS/Atom",
+	"Region": "Région",
+	"Register an account on Mobilizon!": "S'inscrire sur Mobilizon !",
+	"Register": "S'inscrire",
+	"Registration is currently closed.": "Les inscriptions sont actuellement fermées.",
+	"Reject": "Rejetter",
+	"Rejected participations": "Participations rejetées",
+	"Rejected": "Rejetés",
+	"Report this event": "Signaler cet événement",
+	"Report": "Signaler",
+	"Requests": "Requêtes",
+	"Resend confirmation email": "Envoyer à nouveau l'email de confirmation",
+	"Reset my password": "Réinitialiser mon mot de passe",
+	"Save draft": "Enregistrer le brouillon",
+	"Save": "Enregistrer",
+	"Search events, groups, etc.": "Rechercher des événements, des groupes, etc.",
+	"Search results: \"{search}\"": "Résultats de recherche: « {search} »",
+	"Search": "Rechercher",
+	"Searching…": "Recherche en cours…",
+	"Send confirmation email again": "Envoyer l'email de confirmation à nouveau",
+	"Send email to reset my password": "Envoyer un email pour réinitialiser mon mot de passe",
+	"Send the report": "Envoyer le signalement",
+	"Share this event": "Partager l'événement",
+	"Show map": "Afficher la carte",
+	"Show remaining number of places": "Afficher le nombre de places restantes",
+	"Sign up": "S'enregistrer",
+	"Starts on…": "Débute le…",
+	"Status": "Statut",
+	"Street": "Rue",
+	"Tentative: Will be confirmed later": "Provisoire : sera confirmé plus tard",
+	"The content came from another server. Transfer an anonymous copy of the report?": "Le contenu provient d'une autre instance. Transférer une copie anonyme du signalement ?",
+	"The event came from another instance. Your participation will be confirmed after we confirm it with the other instance.": "L'événement provient d'une autre instance. Votre participation sera confirmée après que nous ayons la confirmation de l'autre instance.",
+	"The event organizer didn't add any description.": "L'organisateur de l'événement n'a pas ajouté de description.",
+	"The event organizer has chosen to approve manually the participations to this event. You will receive a notification when your participation has been approved": "L'organisateur⋅ice de l'événement a choisi d'approuver manuellement les participations à cet événement. Vous recevrez une notification lorsque votre participation sera approuvée",
+	"The event title will be ellipsed.": "Le titre de l'événement sera ellipsé.",
+	"The page you're looking for doesn't exist.": "La page que vous recherchez n'existe pas.",
+	"The password was successfully changed": "Le mot de passe a été changé avec succès",
+	"The report will be sent to the moderators of your instance. You can explain why you report this content below.": "Le signalement sera envoyé aux modérateur⋅ices de votre instance. Vous pouvez expliquer pourquoi vous signalez ce contenu ci-dessous.",
+	"The {date} at {time}": "Le {date} à {time}",
+	"The {date} from {startTime} to {endTime}": "Le {date} de {startTime} à {endTime}",
+	"There are {participants} participants.": "Il n'y a qu'un⋅e participant⋅e. | Il y a {participants} participants.",
+	"These events may interest you": "Ces événements peuvent vous intéresser",
+	"This instance isn't opened to registrations, but you can register on other instances.": "Cette instance n'autorise pas les inscriptions, mais vous pouvez vous enregistrer sur d'autres instances.",
+	"This will delete / anonymize all content (events, comments, messages, participations…) created from this identity.": "Cela supprimera / anonymisera tout le contenu (événements, commentaires, messages, participations…) créés avec cette identité.",
+	"Title": "Titre",
+	"To confirm, type your event title \"{eventTitle}\"": "Pour confirmer, entrez le titre de l'événement « {eventTitle} »",
+	"To confirm, type your identity username \"{preferredUsername}\"": "Pour confirmer, entrez le nom de l’identité « {preferredUsername} »",
+	"Transfer to {outsideDomain}": "Transférer à {outsideDomain}",
+	"Unfortunately, your participation request was rejected by the organizers.": "Malheureusement, votre demande de participation a été refusée par les organisateur⋅ices.",
+	"Unknown error.": "Erreur inconnue.",
+	"Unsaved changes": "Modifications non enregistrées",
+	"Upcoming": "À venir",
+	"Update event {name}": "Éditer l'événement {name}",
+	"Update my event": "Éditer mon événement",
+	"User logout": "Déconnexion",
+	"Username": "Pseudo",
+	"Users": "Utilisateurs",
+	"View event page": "Voir la page de l'événement",
+	"View everything": "Voir tout",
+	"Visible everywhere on the web (public)": "Visible partout sur le web (public)",
+	"Waiting for organization team approval.": "En attente d'approbation par l'organisation.",
+	"Waiting list": "Liste d'attente",
+	"We just sent an email to {email}": "Nous venons d'envoyer un email à {email}",
+	"Website / URL": "Site web / URL",
+	"Welcome back {username}": "Bon retour {username}",
+	"Welcome back!": "Bon retour !",
+	"Welcome on your administration panel": "Bienvenue sur votre espace d'administration",
+	"Who can view this event and participate": "Qui peut voir cet événement et y participer",
+	"World map": "Carte mondiale",
+	"You and one other person are going to this event": "Vous êtes le ou la seule à vous rendre à cet événement | Vous et une autre personne vous rendez à cet événement | Vous et {approved} autres personnes vous rendez à cet événement.",
+	"You announced that you're going to this event.": "Vous avez annoncé vous rendre à cet événement.",
+	"You are already logged-in.": "Vous êtes déjà connecté.",
+	"You are an organizer.": "Vous êtes un organisateur.",
+	"You have been disconnected": "Vous avez été déconnecté⋅e",
+	"You have one event in {days} days.": "Vous n'avez pas d'événements dans {days} jours | Vous avez un événement dans {days} jours. | Vous avez {count} événements dans {days} jours",
+	"You have one event today.": "Vous n'avez pas d'évenement aujourd'hui | Vous avez un événement aujourd'hui. | Vous avez {count} événements aujourd'hui",
+	"You have one event tomorrow.": "Vous n'avez pas d'événement demain | Vous avez un événement demain. | Vous avez {count} événements demain",
+	"You need to login.": "Vous devez vous connecter.",
+	"You're not going to any event yet": "Vous n'allez à aucun événement pour le moment",
+	"You're organizing this event": "Vous organisez cet événement",
+	"Your account has been validated": "Votre compte a été validé",
+	"Your account is being validated": "Votre compte est en cours de validation",
+	"Your account is nearly ready, {username}": "Votre compte est presque prêt, {username}",
+	"Your local administrator resumed it's policy:": "Votre administrateur local a résumé sa politique ainsi :",
+	"e.g. 10 Rue Jangot": "par exemple : 10 Rue Jangot",
+	"iCal Feed": "Flux iCal",
+	"meditate a bit": "méditez un peu",
+	"with another identity…": "avec une autre identité…",
+	"with {identity}": "avec {identity}",
+	"{actor}'s avatar": "Avatar de {actor}",
+	"{approved} / {total} seats": "{approved} / {total} places",
+	"{count} participants": "Un⋅e participant⋅e|{count} participant⋅e⋅s",
+	"{count} requests waiting": "Un⋅e demande en attente|{count} demandes en attente",
+	"© The Mobilizon Contributors {date} - Made with Elixir, Phoenix, VueJS & with some love and some weeks": "© Les contributeurs de Mobilizon {date} - Fait avec Elixir, Phoenix, VueJS & et de l'amour et des semaines"
 }
\ No newline at end of file

From f4360468a61dddbaad39dd58adaaba89d26e3bb2 Mon Sep 17 00:00:00 2001
From: Thomas Citharel <tcit@tcit.fr>
Date: Wed, 9 Oct 2019 17:54:35 +0200
Subject: [PATCH 6/8] Use local icons instead of CDN, clean unused deps & fix
 issue with vue-property-decorator

Signed-off-by: Thomas Citharel <tcit@tcit.fr>
---
 js/package.json                           |   6 +-
 js/public/index.html                      |   1 -
 js/src/App.vue                            |   4 +
 js/src/components/Event/EventListCard.vue |  10 +-
 js/src/main.ts                            |   8 +
 js/src/views/Event/Edit.vue               |   8 +-
 js/yarn.lock                              | 212 ++++++++++++----------
 7 files changed, 142 insertions(+), 107 deletions(-)

diff --git a/js/package.json b/js/package.json
index 0936078fa..9f31a85e1 100644
--- a/js/package.json
+++ b/js/package.json
@@ -14,6 +14,7 @@
     "vue-i18n-extract": "vue-i18n-extract"
   },
   "dependencies": {
+    "@mdi/font": "^4.5.95",
     "apollo-absinthe-upload-link": "^1.5.0",
     "apollo-cache-inmemory": "^1.5.1",
     "apollo-client": "^2.5.1",
@@ -23,22 +24,19 @@
     "graphql": "^14.5.8",
     "graphql-tag": "^2.10.1",
     "leaflet": "^1.4.0",
-    "line-clamp": "1.0.0",
     "lodash": "^4.17.11",
     "ngeohash": "^0.6.3",
     "register-service-worker": "^1.6.2",
     "tippy.js": "^5.0.2",
     "tiptap": "^1.26.0",
     "tiptap-extensions": "^1.28.0",
-    "typeface-signika": "0.0.72",
     "vue": "^2.6.10",
     "vue-apollo": "^3.0.0-rc.6",
     "vue-class-component": "^7.0.2",
     "vue-i18n": "^8.14.0",
     "vue-property-decorator": "^8.1.0",
     "vue-router": "^3.0.6",
-    "vue2-leaflet": "^2.0.3",
-    "vuex": "^3.1.0"
+    "vue2-leaflet": "^2.0.3"
   },
   "devDependencies": {
     "@types/chai": "^4.2.3",
diff --git a/js/public/index.html b/js/public/index.html
index 43c959275..413453152 100644
--- a/js/public/index.html
+++ b/js/public/index.html
@@ -6,7 +6,6 @@
   <meta http-equiv="X-UA-Compatible" content="IE=edge">
   <meta name="viewport" content="width=device-width,initial-scale=1.0">
   <link rel="icon" href="<%= BASE_URL %>favicon.ico">
-  <link rel="stylesheet" href="//cdn.materialdesignicons.com/4.4.95/css/materialdesignicons.min.css">
   <title>mobilizon</title>
   <!--server-generated-meta-->
 </head>
diff --git a/js/src/App.vue b/js/src/App.vue
index b597c2a10..ed93be681 100644
--- a/js/src/App.vue
+++ b/js/src/App.vue
@@ -73,6 +73,10 @@ export default class App extends Vue {
 /* Buefy imports */
 @import "~buefy/src/scss/buefy";
 
+/* Icons */
+$mdi-font-path: "~@mdi/font/fonts";
+@import "~@mdi/font/scss/materialdesignicons";
+
 .fade-enter-active, .fade-leave-active {
   transition: opacity .5s;
 }
diff --git a/js/src/components/Event/EventListCard.vue b/js/src/components/Event/EventListCard.vue
index f607fb3cb..ead3c4c44 100644
--- a/js/src/components/Event/EventListCard.vue
+++ b/js/src/components/Event/EventListCard.vue
@@ -58,7 +58,7 @@ export default {
           <div class="date-component" v-if="!mergedOptions.hideDate">
             <date-calendar-icon :date="participation.event.beginsOn" />
           </div>
-          <h2 class="title" ref="title">{{ participation.event.title }}</h2>
+          <h2 class="title">{{ participation.event.title }}</h2>
         </div>
         <div>
           <span v-if="participation.event.physicalAddress && participation.event.physicalAddress.locality">{{ participation.event.physicalAddress.locality }} - </span>
@@ -129,7 +129,6 @@ import EventMixin from '@/mixins/event';
 import { RouteName } from '@/router';
 import { ICurrentUser } from '@/types/current-user.model';
 import { IEventCardOptions } from './EventCard.vue';
-const lineClamp = require('line-clamp');
 
 const defaultOptions: IEventCardOptions = {
   hideDate: true,
@@ -142,9 +141,6 @@ const defaultOptions: IEventCardOptions = {
   components: {
     DateCalendarIcon,
   },
-  mounted() {
-    lineClamp(this.$refs.title, 3);
-  },
   apollo: {
     currentActor: {
       query: CURRENT_ACTOR_CLIENT,
@@ -219,6 +215,10 @@ export default class EventListCard extends mixins(ActorMixin, EventMixin) {
         }
 
         .title {
+          display: -webkit-box;
+          -webkit-line-clamp: 1;
+          -webkit-box-orient: vertical;
+          overflow: hidden;
           font-weight: 400;
           line-height: 1em;
           font-size: 1.6em;
diff --git a/js/src/main.ts b/js/src/main.ts
index 9f3d4c79c..7f0178e51 100644
--- a/js/src/main.ts
+++ b/js/src/main.ts
@@ -3,6 +3,7 @@
 import Vue from 'vue';
 import Buefy from 'buefy';
 import VueI18n from 'vue-i18n';
+import Component from 'vue-class-component';
 import App from '@/App.vue';
 import router from '@/router';
 import { apolloProvider } from './vue-apollo';
@@ -25,6 +26,13 @@ const i18n = new VueI18n({
   messages, // set locale messages
 });
 
+// Register the router hooks with their names
+Component.registerHooks([
+  'beforeRouteEnter',
+  'beforeRouteLeave',
+  'beforeRouteUpdate', // for vue-router 2.2+
+]);
+
 /* eslint-disable no-new */
 new Vue({
   router,
diff --git a/js/src/views/Event/Edit.vue b/js/src/views/Event/Edit.vue
index cc3dd9c3d..f735b85f9 100644
--- a/js/src/views/Event/Edit.vue
+++ b/js/src/views/Event/Edit.vue
@@ -254,7 +254,6 @@ import { ITag } from '@/types/tag.model';
 import AddressAutoComplete from '@/components/Event/AddressAutoComplete.vue';
 import { buildFileFromIPicture, buildFileVariable } from '@/utils/image';
 import IdentityPickerWrapper from '@/views/Account/IdentityPickerWrapper.vue';
-import { ICurrentUser } from '@/types/current-user.model';
 
 @Component({
   components: { IdentityPickerWrapper, AddressAutoComplete, TagInput, DateTimePicker, PictureUpload, Editor },
@@ -266,9 +265,6 @@ import { ICurrentUser } from '@/types/current-user.model';
       query: TAGS,
     },
   },
-  beforeRouteLeave(to, from, next) {
-    this.confirmGoElsewhere(() => next());
-  },
 })
 export default class EditEvent extends Vue {
   @Prop({ type: Boolean, default: false }) isUpdate!: boolean;
@@ -533,6 +529,10 @@ export default class EditEvent extends Vue {
     this.confirmGoElsewhere(() => this.$router.go(-1));
   }
 
+  beforeRouteLeave(to, from, next) {
+    this.confirmGoElsewhere(() => next());
+  }
+
   get isEventModified(): boolean {
     return JSON.stringify(this.event.toEditJSON()) !== JSON.stringify(this.unmodifiedEvent);
   }
diff --git a/js/yarn.lock b/js/yarn.lock
index 52f19dccf..4f9e62a45 100644
--- a/js/yarn.lock
+++ b/js/yarn.lock
@@ -17,24 +17,24 @@
     "@babel/highlight" "^7.0.0"
 
 "@babel/core@^7.0.0":
-  version "7.6.2"
-  resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.6.2.tgz#069a776e8d5e9eefff76236bc8845566bd31dd91"
-  integrity sha512-l8zto/fuoZIbncm+01p8zPSDZu/VuuJhAfA7d/AbzM09WR7iVhavvfNDYCNpo1VvLk6E6xgAoP9P+/EMJHuRkQ==
+  version "7.6.3"
+  resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.6.3.tgz#44de824e89eaa089bb12da7337bc9bdff2ab68f9"
+  integrity sha512-QfQ5jTBgXLzJuo7Mo8bZK/ePywmgNRgk/UQykiKwEtZPiFIn8ZqE6jB+AnD1hbB1S2xQyL4//it5vuAUOVAMTw==
   dependencies:
     "@babel/code-frame" "^7.5.5"
-    "@babel/generator" "^7.6.2"
+    "@babel/generator" "^7.6.3"
     "@babel/helpers" "^7.6.2"
-    "@babel/parser" "^7.6.2"
+    "@babel/parser" "^7.6.3"
     "@babel/template" "^7.6.0"
-    "@babel/traverse" "^7.6.2"
-    "@babel/types" "^7.6.0"
+    "@babel/traverse" "^7.6.3"
+    "@babel/types" "^7.6.3"
     convert-source-map "^1.1.0"
     debug "^4.1.0"
     json5 "^2.1.0"
     lodash "^4.17.13"
     resolve "^1.3.2"
     semver "^5.4.1"
-    source-map "^0.5.0"
+    source-map "^0.6.1"
 
 "@babel/generator@7.0.0-beta.38":
   version "7.0.0-beta.38"
@@ -47,15 +47,15 @@
     source-map "^0.5.0"
     trim-right "^1.0.1"
 
-"@babel/generator@^7.6.2":
-  version "7.6.2"
-  resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.6.2.tgz#dac8a3c2df118334c2a29ff3446da1636a8f8c03"
-  integrity sha512-j8iHaIW4gGPnViaIHI7e9t/Hl8qLjERI6DcV9kEpAIDJsAOrcnXqRS7t+QbhL76pwbtqP+QCQLL0z1CyVmtjjQ==
+"@babel/generator@^7.6.3":
+  version "7.6.3"
+  resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.6.3.tgz#71d5375264f93ec7bac7d9f35a67067733f5578e"
+  integrity sha512-hLhYbAb3pHwxjlijC4AQ7mqZdcoujiNaW7izCT04CIowHK8psN0IN8QjDv0iyFtycF5FowUOTwDloIheI25aMw==
   dependencies:
-    "@babel/types" "^7.6.0"
+    "@babel/types" "^7.6.3"
     jsesc "^2.5.1"
     lodash "^4.17.13"
-    source-map "^0.5.0"
+    source-map "^0.6.1"
 
 "@babel/helper-annotate-as-pure@^7.0.0":
   version "7.0.0"
@@ -242,10 +242,10 @@
     esutils "^2.0.2"
     js-tokens "^4.0.0"
 
-"@babel/parser@^7.2.3", "@babel/parser@^7.6.0", "@babel/parser@^7.6.2":
-  version "7.6.2"
-  resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.6.2.tgz#205e9c95e16ba3b8b96090677a67c9d6075b70a1"
-  integrity sha512-mdFqWrSPCmikBoaBYMuBulzTIKuXVPtEISFbRRVNwMWpCms/hmE2kRq0bblUHaNRKrjRlmVbx1sDHmjmRgD2Xg==
+"@babel/parser@^7.2.3", "@babel/parser@^7.6.0", "@babel/parser@^7.6.3":
+  version "7.6.3"
+  resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.6.3.tgz#9eff8b9c3eeae16a74d8d4ff30da2bd0d6f0487e"
+  integrity sha512-sUZdXlva1dt2Vw2RqbMkmfoImubO0D0gaCrNngV6Hi0DA4x3o4mlrq0tbfY0dZEUIccH8I6wQ4qgEtwcpOR6Qg==
 
 "@babel/plugin-proposal-async-generator-functions@^7.2.0":
   version "7.2.0"
@@ -379,9 +379,9 @@
     "@babel/helper-plugin-utils" "^7.0.0"
 
 "@babel/plugin-transform-block-scoping@^7.3.4":
-  version "7.6.2"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.6.2.tgz#96c33ab97a9ae500cc6f5b19e04a7e6553360a79"
-  integrity sha512-zZT8ivau9LOQQaOGC7bQLQOT4XPkPXgN2ERfUgk1X8ql+mVkLc4E8eKk+FO3o0154kxzqenWCorfmEXpEZcrSQ==
+  version "7.6.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.6.3.tgz#6e854e51fbbaa84351b15d4ddafe342f3a5d542a"
+  integrity sha512-7hvrg75dubcO3ZI2rjYTzUrEuh1E9IyDEhhB6qfcooxhDA33xx2MasuLVgdxzcP6R/lipAC6n9ub9maNW6RKdw==
   dependencies:
     "@babel/helper-plugin-utils" "^7.0.0"
     lodash "^4.17.13"
@@ -497,9 +497,9 @@
     "@babel/helper-plugin-utils" "^7.0.0"
 
 "@babel/plugin-transform-named-capturing-groups-regex@^7.3.0":
-  version "7.6.2"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.6.2.tgz#c1ca0bb84b94f385ca302c3932e870b0fb0e522b"
-  integrity sha512-xBdB+XOs+lgbZc2/4F5BVDVcDNS4tcSKQc96KmlqLEAwz6tpYPEvPdmDfvVG0Ssn8lAhronaRs6Z6KSexIpK5g==
+  version "7.6.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.6.3.tgz#aaa6e409dd4fb2e50b6e2a91f7e3a3149dbce0cf"
+  integrity sha512-jTkk7/uE6H2s5w6VlMHeWuH+Pcy2lmdwFoeWCVnvIrDUnB5gQqTVI8WfmEAhF2CDEarGrknZcmSFg1+bkfCoSw==
   dependencies:
     regexpu-core "^4.6.0"
 
@@ -648,17 +648,17 @@
     semver "^5.3.0"
 
 "@babel/runtime-corejs2@^7.2.0":
-  version "7.6.2"
-  resolved "https://registry.yarnpkg.com/@babel/runtime-corejs2/-/runtime-corejs2-7.6.2.tgz#062f8e31f3df30fc1a3dea68aa1bd854e06e9ba6"
-  integrity sha512-wdyVKnTv9Be4YlwF/7pByYNfcl23qC21aAQ0aIaZOo2ZOvhFEyJdBLJClYZ9i+Pmrz7sUQgg/MwbJa2RZTkygg==
+  version "7.6.3"
+  resolved "https://registry.yarnpkg.com/@babel/runtime-corejs2/-/runtime-corejs2-7.6.3.tgz#de3f446b3fb688b98cbd220474d1a7cad909bcb8"
+  integrity sha512-nuA2o+rgX2+PrNTZ063ehncVcg7sn+tU71BB81SaWRVUbGwCOlb0+yQA1e0QqmzOfRSYOxfvf8cosYqFbJEiwQ==
   dependencies:
     core-js "^2.6.5"
     regenerator-runtime "^0.13.2"
 
 "@babel/runtime@^7.0.0", "@babel/runtime@^7.6.2":
-  version "7.6.2"
-  resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.6.2.tgz#c3d6e41b304ef10dcf13777a33e7694ec4a9a6dd"
-  integrity sha512-EXxN64agfUqqIGeEjI5dL5z0Sw0ZwWo1mLTi4mQowCZ42O59b7DRpZAnTC6OqdF28wMBMFKNb/4uFGrVaigSpg==
+  version "7.6.3"
+  resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.6.3.tgz#935122c74c73d2240cafd32ddb5fc2a6cd35cf1f"
+  integrity sha512-kq6anf9JGjW8Nt5rYfEuGRaEAaH1mkv3Bbu6rYvLOpPh/RusSJXuKPEAoZ7L7gybZkchE8+NV5g9vKF4AGAtsA==
   dependencies:
     regenerator-runtime "^0.13.2"
 
@@ -671,17 +671,17 @@
     "@babel/parser" "^7.6.0"
     "@babel/types" "^7.6.0"
 
-"@babel/traverse@^7.1.0", "@babel/traverse@^7.4.4", "@babel/traverse@^7.5.5", "@babel/traverse@^7.6.2":
-  version "7.6.2"
-  resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.6.2.tgz#b0e2bfd401d339ce0e6c05690206d1e11502ce2c"
-  integrity sha512-8fRE76xNwNttVEF2TwxJDGBLWthUkHWSldmfuBzVRmEDWOtu4XdINTgN7TDWzuLg4bbeIMLvfMFD9we5YcWkRQ==
+"@babel/traverse@^7.1.0", "@babel/traverse@^7.4.4", "@babel/traverse@^7.5.5", "@babel/traverse@^7.6.2", "@babel/traverse@^7.6.3":
+  version "7.6.3"
+  resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.6.3.tgz#66d7dba146b086703c0fb10dd588b7364cec47f9"
+  integrity sha512-unn7P4LGsijIxaAJo/wpoU11zN+2IaClkQAxcJWBNCMS6cmVh802IyLHNkAjQ0iYnRS3nnxk5O3fuXW28IMxTw==
   dependencies:
     "@babel/code-frame" "^7.5.5"
-    "@babel/generator" "^7.6.2"
+    "@babel/generator" "^7.6.3"
     "@babel/helper-function-name" "^7.1.0"
     "@babel/helper-split-export-declaration" "^7.4.4"
-    "@babel/parser" "^7.6.2"
-    "@babel/types" "^7.6.0"
+    "@babel/parser" "^7.6.3"
+    "@babel/types" "^7.6.3"
     debug "^4.1.0"
     globals "^11.1.0"
     lodash "^4.17.13"
@@ -695,10 +695,10 @@
     lodash "^4.2.0"
     to-fast-properties "^2.0.0"
 
-"@babel/types@^7.0.0", "@babel/types@^7.2.0", "@babel/types@^7.4.4", "@babel/types@^7.5.5", "@babel/types@^7.6.0":
-  version "7.6.1"
-  resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.6.1.tgz#53abf3308add3ac2a2884d539151c57c4b3ac648"
-  integrity sha512-X7gdiuaCmA0uRjCmRtYJNAVCc/q+5xSgsfKJHqMN4iNLILX39677fJE1O40arPMh0TTtS9ItH67yre6c7k6t0g==
+"@babel/types@^7.0.0", "@babel/types@^7.2.0", "@babel/types@^7.4.4", "@babel/types@^7.5.5", "@babel/types@^7.6.0", "@babel/types@^7.6.3":
+  version "7.6.3"
+  resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.6.3.tgz#3f07d96f854f98e2fbd45c64b0cb942d11e8ba09"
+  integrity sha512-CqbcpTxMcpuQTMhjI37ZHVgjBkysg5icREQIEZ0eG1yCNwg3oy+5AaLiOKmjsCj6nqOsa6Hf0ObjRVwokb7srA==
   dependencies:
     esutils "^2.0.2"
     lodash "^4.17.13"
@@ -797,6 +797,11 @@
     request-promise "^4.1.1"
     yargs "^8.0.2"
 
+"@mdi/font@^4.5.95":
+  version "4.5.95"
+  resolved "https://registry.yarnpkg.com/@mdi/font/-/font-4.5.95.tgz#43c0d2e7b08d4221a778f58d899455d0c45916ed"
+  integrity sha512-AjR2Zgu1feBXWlTfEjD6JQqLAMCqYn2Gzia5PWqFnysvz5F6JmPHtQFldIHXqyv2s/FwME7ZDBc5N86NEHbyvQ==
+
 "@mrmlnc/readdir-enhanced@^2.2.1":
   version "2.2.1"
   resolved "https://registry.yarnpkg.com/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz#524af240d1a360527b730475ecfa1344aa540dde"
@@ -873,9 +878,9 @@
     "@types/geojson" "*"
 
 "@types/lodash@^4.14.141":
-  version "4.14.141"
-  resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.141.tgz#d81f4d0c562abe28713406b571ffb27692a82ae6"
-  integrity sha512-v5NYIi9qEbFEUpCyikmnOYe4YlP8BMUdTcNCAquAKzu+FA7rZ1onj9x80mbnDdOW/K5bFf3Tv5kJplP33+gAbQ==
+  version "4.14.142"
+  resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.142.tgz#52d5daff878e36e72e299bb9c5871fd6aee55829"
+  integrity sha512-ZhNS7c4D4WQ49Dr1FftQj7SwngRswOnPfxktmqSy5BettRCuum2q784jRwNTYfxH00r8+fEgRz6Da8j5DHNd1Q==
 
 "@types/minimatch@*":
   version "3.0.3"
@@ -888,9 +893,9 @@
   integrity sha512-NYrtPht0wGzhwe9+/idPaBB+TqkY9AhTvOLMkThm0IoEfLaiVQZwBwyJ5puCkO3AUCWrmcoePjp2mbFocKy4SQ==
 
 "@types/node@*", "@types/node@>=6":
-  version "12.7.11"
-  resolved "https://registry.yarnpkg.com/@types/node/-/node-12.7.11.tgz#be879b52031cfb5d295b047f5462d8ef1a716446"
-  integrity sha512-Otxmr2rrZLKRYIybtdG/sgeO+tHY20GxeDjcGmUnmmlCWyEnv2a2x1ZXBo3BTec4OiTXMQCiazB8NMBf0iRlFw==
+  version "12.7.12"
+  resolved "https://registry.yarnpkg.com/@types/node/-/node-12.7.12.tgz#7c6c571cc2f3f3ac4a59a5f2bd48f5bdbc8653cc"
+  integrity sha512-KPYGmfD0/b1eXurQ59fXD1GBzhSQfz6/lKBxkaHX9dKTzjXbK68Zt7yGUxUsCS1jeTy/8aL+d9JEr+S54mpkWQ==
 
 "@types/normalize-package-data@^2.4.0":
   version "2.4.0"
@@ -3398,6 +3403,15 @@ cross-spawn@^5.0.1, cross-spawn@^5.1.0:
     shebang-command "^1.2.0"
     which "^1.2.9"
 
+cross-spawn@^7.0.0:
+  version "7.0.1"
+  resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.1.tgz#0ab56286e0f7c24e153d04cc2aa027e43a9a5d14"
+  integrity sha512-u7v4o84SwFpD32Z8IIcPZ6z1/ie24O6RU3RbtL5Y316l3KuHVPx9ItBgWQ6VlfAFnRnTtMUrsQ9MUUTuEZjogg==
+  dependencies:
+    path-key "^3.1.0"
+    shebang-command "^2.0.0"
+    which "^2.0.1"
+
 crypto-browserify@^3.11.0:
   version "3.12.0"
   resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec"
@@ -4177,9 +4191,9 @@ ejs@^2.6.1:
   integrity sha512-kS/gEPzZs3Y1rRsbGX4UOSjtP/CeJP0CxSNZHYxGfVM/VgLcv0ZqM7C45YyTj2DI2g7+P9Dd24C+IMIg6D0nYQ==
 
 electron-to-chromium@^1.3.103, electron-to-chromium@^1.3.247:
-  version "1.3.277"
-  resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.277.tgz#38b7b297f9b3f67ea900a965c1b11a555de526ec"
-  integrity sha512-Czmsrgng89DOgJlIknnw9bn5431QdtnUwGp5YYiPwU1DbZQUxCLF+rc1ZC09VNAdalOPcvH6AE8BaA0H5HjI/w==
+  version "1.3.279"
+  resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.279.tgz#543d578f118afbb750ff1e8f3e0c898c30a4f574"
+  integrity sha512-iiBT/LeUWKnhd7d/n4IZsx/NIacs7gjFgAT1q5/i0POiS+5d0rVnbbyCRMmsBW7vaQJOUhWyh4PsyIVZb/Ax5Q==
 
 elegant-spinner@^1.0.1:
   version "1.0.1"
@@ -4234,12 +4248,12 @@ end-of-stream@^1.0.0, end-of-stream@^1.1.0:
     once "^1.4.0"
 
 enhanced-resolve@^4.0.0, enhanced-resolve@^4.1.0:
-  version "4.1.0"
-  resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.1.0.tgz#41c7e0bfdfe74ac1ffe1e57ad6a5c6c9f3742a7f"
-  integrity sha512-F/7vkyTtyc/llOIn8oWclcB25KdRaiPBpZYDgJHgh/UHtpgT2p2eldQgtQnLtUvfMKPKxbRaQM/hHkvLHt1Vng==
+  version "4.1.1"
+  resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.1.1.tgz#2937e2b8066cd0fe7ce0990a98f0d71a35189f66"
+  integrity sha512-98p2zE+rL7/g/DzMHMTF4zZlCgeVdJ7yr6xzEpJRYwFYrGi9ANdn5DnJURg6RpBkyk60XYDnWIv51VfIhfNGuA==
   dependencies:
     graceful-fs "^4.1.2"
-    memory-fs "^0.4.0"
+    memory-fs "^0.5.0"
     tapable "^1.0.0"
 
 entities@^1.1.1:
@@ -4566,11 +4580,11 @@ execa@^1.0.0:
     strip-eof "^1.0.0"
 
 execa@^2.0.3:
-  version "2.0.5"
-  resolved "https://registry.yarnpkg.com/execa/-/execa-2.0.5.tgz#5be3e2ea7e61bd038da5a0e11dc6ab2097357f2f"
-  integrity sha512-SwmwZZyJjflcqLSgllk4EQlMLst2p9muyzwNugKGFlpAz6rZ7M+s2nBR97GAq4Vzjwx2y9rcMcmqzojwN+xwNA==
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/execa/-/execa-2.1.0.tgz#e5d3ecd837d2a60ec50f3da78fd39767747bbe99"
+  integrity sha512-Y/URAVapfbYy2Xp/gb6A0E7iR8xeqOCXsuuaoMn7A5PzrXUK84E1gyiEfq0wQd/GHA6GsoHWwhNq8anb0mleIw==
   dependencies:
-    cross-spawn "^6.0.5"
+    cross-spawn "^7.0.0"
     get-stream "^5.0.0"
     is-stream "^2.0.0"
     merge-stream "^2.0.0"
@@ -5759,9 +5773,9 @@ hoopy@^0.1.4:
   integrity sha512-HRcs+2mr52W0K+x8RzcLzuPPmVIKMSv97RGHy0Ea9y/mpcaK+xTrjICA04KAHi4GRzxliNqNJEFYWHghy3rSfQ==
 
 hosted-git-info@^2.1.4:
-  version "2.8.4"
-  resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.4.tgz#44119abaf4bc64692a16ace34700fed9c03e2546"
-  integrity sha512-pzXIvANXEFrc5oFFXRMkbLPQ2rXRoDERwDLyrcUxGhaZhgP54BBSl9Oheh7Vv0T090cszWBxPjkQQ5Sq1PbBRQ==
+  version "2.8.5"
+  resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.5.tgz#759cfcf2c4d156ade59b0b2dfabddc42a6b9c70c"
+  integrity sha512-kssjab8CvdXfcXMXVcvsXum4Hwdq9XGtRD3TteMEvEbq0LXyiNQr6AprqKqfeaDXze7SxWvRxdpwE6ku7ikLkg==
 
 hpack.js@^2.1.6:
   version "2.1.6"
@@ -5976,9 +5990,9 @@ iferr@^0.1.5:
   integrity sha1-xg7taebY/bazEEofy8ocGS3FtQE=
 
 ignore-walk@^3.0.1:
-  version "3.0.2"
-  resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.2.tgz#99d83a246c196ea5c93ef9315ad7b0819c35069b"
-  integrity sha512-EXyErtpHbn75ZTsOADsfx6J/FPo6/5cjev46PXrcTpd8z3BoRkXgYu9/JVqrI7tusjmwCZutGeRJeU0Wo1e4Cw==
+  version "3.0.3"
+  resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.3.tgz#017e2447184bfeade7c238e4aefdd1e8f95b1e37"
+  integrity sha512-m7o6xuOaT1aqheYHKf8W6J5pYH85ZI9w077erOzLje3JsB1gkafkAhHHY19dqjulgIZHFm32Cp5uNZgcQqdJKw==
   dependencies:
     minimatch "^3.0.4"
 
@@ -7095,11 +7109,6 @@ levn@^0.3.0, levn@~0.3.0:
     prelude-ls "~1.1.2"
     type-check "~0.3.2"
 
-line-clamp@1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/line-clamp/-/line-clamp-1.0.0.tgz#e0216489a599e989215595080b912c90ba09192c"
-  integrity sha512-dCDlvMj572RIRBQ3x9aIX0DTdt2St1bMdpi64jVTAi5vqBck7wf+J97//+J7+pS80rFJaYa8HiyXCTp0flpnBA==
-
 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"
@@ -7545,7 +7554,7 @@ mem@^4.0.0:
     mimic-fn "^2.0.0"
     p-is-promise "^2.0.0"
 
-memory-fs@^0.4.0, memory-fs@^0.4.1:
+memory-fs@^0.4.1:
   version "0.4.1"
   resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552"
   integrity sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=
@@ -7553,6 +7562,14 @@ memory-fs@^0.4.0, memory-fs@^0.4.1:
     errno "^0.1.3"
     readable-stream "^2.0.1"
 
+memory-fs@^0.5.0:
+  version "0.5.0"
+  resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.5.0.tgz#324c01288b88652966d161db77838720845a8e3c"
+  integrity sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA==
+  dependencies:
+    errno "^0.1.3"
+    readable-stream "^2.0.1"
+
 meow@^3.7.0:
   version "3.7.0"
   resolved "https://registry.yarnpkg.com/meow/-/meow-3.7.0.tgz#72cb668b425228290abbfa856892587308a801fb"
@@ -8041,9 +8058,9 @@ node-pre-gyp@^0.12.0:
     tar "^4"
 
 node-releases@^1.1.29, node-releases@^1.1.3:
-  version "1.1.34"
-  resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.34.tgz#ced4655ee1ba9c3a2c5dcbac385e19434155fd40"
-  integrity sha512-fNn12JTEfniTuCqo0r9jXgl44+KxRH/huV7zM/KAGOKxDKrHr6EbT7SSs4B+DNxyBE2mks28AD+Jw6PkfY5uwA==
+  version "1.1.35"
+  resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.35.tgz#32a74a3cd497aa77f23d509f483475fd160e4c48"
+  integrity sha512-JGcM/wndCN/2elJlU0IGdVEJQQnJwsLbgPCFd2pY7V0mxf17bZ0Gb/lgOtL29ZQhvEX5shnVhxQyZz3ex94N8w==
   dependencies:
     semver "^6.3.0"
 
@@ -8147,9 +8164,9 @@ npm-bundled@^1.0.1:
   integrity sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g==
 
 npm-packlist@^1.1.6:
-  version "1.4.4"
-  resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.4.4.tgz#866224233850ac534b63d1a6e76050092b5d2f44"
-  integrity sha512-zTLo8UcVYtDU3gdeaFu2Xu0n0EvelfHDGuqtNIn5RO7yQj4H1TqNdBc/yZjxnWA0PVB8D3Woyp0i5B43JwQ6Vw==
+  version "1.4.6"
+  resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.4.6.tgz#53ba3ed11f8523079f1457376dd379ee4ea42ff4"
+  integrity sha512-u65uQdb+qwtGvEJh/DgQgW1Xg7sqeNbmxYyrvlNznaVTjV3E5P6F/EFjM+BVHXl7JJlsdG8A64M0XI8FI/IOlg==
   dependencies:
     ignore-walk "^3.0.1"
     npm-bundled "^1.0.1"
@@ -8760,7 +8777,7 @@ path-key@^2.0.0, path-key@^2.0.1:
   resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40"
   integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=
 
-path-key@^3.0.0:
+path-key@^3.0.0, path-key@^3.1.0:
   version "3.1.0"
   resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.0.tgz#99a10d870a803bdd5ee6f0470e58dfcd2f9a54d3"
   integrity sha512-8cChqz0RP6SHJkMt48FW0A7+qUOn+OsnOsVtzI59tZ8m+5bCSk7hzwET0pulwOM2YMn9J1efb07KB9l9f30SGg==
@@ -9414,9 +9431,9 @@ prosemirror-commands@^1.0.8:
     prosemirror-transform "^1.0.0"
 
 prosemirror-dropcursor@^1.1.2:
-  version "1.1.2"
-  resolved "https://registry.yarnpkg.com/prosemirror-dropcursor/-/prosemirror-dropcursor-1.1.2.tgz#d54428e0fdbc0fb3d4c5809acd1ad031e6cb6855"
-  integrity sha512-QHZbYPr8AY0g88TC/Wp7jpYbUoSpTSO8sqHNGvvZOInsAyylIdOpsrfhY1NC+/lh+iuwka0YogGtq2mmE7cr4g==
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/prosemirror-dropcursor/-/prosemirror-dropcursor-1.2.0.tgz#00b1bdb803ac28f5a68d7e0a16a47c9c11aab97d"
+  integrity sha512-D7JrvOgN32PmOgfimdDMKCuYp4tGyCulpsd39/Nzvn9A+tCJmM8XY1PB07zkr2vjrjF09WYD3Ifer7Z3pk/YRw==
   dependencies:
     prosemirror-state "^1.0.0"
     prosemirror-transform "^1.1.0"
@@ -9465,9 +9482,9 @@ prosemirror-model@^1.0.0, prosemirror-model@^1.1.0, prosemirror-model@^1.7.3:
     orderedmap "^1.0.0"
 
 prosemirror-schema-list@^1.0.3:
-  version "1.0.3"
-  resolved "https://registry.yarnpkg.com/prosemirror-schema-list/-/prosemirror-schema-list-1.0.3.tgz#539caafa4f9314000943bd783be4017165ec0bd6"
-  integrity sha512-+zzSawVds8LsZpl/bLTCYk2lYactF93W219Czh81zBILikCRDOHjp1CQ1os4ZXBp6LlD+JnBqF1h59Q+hilOoQ==
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/prosemirror-schema-list/-/prosemirror-schema-list-1.0.4.tgz#cbb11936e306aa45586af4279529ce61b52cfb6e"
+  integrity sha512-7Y0b6FIG6ATnCcDSLrZfU9yIfOG5Yad3DMNZ9W7GGfMSzdIl0aHExrsIUgviJZjovO2jtLJVbxWGjMR3OrTupA==
   dependencies:
     prosemirror-model "^1.0.0"
     prosemirror-transform "^1.0.0"
@@ -10836,11 +10853,23 @@ shebang-command@^1.2.0:
   dependencies:
     shebang-regex "^1.0.0"
 
+shebang-command@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea"
+  integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==
+  dependencies:
+    shebang-regex "^3.0.0"
+
 shebang-regex@^1.0.0:
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3"
   integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=
 
+shebang-regex@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172"
+  integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==
+
 shell-quote@1.6.1:
   version "1.6.1"
   resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.6.1.tgz#f4781949cce402697127430ea3b3c5476f481767"
@@ -12005,11 +12034,6 @@ typedarray@^0.0.6:
   resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
   integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
 
-typeface-signika@0.0.72:
-  version "0.0.72"
-  resolved "https://registry.yarnpkg.com/typeface-signika/-/typeface-signika-0.0.72.tgz#169761fff93b4f1688b7fd0ad60ffffd3a1c9dee"
-  integrity sha512-fxEQ4lO13tgGroQLnH/xF/SPFKwz3cpTVUoc9NjhoBETlscAPgZuj+6k91outFcwL+OAcmEE8UKkZ8vuzvZoRQ==
-
 typescript@^3.2.2, typescript@^3.6.3:
   version "3.6.3"
   resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.6.3.tgz#fea942fabb20f7e1ca7164ff626f1a9f3f70b4da"
@@ -12587,11 +12611,6 @@ vue@^2.6.10:
   resolved "https://registry.yarnpkg.com/vue/-/vue-2.6.10.tgz#a72b1a42a4d82a721ea438d1b6bf55e66195c637"
   integrity sha512-ImThpeNU9HbdZL3utgMCq0oiMzAkt1mcgy3/E6zWC/G6AaQoeuFdsl9nDhTDU3X1R6FK7nsIUuRACVcjI+A2GQ==
 
-vuex@^3.1.0:
-  version "3.1.1"
-  resolved "https://registry.yarnpkg.com/vuex/-/vuex-3.1.1.tgz#0c264bfe30cdbccf96ab9db3177d211828a5910e"
-  integrity sha512-ER5moSbLZuNSMBFnEBVGhQ1uCBNJslH9W/Dw2W7GZN23UQA69uapP5GTT9Vm8Trc0PzBSVt6LzF3hGjmv41xcg==
-
 w3c-hr-time@^1.0.1:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.1.tgz#82ac2bff63d950ea9e3189a58a65625fedf19045"
@@ -12844,6 +12863,13 @@ which@1, which@^1.2.10, which@^1.2.14, which@^1.2.9, which@^1.3.1:
   dependencies:
     isexe "^2.0.0"
 
+which@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/which/-/which-2.0.1.tgz#f1cf94d07a8e571b6ff006aeb91d0300c47ef0a4"
+  integrity sha512-N7GBZOTswtB9lkQBZA4+zAXrjEIWAUOB93AvzUiudRzRxhUdLURQ7D/gAIMY1gatT/LTbmbcv8SiYazy3eYB7w==
+  dependencies:
+    isexe "^2.0.0"
+
 wide-align@^1.1.0:
   version "1.1.3"
   resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457"

From a205ba6ab8e8863604ba7f592b5fbb5930d1a782 Mon Sep 17 00:00:00 2001
From: Thomas Citharel <tcit@tcit.fr>
Date: Wed, 9 Oct 2019 18:51:55 +0200
Subject: [PATCH 7/8] Add event search field on explore page and fix featured
 events

Closes #195 and #196

Signed-off-by: Thomas Citharel <tcit@tcit.fr>
---
 js/src/graphql/search.ts       |  3 ++
 js/src/views/Event/Explore.vue | 62 +++++++++++++++++++++++++---------
 2 files changed, 49 insertions(+), 16 deletions(-)

diff --git a/js/src/graphql/search.ts b/js/src/graphql/search.ts
index 562a8eab1..56d53d50f 100644
--- a/js/src/graphql/search.ts
+++ b/js/src/graphql/search.ts
@@ -8,6 +8,9 @@ query SearchEvents($searchText: String!) {
       title,
       uuid,
       beginsOn,
+      picture {
+        url,
+      },
       tags {
         slug,
         title
diff --git a/js/src/views/Event/Explore.vue b/js/src/views/Event/Explore.vue
index 4848f576f..909abd301 100644
--- a/js/src/views/Event/Explore.vue
+++ b/js/src/views/Event/Explore.vue
@@ -1,20 +1,33 @@
 <template>
-  <section class="container">
+  <div class="container">
     <h1 class="title">{{ $t('Explore') }}</h1>
-<!--    <pre>{{ events }}</pre>-->
-    <b-loading :active.sync="$apollo.loading"></b-loading>
-    <div v-if="events.length > 0" class="columns is-multiline">
-      <EventCard
-        v-for="event in events"
-        :key="event.uuid"
-        :event="event"
-        class="column is-one-quarter-desktop"
-      />
-    </div>
-    <b-message v-else-if="events.length === 0 && $apollo.loading === false" type="is-danger">
-      {{ $t('No events found') }}
-    </b-message>
-  </section>
+    <section class="hero">
+      <div class="hero-body">
+        <form @submit="submit()">
+          <b-field :label="$t('Event')" grouped label-position="on-border">
+            <b-input icon="magnify" type="search" size="is-large" expanded v-model="searchTerm" :placeholder="$t('For instance: London, Taekwondo, Architecture…')" />
+            <p class="control">
+              <b-button @click="submit" type="is-info" size="is-large">{{ $t('Search') }}</b-button>
+            </p>
+          </b-field>
+        </form>
+      </div>
+    </section>
+    <section class="events-featured">
+      <b-loading :active.sync="$apollo.loading"></b-loading>
+      <h3 class="title">{{ $t('Featured events') }}</h3>
+      <div v-if="events.length > 0" class="columns is-multiline">
+        <div class="column is-one-quarter-desktop" v-for="event in events" :key="event.uuid">
+          <EventCard
+            :event="event"
+          />
+        </div>
+      </div>
+      <b-message v-else-if="events.length === 0 && $apollo.loading === false" type="is-danger">
+        {{ $t('No events found') }}
+      </b-message>
+    </section>
+  </div>
 </template>
 
 <script lang="ts">
@@ -22,6 +35,7 @@ import { Component, Vue } from 'vue-property-decorator';
 import EventCard from '@/components/Event/EventCard.vue';
 import { FETCH_EVENTS } from '@/graphql/event';
 import { IEvent } from '@/types/event.model';
+import { RouteName } from '@/router';
 
 @Component({
   components: {
@@ -35,8 +49,24 @@ import { IEvent } from '@/types/event.model';
 })
 export default class Explore extends Vue {
   events: IEvent[] = [];
+  searchTerm: string = '';
+
+  submit() {
+    this.$router.push({ name: RouteName.SEARCH, params: { searchTerm: this.searchTerm } });
+  }
 }
 </script>
 
-<style scoped>
+<style scoped lang="scss">
+  h3.title {
+    margin-bottom: 1.5rem;
+  }
+
+  .events-featured {
+    margin: 25px auto;
+
+    .columns {
+      margin: 1rem auto 3rem;
+    }
+}
 </style>

From adb8592029746e81047c5242c8cd98224fd17d73 Mon Sep 17 00:00:00 2001
From: Thomas Citharel <tcit@tcit.fr>
Date: Wed, 9 Oct 2019 18:58:13 +0200
Subject: [PATCH 8/8] Add missing language entries

Signed-off-by: Thomas Citharel <tcit@tcit.fr>
---
 js/src/i18n/en_US.json | 1 +
 js/src/i18n/fr_FR.json | 1 +
 2 files changed, 2 insertions(+)

diff --git a/js/src/i18n/en_US.json b/js/src/i18n/en_US.json
index 2c3b93bbf..873a2c93f 100644
--- a/js/src/i18n/en_US.json
+++ b/js/src/i18n/en_US.json
@@ -88,6 +88,7 @@
 	"Features": "Features",
 	"Find an address": "Find an address",
 	"Find an instance": "Find an instance",
+	"For instance: London, Taekwondo, Architecture…": "For instance: London, Taekwondo, Architecture…",
 	"Forgot your password ?": "Forgot your password ?",
 	"From a birthday party with friends and family to a march for climate change, right now, our gatherings are <b>trapped inside the tech giants’ platforms</b>. How can we organize, how can we click “Attend,” without <b>providing private data</b> to Facebook or <b>locking ourselves up</b> inside MeetUp?": "From a birthday party with friends and family to a march for climate change, right now, our gatherings are <b>trapped inside the tech giants’ platforms</b>. How can we organize, how can we click “Attend,” without <b>providing private data</b> to Facebook or <b>locking ourselves up</b> inside MeetUp?",
 	"From the {startDate} at {startTime} to the {endDate} at {endTime}": "From the {startDate} at {startTime} to the {endDate} at {endTime}",
diff --git a/js/src/i18n/fr_FR.json b/js/src/i18n/fr_FR.json
index 72a34fb4f..8db73a79f 100644
--- a/js/src/i18n/fr_FR.json
+++ b/js/src/i18n/fr_FR.json
@@ -84,6 +84,7 @@
 	"Explore": "Explorer",
 	"Features": "Fonctionnalités",
 	"Find an address": "Trouver une adresse",
+	"For instance: London, Taekwondo, Architecture…": "Par exemple: Lyon, Taekwondo, Architecture…",
 	"Forgot your password ?": "Mot de passe oublié ?",
 	"From the {startDate} at {startTime} to the {endDate} at {endTime}": "Du {startDate} à {startTime} au {endDate} à {endTime}",
 	"General information": "Information générales",