diff --git a/package.json b/package.json
index abb7e0b31723d7495246cdd21575cbf8367c9bcf..5ae0acebe82eec78972f9a2902f9a715b83a620c 100644
--- a/package.json
+++ b/package.json
@@ -4,7 +4,7 @@
   "private": true,
   "scripts": {
     "serve": "npm run init-proxy & npm run init-serve",
-    "init-proxy": "lcp  --proxyUrl http://localhost:8000 --origin http://localhost:8080 --proxyPartial ''",
+    "init-proxy": "lcp  --proxyUrl http://127.0.0.1:8000 --origin http://localhost:8080 --proxyPartial ''",
     "init-serve": "vue-cli-service serve",
     "build": "vue-cli-service build",
     "lint": "vue-cli-service lint"
diff --git a/src/assets/styles/base.css b/src/assets/styles/base.css
index 996e2d8b232b0019c8c7b34918f225cc38602448..fbfa9584141b69afcfb3f37e44e8c7ad94887f71 100644
--- a/src/assets/styles/base.css
+++ b/src/assets/styles/base.css
@@ -88,6 +88,12 @@ body {
 .important-flex {
   display: flex !important;
 }
+.pointer:hover {
+  cursor: pointer;
+}
+.dimmer-anchor {
+  position: relative;
+}
 /* ---------------------------------- */
             /* MAIN */
 /* ---------------------------------- */
diff --git a/src/components/Account/UserActivity.vue b/src/components/Account/UserActivity.vue
index 45f7a8ff0ed3a5833783a7fab04a6a1c5623259e..9837974ee10053d2dfe99ce461ac9f806d55bbbe 100644
--- a/src/components/Account/UserActivity.vue
+++ b/src/components/Account/UserActivity.vue
@@ -18,7 +18,7 @@
                 <span v-if="item.event_type === 'create'">
                   <a
                     v-if="item.object_type === 'feature'"
-                    :href="modifyUrl(item.related_feature.feature_url)"
+                     :href="modifyUrl(item.related_feature.feature_url || item.project_url)"
                   >
                     Signalement créé
                   </a>
diff --git a/src/components/Account/UserProjectsList.vue b/src/components/Account/UserProjectsList.vue
index 70ee4fe37cd56427fd65af00f66ae7f0155536d6..d88eff53dca8939ffb3a627aef5549ce0396f5a2 100644
--- a/src/components/Account/UserProjectsList.vue
+++ b/src/components/Account/UserProjectsList.vue
@@ -6,9 +6,16 @@
 
     <div class="ui divided items">
       <div
-        v-for="project in availableProjects"
-        :key="project.slug"
-        class="item"
+        :class="['ui inverted dimmer', { active: projectsLoading }]"
+      >
+        <div class="ui text loader">
+          Récupération des projets en cours...
+        </div>
+      </div>
+      <div
+        v-for="project in projectsArray"
+      :key="project.slug"
+      class="item"
       >
         <div
           v-if="user_permissions[project.slug].can_view_project"
@@ -78,17 +85,38 @@
           </div>
         </div>
       </div>
+
+      <!-- PAGINATION -->
+      <Pagination
+        v-if="count"
+        :nb-pages="Math.ceil(count/10)"
+        :on-page-change="SET_CURRENT_PAGE"
+        @change-page="changePage"
+      />
     </div>
   </div>
 </template>
 
 <script>
+
 import { mapState } from 'vuex';
 
+import Pagination from '@/components/Pagination.vue';
+
 export default {
   
   name: 'UserProjectList',
 
+  components: {
+    Pagination,
+  },
+
+  data() {
+    return {
+      projectsLoading: true,
+    }
+  },
+
   computed: {
     ...mapState([
       'user',
@@ -97,7 +125,8 @@ export default {
     ]),
     // todo : filter projects to user
     ...mapState('projects', [
-      'projects'
+      'projects',
+      'count',
     ]),
 
     DJANGO_BASE_URL() {
@@ -113,13 +142,44 @@ export default {
         return this.projects.filter((el) => el.slug === this.$route.params.slug);
       }
       return this.projects;
+    },
+
+    projectsArray() { //* if only one project, only project object is returned
+      return Array.isArray(this.projects) ? this.projects : [this.projects];
     }
   },
 
+  created(){
+    this.SET_PROJECTS([]); //* empty previous project to avoid undefined user_permissions[project.slug]
+    this.getData();
+  },
+
+
   methods: {
+    ...mapMutations('projects', [
+      'SET_CURRENT_PAGE',
+      'SET_PROJECTS',
+    ]),
+
+    ...mapActions('projects', [
+      'GET_PROJECTS',
+    ]),
+
     refreshId() {
       return '?ver=' + Math.random();
     },
+
+    getData(page) {
+      this.loading = true;
+      this.GET_PROJECTS({ ismyaccount: true, projectSlug: this.$route.params.slug, page })
+        .then(() => this.projectsLoading = false)
+        .catch(() => this.projectsLoading = false);
+    },
+
+    changePage(e) {
+      this.getData(e);
+    },
+
   }
 
 };
diff --git a/src/components/AppHeader.vue b/src/components/AppHeader.vue
index 1450fcaf389776a4bc7c438bf7e3e178eb941979..fadeb11aac7951213fc1ea465cca58f669b96908 100644
--- a/src/components/AppHeader.vue
+++ b/src/components/AppHeader.vue
@@ -55,7 +55,7 @@
             </router-link>
             <router-link
               v-if="
-                project &&
+                project && isOnline &&
                   (user.is_administrator || user.is_superuser || isAdmin)
               "
               :to="{
@@ -68,7 +68,7 @@
             </router-link>
             <router-link
               v-if="
-                project &&
+                project && isOnline &&
                   (user.is_administrator || user.is_superuser || isAdmin)
               "
               :to="{
@@ -81,8 +81,12 @@
             </router-link>
             <div class="mobile">
               <router-link
+                :is="isOnline ? 'router-link' : 'span'"
                 v-if="user"
-                :to="{name: 'my_account', params: { slug: $route.params.slug ? $route.params.slug : '-' }}"
+                :to="{
+                  name: 'my_account',
+                  params: { slug: isSharedProject && $route.params.slug ? $route.params.slug : null }
+                }"
                 class="item"
               >
                 {{ userFullname || user.username || "Utilisateur inconnu" }}
@@ -132,8 +136,12 @@
         </div>
         <div class="desktop flex push-right-desktop">
           <router-link
+            :is="isOnline ? 'router-link' : 'span'"
             v-if="user"
-            :to="{name: 'my_account', params: { slug: $route.params.slug ? $route.params.slug : '-' }}"
+            :to="{
+              name: 'my_account',
+              params: { slug: isSharedProject && $route.params.slug ? $route.params.slug : null }
+            }"
             class="item"
           >
             {{ userFullname || user.username || "Utilisateur inconnu" }}
@@ -201,6 +209,7 @@ export default {
       'configuration',
       'messages',
       'loader',
+      'isOnline'
     ]),
     ...mapState('projects', [
       'projects',
diff --git a/src/components/FeaturesListAndMap/FeatureListTable.vue b/src/components/FeaturesListAndMap/FeatureListTable.vue
index d0a0ad5a90ac960398790d161f4b7dae86dbae5b..e892519aba5b3f83ce0ea1a3a27770028f3cc58f 100644
--- a/src/components/FeaturesListAndMap/FeatureListTable.vue
+++ b/src/components/FeaturesListAndMap/FeatureListTable.vue
@@ -1,322 +1,320 @@
 <template>
-  <div
-    data-tab="list"
-    class="dataTables_wrapper no-footer"
-  >
-    <table
-      id="table-features"
-      class="ui compact table dataTable"
+  <div>
+    <div class="table-mobile-buttons left-align">
+      <FeatureListMassToggle />
+    </div>
+    <div
+      data-tab="list"
+      class="dataTables_wrapper no-footer"
     >
-      <thead>
-        <tr>
-          <th class="dt-center">
-            <div
-              class="switch-buttons pointer"
-              :data-tooltip="`Passer en mode ${mode === 'modify' ? 'suppression':'édition'}`"
-              @click="switchMode"
-            >
-              <div><i :class="['icon pencil', {disabled: mode !== 'modify'}]" /></div>
-              <span class="grey">|&nbsp;</span>
-              <div><i :class="['icon trash', {disabled: mode !== 'delete'}]" /></div>
-            </div>
-          </th>
-
-          <th class="dt-center">
-            <div
-              class="pointer"
-              @click="changeSort('status')"
-            >
-              Statut
-              <i
-                :class="{
-                  down: isSortedAsc('status'),
-                  up: isSortedDesc('status'),
-                }"
-                class="icon sort"
-              />
-            </div>
-          </th>
-          <th class="dt-center">
-            <div
-              class="pointer"
-              @click="changeSort('feature_type')"
-            >
-              Type
-              <i
-                :class="{
-                  down: isSortedAsc('feature_type'),
-                  up: isSortedDesc('feature_type'),
-                }"
-                class="icon sort"
-              />
-            </div>
-          </th>
-          <th class="dt-center">
-            <div
-              class="pointer"
-              @click="changeSort('title')"
+      <table
+        id="table-features"
+        class="ui compact table unstackable dataTable"
+      >
+        <thead>
+          <tr>
+            <th class="dt-center">
+              <FeatureListMassToggle />
+            </th>
+
+            <th class="dt-center">
+              <div
+                class="pointer"
+                @click="changeSort('status')"
+              >
+                Statut
+                <i
+                  :class="{
+                    down: isSortedAsc('status'),
+                    up: isSortedDesc('status'),
+                  }"
+                  class="icon sort"
+                />
+              </div>
+            </th>
+            <th class="dt-center">
+              <div
+                class="pointer"
+                @click="changeSort('feature_type')"
+              >
+                Type
+                <i
+                  :class="{
+                    down: isSortedAsc('feature_type'),
+                    up: isSortedDesc('feature_type'),
+                  }"
+                  class="icon sort"
+                />
+              </div>
+            </th>
+            <th class="dt-center">
+              <div
+                class="pointer"
+                @click="changeSort('title')"
+              >
+                Nom
+                <i
+                  :class="{
+                    down: isSortedAsc('title'),
+                    up: isSortedDesc('title'),
+                  }"
+                  class="icon sort"
+                />
+              </div>
+            </th>
+            <th class="dt-center">
+              <div
+                class="pointer"
+                @click="changeSort('updated_on')"
+              >
+                Dernière modification
+                <i
+                  :class="{
+                    down: isSortedAsc('updated_on'),
+                    up: isSortedDesc('updated_on'),
+                  }"
+                  class="icon sort"
+                />
+              </div>
+            </th>
+            <th
+              v-if="user"
+              class="dt-center"
             >
