Newer
Older
Sébastien DA ROCHA
committed
<template>
<div class="fourteen wide column">
<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>
Sébastien DA ROCHA
committed
<form id="form-project-edit" class="ui form">
<h1>
<span v-if="action === 'edit'"
>Édition du projet "{{ form.title }}"</span
>
<span v-else-if="action === 'create'">Création d'un projet</span>
</h1>
<div class="ui horizontal divider">INFORMATIONS</div>
<div class="two fields">
<div class="required field">
<label for="title">Titre</label>
<input
type="text"
required
maxlength="128"
name="title"
id="title"
v-model="form.title"
/>
<ul id="errorlist-title" class="errorlist">
<li v-for="error in errors.title" :key="error">
{{ error }}
</li>
</ul>
Sébastien DA ROCHA
committed
</div>
<div class="field">
<label>Illustration du projet</label>
<img
class="ui small image"
id="form-input-file-logo"
:src="
thumbnailFileSrc
? thumbnailFileSrc
: DJANGO_BASE_URL + form.thumbnail
"
/>
<label class="ui icon button" for="thumbnail">
<i class="file icon"></i>
<span class="label">{{
form.thumbnail_name ? form.thumbnail_name : fileToImport.name
}}</span>
</label>
<input
@change="onFileChange"
class="file-selection"
type="file"
accept="image/jpeg, image/png"
style="display: none"
name="thumbnail"
id="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"
></textarea>
<!-- {{ form.description.errors }} -->
</div>
<div class="ui horizontal divider">PARAMÈTRES</div>
<div class="four fields">
<div class="field">
<label for="archive_feature">Délai avant archivage</label>
<div class="ui right labeled input">
<input
type="number"
min="0"
Sébastien DA ROCHA
committed
style="padding: 1px 2px"
name="archive_feature"
id="archive_feature"
Sébastien DA ROCHA
committed
v-model="form.archive_feature"
/>
<div class="ui label">jour(s)</div>
</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
type="number"
min="0"
Sébastien DA ROCHA
committed
style="padding: 1px 2px"
name="delete_feature"
id="delete_feature"
Sébastien DA ROCHA
committed
v-model="form.delete_feature"
/>
<div class="ui label">jour(s)</div>
</div>
</div>
<div class="required field">
<label for="access_level_pub_feature"
>Visibilité des signalements publiés</label
>
<Dropdown
:options="levelPermissions"
: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">
{{ error }}
</li>
</ul>
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">
{{ error }}
</li>
</ul>
Sébastien DA ROCHA
committed
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
</div>
</div>
<div class="field">
<div class="ui checkbox">
<input
type="checkbox"
v-model="form.moderation"
name="moderation"
id="moderation"
/>
<label for="moderation">Modération</label>
</div>
<!-- {{ form.moderation.errors }} -->
</div>
<div class="field">
<div class="ui checkbox">
<input
type="checkbox"
v-model="form.is_project_type"
name="is_project_type"
id="is_project_type"
/>
<label for="is_project_type">Est un projet type</label>
</div>
<!-- {{ form.is_project_type.errors }} -->
</div>
<div class="ui divider"></div>
<button @click="postForm" type="button" class="ui teal icon button">
<i class="white save icon"></i> Enregistrer les changements
</button>
</form>
</div>
</template>
<script>
Sébastien DA ROCHA
committed
import Dropdown from "@/components/Dropdown.vue";
Sébastien DA ROCHA
committed
// axios.defaults.headers.common["X-CSRFToken"] = ((name) => {
// var re = new RegExp(name + "=([^;]+)");
// var value = re.exec(document.cookie);
// return value !== null ? unescape(value[1]) : null;
// })("csrftoken");
Sébastien DA ROCHA
committed
export default {
name: "Project_edit",
components: {
Dropdown,
},
data() {
return {
Sébastien DA ROCHA
committed
action: "create",
fileToImport: {
name: "Sélectionner une image ...",
size: 0,
},
errors: {
title: [],
access_level_pub_feature: [],
access_level_arch_feature: [],
},
Sébastien DA ROCHA
committed
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
form: {
title: "",
slug: "",
created_on: "",
updated_on: "",
description: "",
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)
creator: null,
access_level_pub_feature: { name: "", value: "" },
access_level_arch_feature: { name: "", value: "" },
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,
},
thumbnailFileSrc: "",
};
},
computed: {
Sébastien DA ROCHA
committed
...mapGetters(["project"]),
Sébastien DA ROCHA
committed
return this.$store.state.configuration.VUE_APP_DJANGO_BASE;
},
levelPermissions(){
let self = this;
let levels = []
this.levelsPermissions.map(function(item) {
if (item.user_type_id != "super_contributor")
levels.push({
'name': self.traslateRoleToFrench(item.user_type_id),
'value': item.user_type_id,
})
});
return levels
}
Sébastien DA ROCHA
committed
},
methods: {
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";
}
},
traslateRoleToFrench(role){
if (role == "admin") return "Administrateur de projet";
if (role == "moderator") return "Modérateur";
if (role == "contributor") return "Contributeur";
if (role == "logged_user") return "Utilisateur connecté";
if (role == "anonymous") return "Utilisateur anonyme";
},
Sébastien DA ROCHA
committed
truncate(n, len) {
let ext = n.substring(n.lastIndexOf(".") + 1, n.length).toLowerCase();
let filename = n.replace("." + ext, "");
Sébastien DA ROCHA
committed
if (filename.length <= len) {
return n;
}
filename = filename.substr(0, len) + (n.length > len ? "[...]" : "");
return filename + "." + ext;
},
validateImgFile(files, handleFile) {
let url = window.URL || window.webkitURL;
let 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
let 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
},
checkEmpty() {
//* forbid empty fields
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) {
Promise.all([
this.$store.dispatch("GET_USER_LEVEL_PERMISSIONS"), //* refresh projects permissions
this.$store.dispatch("GET_ALL_PROJECTS"), //* & refresh project list
]).then(() =>
// * go back to project list
this.$router.push({
Sébastien DA ROCHA
committed
name: "project_detail",
params: { slug },
Sébastien DA ROCHA
committed
);
},
postProjectThumbnail(projectSlug) {
//* send img to the backend when feature_type is created
if (this.fileToImport) {
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
let formData = new FormData();
formData.append("file", this.fileToImport);
const url =
this.$store.state.configuration.VUE_APP_DJANGO_API_BASE +
"projects/" +
projectSlug +
"/thumbnail/";
return axios
.put(url, formData, {
headers: {
"Content-Type": "multipart/form-data",
},
})
.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."
);
for (const key in this.errors) {
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,
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;
});
} else {
if (this.action === "create_from") {
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;
});
}
},
Sébastien DA ROCHA
committed
if (!this.project) {
this.$store.dispatch("GET_PROJECT_INFO", this.$route.params.slug);
}

Timothee P
committed
this.form = { ...this.project }; //* create a new object to avoid modifying original one
if (this.action === "create_from") {
this.form.title =
this.project.title +
` (Copie-${new Date()
.toLocaleString()
.slice(0, -3)
.replace(",", "")})`;
this.form.is_project_type = false;
}
Sébastien DA ROCHA
committed
//* transform string values to objects for dropdowns display (could be in a computed)
Sébastien DA ROCHA
committed
this.form.access_level_pub_feature = {
name: this.project.access_level_pub_feature,
value: this.levelPermissions.find(
(el) => el.name === this.project.access_level_pub_feature
Sébastien DA ROCHA
committed
).value,
};
this.form.access_level_arch_feature = {
name: this.project.access_level_arch_feature,
value: this.levelPermissions.find(
(el) => el.name === this.project.access_level_arch_feature
Sébastien DA ROCHA
committed
).value,
};
},
},
created() {
this.definePageType();
if (this.action === "create") {
this.thumbnailFileSrc = require("@/assets/img/default.png");
} else if (this.action === "edit" || this.action === "create_from") {
this.fillProjectForm();
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>