philippebeck/vue-elt

View on GitHub
components/setters/ImageSet.vue

Summary

Maintainability
Test Coverage
<template>
  <CardElt id="image-set">
    <template #header>
      <h2>
        <i class="fa-solid fa-image fa-lg"></i>
        {{ val.IMAGE_MANAGER }}
      </h2>
    </template>

    <template #body>
      <form enctype="multipart/form-data">
        <ListElt :items="val.IMAGE_FORM">

          <template #item-1>
            <FieldElt id="image" 
              type="file"
              v-model:value="image"
              :info="val.INFO_IMAGE">
              <template #legend>{{ val.LEGEND_IMAGE }}</template>
              <template #label>{{ val.LABEL_IMAGE }}</template>
            </FieldElt>
          </template>

          <template #item-2>
            <FieldElt id="description" 
              v-model:value="description"
              @keyup.enter="createImage()"
              :info="val.INFO_DESCRIPTION"
              :max="val.TEXT_MAX">
              <template #legend>{{ val.LEGEND_DESCRIPTION }}</template>
              <template #label>{{ val.LABEL_DESCRIPTION }}</template>
            </FieldElt>
          </template>
        </ListElt>

        <BtnElt type="button"
          @click="createImage()"
          class="btn-green"
          :content="val.CONTENT_CREATE"
          :title="val.TITLE_IMAGE">
          <template #btn>
            <i class="fa-solid fa-square-plus fa-lg"></i>
          </template>
        </BtnElt>
      </form>

      <form v-if="images.length > 0">
        <TableElt :items="images">
          <template #head>{{ val.HEAD_UP }}</template>

          <template #cell-id="slotProps">
            <BtnElt :content="slotProps.item.id"
              :href="`${val.UI_URL}/img/galleries/${slotProps.item.name}`"
              :title="slotProps.item.description"
              target="_blank"
              rel="noopener noreferrer"/>
          </template>

          <template #cell-name="slotProps">
            <MediaElt :src="'/img/thumbnails/galleries/' + slotProps.item.name"
              :alt="slotProps.item.description"
              :title="slotProps.item.name"
              loading="lazy"/>

            <FieldElt :id="`image-${slotProps.item.id}`"
              type="file"
              :info="val.INFO_UP_IMAGE">
              <template #legend>{{ val.LEGEND_IMAGE }}</template>
              <template #label>{{ val.LABEL_IMAGE }}</template>
            </FieldElt>
          </template>

          <template #cell-description="slotProps">
            <FieldElt :id="`description-${slotProps.item.id}`"
              type="textarea"
              v-model:value="slotProps.item.description"
              @keyup.enter="updateImage(slotProps.item.id)"
              :info="val.INFO_UP_DESCRIPTION">
              <template #legend>{{ val.LEGEND_DESCRIPTION }}</template>
              <template #label>{{ val.LABEL_DESCRIPTION }}</template>
            </FieldElt>
          </template>

          <template #cell-Gallery="slotProps">
            <FieldElt :id="`gallery-${slotProps.item.id}`"
              type="select"
              :list="getGalleries"
              v-model:value="slotProps.item.Gallery.name"
              :content="slotProps.item.Gallery.name"
              @keyup.enter="updateImage(slotProps.item.id)"
              :info="val.INFO_UP_GALLERY">
              <template #legend>{{ val.LEGEND_NAME }}</template>
              <template #label>{{ val.LABEL_NAME }}</template>
            </FieldElt>
          </template>

          <template #body="slotProps">
            <BtnElt type="button"
              @click="updateImage(slotProps.item.id)" 
              class="btn-sky"
              :title="val.TITLE_UPDATE + slotProps.item.description">
              <template #btn>
                <i class="fa-solid fa-cloud-arrow-up fa-lg fa-fw"></i>
              </template>
            </BtnElt>

            <BtnElt type="button"
              @click="deleteImage(slotProps.item.id)" 
              class="btn-red"
              :title="val.TITLE_DELETE + slotProps.item.description">
              <template #btn>
                <i class="fa-solid fa-trash-arrow-up fa-lg fa-fw"></i>
              </template>
            </BtnElt>
          </template>
        </TableElt>
      </form>
    </template>
  </CardElt>