-              Nom
-              <i
-                :class="{
-                  down: isSortedAsc('title'),
-                  up: isSortedDesc('title'),
-                }"
-                class="icon sort"
-              />
-            </div>
-          </th>
-          <th class="dt-center">
-            <div
-              class="pointer"
-              @click="changeSort('updated_on')"
+              <div
+                class="pointer"
+                @click="changeSort('display_creator')"
+              >
+                Auteur
+                <i
+                  :class="{
+                    down: isSortedAsc('display_creator'),
+                    up: isSortedDesc('display_creator'),
+                  }"
+                  class="icon sort"
+                />
+              </div>
+            </th>
+            <th
+              v-if="user"
+              class="dt-center"
             >
-              Dernière modification
-              <i
-                :class="{
-                  down: isSortedAsc('updated_on'),
-                  up: isSortedDesc('updated_on'),
-                }"
-                class="icon sort"
-              />
-            </div>
-          </th>
-          <th
-            v-if="user"
-            class="dt-center"
+              <div
+                class="pointer"
+                @click="changeSort('display_last_editor')"
+              >
+                Dernier éditeur
+                <i
+                  :class="{
+                    down: isSortedAsc('display_last_editor'),
+                    up: isSortedDesc('display_last_editor'),
+                  }"
+                  class="icon sort"
+                />
+              </div>
+            </th>
+          </tr>
+        </thead>
+        <tbody>
+          <tr
+            v-for="(feature, index) in paginatedFeatures"
+            :key="index"
           >
-            <div
-              class="pointer"
-              @click="changeSort('display_creator')"
-            >
-              Auteur
-              <i
-                :class="{
-                  down: isSortedAsc('display_creator'),
-                  up: isSortedDesc('display_creator'),
+            <td class="dt-center">
+              <div
+                :class="['ui checkbox', {disabled: !checkRights(feature)}]"
+              >
+                <input
+                  :id="feature.id"
+                  v-model="checked"
+                  type="checkbox"
+                  :value="feature.id"
+                  :disabled="!checkRights(feature)"
+                  name="select"
+                  @input="storeClickedFeature(feature)"
+                >
+                <label for="select" />
+              </div>
+            </td>
+
+            <td class="dt-center">
+              <div v-if="feature.properties.status.value === 'archived'">
+                <span data-tooltip="Archivé">
+                  <i class="grey archive icon" />
+                </span>
+              </div>
+              <div v-else-if="feature.properties.status.value === 'pending'">
+                <span data-tooltip="En attente de publication">
+                  <i class="teal hourglass outline icon" />
+                </span>
+              </div>
+              <div v-else-if="feature.properties.status.value === 'published'">
+                <span data-tooltip="Publié">
+                  <i class="olive check icon" />
+                </span>
+              </div>
+              <div v-else-if="feature.properties.status.value === 'draft'">
+                <span data-tooltip="Brouillon">
+                  <i class="orange pencil alternate icon" />
+                </span>
+              </div>
+            </td>
+            <td class="dt-center">
+              <router-link
+                :to="{
+                  name: 'details-type-signalement',
+                  params: {
+                    feature_type_slug: feature.properties.feature_type.slug,
+                  },
                 }"
-                class="icon sort"
-              />
-            </div>
-          </th>
-          <th
-            v-if="user"
-            class="dt-center"
-          >
-            <div
-              class="pointer"
-              @click="changeSort('display_last_editor')"
-            >
-              Dernier éditeur
-              <i
-                :class="{
-                  down: isSortedAsc('display_last_editor'),
-                  up: isSortedDesc('display_last_editor'),
+              >
+                {{ feature.properties.feature_type.title }}
+              </router-link>
+            </td>
+            <td class="dt-center">
+              <router-link
+                :to="{
+                  name: 'details-signalement',
+                  params: {
+                    slug_type_signal: feature.properties.feature_type.slug,
+                    slug_signal: feature.properties.slug || feature.id,
+                  },
                 }"
-                class="icon sort"
-              />
-            </div>
-          </th>
-        </tr>
-      </thead>
-      <tbody>
-        <tr
-          v-for="(feature, index) in paginatedFeatures"
-          :key="index"
-        >
-          <td class="dt-center">
-            <div
-              :class="['ui checkbox', {disabled: !checkRights(feature)}]"
-            >
-              <input
-                :id="feature.id"
-                v-model="checked"
-                type="checkbox"
-                :value="feature.id"
-                :disabled="!checkRights(feature)"
-                name="select"
-                @input="storeClickedFeature(feature)"
               >
-              <label for="select" />
-            </div>
-          </td>
-
-          <td class="dt-center">
-            <div
-              v-if="feature.properties.status.value === 'archived'"
-              data-tooltip="Archivé"
-            >
-              <i class="grey archive icon" />
-            </div>
-            <div
-              v-else-if="feature.properties.status.value === 'pending'"
-              data-tooltip="En attente de publication"
-            >
-              <i class="teal hourglass outline icon" />
-            </div>
-            <div
-              v-else-if="feature.properties.status.value === 'published'"
-              data-tooltip="Publié"
-            >
-              <i class="olive check icon" />
-            </div>
-            <div
-              v-else-if="feature.properties.status.value === 'draft'"
-              data-tooltip="Brouillon"
-            >
-              <i class="orange pencil alternate icon" />
-            </div>
-          </td>
-          <td class="dt-center">
-            <router-link
-              :to="{
-                name: 'details-type-signalement',
-                params: {
-                  feature_type_slug: feature.properties.feature_type.slug,
-                },
-              }"
+                {{ getFeatureDisplayName(feature) }}
+              </router-link>
+            </td>
+            <td class="dt-center">
+              {{ feature.properties.updated_on }}
+            </td>
+            <td
+              v-if="user"
+              class="dt-center"
             >
-              {{ feature.properties.feature_type.title }}
-            </router-link>
-          </td>
-          <td class="dt-center">
-            <router-link
-              :to="{
-                name: 'details-signalement',
-                params: {
-                  slug_type_signal: feature.properties.feature_type.slug,
-                  slug_signal: feature.properties.slug || feature.id,
-                },
-              }"
+              {{ getUserName(feature) }}
+            </td>
+            <td
+              v-if="user"
+              class="dt-center"
             >
-              {{ getFeatureDisplayName(feature) }}
-            </router-link>
-          </td>
-          <td class="dt-center">
-            {{ feature.properties.updated_on }}
-          </td>
-          <td
-            v-if="user"
-            class="dt-center"
+              {{ feature.properties.display_last_editor }}
+            </td>
+          </tr>
+          <tr
+            v-if="featuresCount === 0"
+            class="odd"
           >
