You need to sign in or sign up before continuing.
Newer
Older
<template>
<div class="fourteen wide column">
<script
type="application/javascript"
:src="
baseUrl +
'/resources/leaflet-control-geocoder-1.13.0/Control.Geocoder.js'
"
></script>
<div id="feature-list-container" class="ui grid mobile-column">
<div class="four wide column mobile-fullwidth">
<h1>Signalements</h1>
</div>
<div class="twelve-wide column no-padding-mobile mobile-fullwidth">
<a
@click="showMap = true"
data-tab="map"
data-tooltip="Carte"
><i class="map fitted icon"></i
></a>
<a
@click="showMap = false"
data-tab="list"
data-tooltip="Liste"
><i class="list fitted icon"></i
></a>
<div class="item">
<h4>

Timothee P
committed
{{ filteredFeatures.length }} signalement{{
filteredFeatures.length > 1 ? "s" : ""
}}
</h4>
</div>
<div
v-if="project && feature_types && permissions.can_create_feature"
class="item right"
>
<div
@click="showAddFeature = !showAddFeature"
data-tooltip="Ajouter un signalement"
data-position="bottom left"
>
<i class="plus fitted icon"></i>
class="menu transition visible"
style="z-index: 9999"
>
<div class="header">Ajouter un signalement du type</div>
<div class="scrolling menu text-wrap">
<router-link
:to="{
name: 'ajouter-signalement',
v-for="(type, index) in feature_types"
:key="type.slug + index"
class="item"
>
{{ type.title }}
</router-link>
</div>
</div>
</div>
<div
v-if="checkedFeatures.length"
class="ui button compact button-hover-red margin-left-25"
data-tooltip="Effacer tous les types de signalements sélectionnés"
data-position="left center"
data-variation="mini"
>
<i class="grey trash fitted icon" @click="modalAllDelete"></i>
</div>
</div>
</div>
</div>
<form id="form-filters" class="ui form grid" action="" method="get">
<label>Type</label>
:options="form.type.choices"
:selected="form.type.selected"
:selection.sync="form.type.selected"
</div>
<div class="field wide four column no-padding-mobile no-margin-mobile">
<label>Statut</label>
<!-- //* giving an object mapped on key name -->
@update:selection="onFilterStatusChange($event)"
:options="form.status.choices"
:selected="form.status.selected.name"
:selection.sync="form.status.selected"
</div>
<div class="field wide four column">
<label>Nom</label>
<div class="ui icon input">
<i class="search icon"></i>
<div class="ui action input">
<input
type="text"
name="title"
v-model="form.title"
@input="onFilterChange()"
/>
<button
type="button"
class="ui teal icon button"
id="submit-search"
>
<i class="search icon"></i>
</button>
</div>
</div>
</div>
<!-- map params, updated on map move // todo : brancher sur la carte probablement -->
<input type="hidden" name="zoom" v-model="zoom" />
<input type="hidden" name="lat" v-model="lat" />
<input type="hidden" name="lng" v-model="lng" />
</form>
<div v-show="showMap" class="ui tab active map-container" data-tab="map">
<div id="map"></div>
</div>
<FeatureListTable
v-show="!showMap"
:filteredFeatures="filteredFeatures"
:user="user"
:checkedFeatures.sync="checkedFeatures"
/>
<!-- MODAL ALL DELETE FEATURE TYPE -->
<div
v-if="modalAllDeleteOpen"
class="ui dimmer modals page transition visible active"
style="display: flex !important"
<div
:class="[
'ui mini modal subscription',
{ 'active visible': modalAllDeleteOpen },
]"
>
<i @click="modalAllDeleteOpen = false" class="close icon"></i>
<div class="ui icon header">
<i class="trash alternate icon"></i>
<span v-if="checkedFeatures.length === 1"> un signalement ? </span>
<span v-else> ces {{ checkedFeatures.length }} signalements ? </span>