</template>

<script>
import { checkRange, deleteData, putData, postData, setError } from "servidio"

import BtnElt from "../elements/BtnElt"
import CardElt from "../elements/CardElt"
import FieldElt from "../elements/FieldElt"
import ListElt from "../elements/ListElt"
import MediaElt from "../elements/MediaElt"
import TableElt from "../elements/TableElt"

export default {
  name: "ImageSet",
  components: { BtnElt, CardElt, FieldElt, ListElt, MediaElt, TableElt },
  props: ["galleries", "images", "token", "val"],
  data() {
    return {
      description: "",
      gallery: ""
    }
  },

  computed: {
    /**
     * ? GET GALLERIES
     * * Retrieves the galleries & transforms them into an array of objects.
     * @return {Array} An array of objects with the content & value properties.
     */
    getGalleries() {
      const galleries = [];

      for (let i = 0; i < this.galleries.length; i++) {
        galleries.push({
          content: this.galleries[i].name,
          value: this.galleries[i].id
        })
      }

      return galleries; 
    }
  },

  methods: {
    /**
     * ? CREATE IMAGE
     * * Create an image by sending a POST request to the server.
     */
    createImage() {
      const { CHECK_STRING, API_URL, ALERT_CREATED, ALERT_IMG } = this.val;

      if (checkRange(this.description, CHECK_STRING)) {
        const img = document.getElementById("image")?.files[0];

        if (img !== undefined) {
          const URL   = API_URL + "/images";
          const data  = new FormData();

          data.append("image", img);
          data.append("description", this.description);
          data.append("galleryId", this.$route.params.id);

          postData(URL, data, this.token)
            .then(() => {
              alert(this.description + ALERT_CREATED);
              this.$router.go();
            })
            .catch(err => setError(err));

        } else {
          alert(ALERT_IMG);
        }
      }
    },

    /**
     * ? UPDATE IMAGE
     * * Updates an image.
     * @param {number} id - The ID of the image to be updated.
     */
    updateImage(id) {
      const { ALERT_IMAGE, ALERT_UPDATED, API_URL, CHECK_STRING } = this.val;

      const image = this.images.find(i => i.id === id);
      let { name, description, galleryId } = image;

      const IS_NAME_CHECKED = image && checkRange(name, CHECK_STRING);
      const IS_DESC_CHECKED = image && checkRange(description, CHECK_STRING);

      if (IS_NAME_CHECKED && IS_DESC_CHECKED) {
        const URL   = `${API_URL}/images/${id}`
        const img   = document.getElementById(`image-${id}`)?.files[0] ?? name;
        const data  = new FormData();

        data.append("name", name);
        data.append("image", img);
        data.append("description", description);
        data.append("galleryId", galleryId);

        putData(URL, data, this.token)
          .then(() => {
            alert(ALERT_IMAGE + id + ALERT_UPDATED);
            this.$router.go();
          })
          .catch(err => setError(err));
      }
    },

    /**
     * ? DELETE IMAGE
     * * Deletes an image from the server based on the provided ID.
     * @param {number} id - The ID of the image to be deleted.
     */
    deleteImage(id) {
      const { TITLE_DELETE_IMAGE, API_URL, ALERT_IMAGE, ALERT_DELETED } = this.val;

      if (confirm(`${TITLE_DELETE_IMAGE} ${id} ?`)) {
        const URL = `${API_URL}/images/${id}`

        deleteData(URL, this.token)
          .then(() => {
            alert(ALERT_IMAGE + id + ALERT_DELETED);
            this.$router.go();
          })
          .catch(err => setError(err));
      }
    }
  }
}
</script>