-            {{ getUserName(feature) }}
-          </td>
-          <td
-            v-if="user"
-            class="dt-center"
-          >
-            {{ feature.properties.display_last_editor }}
-          </td>
-        </tr>
-        <tr
-          v-if="featuresCount === 0"
-          class="odd"
-        >
-          <td
-            colspan="5"
-            class="dataTables_empty"
-            valign="top"
-          >
-            Aucune donnée disponible
-          </td>
-        </tr>
-      </tbody>
-    </table>
-    <div
-      v-if="pageNumbers.length > 1"
-      id="table-features_info"
-      class="dataTables_info"
-      role="status"
-      aria-live="polite"
-    >
-      Affichage de l'élément {{ pagination.start + 1 }} à
-      {{ displayedPageEnd }}
-      sur {{ featuresCount }} éléments
-    </div>
-    <div
-      v-if="pageNumbers.length > 1"
-      id="table-features_paginate"
-      class="dataTables_paginate paging_simple_numbers"
-    >
-      <a
-        id="table-features_previous"
-        :class="[
-          'paginate_button previous',
-          { disabled: pagination.currentPage === 1 },
-        ]"
-        aria-controls="table-features"
-        data-dt-idx="0"
-        tabindex="0"
-        @click="$emit('update:page', 'previous')"
-      >Précédent</a>
-      <span>
-        <span v-if="pagination.currentPage >= 5">
-          <a
-            key="page1"
-            class="paginate_button"
-            aria-controls="table-features"
-            data-dt-idx="1"
-            tabindex="0"
-            @click="$emit('update:page', 1)"
-          >{{ 1 }}</a>
-          <span class="ellipsis">…</span>
-        </span>
+            <td
+              colspan="5"
+              class="dataTables_empty"
+              valign="top"
+            >
+              Aucune donnée disponible
+            </td>
+          </tr>
+        </tbody>
+      </table>
+      <div
+        v-if="pageNumbers.length > 1"
+        id="table-features_info"
+        class="dataTables_info"
+        role="status"
+        aria-live="polite"
+      >
+        Affichage de l'élément {{ pagination.start + 1 }} à
+        {{ displayedPageEnd }}
+        sur {{ featuresCount }} éléments
+      </div>
+      <div
+        v-if="pageNumbers.length > 1"
+        id="table-features_paginate"
+        class="dataTables_paginate paging_simple_numbers"
+      >
         <a
-          v-for="pageNumber in displayedPageNumbers"
-          :key="'page' + pageNumber"
+          id="table-features_previous"
           :class="[
-            'paginate_button',
-            { current: pageNumber === pagination.currentPage },
+            'paginate_button previous',
+            { disabled: pagination.currentPage === 1 },
           ]"
           aria-controls="table-features"
-          data-dt-idx="1"
+          data-dt-idx="0"
           tabindex="0"
-          @click="$emit('update:page', pageNumber)"
-        >{{ pageNumber }}</a>
-        <span v-if="(lastPageNumber - pagination.currentPage) >= 4">
-          <span class="ellipsis">…</span>
+          @click="$emit('update:page', 'previous')"
+        >Précédent</a>
+        <span>
+          <span v-if="pagination.currentPage >= 5">
+            <a
+              key="page1"
+              class="paginate_button"
+              aria-controls="table-features"
+              data-dt-idx="1"
+              tabindex="0"
+              @click="$emit('update:page', 1)"
+            >{{ 1 }}</a>
+            <span class="ellipsis">…</span>
+          </span>
           <a
-            :key="'page' + lastPageNumber"
-            class="paginate_button"
+            v-for="pageNumber in displayedPageNumbers"
+            :key="'page' + pageNumber"
+            :class="[
+              'paginate_button',
+              { current: pageNumber === pagination.currentPage },
+            ]"
             aria-controls="table-features"
             data-dt-idx="1"
             tabindex="0"
-            @click="$emit('update:page', lastPageNumber)"
-          >{{ lastPageNumber }}</a>
+            @click="$emit('update:page', pageNumber)"
+          >{{ pageNumber }}</a>
+          <span v-if="(lastPageNumber - pagination.currentPage) >= 4">
+            <span class="ellipsis">…</span>
+            <a
+              :key="'page' + lastPageNumber"
+              class="paginate_button"
+              aria-controls="table-features"
+              data-dt-idx="1"
+              tabindex="0"
+              @click="$emit('update:page', lastPageNumber)"
+            >{{ lastPageNumber }}</a>
+          </span>
         </span>
-      </span>
-      <a
-        id="table-features_next"
-        :class="[
-          'paginate_button next',
-          { disabled: pagination.currentPage === pageNumbers.length },
-        ]"
-        aria-controls="table-features"
-        data-dt-idx="7"
-        tabindex="0"
-        @click="$emit('update:page', 'next')"
-      >Suivant</a>
+        <a
+          id="table-features_next"
+          :class="[
+            'paginate_button next',
+            { disabled: pagination.currentPage === pageNumbers.length },
+          ]"
+          aria-controls="table-features"
+          data-dt-idx="7"
+          tabindex="0"
+          @click="$emit('update:page', 'next')"
+        >Suivant</a>
+      </div>
     </div>
   </div>
 </template>
 
 <script>
+import { mapState, mapGetters, mapMutations } from 'vuex';
+import FeatureListMassToggle from '@/components/feature/FeatureListMassToggle';
 