Timothee P
committed
@click="deleteAllFeatureSelection"
type="button"
class="ui red compact fluid button"
>
Confirmer la suppression
</button>
</div>
</template>
<script>
import { mapGetters, mapState } from "vuex";
import { mapUtil } from "@/assets/js/map-util.js";
import SidebarLayers from "@/components/map-layers/SidebarLayers";
import FeatureListTable from "@/components/feature/FeatureListTable";
import Dropdown from "@/components/Dropdown.vue";
export default {
name: "Feature_list",
components: {
SidebarLayers,
data() {
return {
form: {
type: {
choices: [],
},
status: {
selected: {
name: null,
{
name: "Brouillon",
value: "draft",
},
{
name: "En attente de publication",
value: "pending",
},
{
name: "Publié",
value: "published",
},
{
name: "Archivé",
value: "archived",
},

Timothee P
committed
geojsonFeatures: [],
filterStatus: null,
filterType: null,
baseUrl: this.$store.state.configuration.BASE_URL,
map: null,
zoom: null,
lat: null,
lng: null,
showAddFeature: false,
};
},
computed: {
...mapState("feature", ["features"]),
...mapState("feature_type", ["feature_types"]),

Timothee P
committed
filteredFeatures() {
let results = this.geojsonFeatures;
if (this.filterType) {
results = results.filter(
(el) => el.properties.feature_type.title === this.filterType
);
}
if (this.filterStatus) {
console.log("filter by" + this.filterStatus);
results = results.filter(
(el) => el.properties.status.value === this.filterStatus
);
}
if (this.form.title) {
results = results.filter((el) => {
if (el.properties.title) {
return el.properties.title
.toLowerCase()
.includes(this.form.title.toLowerCase());
} else
return el.id.toLowerCase().includes(this.form.title.toLowerCase());

Timothee P
committed
}
return results;

Timothee P
committed
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
},
methods: {
modalAllDelete() {
this.modalAllDeleteOpen = !this.modalAllDeleteOpen;
},
deleteFeature(feature) {
const url = `${this.$store.state.configuration.VUE_APP_DJANGO_API_BASE}features/${feature.feature_id}`;
axios
.delete(url, {})
.then(() => {
if (!this.modalAllDeleteOpen) {
this.$router.go();
}
})
.catch(() => {
return false;
});
},
deleteAllFeatureSelection() {
let feature = {};
this.checkedFeatures.forEach((feature_id) => {
feature = { feature_id: feature_id };
this.deleteFeature(feature);
});
this.modalAllDelete();
},
onFilterStatusChange(newvalue) {
this.filterStatus = null;
if (newvalue) {
console.log("filter change", newvalue.value);
this.filterStatus = newvalue.value;

Timothee P
committed
onFilterTypeChange(newvalue) {
this.filterType = null;
if (newvalue) {
console.log("filter change", newvalue);
this.filterType = newvalue;

Timothee P
committed
var features = this.filteredFeatures;
this.featureGroup.clearLayers();
this.featureGroup = mapUtil.addFeatures(features, {});
mapUtil
.getMap()
.fitBounds(this.featureGroup.getBounds(), { padding: [25, 25] });

Timothee P
committed
initMap() {
this.zoom = this.$route.query.zoom || "";
this.lat = this.$route.query.lat || "";
this.lng = this.$route.query.lng || "";
var mapDefaultViewCenter =
this.$store.state.configuration.DEFAULT_MAP_VIEW.center;
var mapDefaultViewZoom =
this.$store.state.configuration.DEFAULT_MAP_VIEW.zoom;
this.map = mapUtil.createMap({
zoom: this.zoom,
lat: this.lat,
lng: this.lng,
mapDefaultViewCenter,
mapDefaultViewZoom,
});
document.addEventListener("change-layers-order", (event) => {
// Reverse is done because the first layer in order has to be added in the map in last.
// Slice is done because reverse() changes the original array, so we make a copy first
mapUtil.updateOrder(event.detail.layers.slice().reverse());
});

Timothee P
committed
// --------- End sidebar events ----------
if (this.$store.state.map.geojsonFeatures) {
this.loadFeatures(this.$store.state.map.geojsonFeatures);
} else {
const url = `${this.$store.state.configuration.VUE_APP_DJANGO_API_BASE}projects/${this.$route.params.slug}/feature/?output=geojson`;
this.$store.commit(
"DISPLAY_LOADER",
"Récupération des signalements en cours..."
);
axios
.get(url)
.then((response) => {
this.loadFeatures(response.data.features);
this.$store.commit("DISCARD_LOADER");
this.$store.commit("DISCARD_LOADER");
setTimeout(
function () {
mapUtil.addGeocoders(this.$store.state.configuration);
}.bind(this),
1000
);

Timothee P
committed
this.geojsonFeatures = features;
const urlParams = new URLSearchParams(window.location.search);
const featureType = urlParams.get("feature_type");
const featureStatus = urlParams.get("status");
const featureTitle = urlParams.get("title");
this.featureGroup = mapUtil.addFeatures(this.geojsonFeatures, {
featureType,
featureStatus,
featureTitle,
});
// Fit the map to bound only if no initial zoom and center are defined
if (
(this.lat === "" || this.lng === "" || this.zoom === "") &&
this.geojsonFeatures.length > 0
) {
mapUtil
.getMap()
.fitBounds(this.featureGroup.getBounds(), { padding: [25, 25] });
//* converting Set to an Array with spread "..."
...new Set(
this.geojsonFeatures.map((el) => el.properties.feature_type.title)
), //* use Set to eliminate duplicate values
];
created() {
if (!this.project) {
//this.$store.dispatch("GET_PROJECT_MESSAGES", this.$route.params.slug);
this.$store.dispatch("GET_PROJECT_INFO", this.$route.params.slug);
}
},

Timothee P
committed
mounted() {
},
destroyed() {
//* allow user to change page if ever stuck on loader
this.$store.commit("DISCARD_LOADER");
},
};
</script>
#map {
width: 100%;
min-height: 300px;
height: calc(100vh - 300px);
border: 1px solid grey;
/* To not hide the filters */
z-index: 1;
}
justify-content: flex-start;
}
#feature-list-container .ui.menu:not(.vertical) .right.item {
padding-right: 0;
}
.map-container {
width: 80vw;
transform: translateX(-50%);
margin-left: 50%;
}
.margin-left-25 {
margin-left: 0.25em !important;
}
.no-margin {
margin: 0 !important;
}
.no-padding {
padding: 0 !important;
}
@media screen and (min-width: 767px) {
.twelve-wide {
@media screen and (max-width: 767px) {
#feature-list-container > .mobile-fullwidth {
width: 100% !important;
}
.no-margin-mobile {
margin: 0 !important;
}
.no-padding-mobile {
padding-top: 0 !important;
padding-bottom: 0 !important;
}
.mobile-column {
flex-direction: column !important;
}
#form-filters > .field.column {
width: 100% !important;
}
.map-container {
width: 100%;
}
}