Skip to content
Snippets Groups Projects
Project_edit.vue 13.1 KiB
Newer Older
<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"
          />
Timothee P's avatar
Timothee P committed
          <ul id="errorlist-title" class="errorlist">
            <li v-for="error in errors.title" :key="error">
              {{ error }}
            </li>
          </ul>
        </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"
leandro's avatar
leandro committed
              oninput="validity.valid||(value='');"
              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"
leandro's avatar
leandro committed
              oninput="validity.valid||(value='');"
              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"
          />
Timothee P's avatar
Timothee P committed
          <ul id="errorlist-access_level_pub_feature" class="errorlist">
            <li v-for="error in errors.access_level_pub_feature" :key="error">
              {{ error }}
            </li>
          </ul>
        </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"
          />
Timothee P's avatar
Timothee P committed
          <ul id="errorlist-access_level_arch_feature" class="errorlist">
            <li v-for="error in errors.access_level_arch_feature" :key="error">
              {{ error }}
            </li>
          </ul>
        </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");
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,
      },
Timothee P's avatar
Timothee P committed
      errors: {
        title: [],
        access_level_pub_feature: [],
        access_level_arch_feature: [],
      },
      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"]),
Timothee P's avatar
Timothee P committed
    DJANGO_BASE_URL: function () {
      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) {
Timothee P's avatar
Timothee P committed
      let ext = n.substring(n.lastIndexOf(".") + 1, n.length).toLowerCase();
      let filename = n.replace("." + ext, "");
      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;
        });
Timothee P's avatar
Timothee P 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;
    },

Timothee P's avatar
Timothee P committed
      if (!this.checkForm()) return;
      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
Timothee P's avatar
Timothee P committed
          .post(
            `${this.$store.state.configuration.VUE_APP_DJANGO_API_BASE}projects/`,
            projectData
          )
          .then((response) => {
            if (response && response.status === 201 && response.data) {
              //* send thumbnail after feature_type was created
Timothee P's avatar
Timothee P committed
              if (this.fileToImport.size > 0) {
                this.postProjectThumbnail(response.data.slug);
Timothee P's avatar
Timothee P committed
              } else {
                this.goBackNrefresh(response.data.slug);
              }
            }
          })
          .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) {
                this.postProjectThumbnail(this.project.slug);
              } else {
                this.goBackNrefresh(this.project.slug);
              }
    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("GET_PROJECT_INFO", this.$route.params.slug);
      }
      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;
      }
      //* 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>