-import { mapState, mapGetters } from 'vuex';
 
 export default {
   name: 'FeatureListTable',
 
+  components: {
+    FeatureListMassToggle,
+  },
+
   props: {
     paginatedFeatures: {
       type: Array,
       default: null,
     },
-    checkedFeatures: {
+    pageNumbers: {
       type: Array,
       default: null,
     },
-    clickedFeatures: {
+    checkedFeatures: {
       type: Array,
       default: null,
     },
@@ -332,16 +330,13 @@ export default {
       type: Object,
       default: null,
     },
-    mode: {
-      type: String,
-      default: null,
-    }
   },
 
   computed: {
     ...mapGetters(['permissions']),
     ...mapState(['user', 'USER_LEVEL_PROJECTS']),
     ...mapState('projects', ['project']),
+    ...mapState('feature', ['clickedFeatures', 'massMode']),
 
     userStatus() {
       return this.USER_LEVEL_PROJECTS[this.$route.params.slug];
@@ -362,16 +357,6 @@ export default {
         : this.pagination.end;
     },
 
-    pageNumbers() {
-      const totalPages = Math.ceil(
-        this.featuresCount / this.pagination.pagesize
-      );
-      return [...Array(totalPages).keys()].map((pageNumb) => {
-        ++pageNumb;
-        return pageNumb;
-      });
-    },
-
     lastPageNumber() {
       return this.pageNumbers.slice(-1)[0];
     },
@@ -396,12 +381,20 @@ export default {
   },
 
   destroyed() {
-    this.$store.commit('feature/UPDATE_CHECKED_FEATURES', []);
+    this.UPDATE_CHECKED_FEATURES([]);
   },
 
   methods: {
+    ...mapMutations('feature', [
+      'UPDATE_CLICKED_FEATURES',
+      'UPDATE_CHECKED_FEATURES',
+    ]),
+
     storeClickedFeature(feature) {
-      this.$emit('update:clickedFeatures', [...this.clickedFeatures, { feature_id: feature.id, feature_type: feature.properties.feature_type.slug }]);
+      this.UPDATE_CLICKED_FEATURES([
+        ...this.clickedFeatures,
+        { feature_id: feature.id, feature_type: feature.properties.feature_type.slug }
+      ]);
     },
 
     canDeleteFeature(feature) {
@@ -428,7 +421,7 @@ export default {
     },
 
     checkRights(feature) {
-      switch (this.mode) {
+      switch (this.massMode) {
       case 'modify':
         return this.canEditFeature(feature);
       case 'delete':
@@ -436,12 +429,6 @@ export default {
       } 
     },
 
-    switchMode() {
-      this.$emit('update:mode', this.mode === 'modify' ? 'delete' : 'modify');
-      this.$emit('update:clickedFeatures', []);
-      this.$store.commit('feature/UPDATE_CHECKED_FEATURES', []);
-    },
-    
     getUserName(feature) {
       if (!feature.properties.creator) {
         return ' ---- ';
@@ -565,15 +552,6 @@ table.dataTable th.dt-center, table.dataTable td.dt-center, table.dataTable td.d
 i.icon.sort:not(.down):not(.up) {
   color: rgb(220, 220, 220);
 }
-.pointer:hover {
-  cursor: pointer;
-}
-
-.switch-buttons {
-  display: flex;
-  justify-content: center;
-  align-items: baseline;
-}
 
 .grey {
   color: #bbbbbb;
@@ -582,13 +560,28 @@ i.icon.sort:not(.down):not(.up) {
 .ui.dropdown .menu .left.menu, .ui.dropdown > .left.menu .menu {
   margin-right: 0 !important;
 }
+
+.table-mobile-buttons {
+  margin-bottom: 1em;
+}
+@media only screen and (min-width: 761px) {
+  .table-mobile-buttons {
+    display: none !important;
+  }
+}
 /* 
 Max width before this PARTICULAR table gets nasty
 This query will take effect for any screen smaller than 760px
 and also iPads specifically.
 */
-@media only screen and (max-width: 760px),
-  (min-device-width: 768px) and (max-device-width: 1024px) {
+@media only screen and (max-width: 760px) {
+  .table-mobile-buttons {
+    display: flex !important;
+    }
+  /* hide table border */
+  .ui.table {
+    border: none !important;
+  }
   /* Force table to not be like tables anymore */
   table,
   thead,
@@ -606,8 +599,12 @@ and also iPads specifically.
     left: -9999px;
   }
 
-  tr {
+  tr { /* style as a card */
     border: 1px solid #ccc;
+    border-radius: 7px;
+    margin-bottom: 3vh;
+    padding: 0 1vw .5em 1vw;
+    box-shadow: rgba(50, 50, 50, 0.1) 2px 5px 10px ;
   }
 
   td {
@@ -617,7 +614,19 @@ and also iPads specifically.
     position: relative;
     padding-left: 50%;
   }
-
+  .ui.table tr td {
+    border-top: none;
+  }
+  .ui.compact.table td {
+    padding: .2em;
+  }
+  td:nth-of-type(1) {
+    border: none !important;
+    padding: .25em !important;
+  }
+  td:nth-of-type(7) {
+    border-bottom: none !important;
+  }
   td:before {
     /* Now like a table header */
     position: absolute;
@@ -628,7 +637,6 @@ and also iPads specifically.
     padding-right: 10px;
     white-space: nowrap;
   }
-
   /*
 	Label the data
 	*/
@@ -650,20 +658,29 @@ and also iPads specifically.
   td:nth-of-type(6):before {
     content: "Auteur";
   }
+  td:nth-of-type(7):before {
+    content: "Dernier éditeur";
+  }
 
   table.dataTable th.dt-center, table.dataTable td.dt-center, table.dataTable td.dataTables_empty {
     text-align: right;
   }
 
-  #table-features {
-    margin-left: 1em;
-    width: calc(100% - 1em);
-  }
-
   .ui.checkbox {
     position: absolute;
-    left: -1.75em;
-    top: 5em;
+    left: calc(-1vw - .75em);
+    top: -.75em;
+  }
+  .dataTables_wrapper .dataTables_info,
+  .dataTables_wrapper .dataTables_paginate {
+    width: 100%;
+    text-align: center;
+    margin: .5em 0;
+  }
+}
+@media only screen and (max-width: 410px) {
+  .ui.table tr td {
+    border: none;
   }
 }
 </style>
\ No newline at end of file
diff --git a/src/components/Pagination.vue b/src/components/Pagination.vue
index d0f730bab725b56ccaab46e4c02835e7c197da65..2afc85dfff08547813bd8d477c290efe1632ddd3 100644
--- a/src/components/Pagination.vue
+++ b/src/components/Pagination.vue
@@ -8,7 +8,7 @@
         >
           <a
             class="page-link"
-            href="#"
+            :href="currentLocation"
             @click="page -= 1"
           >
             <i class="ui icon big angle left" />
@@ -26,7 +26,7 @@
           >
             <a
               class="page-link"
-              href="#"
+              :href="currentLocation"
               @click="changePage(index)"
             >
               {{ index }}
@@ -45,7 +45,7 @@
           >
             <a
               class="page-link"
-              href="#"
+              :href="currentLocation"
               @click="page = index"
             >
               {{ index }}
@@ -58,7 +58,7 @@
         >
           <a
             class="page-link"
-            href="#"
+            :href="currentLocation"
             @click="page += 1"
           >
             <i class="ui icon big angle right" />
@@ -89,7 +89,8 @@ export default {
 
   data() {
     return {
-      page: 1
+      page: 1,
+      currentLocation: window.location.origin + window.location.pathname + '#',
     };
   },
 
diff --git a/src/components/ProjectDetail/ProjectHeader.vue b/src/components/ProjectDetail/ProjectHeader.vue
index 32d587355015cb4c3d3b1bceb550179439ab705f..124d5fffc49d30ce0eb64f8d47dd35015c3fccca 100644
--- a/src/components/ProjectDetail/ProjectHeader.vue
+++ b/src/components/ProjectDetail/ProjectHeader.vue
@@ -114,9 +114,9 @@
       <div v-if="arraysOffline.length > 0">
         {{ arraysOffline.length }} modification<span v-if="arraysOffline.length>1">s</span> en attente
         <button
-          :disabled="isOffline()"
+          :disabled="isOffline"
           class="ui fluid labeled teal icon button"
-          @click="sendOfflineFeatures()"
+          @click="sendOfflineFeatures"
         >
           <i class="upload icon" />
           Envoyer au serveur
@@ -180,6 +180,9 @@ export default {
   },
 
   methods: {
+    ...mapState([
+      'isOnline'
+    ]),
     ...mapMutations('modals', [
       'OPEN_PROJECT_MODAL'
     ]),
@@ -203,6 +206,48 @@ export default {
       );
     },
 
+    sendOfflineFeatures() {
+      this.arraysOfflineErrors = [];
+
+      const promises = this.arraysOffline.map((feature) => featureAPI.postOrPutFeature({
+        data: feature.geojson,
+        feature_id: feature.featureId,
+        project__slug: feature.project,
+        feature_type__slug: feature.geojson.properties.feature_type,
+        method: feature.type.toUpperCase(),
+      })
+        .then((response) => {
+          if (!response) this.arraysOfflineErrors.push(feature);
+        })
+        .catch((error) => {
+          console.error(error);
+          this.arraysOfflineErrors.push(feature);
+        })
+      );
+      this.DISPLAY_LOADER('Envoi des signalements en cours.');
+
+      Promise.all(promises).then(() => {
+        this.updateLocalStorage();
+        this.$emit('retrieve-info');
+      });
+    },
+
+    updateLocalStorage() {
+      let arraysOffline = [];
+      const localStorageArray = localStorage.getItem('geocontrib_offline');
+      if (localStorageArray) {
+        arraysOffline = JSON.parse(localStorageArray);
+      }
+      const arraysOfflineOtherProject = arraysOffline.filter(
+        (x) => x.project !== this.slug
+      );
+      this.arraysOffline = [];
+      arraysOffline = arraysOfflineOtherProject.concat(
+        this.arraysOfflineErrors
+      );
+      localStorage.setItem('geocontrib_offline', JSON.stringify(arraysOffline));
+    },
+
   }
 
 };
diff --git a/src/components/SidebarLayers.vue b/src/components/SidebarLayers.vue
index 082d679d96952f01d122c10be1985078f7d26578..9e9782e1827b4b228434b1c5509f1c4128721b9c 100644
--- a/src/components/SidebarLayers.vue
+++ b/src/components/SidebarLayers.vue
@@ -1,5 +1,8 @@
 <template>
-  <div :class="['sidebar-container', { expanded }]">
+  <div
+    v-if="isOnline"
+    :class="['sidebar-container', { expanded }]"
+  >
     <!-- <div class="sidebar-layers"></div> -->
     <div
       class="layers-icon"
@@ -132,7 +135,12 @@ export default {
   },
 
   computed: {
-    ...mapState('map', ['availableLayers']),
+    ...mapState([
+      'isOnline',
+    ]),
+    ...mapState('map', [
+      'availableLayers'
+    ]),
   },
 
   mounted() {
diff --git a/src/components/feature/FeatureListMassToggle.vue b/src/components/feature/FeatureListMassToggle.vue
new file mode 100644
index 0000000000000000000000000000000000000000..02aaa775df28a1cb77c6dbbf47ff1111b31a5e16
--- /dev/null
+++ b/src/components/feature/FeatureListMassToggle.vue
@@ -0,0 +1,48 @@
+<template>
+  <div
+    class="switch-buttons pointer"
+    :data-tooltip="`Passer en mode ${massMode === 'modify' ? 'suppression':'édition'}`"
+    @click="switchMode"
+  >
+    <div><i :class="['icon pencil', {disabled: massMode !== 'modify'}]" /></div>
+    <span class="grey">|&nbsp;</span>
+    <div><i :class="['icon trash', {disabled: massMode !== 'delete'}]" /></div>
+  </div>
+</template>
+
+<script>
+import { mapMutations, mapState } from 'vuex';
+export default {
+  name: 'FeatureListMassToggle',
+
+  computed: {
+    ...mapState('feature', ['massMode'])
+  },
+
+  methods: {
+    ...mapMutations('feature', [
+      'TOGGLE_MASS_MODE',
+      'UPDATE_CHECKED_FEATURES',
+      'UPDATE_CLICKED_FEATURES']),
+
+    switchMode() {
+      this.TOGGLE_MASS_MODE(this.massMode === 'modify' ? 'delete' : 'modify');
+      this.UPDATE_CLICKED_FEATURES([]);
+      this.UPDATE_CHECKED_FEATURES([]);
+    }
+  },
+};
+</script>
+
+<style scoped>
+.switch-buttons {
+  display: flex;
+  justify-content: center;
+  align-items: baseline;
+}
+
+.grey {
+  color: #bbbbbb;
+}
+
+</style>
\ No newline at end of file
diff --git a/src/main.js b/src/main.js
index 2aaa4ad7377d468b804c8deb1513ee05de3a0e6a..c8dd8f15eafac74b7b953c484289b8d7f401381b 100644
--- a/src/main.js
+++ b/src/main.js
@@ -38,6 +38,9 @@ if(navigator.serviceWorker){
 
 let onConfigLoaded = function(config){
   store.commit('SET_CONFIG', config);
+  setInterval(() => { //* check if navigator is online
+    store.commit('SET_IS_ONLINE', navigator.onLine);
+  }, 1000);
 
   // set title and favico
   document.title= config.VUE_APP_APPLICATION_NAME+' '+config.VUE_APP_APPLICATION_ABSTRACT;
diff --git a/src/service-worker.js b/src/service-worker.js
index 1b04819c7a0f9e3a915b944b3b5e3d53954d0d27..7dd25fb94ea383cea55ef57465533c7422199f08 100644
--- a/src/service-worker.js
+++ b/src/service-worker.js
@@ -29,10 +29,15 @@ if (workbox) {
     new RegExp('.*/api/.*'),
     new workbox.strategies.NetworkFirst({
       cacheName: 'api',
+      plugins: [
+        new workbox.cacheableResponse.Plugin({
+          statuses: [0, 200],
+        }),
+      ],
     })
   );
   workbox.routing.registerRoute(
-    /^https:\/\/c\.tile\.openstreetmap\.fr/,
+    /^https:\/\/[a-zA-Z]\.tile\.openstreetmap\.fr/,
     new workbox.strategies.CacheFirst({
       cacheName: 'osm',
       plugins: [
@@ -46,6 +51,21 @@ if (workbox) {
       ],
     })
   );
+  workbox.routing.registerRoute(
+    /^https:\/\/osm\.geo2france\.fr\/mapcache/,
+    new workbox.strategies.CacheFirst({
+      cacheName: 'mapcache',
+      plugins: [
+        new workbox.cacheableResponse.Plugin({
+          statuses: [0, 200],
+        }),
+        new workbox.expiration.Plugin({
+          maxAgeSeconds: 60 * 60 * 24 * 365,
+          // maxEntries: 30, pour limiter le nombre d'entrée dans le cache
+        }),
+      ],
+    })
+  );
 
 }
 
diff --git a/src/services/feature-api.js b/src/services/feature-api.js
index a2278387d8e0f5c1f1bd980a3e133d899253d710..690df05e61decf02e2d0749458d73350a13f5d84 100644
--- a/src/services/feature-api.js
+++ b/src/services/feature-api.js
@@ -62,6 +62,55 @@ const featureAPI = {
     }
   },
 
+  async getFeatureLinks(featureId) {
+    const response = await axios.get(
+      `${baseUrl}features/${featureId}/feature-links/`
+    );
+    if (
+      response.status === 200 &&
+      response.data
+    ) {
+      return response.data;
+    } else {
+      return null;
+    }
+  },
+
+  async getFeaturesBlob(url) {
+    const response = await axios
+      .get(url, { responseType: 'blob' });
+    if (
+      response.status === 200 &&
+      response.data
+    ) {
+      return response.data;
+    } else {
+      return null;
+    }
+  },
+  // todo : fonction pour faire un post ou un put du signalement
+
+
+  async postOrPutFeature({ method, feature_id, feature_type__slug, project__slug, data }) {
+    let url = `${baseUrl}features/`;
+    if (method === 'PUT') {
+      url += `${feature_id}/?
+      feature_type__slug=${feature_type__slug}
+      &project__slug=${project__slug}`;
+    }
+
+    const response = await axios({
+      url,
+      method,
+      data,
+    });
+    if ((response.status === 200 || response.status === 201) && response.data) {
+      return response;
+    } else {
+      return null;
+    }
+  },
+
   async updateFeature({ feature_id, feature_type__slug, project__slug, newStatus }) {
     let url = `${baseUrl}features/${feature_id}/?feature_type__slug=${feature_type__slug}&project__slug=${project__slug}`;
 
@@ -108,33 +157,6 @@ const featureAPI = {
       return null;
     }
   },
-
-  async getFeatureLinks(featureId) {
-    const response = await axios.get(
-      `${baseUrl}features/${featureId}/feature-links/`
-    );
-    if (
-      response.status === 200 &&
-      response.data
-    ) {
-      return response.data;
-    } else {
-      return null;
-    }
-  },
-
-  async getFeaturesBlob(url) {
-    const response = await axios
-      .get(url, { responseType: 'blob' });
-    if (
-      response.status === 200 &&
-      response.data
-    ) {
-      return response.data;
-    } else {
-      return null;
-    }
-  },
 };
 
 export default featureAPI;
diff --git a/src/services/project-api.js b/src/services/project-api.js
index f150a81ed390fc9d128cb131201e1cc2fae1a135..8866ad935e563ed5f947be4f3b178760d825d937 100644
--- a/src/services/project-api.js
+++ b/src/services/project-api.js
@@ -45,21 +45,22 @@ const projectAPI = {
     }
   },
 
-  async getProjects(baseUrl, filters, page) {
+  async getProjects({ baseUrl, filters, page, projectSlug, myaccount }) {
+    let url = `${baseUrl}projects/`;
+    if (projectSlug) url += `${projectSlug}/`;
+    url += `?page=${page}`;
+    if (myaccount) {
+      url += '&myaccount=true';
+    }
     try {
-      const url = `${baseUrl}projects/?page=${page}`;
-
-      let filteredUrl;
       if (Object.values(filters).some(el => el && el.length > 0)) {
-        filteredUrl = url;
         for (const filter in filters) {
           if (filters[filter]) {
-            filteredUrl = filteredUrl.concat('', `&${filter}=${filters[filter]}`);
+            url = url.concat('', `&${filter}=${filters[filter]}`);
           }
         }
       }
-
-      const response = await axios.get(filteredUrl ? filteredUrl : url);
+      const response = await axios.get(url);
       if (response.status === 200 && response.data) {
         return response.data;
       }
diff --git a/src/store/index.js b/src/store/index.js
index 3aa9c61d5fa0359782e1ac3544647c40ab22ee7b..805c0fe99a5e12cc883303ce88bbe294b4c7fa25 100644
--- a/src/store/index.js
+++ b/src/store/index.js
@@ -23,25 +23,29 @@ const noPermissions = {
 
 export default new Vuex.Store({
   modules,
-  
+
   state: {
-    logged: false,
-    user: false,
+    cancellableSearchRequest: [],
     configuration: null,
-    staticPages: null,
-    USER_LEVEL_PROJECTS: null,
-    user_permissions: null,
+    isOnline: true,
     levelsPermissions: [],
-    messages: [],
     loader: {
       isLoading: false,
       message: 'En cours de chargement'
     },
-    cancellableSearchRequest: [],
-    reloadIntervalId: null
+    logged: false,
+    messages: [],
+    reloadIntervalId: null,
+    staticPages: null,
+    user: false,
+    USER_LEVEL_PROJECTS: null,
+    user_permissions: null,
   },
 
   mutations: {
+    SET_IS_ONLINE(state, payload) {
+      state.isOnline = payload;
+    },
     SET_USER(state, payload) {
       state.user = payload;
     },
@@ -106,7 +110,7 @@ export default new Vuex.Store({
     CLEAR_RELOAD_INTERVAL_ID(state) {
       clearInterval(state.reloadIntervalId);
       state.reloadIntervalId = null;
-    }
+    },
   },
 
   getters: {
diff --git a/src/store/modules/feature.store.js b/src/store/modules/feature.store.js
index 3039126bf92273a558eacab63830e5599198ed99..d57046265453d56dbb28da4e8dc4dca686a461a0 100644
--- a/src/store/modules/feature.store.js
+++ b/src/store/modules/feature.store.js
@@ -1,13 +1,13 @@
 import axios from '@/axios-client.js';
 import router from '../../router';
 
-
 const feature = {
   namespaced: true,
   state: {
     attachmentFormset: [],
     attachmentsToDelete: [],
     checkedFeatures: [],
+    clickedFeatures: [],
     extra_form: [],
     features: [],
     features_count: 0,
@@ -15,6 +15,7 @@ const feature = {
     form: null,
     linkedFormset: [],
     linked_features: [],
+    massMode: 'modify',
     statusChoices: [
       {
         name: 'Brouillon',
@@ -100,7 +101,13 @@ const feature = {
     },
     UPDATE_CHECKED_FEATURES(state, checkedFeatures) {
       state.checkedFeatures = checkedFeatures;
-    }
+    },
+    UPDATE_CLICKED_FEATURES(state, clickedFeatures) {
+      state.clickedFeatures = clickedFeatures;
+    },
+    TOGGLE_MASS_MODE(state, payload) {
+      state.massMode = payload;
+    },
   },
   getters: {
   },
@@ -235,6 +242,9 @@ const feature = {
         &project__slug=${rootState.projects.project.slug}`;
       }
 
+      //* postOrPutFeature function from service featureAPI could be used here, but because configuration is in store,
+      //* projectBase would need to be sent with each function which imply to modify all function from this service,
+      //* which could create regression
       return axios({
         url,
         method: routeName === 'editer-signalement' ? 'PUT' : 'POST',
@@ -252,7 +262,7 @@ const feature = {
       })
         .catch((error) => {
           commit('DISCARD_LOADER', null, { root: true });
-          if (error.message === 'Network Error' || window.navigator.onLine === false) {
+          if (error.message === 'Network Error' || !rootState.isOnline) {
             let arraysOffline = [];
             let localStorageArray = localStorage.getItem('geocontrib_offline');
             if (localStorageArray) {
@@ -372,10 +382,11 @@ const feature = {
         });
     },
 
-    DELETE_FEATURE({ rootState }, feature_id) {
-      const url = `${rootState.configuration.VUE_APP_DJANGO_API_BASE}features/${feature_id}/?` +
-        `feature_type__slug=${rootState.feature_type.current_feature_type_slug}` +
-        `&project__slug=${rootState.projects.project.slug}`;
+    DELETE_FEATURE({ rootState }, payload) {
+      const { feature_id, noFeatureType } = payload;
+      let url = `${rootState.configuration.VUE_APP_DJANGO_API_BASE}features/${feature_id}/?` +
+      `project__slug=${rootState.projects.project.slug}`;
+      if (!noFeatureType) url +=`&feature_type__slug=${rootState.feature_type.current_feature_type_slug}`;
       return axios
         .delete(url)
         .then((response) => response)
diff --git a/src/store/modules/projects.store.js b/src/store/modules/projects.store.js
index 2f0b5eabe364686160fdef794578ec3f3260469b..68adf8ddc44f56fa4f074ac47897c7706997c80e 100644
--- a/src/store/modules/projects.store.js
+++ b/src/store/modules/projects.store.js
@@ -1,6 +1,13 @@
 import axios from '@/axios-client.js';
 import projectAPI from '@/services/project-api';
 
+const initialFilters = {
+  moderation: null,
+  access_level: null,
+  user_access_level: null,
+  accessible: null
+};
+
 const projects = {
 
   namespaced: true,
@@ -8,12 +15,7 @@ const projects = {
   state: {
     count: 0,
     currentPage: 1,
-    filters: {
-      moderation: null,
-      access_level: null,
-      user_access_level: null,
-      accessible: null
-    },
+    filters: { ...initialFilters },
     isProjectsListSearched: null,
     last_comments: [],
     projects: [],
@@ -22,11 +24,6 @@ const projects = {
     searchProjectsFilter: null,
   },
 
-  getters: {
-    project_types: state => state.projects.filter(projet => projet.is_project_type),
-    project_user: state => state.projects.filter(projet => projet.creator === state.user.id),
-  },
-
   mutations: {
     SET_CURRENT_PAGE (state, payload) {
       state.currentPage = payload;
@@ -54,6 +51,10 @@ const projects = {
       state.filters[payload.filter] = payload.value;
     },
 
+    RESET_PROJECTS_FILTER(state) {
+      state.filters = { ...initialFilters };
+    },
+
     SET_PROJECTS_SEARCH_STATE(state, payload) {
       state.isProjectsListSearched = payload.isSearched;
       state.searchProjectsFilter = payload.text;
@@ -78,13 +79,21 @@ const projects = {
       }
     },
 
-    async GET_PROJECTS({ state, rootState, commit }, page) {
+    async GET_PROJECTS({ state, rootState, commit }, payload) {
+      let { page, myaccount, projectSlug } = payload || {};
       if (!page) {
         page = state.currentPage;
       }
       const baseUrl = rootState.configuration.VUE_APP_DJANGO_API_BASE;
-      const projects = await projectAPI.getProjects(baseUrl, state.filters, page);
+      const projects = await projectAPI.getProjects({
+        baseUrl,
+        filters : state.filters,
+        page,
+        projectSlug,
+        myaccount,
+      });
       commit('SET_PROJECTS', projects);
+      return;
     },
 
     async SEARCH_PROJECTS({ commit, dispatch }, text) {
@@ -99,7 +108,7 @@ const projects = {
       }
     },
 
-    async GET_PROJECT({ rootState, commit }, slug) {
+    async GET_PROJECT({ rootState, commit }, slug) { // todo : use GET_PROJECTS instead, with slug
       const baseUrl = rootState.configuration.VUE_APP_DJANGO_API_BASE;
       const project = await projectAPI.getProject(baseUrl, slug);
       commit('SET_PROJECT', project);
diff --git a/src/views/Feature/FeatureDetail.vue b/src/views/Feature/FeatureDetail.vue
index 00dbd89ab737cb92332fee5ceb0c1e4a07b4ad7d..ce9347403959caba79c870d8aae16750d7031a7b 100644
--- a/src/views/Feature/FeatureDetail.vue
+++ b/src/views/Feature/FeatureDetail.vue
@@ -42,7 +42,7 @@
                   <i class="inverted grey pencil alternate icon" />
                 </router-link>
                 <a
-                  v-if="isFeatureCreator"
+                  v-if="((permissions && permissions.can_update_feature) || isFeatureCreator) && isOnline"
                   id="feature-delete"
                   class="ui button button-hover-red"
                   @click="isCanceling = true"
@@ -268,7 +268,7 @@
           </div>
 
           <div
-            v-if="permissions && permissions.can_create_feature && isOffline() !== true"
+            v-if="permissions && permissions.can_create_feature && isOnline"
             class="ui segment"
           >
             <form
@@ -433,7 +433,8 @@ export default {
   computed: {
     ...mapState([
       'user',
-      'USER_LEVEL_PROJECTS'
+      'USER_LEVEL_PROJECTS',
+      'isOnline',
     ]),
     ...mapState('projects', [
       'project'
@@ -541,9 +542,7 @@ export default {
     ...mapActions('feature', [
       'GET_PROJECT_FEATURES'
     ]),
-    isOffline() {
-      return navigator.onLine == false;
-    },
+
     pushNgo(link) {
       this.$router.push({
         name: 'details-signalement',
@@ -662,7 +661,7 @@ export default {
 
     deleteFeature() {
       this.$store
-        .dispatch('feature/DELETE_FEATURE', this.feature.feature_id)
+        .dispatch('feature/DELETE_FEATURE', { feature_id: this.feature.feature_id })
         .then((response) => {
           if (response.status === 204) {
             this.GET_PROJECT_FEATURES({
diff --git a/src/views/Feature/FeatureEdit.vue b/src/views/Feature/FeatureEdit.vue
index 57b7b792b695fac31e41181d5e4dc14d5c59e2ee..31c8b7c0825ba95f5c78804b794b62b4b62290e7 100644
--- a/src/views/Feature/FeatureEdit.vue
+++ b/src/views/Feature/FeatureEdit.vue
@@ -74,7 +74,7 @@
             v-if="feature_type && feature_type.geom_type === 'point'"
             v-frag
           >
-            <p v-if="isOffline() !== true">
+            <p v-if="isOnline">
               <button
                 id="add-geo-image"
                 type="button"
@@ -229,12 +229,12 @@
         </div>
 
         <!-- Pièces jointes -->
-        <div v-if="isOffline() !== true">
+        <div v-if="isOnline">
           <div class="ui horizontal divider">
             PIÈCES JOINTES
           </div>
           <div
-            v-if="isOffline() !== true"
+            v-if="isOnline"
             id="formsets-attachment"
           >
             <FeatureAttachmentForm
@@ -256,7 +256,7 @@
         </div>
 
         <!-- Signalements liés -->
-        <div v-if="isOffline() !== true">
+        <div v-if="isOnline">
           <div class="ui horizontal divider">
             SIGNALEMENTS LIÉS
           </div>
@@ -372,10 +372,15 @@ export default {
 
   computed: {
     ...mapGetters(['permissions']),
+<<<<<<< HEAD:src/views/Feature/FeatureEdit.vue
     ...mapGetters('feature-type', [
       'feature_type'
     ]),
     ...mapState(['user', 'USER_LEVEL_PROJECTS']),
+=======
+    ...mapGetters('feature_type', ['feature_type']),
+    ...mapState(['user', 'USER_LEVEL_PROJECTS', 'isOnline']),
+>>>>>>> develop:src/views/feature/Feature_edit.vue
     ...mapState('projects', ['project']),
     ...mapState('map', ['basemaps']),
     ...mapState('feature', [
@@ -488,9 +493,6 @@ export default {
   },
 
   methods: {
-    isOffline() {
-      return navigator.onLine == false;
-    },
     initForm() {
       if (this.currentRouteName === 'editer-signalement') {
         for (let key in this.feature) {
diff --git a/src/views/FeatureType/FeatureTypeDetail.vue b/src/views/FeatureType/FeatureTypeDetail.vue
index 0bdca9f75f9ea6906b78bc2f4a9acc9f3d0a207b..492206d77490946f8383addaff89252b376c3007 100644
--- a/src/views/FeatureType/FeatureTypeDetail.vue
+++ b/src/views/FeatureType/FeatureTypeDetail.vue
@@ -70,9 +70,13 @@
 
         <div class="ui bottom attached secondary segment">
           <div
-            v-if="permissions.can_create_feature"
-            class="ui styled accordion"
+            :class="['title', { active: showImport && isOnline, nohover: !isOnline }]"
+            @click="toggleShowImport"
           >
+            <i class="dropdown icon" />
+            Importer des signalements
+          </div>
+          <div :class="['content', { active: showImport && isOnline }]">
             <div
               :class="['title', { active: showImport }]"
               @click="toggleShowImport"
@@ -82,9 +86,8 @@
             </div>
             <div :class="['content', { active: showImport }]">
               <div
-                id="form-import-features"
-                class="ui form"
-                :class="loadingImportFile ? 'loading' : ''"
+                v-if="$route.params.geojson"
+                class="ui button import-catalog basic active teal nohover"
               >
                 <div class="field">
                   <label
@@ -173,6 +176,28 @@
             </div>
           </div>
         </div>
+        <div class="ui styled accordion">
+          <div
+            :class="['title', { active: !showImport && isOnline, nohover: !isOnline }]"
+            @click="toggleShowImport"
+          >
+            <i class="dropdown icon" />
+            Exporter les signalements
+          </div>
+          <div :class="['content', { active: !showImport && isOnline}]">
+            <p>
+              Vous pouvez télécharger tous les signalements qui vous sont
+              accessibles.
+            </p>
+            <button
+              type="button"
+              class="ui fluid teal icon button"
+              @click="exportFeatures"
+            >
+              <i class="download icon" /> Exporter
+            </button>
+          </div>
+        </div>
       </div>
 
       <div class="nine wide column">
@@ -337,7 +362,7 @@ export default {
 
   computed: {
     ...mapGetters([
-      'permissions'
+      'permissions',
     ]),
     ...mapGetters('projects', [
       'project'
@@ -345,6 +370,7 @@ export default {
     ...mapState([
       'reloadIntervalId',
       'configuration',
+      'isOnline',
     ]),
     ...mapState('projects', [
       'project'
@@ -603,7 +629,11 @@ export default {
   margin-bottom: 1em;
 }
 
-.no-hover {
+.nohover, .nohover:hover {
   cursor: default;
 }
+
+.ui.styled.accordion .nohover.title:hover {
+  color: rgba(0, 0, 0, .4);
+}
 </style>
\ No newline at end of file
diff --git a/src/views/Project/FeaturesListAndMap.vue b/src/views/Project/FeaturesListAndMap.vue
index ea9db05f300cb2b50d84935d6ce58efa863a288e..35135fbc7ded1f3a8025ffdae16bc931995a96a0 100644
--- a/src/views/Project/FeaturesListAndMap.vue
+++ b/src/views/Project/FeaturesListAndMap.vue
@@ -76,7 +76,7 @@
             </div>
 
             <div
-              v-if="checkedFeatures.length > 0 && mode === 'modify'"
+              v-if="checkedFeatures.length > 0 && massMode === 'modify'"
               class="ui dropdown button compact button-hover-green margin-left-25"
               data-tooltip="Modifier le statut des Signalements"
               data-position="bottom right"
@@ -105,11 +105,11 @@
             </div>
 
             <div
-              v-if="checkedFeatures.length > 0 && mode === 'delete'"
+              v-if="checkedFeatures.length > 0 && massMode === 'delete'"
               class="ui button compact button-hover-red margin-left-25"
-              data-tooltip="Effacer tous les types de signalements sélectionnés"
+              data-tooltip="Supprimer tous les signalements sélectionnés"
               data-position="bottom right"
-              @click="modalAllDelete"
+              @click="toggleDeleteModal"
             >
               <i class="grey trash fitted icon" />
             </div>
@@ -197,10 +197,9 @@
     <FeatureListTable
       v-else
       :paginated-features="paginatedFeatures"
+      :page-numbers="pageNumbers"
       :checked-features.sync="checkedFeatures"
       :features-count="featuresCount"
-      :clicked-features.sync="clickedFeatures"
-      :mode.sync="mode"
       :pagination="pagination"
       :sort="sort"
       @update:page="handlePageChange"
@@ -209,19 +208,19 @@
 
     <!-- MODAL ALL DELETE FEATURE TYPE -->
     <div
-      v-if="modalAllDeleteOpen"
+      v-if="isDeleteModalOpen"
       class="ui dimmer modals page transition visible active"
       style="display: flex !important"
     >
       <div
         :class="[
           'ui mini modal subscription',
-          { 'active visible': modalAllDeleteOpen },
+          { 'active visible': isDeleteModalOpen },
         ]"
       >
         <i
           class="close icon"
-          @click="modalAllDeleteOpen = false"
+          @click="isDeleteModalOpen = false"
         />
         <div class="ui icon header">
           <i class="trash alternate icon" />
@@ -244,16 +243,23 @@
 </template>
 
 <script>
-import axios from '@/axios-client.js';
-import featureAPI from '@/services/feature-api';
 
-import { mapGetters, mapState, mapActions } from 'vuex';
+import { mapState, mapGetters, mapActions, mapMutations } from 'vuex';
 import { mapUtil } from '@/assets/js/map-util.js';
 import { allowedStatus2change } from '@/utils';
 
+import featureAPI from '@/services/feature-api';
+
+import SidebarLayers from '@/components/map-layers/SidebarLayers';
+import FeatureListTable from '@/components/feature/FeatureListTable';
 import Dropdown from '@/components/Dropdown.vue';
-import SidebarLayers from '@/components/SidebarLayers';
-import FeatureListTable from '@/components/FeaturesListAndMap/FeatureListTable';
+
+const initialPagination = {
+  currentPage: 1,
+  pagesize: 15,
+  start: 0,
+  end: 15,
+};
 
 export default {
   name: 'FeaturesListAndMap',
@@ -266,7 +272,6 @@ export default {
 
   data() {
     return {
-      clickedFeatures: [],
       currentLayer: null,
       featuresCount: 0,
       form: {
@@ -278,20 +283,12 @@ export default {
         },
         title: null,
       },
+      isDeleteModalOpen: false,
       lat: null,
       lng: null,
       map: null,
-      modalAllDeleteOpen: false,
-      mode: 'modify',
-      next: null,
       paginatedFeatures: [],
-      pagination: {
-        currentPage: 1,
-        pagesize: 15,
-        start: 0,
-        end: 15,
-      },
-      previous: null,
+      pagination: { ...initialPagination },
       projectSlug: this.$route.params.slug,
       showMap: true,
       showAddFeature: false,
@@ -317,7 +314,9 @@ export default {
     ]),
     ...mapState('feature', [
       'checkedFeatures',
+      'clickedFeatures',
       'statusChoices',
+      'massMode',
     ]),
     ...mapState('feature-type', [
       'feature_types',
@@ -349,6 +348,10 @@ export default {
     featureTypeChoices() {
       return this.feature_types.map((el) => el.title);
     },
+
+    pageNumbers() {
+      return this.createPagesArray(this.featuresCount, this.pagination.pagesize);
+    },
   },
 
   watch: {
@@ -418,7 +421,12 @@ export default {
   methods: {
     ...mapActions('feature', [
       'GET_PROJECT_FEATURES',
-      'SEND_FEATURE'
+      'SEND_FEATURE',
+      'DELETE_FEATURE',
+    ]),
+
+    ...mapMutations('feature', [
+      'UPDATE_CHECKED_FEATURES'
     ]),
 
     toggleAddFeature() {
@@ -431,8 +439,8 @@ export default {
       this.showAddFeature = false;
     },
 
-    modalAllDelete() {
-      this.modalAllDeleteOpen = !this.modalAllDeleteOpen;
+    toggleDeleteModal() {
+      this.isDeleteModalOpen = !this.isDeleteModalOpen;
     },
 
     clickOutsideDropdown(e) {
@@ -456,7 +464,9 @@ export default {
             newStatus
           }).then((response) => {
             if (response && response.data && response.status === 200) {
-              this.checkedFeatures.splice(this.checkedFeatures.indexOf(response.data.id), 1);
+              let newCheckedFeatures = [...this.checkedFeatures];
+              newCheckedFeatures.splice(this.checkedFeatures.indexOf(response.data.id), 1);
+              this.UPDATE_CHECKED_FEATURES(newCheckedFeatures);
               this.modifyStatus(newStatus);
             } else {
               this.$store.commit('DISPLAY_MESSAGE', {
@@ -476,33 +486,26 @@ export default {
       }
     },
 
-    deleteFeature(feature_id) {
-      const url = `${this.API_BASE_URL}features/${feature_id}/?project__slug=${this.projectSlug}`;
-      axios //TODO: REFACTO -> Delete function already exist in store
-        .delete(url, {})
-        .then(() => {
-          if (!this.modalAllDeleteOpen) {
-            this.GET_PROJECT_FEATURES({
-              project_slug: this.projectSlug,
-            })
-              .then(() => {
-                this.fetchPagedFeatures();
-                this.checkedFeatures.splice(feature_id);
-              });
-          }
-        })
-        .catch(() => {
-          return false;
-        });
-    },
-
     deleteAllFeatureSelection() {
-      let feature = {};
-      this.checkedFeatures.forEach((feature_id) => {
-        feature = { feature_id: feature_id }; // ? Is this usefull ?
-        this.deleteFeature(feature.feature_id); //? since property feature_id is directly used after...
-      });
-      this.modalAllDelete();
+      const initialFeaturesCount = this.featuresCount;
+      const initialCurrentPage = this.pagination.currentPage;
+      const promises = this.checkedFeatures.map(
+        (feature_id) => this.DELETE_FEATURE({ feature_id, noFeatureType: true })
+      );
+      Promise.all(promises).then((response) => {
+        const deletedFeaturesCount = response.reduce((acc, curr) => curr.status === 204 ? acc += 1 : acc, 0);
+        const newFeaturesCount = initialFeaturesCount - deletedFeaturesCount;
+        const newPagesArray = this.createPagesArray(newFeaturesCount, this.pagination.pagesize);
+        const newLastPageNum = newPagesArray[newPagesArray.length - 1];
+        this.$store.commit('feature/UPDATE_CHECKED_FEATURES', []);
+        if (initialCurrentPage > newLastPageNum) { //* if page doesn't exist anymore
+          this.toPage(newLastPageNum); //* go to new last page
+        } else {
+          this.fetchPagedFeatures();
+        }
+      })
+        .catch((err) => console.error(err));
+      this.toggleDeleteModal();
     },
 
     onFilterChange() {
@@ -560,8 +563,9 @@ export default {
       featureAPI
         .getFeaturesBbox(this.projectSlug, queryParams)
         .then((bbox) => {
-          if (bbox) {
-            mapUtil.getMap().fitBounds(bbox, { padding: [25, 25] });
+          const map = mapUtil.getMap();
+          if (bbox && map) {
+            map.fitBounds(bbox, { padding: [25, 25] });
           }
         });
     },
@@ -600,14 +604,13 @@ export default {
 
     fetchPagedFeatures(newUrl) {
       let url = `${this.API_BASE_URL}projects/${this.projectSlug}/feature-paginated/?output=geojson&limit=${this.pagination.pagesize}&offset=${this.pagination.start}`;
-      //* if receiving next & previous url
+      //* if receiving next & previous url (// todo : might be not used anymore, to check)
       if (newUrl && typeof newUrl === 'string') {
         //newUrl = newUrl.replace("8000", "8010"); //* for dev uncomment to use proxy link
         url = newUrl;
       }
       const queryString = this.buildQueryString();
       url += queryString;
-
       this.$store.commit(
         'DISPLAY_LOADER',
         'Récupération des signalements en cours...'
@@ -630,17 +633,22 @@ export default {
     },
 
     resetPaginationNfetchFeatures() {
-      this.pagination = {
-        currentPage: 1,
-        pagesize: 15,
-        start: 0,
-        end: 15,
-      },
+      this.pagination = { ...initialPagination };
       this.fetchPagedFeatures();
     },
 
     //* Pagination for table *//
 
+    createPagesArray(featuresCount, pagesize) {
+      const totalPages = Math.ceil(
+        featuresCount / pagesize
+      );
+      return [...Array(totalPages).keys()].map((pageNumb) => {
+        ++pageNumb;
+        return pageNumb;
+      });
+    },
+
     handlePageChange(page) {
       if (page === 'next') {
         this.toNextPage();
@@ -676,7 +684,7 @@ export default {
           this.pagination.end -= this.pagination.pagesize;
           this.pagination.currentPage -= 1;
         }
-        this.fetchPagedFeatures(this.previous);
+        this.fetchPagedFeatures();
       }
     },
 
@@ -687,7 +695,7 @@ export default {
           this.pagination.end += this.pagination.pagesize;
           this.pagination.currentPage += 1;
         }
-        this.fetchPagedFeatures(this.next);
+        this.fetchPagedFeatures();
       }
     },
   },
@@ -742,6 +750,10 @@ export default {
   margin-right: 0 !important;
 }
 
+#button-dropdown {
+  z-index: 1;
+}
+
 @media screen and (min-width: 767px) {
   .twelve-wide {
     width: 75% !important;
diff --git a/src/views/Project/ProjectDetail.vue b/src/views/Project/ProjectDetail.vue
index 06b2e8b56eb130f489f880d4ba876b5cd70c46de..c3eea4577ab546913056b2d9510449555ac7d174 100644
--- a/src/views/Project/ProjectDetail.vue
+++ b/src/views/Project/ProjectDetail.vue
@@ -38,6 +38,7 @@
 
       <ProjectHeader
         :arrays-offline="arraysOffline"
+        @retrieveInfo="retrieveProjectInfo"
       />
 
       <div class="ui grid">
@@ -231,6 +232,8 @@ export default {
       'SET_RELOAD_INTERVAL_ID',
       'CLEAR_RELOAD_INTERVAL_ID',
       'DISPLAY_MESSAGE',
+      'DISPLAY_LOADER',
+      'DISCARD_LOADER',
     ]),
     ...mapMutations('modals', [
       'CLOSE_PROJECT_MODAL'
@@ -257,13 +260,13 @@ export default {
     },
 
     retrieveProjectInfo() {
-      this.$store.commit('DISPLAY_LOADER', 'Projet en cours de chargement.');
+      this.DISPLAY_LOADER('Projet en cours de chargement.');
       Promise.all([
         this.GET_PROJECT(this.slug),
         this.GET_PROJECT_INFO(this.slug)
       ])
         .then(() => {
-          this.$store.commit('DISCARD_LOADER');
+          this.DISCARD_LOADER();
           this.projectInfoLoading = false;
           setTimeout(() => {
             let map = mapUtil.getMap();
@@ -273,14 +276,14 @@ export default {
         })
         .catch((err) => {
           console.error(err);
-          this.$store.commit('DISCARD_LOADER');
+          this.DISCARD_LOADER();
           this.projectInfoLoading = false;
         });
     },
 
     checkForOfflineFeature() {
       let arraysOffline = [];
-      let localStorageArray = localStorage.getItem('geocontrib_offline');
+      const localStorageArray = localStorage.getItem('geocontrib_offline');
       if (localStorageArray) {
         arraysOffline = JSON.parse(localStorageArray);
         this.arraysOffline = arraysOffline.filter(
@@ -289,70 +292,6 @@ export default {
       }
     },
 
-    sendOfflineFeatures() {
-      var promises = [];
-      let self = this;
-      this.arraysOfflineErrors = [];
-      this.arraysOffline.forEach((feature) => {
-        if (feature.type === 'post') {
-          promises.push(
-            axios
-              .post(`${this.API_BASE_URL}features/`, feature.geojson)
-              .then((response) => {
-                if (response.status === 201 && response.data) {
-                  return 'OK';
-                } else {
-                  self.arraysOfflineErrors.push(feature);
-                }
-              })
-              .catch((error) => {
-                console.error(error);
-                self.arraysOfflineErrors.push(feature);
-              })
-          );
-        } else if (feature.type === 'put') {
-          promises.push(
-            axios
-              .put(
-                `${this.API_BASE_URL}features/${feature.featureId}`,
-                feature.geojson
-              )
-              .then((response) => {
-                if (response.status === 200 && response.data) {
-                  return 'OK';
-                } else {
-                  self.arraysOfflineErrors.push(feature);
-                }
-              })
-              .catch((error) => {
-                console.error(error);
-                self.arraysOfflineErrors.push(feature);
-              })
-          );
-        }
-      });
-      Promise.all(promises).then(() => {
-        this.updateLocalStorage();
-        window.location.reload();
-      });
-    },
-
-    updateLocalStorage() {
-      let arraysOffline = [];
-      let localStorageArray = localStorage.getItem('geocontrib_offline');
-      if (localStorageArray) {
-        arraysOffline = JSON.parse(localStorageArray);
-      }
-      let arraysOfflineOtherProject = arraysOffline.filter(
-        (x) => x.project !== this.slug
-      );
-      this.arraysOffline = [];
-      arraysOffline = arraysOfflineOtherProject.concat(
-        this.arraysOfflineErrors
-      );
-      localStorage.setItem('geocontrib_offline', JSON.stringify(arraysOffline));
-    },
-
     subscribeProject() {
       projectAPI
         .subscribeProject({
diff --git a/src/views/Projects/ProjectsList.vue b/src/views/Projects/ProjectsList.vue
index 30c0b843b8be4583df5b01b534f1bfdcf6b546d9..0da07cffd48737375f3a721a3b80a7ee08296d90 100644
--- a/src/views/Projects/ProjectsList.vue
+++ b/src/views/Projects/ProjectsList.vue
@@ -9,14 +9,14 @@
 
     <div class="flex">
       <router-link
-        v-if="user && user.can_create_project && isOffline() != true"
+        v-if="user && user.can_create_project && isOnline"
         :to="{ name: 'project_create', params: { action: 'create' } }"
         class="ui green basic button"
       >
         <i class="plus icon" /> Créer un nouveau projet
       </router-link>
       <router-link
-        v-if="user && user.can_create_project && isOffline() != true"
+        v-if="user && user.can_create_project && isOnline"
         :to="{
           name: 'project_type_list',
         }"
@@ -68,16 +68,20 @@
         v-if="!projects || projects.length === 0"
       >Vous n'avez accès à aucun projet.</span>
 
-      <div class="item" />
-    </div>
+      <div
+        :class="{ active: loading }"
+        class="ui inverted dimmer"
+      >
+        <div class="ui loader" />
+      </div>
 
-    <!-- PAGINATION -->
-    <Pagination
-      v-if="count"
-      :nb-pages="Math.ceil(count/10)"
-      :on-page-change="SET_CURRENT_PAGE"
-      @change-page="changePage"
-    />
+      <!-- PAGINATION -->
+      <Pagination
+        v-if="count"
+        :nb-pages="Math.ceil(count/10)"
+        :on-page-change="SET_CURRENT_PAGE"
+        @change-page="changePage"
+      />
   </div>
 </template>
 
@@ -107,12 +111,13 @@ export default {
   computed: {
     ...mapState([
       'configuration',
-      'user'
+      'user',
+      'isOnline',
     ]),
     ...mapState('projects', [
       'projects',
       'count',
-      'filters'
+      'filters',
     ]),
     DJANGO_BASE_URL() {
       return this.$store.state.configuration.VUE_APP_DJANGO_BASE;
@@ -162,13 +167,19 @@ export default {
       'GET_PROJECTS'
     ]),
 
+<<<<<<< HEAD:src/views/Projects/ProjectsList.vue
     isOffline() {
       return navigator.onLine == false;
+=======
+    refreshId() {
+      //* change path of thumbnail to update image
+      return '?ver=' + Math.random();
+>>>>>>> develop:src/views/Projects.vue
     },
 
     getData(page) {
       this.loading = true;
-      this.GET_PROJECTS(page)
+      this.GET_PROJECTS({ page })
         .then(() => {
           this.loading = false;
         })