Bladeren bron

entite image is now editable, add, delete. remains the alt field

bach 1 jaar geleden
bovenliggende
commit
e9b6b90816

+ 4 - 2
src/api/gql/entite.fragment.gql

@@ -1,9 +1,11 @@
 fragment EntiteFields on Entite {
   id
-  action
-  menacemaintien
+  uuid
   title
   can_update
+  agissante
+  action
+  menacemaintien
   image {
     alt
     url

+ 31 - 2
src/assets/main.scss

@@ -1047,12 +1047,41 @@ body{
   border: #eee 2px solid;
   border-radius: 5px;
   padding: 0.3em!important;
-  margin-bottom: 1em;
+  margin: 1em 0 0;
   font-size: 0.756em;
   &>*{ 
     display: inline-block!important;
     padding: 0!important;
     cursor: pointer;
   }
-  
+}
+
+div.editable-image{
+  background: #eee;
+  max-width: 100%;
+  div.btn{
+    border: #eee 2px solid;
+    border-radius: 5px;
+    margin: 1em 0 0;
+    font-size: 1em;
+    width: 100%;
+    height: 100px;
+    line-height:100px;
+    text-align: center;
+    transition: all 0.2s ease-in-out;
+    position: relative;
+    >span{
+      display: inline-block;
+      vertical-align: middle;
+    }
+    cursor: pointer;
+    box-sizing: border-box;
+    &:hover{
+      border: #01ffe2 2px solid;
+    }
+
+  }
+  input[type="file"]{
+    display: none;
+  }
 }

+ 30 - 24
src/components/contents/Entite.vue

@@ -1,12 +1,19 @@
 <script>
 
+import REST from '@api/rest-axios'
+import JSONAPI from '@api/json-axios'
+
 import { mapActions, mapState } from 'pinia'
 import { ConcernementsStore } from '@stores/concernements'
+import { UserStore } from '@stores/user'
 
 import ContentEditable from '@components/editable/ContentEditable.vue';
 import CheckboxEditable from '@components/editable/CheckboxEditable.vue';
+import ImageEditable from '@components/editable/ImageEditable.vue';
+
 export default {
   props: ['concernement', 'entite', 'eid'],
+  emits: ['reloadEntite'],
   data() {
     return {
     }
@@ -15,6 +22,7 @@ export default {
     ...mapState(ConcernementsStore,['opened_concernement',
                                     'ct_concernement',
                                     'ct_entite']),
+    ...mapState(UserStore,['csrf_token']),
     field_menace_maintien_label (){
       let str;
       if (this.concernement.entites_byid[this.eid].menacemaintien < 0) {
@@ -35,38 +43,34 @@ export default {
     }
   },
   methods: {
-    
+    reloadEntite(){
+      this.$emit('reloadEntite');
+    }
   },
   components: {
     ContentEditable,
-    CheckboxEditable
+    CheckboxEditable,
+    ImageEditable,
   }
 }
 </script>
 
 <template>
   <section class="entite">
-    <!-- <section v-if="entite.can_update" class="editable">
-      <label><input type="checkbox" name="action"> Entité action</label>
-    </section> -->
-    <CheckboxEditable 
-      v-if="entite.can_update"
-      label="Entité action" 
-      :data="{
-        entitytype: 'node',
-        bundle: 'entite',
-        nid: this.entite.id,
-        field: 'field_entite_agissante'
-      }" />
+    <section v-if="entite.image.length || entite.can_update" class="image">
+      <ImageEditable 
+        :image="entite.image"
+        :data="{
+          entitytype: 'node',
+          bundle: 'entite',
+          nid: this.entite.id,
+          uuid: this.entite.uuid,
+          field: 'field_image'
+        }"
+        v-on:updated="reloadEntite" />
 
-    <section v-if="entite.image.length" class="image">
-      <figure>
-        <img :src="entite.image[0].url" :alt="entite.image[0].alt"/>
-        <figcaption>{{ entite.image[0].alt }}</figcaption>
-      </figure>
-      <!-- TODO admin add image -->
     </section>
-    <section v-if="entite.action" class="action">
+    <section v-if="entite.action || entite.can_update" class="action">
         <label v-if="ct_entite">{{ ct_entite.field_action.description }}</label>
         <!-- <p>{{ entite.action }}</p> -->
         <ContentEditable 
@@ -78,10 +82,11 @@ export default {
             bundle: 'entite',
             nid: this.entite.id,
             field: 'field_action'
-          }" />
+          }"
+          v-on:updated="reloadEntite" />
           
     </section>
-    <section v-if="entite.menacemaintien" class="menace-maintien">
+    <section v-if="entite.menacemaintien || entite.can_update" class="menace-maintien">
         <label v-if="ct_entite">{{ field_menace_maintien_label }}</label>
         <!-- <p>{{ entite.menacemaintien }}</p> -->
         <ContentEditable 
@@ -93,7 +98,8 @@ export default {
             bundle: 'entite',
             nid: this.entite.id,
             field: 'field_menace_maintien'
-          }" />
+          }"
+          v-on:updated="reloadEntite" />
         
     </section>
     <!-- SOURCES (experiences vecues) -->

+ 18 - 5
src/components/contents/TerrainDeVie.vue

@@ -22,6 +22,7 @@ import { mdiChevronRight } from '@mdi/js';
 import { mdiChevronDown } from '@mdi/js';
 
 import ContentEditable from '@components/editable/ContentEditable.vue';
+import CheckboxEditable from '@components/editable/CheckboxEditable.vue';
 
 export default {
   props: ['cid', 'eid'],
@@ -221,7 +222,8 @@ export default {
     Entite,
     VueSlider,
     SvgIcon,
-    ContentEditable
+    ContentEditable,
+    CheckboxEditable
   }
 }
 
@@ -246,14 +248,25 @@ export default {
             nid: this.entite.id,
             field: 'title'
           }" />
-          
+
+        <CheckboxEditable 
+          v-if="entite && entite.can_update"
+          :checked="entite.agissante"
+          label="Entité action" 
+          :data="{
+            entitytype: 'node',
+            bundle: 'entite',
+            nid: this.entite.id,
+            field: 'field_entite_agissante'
+          }" />
+
       </div>
     </template>
     
     <template v-slot:main>
       <!-- concernement -->
       <template v-if="!entite">
