<template> <div v-frag> <div v-frag v-if="permissions.can_view_project && project"> <div id="message" class="fullwidth"> <div v-if="tempMessage" class="ui positive message"> <!-- <i class="close icon"></i> --> <!-- <div class="header">You are eligible for a reward</div> --> <p><i class="check icon"></i> {{ tempMessage }}</p> </div> </div> <div class="row"> <div class="four wide middle aligned column"> <img class="ui small spaced image" :src=" project.thumbnail.includes('default') ? require('@/assets/img/default.png') : DJANGO_BASE_URL + project.thumbnail " /> <div class="ui hidden divider"></div> <div class="ui basic teal label" data-tooltip="Membres"> <i class="user icon"></i>{{ project.nb_contributors }} </div> <div class="ui basic teal label" data-tooltip="Signalements"> <i class="map marker icon"></i>{{ project.nb_published_features }} </div> <div class="ui basic teal label" data-tooltip="Commentaires"> <i class="comment icon"></i >{{ project.nb_published_features_comments }} </div> </div> <div class="ten wide column"> <h1 class="ui header"> <div class="content"> {{ project.title }} <div class="ui icon right floated compact buttons"> <!-- {% if permissions|lookup:'can_view_project' %} --> <a id="subscribe-button" class="ui button button-hover-green" data-tooltip="S'abonner au projet" data-position="top center" data-variation="mini" @click="isModalOpen = true" > <i class="inverted grey envelope icon"></i> </a> <!-- {% endif %} {% if project and permissions|lookup:'can_update_project' %} --> <router-link v-if="user" :to="{ name: 'project_edit', params: { slug: project.slug } }" class="ui button button-hover-orange" data-tooltip="Modifier le projet" data-position="top center" data-variation="mini" > <i class="inverted grey pencil alternate icon"></i> </router-link> <!-- {% endif %} --> </div> <div class="ui hidden divider"></div> <div class="sub header"> {{ project.description }} <!-- {{ project.description | linebreaks }} --> </div> </div> </h1> </div> </div> <div class="row"> <div class="seven wide column"> <h3 class="ui header">Types de signalements</h3> <!-- // todo : Create endpoints for feature_types --> <div class="ui middle aligned divided list"> <div v-for="(type, index) in feature_types" :key="type.title + '-' + index" class="item" > <div class="middle aligned content"> <router-link :to="{ name: 'details-type-signalement', params: { feature_type_slug: type.slug }, }" > <img v-if="type.geom_type == 'point'" class="list-image-type" src="@/assets/img/marker.png" /> <img v-if="type.geom_type == 'linestring'" class="list-image-type" src="@/assets/img/line.png" /> <img v-if="type.geom_type == 'polygon'" class="list-image-type" src="@/assets/img/polygon.png" /> {{ type.title }} </router-link> <!-- {% if project and feature_types and permissions|lookup:'can_create_feature' %} --> <!-- // todo: add permissions.can_create_feature and type.is_editable --> <!-- v-if=" project && permissions.can_create_feature && type.is_editable " --> <router-link :to="{ name: 'ajouter-signalement', params: { slug_type_signal: type.slug }, }" v-if="project && permissions.can_create_feature" class=" ui compact small icon right floated button button-hover-green " data-tooltip="Ajouter un signalement" data-position="left center" data-variation="mini" ><!-- // todo : adapt --> <i class="ui plus icon"></i> </router-link> <router-link :to="{ name: 'dupliquer-type-signalement', params: { slug_type_signal: type.slug }, }" v-if="project && permissions.can_create_feature" class=" ui compact small icon right floated button button-hover-green " data-tooltip="Dupliquer un type de signalement" data-position="left center" data-variation="mini" ><!-- // todo : adapt --> <i class="inverted grey copy alternate icon"></i> </router-link> <router-link :to="{ name: 'editer-type-signalement', params: { slug_type_signal: type.slug }, }" v-if="project" class=" ui compact small icon right floated button button-hover-green " data-tooltip="Éditer le type de signalement" data-position="left center" data-variation="mini" > <i class="inverted grey pencil alternate icon"></i> </router-link> <!-- {% endif %} --> </div> </div> <div v-if="feature_types.length === 0"> <i> Le projet ne contient pas encore de type de signalements. </i> </div> </div> <!-- // todo: gérer permissions: {% if project and permissions|lookup:'can_update_project' %} --> <div class="nouveau-type-signalement"> <router-link :to="{ name: 'ajouter-type-signalement', params: { slug: project.slug }, }" class="ui compact basic button button-hover-green" > <i class="ui plus icon"></i>Créer un nouveau type de signalement </router-link> </div> <div class="nouveau-type-signalement"> <div class="ui compact basic button button-hover-green"> <div onclick="document.getElementById('json_file').click()"> <label class="ui" for="json_file"> <i class="ui plus icon"></i> <span class="label" >Créer un nouveau type de signalement à partir d'un GeoJSON</span > </label> <input type="file" accept="application/json, .json, .geojson" style="display: none" name="json_file" id="json_file" @change="onFileChange" /> </div> </div> <br /> <div id="button-import" v-if="fileToImport.size > 0"> <button :disabled="fileToImport.size == 0" @click="toNewFeatureType" class="ui fluid teal icon button" > <i class="upload icon"></i> Lancer l'import avec le fichier {{ fileToImport.name }} </button> </div> </div> </div> <div class="seven wide column"> <div id="map"></div> </div> </div> <div class="row"> <div class="fourteen wide column"> <div class="ui two stackable cards"> <div class="red card"> <div class="content"> <div class="center aligned header">Derniers signalements</div> <div class="center aligned description"> <div class="ui relaxed list"> <div v-for="(item, index) in last_features" :key="item.title + index" class="item" > <div class="content"> <div> <router-link :to="{ name: 'details-signalement', params: { slug: project.slug, slug_type_signal: item.feature_type.slug, slug_signal: item.feature_id, }, }" >{{ item.title || item.feature_id }}</router-link > </div> <div class="description"> <i >[{{ item.created_on | setDate }}<span v-if="user && item.display_creator" >, par {{ item.display_creator }} </span> ]</i > </div> </div> </div> <i v-if="last_features.length === 0" >Aucun signalement pour le moment.</i > </div> </div> </div> </div> <div class="orange card"> <div class="content"> <div class="center aligned header">Derniers commentaires</div> <div class="center aligned description"> <div class="ui relaxed list"> <div v-for="(item, index) in last_comments" :key="'comment ' + index" class="item" > <div class="content"> <div> <router-link :to="item.related_feature.feature_url" >"{{ item.comment }}"</router-link > </div> <div class="description"> <i >[ {{ item.created_on }}<span v-if="user && item.display_author" >, par {{ item.display_author }} </span> ]</i > </div> </div> </div> <i v-if="!last_comments || last_comments.length === 0" >Aucun commentaire pour le moment.</i > </div> </div> </div> </div> </div> </div> </div> <div class="row"> <div class="fourteen wide column"> <div class="ui grey segment"> <h3 class="ui header">Paramètres du projet</h3> <div class="ui five stackable cards"> <div class="card"> <div class="center aligned content"> <h4 class="ui center aligned icon header"> <i class="disabled grey archive icon"></i> <div class="content">Délai avant archivage automatique</div> </h4> </div> <div class="center aligned extra content"> <!-- {{ project.archive_feature|default_if_none:"0" }} jours --> {{ project.archive_feature }} jours </div> </div> <div class="card"> <div class="content"> <h4 class="ui center aligned icon header"> <i class="disabled grey trash alternate icon"></i> <div class="content"> Délai avant suppression automatique </div> </h4> </div> <div class="center aligned extra content"> <!-- {{ project.delete_feature|default_if_none:"0" }} jours --> {{ project.delete_feature }} jours </div> </div> <div class="card"> <div class="content"> <h4 class="ui center aligned icon header"> <i class="disabled grey eye icon"></i> <div class="content"> Visibilité des signalements publiés </div> </h4> </div> <div class="center aligned extra content"> {{ project.access_level_pub_feature }} </div> </div> <div class="card"> <div class="content"> <h4 class="ui center aligned icon header"> <i class="disabled grey eye icon"></i> <div class="content"> Visibilité des signalements archivés </div> </h4> </div> <div class="center aligned extra content"> {{ project.access_level_arch_feature }} </div> </div> <div class="card"> <div class="content"> <h4 class="ui center aligned icon header"> <i class="disabled grey cogs icon"></i> <div class="content">Modération</div> </h4> </div> <div class="center aligned extra content"> {{ project.moderation ? "Oui" : "Non" }} </div> </div> </div> </div> </div> </div> </div> <!-- {% else %} --> <span v-else-if="!permissions.can_view_project"> <i class="icon exclamation triangle"></i> <span >Vous ne disposez pas des droits nécessaires pour consulter ce projet.</span > </span> <!-- {% endif %} --> <div v-if="isModalOpen" class="ui dimmer modals page transition visible active" style="display: flex !important" > <div :class="[ 'ui mini modal subscription', { 'transition visible active': isModalOpen }, ]" > <i @click="isModalOpen = false" class="close icon"></i> <div class="ui icon header"> <i class="envelope icon"></i> Notifications du projet </div> <div class="content"> <!-- {% if is_suscriber %} --> <!-- <form action="{% url 'geocontrib:subscription' slug=project.slug action='annuler' %}" method="GET" > --> <button v-if="is_suscriber" class="ui red compact fluid button"> Se désabonner de ce projet </button> <!-- </form> --> <!-- {% else %} --> <!-- <form action="{% url 'geocontrib:subscription' slug=project.slug action='ajouter' %}" method="GET" > --> <button v-else @click="subsribeProject" class="ui green compact fluid button" > <!-- <button type="submit" class="ui green compact fluid button"> --> S'abonner à ce projet </button> <!-- </form> --> <!-- {% endif %} --> </div> <!-- </div> --> </div> </div> </div> </template> <script> import frag from "vue-frag"; import { mapGetters, mapState } from "vuex"; export default { name: "Project_details", props: ["message"], directives: { frag, }, filters: { setDate: function (value) { let date = new Date(value); let d = date.toLocaleDateString("fr", { year: "2-digit", month: "numeric", day: "numeric", }); return d; }, }, data() { return { geojsonImport: [], fileToImport: { name: "", size: 0 }, slug: this.$route.params.slug, isModalOpen: false, is_suscriber: false, permissions: { can_view_project: true, can_create_feature: true, }, tempMessage: null, }; }, computed: { ...mapGetters(["project"]), ...mapState("feature_type", ["feature_types"]), ...mapState(["last_comments", "user"]), DJANGO_BASE_URL: () => process.env.VUE_APP_DJANGO_BASE, last_features: function () { // * limit to last five element of array (looks sorted chronologically, but not sure...) return this.$store.state.feature.features.slice(-5); }, }, methods: { toNewFeatureType() { this.$router.push({ name: "ajouter-type-signalement", params: { geojson: this.geojsonImport, fileToImport: this.fileToImport, }, }); }, onFileChange(e) { var files = e.target.files || e.dataTransfer.files; if (!files.length) return; this.fileToImport = files[0]; // TODO : VALIDATION IF FILE IS JSON if (this.fileToImport.size > 0) { const fr = new FileReader(); fr.onload = (e) => { this.geojsonImport = JSON.parse(e.target.result); }; fr.readAsText(this.fileToImport); //* stock filename to import features afterward this.$store.commit( "feature_type/SET_FILE_TO_IMPORT", this.fileToImport ); } }, subsribeProject() { //console.log("Subsribe to project"); }, }, created() { this.$store.dispatch("GET_PROJECT_INFO", this.slug); }, mounted() { if (this.project) { this.$store.dispatch("map/INITIATE_MAP"); } if (this.message) { this.tempMessage = this.message; document .getElementById("message") .scrollIntoView({ block: "end", inline: "nearest" }); setTimeout(() => { this.tempMessage = null; }, 5000); } }, }; </script> <style> @import "../../assets/resources/semantic-ui-2.4.2/semantic.min.css"; #map { width: 100%; height: 100%; min-height: 250px; } .list-image-type { margin-right: 5px; height: 25px; vertical-align: bottom; } /* // ! missing style in semantic.min.css, je ne comprends pas comment... */ .ui.right.floated.button { float: right; margin: 0 0 0 1em; } .nouveau-type-signalement { padding-top: 1em; } #button-import { padding-top: 0.5em; } .fullwidth { width: 100%; } </style>