Newer
Older
Sébastien DA ROCHA
committed
<template>
<div class="fourteen wide column">
<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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
</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"
/>
<!-- {{ form.thumbnail.errors }} -->
</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"
v-model="form.archive_feature"
/>
<div class="ui label">jour(s)</div>
</div>
</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"
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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
</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>
const axios = require("axios");
import Dropdown from "@/components/Dropdown.vue";
import { mapGetters } from "vuex";
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 {
action: "create",
levelPermissions: [
{ name: "Utilisateur anonyme", value: "anonymous" },
{ name: "Utilisateur connecté", value: "logged_user" },
{ name: "Contributeur", value: "contributor" },
],
fileToImport: {
name: "Sélectionner une image ...",
size: 0,
},
errors: {
title: [],
access_level_pub_feature: [],
access_level_arch_feature: [],
},
Sébastien DA ROCHA
committed
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
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: {
...mapGetters(["project"]),
Sébastien DA ROCHA
committed
return this.$store.state.configuration.VUE_APP_DJANGO_BASE;
},
},
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";
}
},
truncate(n, len) {
let ext = n.substring(n.lastIndexOf(".") + 1, n.length).toLowerCase();
let filename = n.replace("." + ext, "");
Sébastien DA ROCHA
committed
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
if (filename.length <= len) {
return n;
}
filename = filename.substr(0, len) + (n.length > len ? "[...]" : "");
return filename + "." + ext;
},
onFileChange(e) {
// * read image file
const files = e.target.files || e.dataTransfer.files;
if (!files.length) return; //* abort if no file
this.fileToImport = files[0]; //* stock the file to post later
let reader = new FileReader(); //* read the file to display in the page
let _this = this; //* 'this' is different in onload function
reader.onload = function (e) {
_this.thumbnailFileSrc = e.target.result;
};
reader.readAsDataURL(this.fileToImport);
},
goBackNrefresh(slug) {
let _this = this;
// * go back to project list
this.$router.push(
{
name: "project_detail",
params: { slug },
},
function () {
_this.$store.dispatch("GET_ALL_PROJECTS"); //* & refresh project list
}
);
},
postProjectThumbnail(projectSlug) {
//* send img to the backend when feature_type is created
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) {
//dispatch("GET_IMPORTS", feature_type_slug); // ? Besoin de vérifier le statut de l'import ?
this.goBackNrefresh(projectSlug);
}
})
.catch((error) => {
throw error;
});
Sébastien DA ROCHA
committed
},
checkForm() {
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,
};
if (this.action === "create" || this.action === "duplicate") {
await axios
.post(
`${this.$store.state.configuration.VUE_APP_DJANGO_API_BASE}projects/`,
projectData
)
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
this.postProjectThumbnail(response.data.slug);
this.goBackNrefresh(response.data.slug);
}
Sébastien DA ROCHA
committed
}
})
.catch((error) => {
throw error;
});
} else if (this.action === "edit") {
await axios
.put(
`${this.$store.state.configuration.VUE_APP_DJANGO_API_BASE}projects/${this.project.slug}/`,
projectData
)
.then((response) => {
if (response && response.status === 200) {
//* send thumbnail after feature_type was updated
if (this.fileToImport.size > 0) {
Sébastien DA ROCHA
committed
this.postProjectThumbnail(this.project.slug);
} else {
this.goBackNrefresh(this.project.slug);
}
Sébastien DA ROCHA
committed
}
})
.catch((error) => {
throw error;
});
}
},
},
created() {
this.definePageType();

Timothee P
committed
console.log(this.action);
Sébastien DA ROCHA
committed
if (this.action === "create") {
this.thumbnailFileSrc = require("@/assets/img/default.png");

Timothee P
committed
} else if (this.action === "edit" || this.action === "create_from") {
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
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
//* transform string values to objects for dropdowns display (could be in a computed)
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)
).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)
).value,
};
}
},
};
</script>
<style media="screen">
#form-input-file-logo {
margin-left: auto;
margin-right: auto;
}
.close.icon:hover {
cursor: pointer;
}
</style>