-        <section v-if="concernement.description" class="description">
+        <section v-if="concernement.description || concernement.can_update" class="description">
             <label v-if="ct_concernement">{{ ct_concernement.field_description.description }}</label>
             
             <ContentEditable 
@@ -270,7 +283,7 @@ export default {
               }" />
 
         </section>
-        <section v-if="concernement.caillou" class="caillou">
+        <section v-if="concernement.caillou || concernement.can_update" class="caillou">
             <label v-if="ct_concernement">{{ ct_concernement.field_caillou.description }}</label>
             
             <ContentEditable 
@@ -289,7 +302,7 @@ export default {
       </template>
 
       <!-- entite -->
-      <Entite v-if="entite" :concernement="concernement" :entite="entite" :eid="eid"/>
+      <Entite v-if="entite" :concernement="concernement" :entite="entite" :eid="eid" v-on:reloadEntite="loadEntite"/>
     </template>
 
     <template v-slot:footer>

+ 8 - 3
src/components/editable/CheckboxEditable.vue

@@ -3,15 +3,17 @@
 import REST from '@api/rest-axios'
 
 import { mapActions, mapState } from 'pinia'
+import { ConcernementsStore } from '@stores/concernements'
 import { UserStore } from '@stores/user'
 
 
 export default {
   props: {
+    checked: Boolean,
     label: String, 
     data: Object
   },
-  // emits: ['returned'],
+  emits: ['updated'],
   data(){
     return {
       
@@ -21,12 +23,13 @@ export default {
     ...mapState(UserStore,['csrf_token']),
   },
   created () {
-    console.log('ContentEditable created');
+    console.log('CheckboxEditable created');
   },
   mounted () {
 
   },
   methods: {
+    ...mapActions(ConcernementsStore, ['reloadConcernements']),
     onInput(e){
       // console.log('onInput checkbox e', e);
       let checked  = e.target.checked;
@@ -47,6 +50,8 @@ export default {
         .then(({ data }) => {
           console.log('user REST post node data', data)
           // TODO if success update the data in pinia 
+          // this.reloadConcernements();
+          this.$emit('updated');
         })
         .catch(error => {
           console.warn(`Issue with patch node ${this.data.bundle}`, error)
@@ -59,6 +64,6 @@ export default {
 
 <template>
   <section class="editable">
-    <label><input type="checkbox" @input="onInput"> {{ label }}</label>
+    <label><input type="checkbox" :checked="checked" @input="onInput"> {{ label }}</label>
   </section>
 </template>

+ 5 - 1
src/components/editable/ContentEditable.vue

@@ -3,6 +3,7 @@
 import REST from '@api/rest-axios'
 
 import { mapActions, mapState } from 'pinia'
+import { ConcernementsStore } from '@stores/concernements'
 import { UserStore } from '@stores/user'
 
 
@@ -20,7 +21,7 @@ export default {
     }, 
     data: Object
   },
-  // emits: ['returned'],
+  emits: ['updated'],
   data(){
     return {
       
@@ -36,6 +37,7 @@ export default {
 
   },
   methods: {
+    ...mapActions(ConcernementsStore, ['reloadConcernements']),
     onContentEditableFocusOut(e){
       console.log('onContentEditableFocusOut', e);
       // console.log('onContentEditableFocusOut data', this.data);
@@ -57,6 +59,8 @@ export default {
         .then(({ data }) => {
           console.log('user REST post node data', data)
           // TODO if success update the data in pinia 
+          // this.reloadConcernements();
+          this.$emit('updated');
         })
         .catch(error => {
           console.warn(`Issue with patch node ${this.data.bundle}`, error)

+ 136 - 0
src/components/editable/ImageEditable.vue

@@ -0,0 +1,136 @@
+<script>
+
+import JSONAPI from '@api/json-axios'
+import REST from '@api/rest-axios'
+
+import { mapActions, mapState } from 'pinia'
+import { ConcernementsStore } from '@stores/concernements'
+import { UserStore } from '@stores/user'
+
+import SvgIcon from '@jamescoyle/vue-icon';
+import { mdiTrashCanOutline } from '@mdi/js';
+
+export default {
+  props: {
+    image: Object,
+    data: Object
+  },
+  emits: ['updated'],
+  data(){
+    return {
+      mdiTrashCanOutline_path: mdiTrashCanOutline
+    }
+  },
+  computed: {
+    ...mapState(UserStore,['csrf_token']),
+  },
+  created () {
+    console.log('ImageEditable created');
+  },
+  mounted () {
+
+  },
+  methods: {
+    ...mapActions(ConcernementsStore, ['reloadConcernements']),
+    addImage(e){
+      console.log('addImage', this.$refs);
+      this.$refs.image_input.click();
+    },
+    onInput(e){
+      console.log('onFileInput', e);
+      let file = e.target.files[0];
+      console.log('onFileInput file', file);
+      this.save(file);
+    },
+    save(file){
+      const configs = {
+        headers: {
+          'X-CSRF-Token': this.csrf_token,
+          'Content-Type': 'application/octet-stream',
+          'Content-Disposition': `file; filename="${file.name}"`,
+        },
+      };
+
+      JSONAPI.post(`/${this.data.entitytype}/${this.data.bundle}/${this.data.uuid}/${this.data.field}`, file, configs)
+        .then(({ data : { data } }) => {
+          console.log('jsonapi post image', data)
+          this.$emit('updated');
+        })
+        .catch(error => {
+          console.warn('Issue with jsonapi post image', error)
+          Promise.reject(error)
+        })
+    },
+    onDeleteImg(e){
+      console.log('onDeleteImg', e);
+
+      const params = {
+        type: this.data.bundle,
+        nid: [{"value":this.data.nid}],
+        [this.data.field]: {value: null}
+      };
+      const configs = {
+        headers: {'X-CSRF-Token': this.csrf_token}
+      };
+      REST.patch(`/node/${this.data.nid}?_format=json`, params, configs)
+        .then(({ data }) => {
+          console.log(`user REST patch node ${this.data.bundle} ${this.data.field}`, data)
+          // TODO if success update the data in pinia 
+          // this.reloadConcernements();
+          this.$emit('updated');
+        })
+        .catch(error => {
+          console.warn(`Issue with patch node ${this.data.bundle} ${this.data.field}`, error)
+          Promise.reject(error)
+        })
+
+      // 405 JSONAPI operation not allowed, don't know why
+      
+      // const configs = {
+      //   headers: {
+      //     'X-CSRF-Token': this.csrf_token,
+      //     'Content-Type': 'application/octet-stream',
+      //     'Content-Disposition': `file; filename=""`,
+      //   },
+      // };
+
+      // JSONAPI.delete(`/${this.data.entitytype}/${this.data.bundle}/${this.data.uuid}/${this.data.field}`, {}, configs)
+      //   .then(({ data : { data } }) => {
+      //     console.log('jsonapi delete image', data)
+      //     this.$emit('updated');
+      //   })
+      //   .catch(error => {
+      //     console.warn('Issue with jsonapi post image', error)
+      //     Promise.reject(error)
+      //   })
+      // console.log('save csrf_token', this.csrf_token);
+
+    }
+  },
+  components: {
+    SvgIcon,
+  }
+}
+</script>
+
+<template>
+  <div class="editable-image">
+    <!-- with img -->
+    <template v-if="image.length">
+      <figure>
+        <img :src="image[0].url" :alt="image[0].alt"/>
+        <figcaption v-if="image[0].alt">{{ image[0].alt }}</figcaption>
+      </figure>
+      <svg-icon type="mdi" :path="mdiTrashCanOutline_path" @click="onDeleteImg" />
+    </template>
+    <!-- with out img -->
+    <template v-else>
+      <div @click="addImage" class="btn">
+
+        <span>ajouter une image</span>
+      </div>
+      <input ref="image_input" type="file" accept ="image/jpeg, image/png, image/jpg" @input="onInput">
+    </template>
+    
+  </div>
+</template>

+ 3 - 3
src/stores/concernements.js

@@ -251,9 +251,9 @@ export const ConcernementsStore = defineStore({
     reloadConcernements () {
       console.log('reloadConcernements');
       // reset the arrays
-      this.concernements = [];
-      this.concernementsByID = {};
-      this.concernements_loaded = false;
+      // this.concernements = [];
+      // this.concernementsByID = {};
+      // this.concernements_loaded = false;
       this.loadConcernements();
     },
     loadContentTypeDefinition () {