Newer
Older
Sébastien DA ROCHA
committed
<template>
<div
:class="{ active: loading }"
class="ui inverted dimmer"
>
<div class="ui text loader">
Projet en cours de création. Vous allez être redirigé.
</div>
</div>
<form
id="form-project-edit"
class="ui form"
>
Sébastien DA ROCHA
committed
<h1>
<span
v-if="action === 'edit'"
>Édition du projet "{{ form.title }}"</span>
Sébastien DA ROCHA
committed
<span v-else-if="action === 'create'">Création d'un projet</span>
</h1>
<div class="ui horizontal divider">
INFORMATIONS
</div>
Sébastien DA ROCHA
committed
<div class="two fields">
<div class="required field">
<label for="title">Titre</label>
<input
Sébastien DA ROCHA
committed
type="text"
required
maxlength="128"
name="title"
>
<ul
id="errorlist-title"
class="errorlist"
>
<li
v-for="error in errors.title"
:key="error"
>
Sébastien DA ROCHA
committed
</div>
<div class="field">
<label>Illustration du projet</label>
<img
v-if="thumbnailFileSrc.length || form.thumbnail.length"
Sébastien DA ROCHA
committed
id="form-input-file-logo"
Sébastien DA ROCHA
committed
:src="
thumbnailFileSrc
? thumbnailFileSrc
: DJANGO_BASE_URL + form.thumbnail
"
>
<label
class="ui icon button"
for="thumbnail"
>
Sébastien DA ROCHA
committed
<span class="label">{{
form.thumbnail_name ? form.thumbnail_name : fileToImport.name
}}</span>
</label>
<input
Sébastien DA ROCHA
committed
class="file-selection"
type="file"
accept="image/jpeg, image/png"
style="display: none"
name="thumbnail"
<ul
v-if="errorThumbnail.length"
id="errorlist-thumbnail"
class="errorlist"
>
Sébastien DA ROCHA
committed
</div>
</div>
<div class="field">
<label for="description">Description</label>
<textarea
v-model="form.description"
name="description"
rows="5"
Sébastien DA ROCHA
committed
<!-- {{ form.description.errors }} -->
</div>
<div class="ui horizontal divider">
PARAMÈTRES
</div>
Sébastien DA ROCHA
committed
<div class="two fields">
<!-- <div class="field">
Sébastien DA ROCHA
committed
<label for="archive_feature">Délai avant archivage</label>
<div class="ui right labeled input">
<input
id="archive_feature"
v-model="form.archive_feature"
Sébastien DA ROCHA
committed
type="number"
min="0"
Sébastien DA ROCHA
committed
style="padding: 1px 2px"
name="archive_feature"
>
<div class="ui label">
jour(s)
</div>
Sébastien DA ROCHA
committed
</div>
<ul
v-if="errors_archive_feature.length"
id="errorlist-achivage"
class="errorlist"
>
<li>
{{ errors_archive_feature[0] }}
</li>
</ul>
Sébastien DA ROCHA
committed
</div>
<div class="field">
<label for="delete_feature">Délai avant suppression</label>
<div class="ui right labeled input">
<input
id="delete_feature"
v-model="form.delete_feature"
Sébastien DA ROCHA
committed
type="number"
min="0"
Sébastien DA ROCHA
committed
style="padding: 1px 2px"
name="delete_feature"
>
<div class="ui label">
jour(s)
</div>
Sébastien DA ROCHA
committed
</div>
Sébastien DA ROCHA
committed
<div class="required field">
<label
for="access_level_pub_feature"
>Visibilité des signalements publiés</label>
Sébastien DA ROCHA
committed
<Dropdown
Sébastien DA ROCHA
committed
:selected="form.access_level_pub_feature.name"
:selection.sync="form.access_level_pub_feature"
/>
<ul
id="errorlist-access_level_pub_feature"
class="errorlist"
>
<li
v-for="error in errors.access_level_pub_feature"
:key="error"
>
Sébastien DA ROCHA
committed
</div>
<div class="required field">
<label for="access_level_arch_feature">
Visibilité des signalements archivés
</label>
<Dropdown
:options="levelPermissions"
:selected="form.access_level_arch_feature.name"
:selection.sync="form.access_level_arch_feature"
/>
<ul
id="errorlist-access_level_arch_feature"
class="errorlist"
>
<li
v-for="error in errors.access_level_arch_feature"
:key="error"
>
Sébastien DA ROCHA
committed
</div>
</div>
<div class="field">
<div class="ui checkbox">
<input
class="hidden"
Sébastien DA ROCHA
committed
type="checkbox"
name="moderation"
Sébastien DA ROCHA
committed
<label for="moderation">Modération</label>
</div>
</div>
<div class="field">
<div class="ui checkbox">
<input
class="hidden"
Sébastien DA ROCHA
committed
type="checkbox"
name="is_project_type"
Sébastien DA ROCHA
committed
<label for="is_project_type">Est un projet type</label>
</div>
</div>
<div class="field">
<div class="ui checkbox">
<input
id="generate_share_link"
v-model="form.generate_share_link"
class="hidden"
type="checkbox"
name="generate_share_link"
>
<label for="generate_share_link">Génération d'un lien de partage externe</label>
</div>
Sébastien DA ROCHA
committed
</div>
Sébastien DA ROCHA
committed
<button
type="button"
class="ui teal icon button"
@click="postForm"
>
<i
class="white save icon"
aria-hidden="true"
/> Enregistrer les changements
Sébastien DA ROCHA
committed
</button>
</form>
</div>
</template>
<script>
import Dropdown from '@/components/Dropdown.vue';
Sébastien DA ROCHA
committed
import { mapState, mapActions } from 'vuex';
Sébastien DA ROCHA
committed
export default {
Sébastien DA ROCHA
committed
components: {
Dropdown,
},
data() {
return {
Sébastien DA ROCHA
committed
fileToImport: {
Sébastien DA ROCHA
committed
size: 0,
},
errors: {
title: [],
access_level_pub_feature: [],
access_level_arch_feature: [],
},
Sébastien DA ROCHA
committed
form: {
title: '',
slug: '',
created_on: '',
updated_on: '',
description: '',
Sébastien DA ROCHA
committed
moderation: false,
thumbnail: '', // todo : utiliser l'image par défaut
thumbnail_name: '', // todo: delete after getting image in jpg or png instead of data64 (require post to django)
Sébastien DA ROCHA
committed
creator: null,
access_level_pub_feature: { name: '', value: '' },
access_level_arch_feature: { name: '', value: '' },
Sébastien DA ROCHA
committed
archive_feature: 0,
delete_feature: 0,
nb_features: 0,
nb_published_features: 0,
nb_comments: 0,
nb_published_features_comments: 0,
nb_contributors: 0,
is_project_type: false,
generate_share_link: false,
Sébastien DA ROCHA
committed
},
Sébastien DA ROCHA
committed
};
},
computed: {
...mapState('projects', ['project']),
Sébastien DA ROCHA
committed
return this.$store.state.configuration.VUE_APP_DJANGO_BASE;
},
const levels = new Array();
if(this.levelsPermissions) {
this.levelsPermissions.forEach((item) => {
name: this.translateRoleToFrench(item.user_type_id),
}
if (!this.form.moderation && item.user_type_id == 'moderator') {
const levels = new Array();
if (this.levelsPermissions) {
this.levelsPermissions.forEach((item) => {
if (
item.user_type_id !== 'super_contributor' &&
item.user_type_id !== 'admin' &&
item.user_type_id !== 'moderator'
) {
name: this.translateRoleToFrench(item.user_type_id),
Sébastien DA ROCHA
committed
},
watch: {
'form.moderation': function (newValue){
if(!newValue && this.form.access_level_arch_feature.value === 'moderator') {
this.form.access_level_arch_feature = { name: '', value: '' };
}
}
},
created() {
this.definePageType();
if (this.action === 'create') {
this.thumbnailFileSrc = require('@/assets/img/default.png');
} else if (this.action === 'edit' || this.action === 'create_from') {
if (!this.project) {
this.$store.dispatch('projects/GET_PROJECT', this.$route.params.slug)
.then((projet) => {
});
} else {
this.fillProjectForm();
}
Sébastien DA ROCHA
committed
methods: {
Sébastien DA ROCHA
committed
definePageType() {
if (this.$router.history.current.name === 'project_create') {
this.action = 'create';
} else if (this.$router.history.current.name === 'project_edit') {
this.action = 'edit';
} else if (this.$router.history.current.name === 'project_create_from') {
this.action = 'create_from';
Sébastien DA ROCHA
committed
}
},
translateRoleToFrench(role){
switch (role) {
case 'admin':
return 'Administrateur projet';
case 'moderator':
return 'Modérateur';
case 'contributor':
return 'Contributeur';
case 'logged_user':
return 'Utilisateur connecté';
case 'anonymous':
return 'Utilisateur anonyme';
}
Sébastien DA ROCHA
committed
truncate(n, len) {
const ext = n.substring(n.lastIndexOf('.') + 1, n.length).toLowerCase();
Sébastien DA ROCHA
committed
if (filename.length <= len) {
return n;
}
filename = filename.substr(0, len) + (n.length > len ? '[...]' : '');
return filename + '.' + ext;
Sébastien DA ROCHA
committed
},
const url = window.URL || window.webkitURL;
const image = new Image();
image.onload = function () {
handleFile(true);
};
image.onerror = function () {
handleFile(false);
};
image.src = url.createObjectURL(files);
},
Sébastien DA ROCHA
committed
onFileChange(e) {
// * read image file
const files = e.target.files || e.dataTransfer.files;
const _this = this; //* 'this' is different in onload function
function handleFile(isValid) {
if (isValid) {
_this.fileToImport = files[0]; //* store the file to post later
const reader = new FileReader(); //* read the file to display in the page
reader.onload = function (e) {
_this.thumbnailFileSrc = e.target.result;
};
reader.readAsDataURL(_this.fileToImport);
_this.errorThumbnail = [];
} else {
_this.errorThumbnail.push(
"Transférez une image valide. Le fichier que vous avez transféré n'est pas une image, ou il est corrompu."
);
}
}
if (files.length) {
//* check if file is an image and pass callback to handle file
this.validateImgFile(files[0], handleFile);
}
Sébastien DA ROCHA
committed
},
if (!this.form.archive_feature) {
this.form.archive_feature = 0;
}
if (!this.form.delete_feature) {
this.form.delete_feature = 0;
}
Sébastien DA ROCHA
committed
goBackNrefresh(slug) {
this.$store.dispatch('GET_USER_LEVEL_PROJECTS'), //* refresh projects user levels
this.$store.dispatch('GET_USER_LEVEL_PERMISSIONS'), //* refresh projects permissions
]).then(() =>
// * go back to project list
this.$router.push({
Sébastien DA ROCHA
committed
params: { slug },
Sébastien DA ROCHA
committed
);
},
postProjectThumbnail(projectSlug) {
//* send img to the backend when feature_type is created
if (this.fileToImport) {
formData.append('file', this.fileToImport);
const url =
this.$store.state.configuration.VUE_APP_DJANGO_API_BASE +
return axios
.put(url, formData, {
headers: {
},
})
.then((response) => {
if (response && response.status === 200) {
this.goBackNrefresh(projectSlug);
}
})
.catch((error) => {
let err_msg =
"Transférez une image valide. Le fichier que vous avez transféré n'est pas une image, ou il est corrompu.";
if (error.response.data[0]) {
err_msg = error.response.data[0];
}
this.errorThumbnail.push(err_msg);
throw error;
});
}
Sébastien DA ROCHA
committed
},
if (this.form.archive_feature > this.form.delete_feature) {
this.errors_archive_feature.push(
"Le délais de suppression doit être supérieur au délais d'archivage."
);
if ((key === 'title' && this.form[key]) || this.form[key].value) {
this.errors[key] = [];
} else if (!this.errors[key].length) {
this.errors[key].push(
key === 'title'
? 'Veuillez compléter ce champ.'
: 'Sélectionnez un choix valide. Ce choix ne fait pas partie de ceux disponibles.'
);
document
.getElementById(`errorlist-${key}`)
.scrollIntoView({ block: 'end', inline: 'nearest' });
return false;
}
}
return true;
},
Sébastien DA ROCHA
committed
async postForm() {
Sébastien DA ROCHA
committed
const projectData = {
title: this.form.title,
description: this.form.description,
access_level_arch_feature: this.form.access_level_arch_feature.value,
access_level_pub_feature: this.form.access_level_pub_feature.value,
archive_feature: this.form.archive_feature,
delete_feature: this.form.delete_feature,
is_project_type: this.form.is_project_type,
generate_share_link: this.form.generate_share_link,
Sébastien DA ROCHA
committed
moderation: this.form.moderation,
};
let url = `${this.$store.state.configuration.VUE_APP_DJANGO_API_BASE}projects/`;
Sébastien DA ROCHA
committed
Sébastien DA ROCHA
committed
await axios
.put((url += `${this.project.slug}/`), projectData)
Sébastien DA ROCHA
committed
.then((response) => {
if (response && response.status === 200) {
//* send thumbnail after feature_type was updated
Sébastien DA ROCHA
committed
}
})
.catch((error) => {
if (error.response && error.response.data.title[0]) {
this.errors.title.push(error.response.data.title[0]);
}
Sébastien DA ROCHA
committed
throw error;
});
url += `${this.project.slug}/duplicate/`;
}
this.loading = true;
Sébastien DA ROCHA
committed
await axios
Sébastien DA ROCHA
committed
.then((response) => {
if (response && response.status === 201 && response.data) {
//* send thumbnail after feature_type was created
Sébastien DA ROCHA
committed
}
Sébastien DA ROCHA
committed
})
.catch((error) => {
if (error.response && error.response.data.title[0]) {
this.errors.title.push(error.response.data.title[0]);
}
Sébastien DA ROCHA
committed
throw error;
});
}
},

Timothee P
committed
this.form = { ...this.project }; //* create a new object to avoid modifying original one
if (this.action === 'create_from') { //* if duplication of project, generate new name

Timothee P
committed
this.form.title =
this.project.title +
` (Copie-${new Date()
.toLocaleString()
.slice(0, -3)

Timothee P
committed
this.form.is_project_type = false;
}
Sébastien DA ROCHA
committed
//* transform string values to objects for dropdowns display (could be in a computed)
if (this.levelPermissionsPub) {
(el) => el.name === this.project.access_level_pub_feature
);
if(value){
this.form.access_level_pub_feature = {
name: this.project.access_level_pub_feature,
value: value.value ,
};
}
}
if (this.levelPermissions) {
(el) => el.name === this.project.access_level_arch_feature
);
if(value){
this.form.access_level_arch_feature = {
name: this.project.access_level_arch_feature,
value: value.value ,
};
}
}
Sébastien DA ROCHA
committed
};
</script>
<style media="screen">
#form-input-file-logo {
margin-left: auto;
margin-right: auto;
}
.close.icon:hover {
cursor: pointer;
}
</style>