Browse Source

big refactoring, opening flagcollection (folder) on the left of main-content

Bachir Soussi Chiadmi 3 years ago
parent
commit
93c4707c45

+ 2 - 2
config/sync/image.style.card_medium.yml

@@ -3,13 +3,13 @@ langcode: en
 status: true
 dependencies: {  }
 name: card_medium
-label: 'card-medium (210x295)'
+label: 'card-medium (205x295)'
 effects:
   34e936a0-1fee-4327-9553-b4f48bde14e6:
     uuid: 34e936a0-1fee-4327-9553-b4f48bde14e6
     id: image_scale_and_crop
     weight: 1
     data:
-      width: 210
+      width: 205
       height: 295
       anchor: center-center

+ 15 - 0
config/sync/image.style.card_medium_half.yml

@@ -0,0 +1,15 @@
+uuid: 56308ed7-1b40-435a-bfd0-fbf99f97e7ca
+langcode: en
+status: true
+dependencies: {  }
+name: card_medium_half
+label: 'card-medium-half (205x100)'
+effects:
+  34e936a0-1fee-4327-9553-b4f48bde14e6:
+    uuid: 34e936a0-1fee-4327-9553-b4f48bde14e6
+    id: image_scale_and_crop
+    weight: 1
+    data:
+      width: 205
+      height: 100
+      anchor: center-center

+ 2 - 1
config/sync/jsonapi_extras.jsonapi_resource_config.node--materiau.yml

@@ -210,9 +210,10 @@ resourceFields:
         styles:
           refine: true
           custom_selection:
-            - card_medium
             - card_big
             - card_full
+            - card_medium
+            - card_medium_half
     disabled: false
   field_memo:
     disabled: true

+ 6 - 0
package-lock.json

@@ -11891,6 +11891,12 @@
       "resolved": "https://registry.npmjs.org/vuex/-/vuex-3.6.0.tgz",
       "integrity": "sha512-W74OO2vCJPs9/YjNjW8lLbj+jzT24waTo2KShI8jLvJW8OaIkgb3wuAMA7D+ZiUxDOx3ubwSZTaJBip9G8a3aQ=="
     },
+    "vuex-extensions": {
+      "version": "1.1.5",
+      "resolved": "https://registry.npmjs.org/vuex-extensions/-/vuex-extensions-1.1.5.tgz",
+      "integrity": "sha512-1Jfi8o6coel3jj20k6SaEtinddzS0jEG41lyyWmodAorXoN85AzuYa4oou71e99B6V+Y+gSVUysa3yHVhWpTrQ==",
+      "dev": true
+    },
     "walker": {
       "version": "1.0.7",
       "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.7.tgz",

+ 1 - 0
package.json

@@ -66,6 +66,7 @@
     "vue-server-renderer": "^2.6.12",
     "vue-style-loader": "^4.1.2",
     "vue-template-compiler": "^2.6.12",
+    "vuex-extensions": "^1.1.5",
     "webpack": "^5.6.0",
     "webpack-cli": "^4.2.0",
     "webpack-merge": "^5.4.0"

File diff suppressed because it is too large
+ 67 - 40
web/themes/custom/materiotheme/assets/dist/main.css


File diff suppressed because it is too large
+ 0 - 0
web/themes/custom/materiotheme/assets/dist/main.js


+ 7 - 4
web/themes/custom/materiotheme/assets/styles/base/_layout.scss

@@ -23,6 +23,8 @@ body.toolbar-horizontal.toolbar-themes.toolbar-no-tabs{
   padding-top: 24px!important;
 }
 
+// build break points for each multiple of cards row
+// cards will always be centered, using all available space
 %grided-width{
   margin:0 auto;
   $m: $column_goutiere;
@@ -31,7 +33,7 @@ body.toolbar-horizontal.toolbar-themes.toolbar-no-tabs{
   @while  $bp < 4096px {
     $upbp: $bp + $colw + $m;
     @media only screen and (min-width: $bp + 1px) and (max-width: $upbp) {
-      width:$bp - $m;
+      width:$bp;
     }
     $bp: $upbp;
   }
@@ -100,14 +102,15 @@ main[role="main"]{
       display: flex;
       flex-direction: row-reverse;
       #content-left{
-        flex-basis: $column_width*2+$column_goutiere;
+        flex-basis: $column_width+$column_goutiere;
+        flex-shrink: 0;
         // width:$column_width*2+$column_goutiere;
         >*{
-          width:$column_width*2+$column_goutiere;
+          width:100%;
         }
       }
       #content-center{
-        flex-basis: $column_width*10+$column_goutiere*9;
+        flex-basis: 110%;
       }
     }
   }

+ 2 - 2
web/themes/custom/materiotheme/assets/styles/base/_variables.scss

@@ -5,7 +5,7 @@ $base_font_size:16px;
 // card-medium (210x295)
 // card-small (100x140)
 
-$column_width: 210px;
-$column_goutiere: 15px;
+$column_width: 205px;
+$column_goutiere: 13px;
 
 $card_height: 295px;

+ 47 - 0
web/themes/custom/materiotheme/assets/styles/main.scss

@@ -395,11 +395,55 @@ aside.messages{
 // | (__/ _ \ ' \  _/ -_) ' \  _|___| |__/ -_)  _|  _|
 //  \___\___/_||_\__\___|_||_\__|   |____\___|_|  \__|
 #content-left{
+  z-index: 5;
+  box-sizing: content-box;
   max-width:1px;
   overflow-x: hidden;
   transition: all 0.3s ease-in-out;
   &.opened{
     max-width: 500px;
+    padding: 0.3em;
+  }
+  >*{
+    box-sizing: border-box;
+    background-color: #fff;
+    box-shadow: -2px 0px 4px rgba(0, 0, 0, 0.2);
+    padding: 0.5em;
+  }
+  .flag-collection{
+    >header{
+      display: flex;
+      flex-direction: row;
+      justify-content: space-between;
+      h3{
+        // flex-basis: calc(100% - 1em);
+      }
+      .mdi-close{
+        // display: block;
+        // flex-basis: 1em;
+        cursor:pointer;
+        align-self: flex-end;
+      }
+    }
+    >ul{
+      >li{
+        margin:0 0 $column_goutiere 0;
+        padding:0;
+        article.card.minicard{
+          width:100%;
+
+          >header{
+            padding: 0.3em 0.3em 0.1em;
+            h1{
+              margin:0;
+            }
+          }
+          >nav.tools{
+            padding:0 0.2em;
+          }
+        }
+      }
+    }
   }
 }
 
@@ -663,6 +707,9 @@ article.card{
   &.article{
     width:$column_width*2 + $column_goutiere; height:$card_height;
   }
+  &.minicard{
+    height:100px;
+  }
   // &.card-small{
   //   width:100px; height:140px;
   // }

+ 3 - 49
web/themes/custom/materiotheme/vuejs/components/Content/Card.vue

@@ -1,5 +1,5 @@
 <template>
-  <article class="card">
+  <article class="card search-card">
     <header>
       <h1>{{ item.title }}</h1>
       <h4>{{ item.field_short_description }}</h4>
@@ -45,10 +45,12 @@
 
 <script>
 import { mapState, mapActions } from 'vuex'
+import cardMixins from 'vuejs/components/cardMixins'
 
 export default {
   name: "Card",
   props: ['item'],
+  mixins: [cardMixins],
   data() {
     return {
       blanksrc:`${drupalSettings.path.themePath}/assets/img/blank.gif`,
@@ -60,54 +62,6 @@ export default {
       flagcolls: state => state.User.flagcolls
     })
   },
-  directives: {
-    lazy: {
-      bind(img,binding){
-        // console.log('lazy bind', img, binding);
-        if(binding.value === 0){
-          img.setAttribute('src', img.getAttribute('data-src'))
-          img.removeAttribute('data-src')
-          img.classList.remove('lazy')
-        }
-      }
-    },
-    switcher: {
-      inserted(el,binding){
-        // switch images on mousemove
-        el.addEventListener('mousemove', function(event) {
-          let figs = this.querySelectorAll('figure')
-          // console.log('mousemove', this, event, figs.length);
-          // let len = figs.length
-          // let w = this.clientWidth;
-          // let g = w / len;
-          // let delta = Math.floor(event.layerX / g)
-          let delta = Math.floor(event.layerX / (this.clientWidth / figs.length))
-          // console.log('delta', delta);
-          figs.forEach((fig, index) => {
-            // console.log(index);
-            if(index == delta){
-              fig.style.display = "block"
-            }else{
-              fig.style.display = "none"
-            }
-          })
-        })
-      }
-    }
-  },
-  mounted() {
-    // lazy load images on mouseover
-    this.$el.addEventListener('mouseover', function(event) {
-      let imgs = this.querySelectorAll('.images figure img.lazy')
-      // console.log('mouseover', this, imgs);
-      imgs.forEach((img) => {
-        // console.log('forEach img',img);
-        img.setAttribute('src', img.getAttribute('data-src'))
-        img.removeAttribute('data-src')
-        img.classList.remove('lazy')
-      })
-    }, {once : true})
-  },
   methods: {
     ...mapActions({
       flag: 'User/flag',

+ 93 - 0
web/themes/custom/materiotheme/vuejs/components/Content/MiniCard.vue

@@ -0,0 +1,93 @@
+<template>
+  <article class="card minicard">
+    <header>
+      <h1>{{ item.title }}</h1>
+      <span class="ref">{{ item.field_reference }}</span>
+    </header>
+    <nav class="tools">
+      <section class="tool flags">
+        <span class="mdi mdi-folder-remove-outline"/>
+      </section>
+    </nav>
+    <section class="images" v-switcher>
+      <figure
+        v-for="(img, index) in item.images"
+        :key="img.url"
+      >
+        <img
+          class="lazy"
+          v-lazy="index"
+          :data-src="img.url"
+          :title="img.title"
+        />
+        <img class="blank" :src="blanksrc">
+      </figure>
+    </section>
+  </article>
+</template>
+
+<script>
+import { mapState, mapActions } from 'vuex'
+import cardMixins from 'vuejs/components/cardMixins'
+
+export default {
+  name: "MiniCard",
+  props: ['item'],
+  mixins: [cardMixins],
+  data() {
+    return {
+      blanksrc:`${drupalSettings.path.themePath}/assets/img/blank.gif`,
+      // loadingFlag: false
+    }
+  },
+  computed: {
+    // ...mapState({
+    //   flagcolls: state => state.User.flagcolls
+    // })
+  },
+  methods: {
+    // ...mapActions({
+    //   flag: 'User/flag',
+    //   unFlag: 'User/unFlag'
+    // }),
+    // flagIsActive(collid) {
+    //   // console.log(this.item.uuid);
+    //   // console.log(this.flagcolls[collid].items_uuids);
+    //   return this.flagcolls[collid].items_uuids.indexOf(this.item.uuid) !== -1;
+    // },
+    // flagIsLoading(collid) {
+    //   // console.log(this.item.uuid);
+    //   // console.log(this.flagcolls[collid].items_uuids);
+    //   return collid === this.loadingFlag;
+    // },
+    // onFlagActionCard (e) {
+    //   console.log("Card onFlagActionCard", e);
+    //   if (!this.loadingFlag) {
+    //     let collid = e.target.getAttribute('collid');
+    //     let isActive = this.flagIsActive(collid);
+    //     // console.log('collid', collid);
+    //     // console.log("this.item", this.item);
+    //     this.loadingFlag = collid;
+    //     if (isActive) {
+    //       this.unFlag({uuid: this.item.uuid, collid: collid})
+    //       .then(data => {
+    //         console.log("onFlagActionCard then", data);
+    //         this.loadingFlag = false;
+    //       })
+    //     }else{
+    //       this.flag({uuid: this.item.uuid, collid: collid})
+    //       .then(data => {
+    //         console.log("onFlagActionCard then", data);
+    //         this.loadingFlag = false;
+    //       })
+    //     }
+    //   }
+    // }
+  }
+}
+
+</script>
+
+<style lang="scss" scoped>
+
+</style>

+ 6 - 2
web/themes/custom/materiotheme/vuejs/components/Pages/Base.vue

@@ -1,13 +1,16 @@
 <template>
   <div id="Base">
-    <div class="loading" v-if="!items.length">
+    <div class="loading" v-if="!searchinfos">
       <span>Loading ...</span>
     </div>
     <div class="cards-list" v-else>
       <aside class="search-info">
         {{ searchinfos }}
       </aside>
-      <ul>
+      <div class="loading" v-if="!items.length & !noresults">
+        <span>Loading ...</span>
+      </div>
+      <ul v-else>
         <li v-for="item in items" v-bind:key="item.uuid">
           <Card :item="item"/>
         </li>
@@ -42,6 +45,7 @@ export default {
       items: state => state.Search.items,
       searchinfos: state =>  state.Search.infos,
       count: state => state.Search.count,
+      noresults: state => state.Search.noresults,
       limit: state => state.Search.limit
     })
   },

+ 38 - 11
web/themes/custom/materiotheme/vuejs/components/User/FlagCollection.vue

@@ -1,11 +1,20 @@
 <template>
   <section class="flag-collection">
-    <h3>{{collection.name}}</h3>
+    <header>
+      <h3 class="mdi mdi-folder-outline">{{collection.name}}</h3>
+      <span
+        class="mdi mdi-close"
+        title="close"
+        @click.prevent="onCloseFlagColl"
+      />
+    </header>
     <ul v-if="loadedItems">
       <li
         v-for="item in loadedItems"
         :key="item.id"
-      >{{item.attributes.title}}</li>
+      >
+        <MiniCard :item="item"/>
+      </li>
     </ul>
     <span v-else class="loading">Loading</span>
   </section>
@@ -13,6 +22,7 @@
 
 <script>
 import { mapState, mapActions } from 'vuex'
+import MiniCard from 'vuejs/components/Content/MiniCard'
 
 export default {
   name: "FlagCollection",
@@ -22,8 +32,8 @@ export default {
   }),
   computed: {
     ...mapState({
-      flagcolls: state => state.User.flagcolls
-      // openedCollid: state => state.User.openedCollid
+      flagcolls: state => state.User.flagcolls,
+      openedCollid: state => state.User.openedCollid
     })
   },
   // watch: {
@@ -35,11 +45,22 @@ export default {
   //   }
   // },
   created() {
+    if (typeof this.collection.loadedItems !== 'undefined') {
+      // if loadedItems are alredy loaded,
+      // the mutation occurs before this subscription
+      // so we first check if they are already available
+      this.loadedItems = this.collection.loadedItems
+    }
+
     this.unsubscribe = this.$store.subscribe((mutation, state) => {
       if (mutation.type === 'User/setLoadedCollItems') {
-        this.loadedItems = state.User.flagcolls[this.collection.id].loadedItems
+        console.log("mutation setLoadedCollItems collid", this.openedCollid)
+        // mutation is triggered before the component update
+        // so this.collection.id is not good
+        this.loadedItems = state.User.flagcolls[this.openedCollid].loadedItems
       }
-    });
+    })
+
   },
   beforeDestroy() {
     this.unsubscribe()
@@ -49,11 +70,17 @@ export default {
   //     this.
   //   }
   // },
-  // methods: {
-  //   ...mapActions({
-  //     loadFlagCollItems: 'User/loadFlagCollItems'
-  //   })
-  // }
+  methods: {
+    ...mapActions({
+      closeFlagColl: 'User/closeFlagColl'
+    }),
+    onCloseFlagColl(e) {
+      this.closeFlagColl()
+    }
+  },
+  components: {
+    MiniCard
+  }
 }
 </script>
 <style lang="scss" scoped>

+ 2 - 2
web/themes/custom/materiotheme/vuejs/components/User/UserFlags.vue

@@ -26,7 +26,7 @@
         <span
           class="add-btn mdi"
           :class="addFlagBtnClassObj"
-          @click.prevent="onCreateFlagColl"
+          @click.prevent.stop="onCreateFlagColl"
         />
       </li>
     </ul>
@@ -92,7 +92,7 @@ export default {
     },
     onOpenFlagColl (e) {
       const flagcollid = e.target.getAttribute('flagcollid');
-      console.log("UserFlags onDeleteFlagColl", flagcollid);
+      console.log("UserFlags onOpenFlagColl", flagcollid);
       this.openFlagColl(flagcollid)
         .then(() => {
           // console.log("onDeleteFlagColl then", data);

+ 56 - 0
web/themes/custom/materiotheme/vuejs/components/cardMixins.js

@@ -0,0 +1,56 @@
+// https://forum.vuejs.org/t/how-to-use-helper-functions-for-imported-modules-in-vuejs-vue-template/6266/5
+export default {
+  directives: {
+    lazy: {
+      bind(img,binding){
+        // console.log('lazy bind', img, binding);
+        if(binding.value === 0){
+          img.setAttribute('src', img.getAttribute('data-src'))
+          img.removeAttribute('data-src')
+          img.classList.remove('lazy')
+        }
+      }
+    },
+    switcher: {
+      inserted(el,binding){
+        // switch images on mousemove
+        el.addEventListener('mousemove', function(event) {
+          let figs = this.querySelectorAll('figure')
+          // console.log('mousemove', this, event, figs.length);
+          // let len = figs.length
+          // let w = this.clientWidth;
+          // let g = w / len;
+          // let delta = Math.floor(event.layerX / g)
+          let delta = Math.floor(event.layerX / (this.clientWidth / figs.length))
+          // console.log('delta', delta);
+          figs.forEach((fig, index) => {
+            // console.log(index);
+            if(index == delta){
+              fig.style.display = "block"
+            }else{
+              fig.style.display = "none"
+            }
+          })
+        })
+      }
+    }
+  },
+  mounted() {
+    // lazy load images on mouseover
+    this.$el.addEventListener('mouseover', function(event) {
+      let imgs = this.querySelectorAll('.images figure img.lazy')
+      // console.log('mouseover', this, imgs);
+      imgs.forEach((img) => {
+        // console.log('forEach img',img);
+        img.setAttribute('src', img.getAttribute('data-src'))
+        img.removeAttribute('data-src')
+        img.classList.remove('lazy')
+      })
+    }, {once : true})
+  },
+  methods: {
+    // deg2rad (deg) {
+    //   return deg * (Math.PI / 180)
+    // },
+  }
+}

+ 90 - 1
web/themes/custom/materiotheme/vuejs/store/index.js

@@ -1,5 +1,11 @@
 import Vue from 'vue'
 import Vuex from 'vuex'
+
+import { createStore } from 'vuex-extensions'
+
+import { JSONAPI } from 'vuejs/api/json-axios'
+import qs from 'querystring-es3'
+
 import Common from './modules/common'
 import User from './modules/user'
 import Search from './modules/search'
@@ -10,7 +16,8 @@ import Pages from './modules/pages'
 // https://github.com/vuejs/vuex/tree/dev/examples/shopping-cart
 
 Vue.use(Vuex)
-export default new Vuex.Store({
+// export default new Vuex.Store({
+export default createStore(Vuex.Store, {
   modules: {
     Common,
     User,
@@ -18,5 +25,87 @@ export default new Vuex.Store({
     Blabla,
     Showrooms,
     Pages
+  },
+  // https://github.com/huybuidac/vuex-extensions
+  mixins: {
+    actions: {
+      loadMaterials ({ dispatch }, { uuids, imgStyle, callBack, callBackArgs }) {
+        const params = {
+          // include: 'images', // no needs to include thanks to consumers_image_styles module
+          // include: 'drupal_internal__nid',
+          'filter[uuids-groupe][group][conjunction]': 'OR'
+        }
+        for (let i = 0; i < uuids.length; i++) {
+          const uuid = uuids[i]
+          params[`filter[${uuid}][condition][path]`] = 'id'
+          params[`filter[${uuid}][condition][value]`] = uuid
+          params[`filter[${uuid}][condition][operator]`] = '='
+          params[`filter[${uuid}][condition][memberOf]`] = 'uuids-groupe'
+        }
+        // console.log('search JSONAPI params', params);
+        const q = qs.stringify(params)
+        return JSONAPI.get('node/materiau?' + q)
+          .then(({ data }) => {
+            console.log('mixin getMaterials data', data)
+            dispatch('parseMaterials', { data: data.data, uuids: uuids, imgStyle: imgStyle, callBack: callBack, callBackArgs: callBackArgs })
+            // commit('setItems', data.items)
+          })
+          .catch((error) => {
+            console.warn('Issue with getItems', error)
+            Promise.reject(error)
+          })
+      },
+      parseMaterials ({ dispatch }, { data, uuids, imgStyle, callBack, callBackArgs }) {
+        // data comes from jsonapi query
+        // uuids comes from original query (solr, FlagCollection, etc)
+        // so we loop from uuids to conserve the original order
+        console.log('mixin parseMaterials', data, uuids, callBack, callBackArgs)
+        const items = []
+        // for (var i = 0; i < data.length; i++) {
+        for (let i = 0; i < uuids.length; i++) {
+          const uuid = uuids[i]
+          // https://stackoverflow.com/questions/11258077/how-to-find-index-of-an-object-by-key-and-value-in-an-javascript-array
+          const item_index = data.findIndex(p => p.id === uuid)
+          // console.log('item_index', item_index);
+          if (item_index === -1) continue
+
+          const item_src = data[item_index]
+          const attrs = item_src.attributes
+          const relations = item_src.relationships
+
+          // get field values
+          const item = {
+            uuid: uuid,
+            title: attrs.title,
+            field_short_description: attrs.field_short_description,
+            body: attrs.body,
+            field_reference: attrs.field_reference
+          }
+
+          // get images included values
+          const img_src = relations.images.data
+          // console.log('img_src', img_src);
+          // this is a temporary deactivation of images
+          // img_src = [];
+          item.images = []
+          for (let j = 0; j < img_src.length; j++) {
+            if (img_src[j].meta.imageDerivatives) {
+              item.images.push({
+                title: img_src[j].meta.title,
+                // meta.imageDerivatives.style.href link is provided by drupal consumers_image_styles module
+                // BUG: missing all image derivative but first
+                url: img_src[j].meta.imageDerivatives.links.[imgStyle].href
+              })
+            } else {
+              console.warn('missing image derivative ' + j + '/' + img_src.length + ' for ' + attrs.title)
+            }
+          }
+
+          items.push(item)
+        }
+        console.log('items', items)
+        dispatch(callBack, { items: items, callBackArgs: callBackArgs })
+      }
+    }
   }
 })

+ 28 - 78
web/themes/custom/materiotheme/vuejs/store/modules/search.js

@@ -16,6 +16,7 @@ export default {
     limit: 15,
     infos: null,
     count: 0,
+    noresults: false,
     // infinteState will come from vue-infinite-loading plugin
     // implemented in vuejs/components/Content/Base.vue
     infiniteLoadingState: null
@@ -32,7 +33,7 @@ export default {
     resetUuids (state) {
       state.uuids = []
     },
-    setItems (state, items) {
+    setMaterials (state, items) {
       state.items = state.items.concat(items)
     },
     resetItems (state) {
@@ -50,6 +51,15 @@ export default {
     setCount (state, count) {
       state.count = count
     },
+    resetCount (state, count) {
+      state.count = false
+    },
+    setNoresults (state) {
+      state.noresults = true
+    },
+    resetNoresults (state) {
+      state.noresults = false
+    },
     resetOffset (state) {
       state.offset = 0
     },
@@ -67,6 +77,8 @@ export default {
       console.log('Search newSearch')
       commit('resetUuids')
       commit('resetItems')
+      commit('resetCount')
+      commit('resetNoresults')
       commit('resetOffset')
       this.commit('Common/setPagetitle', state.keys)
       dispatch('getResults')
@@ -92,89 +104,27 @@ export default {
           // commit('setItems', data.items)
           commit('setInfos', data.infos)
           commit('setCount', data.count)
-          commit('setUuids', data.uuids)
-          dispatch('getItems', data.uuids)
+          if (data.count) {
+            commit('setUuids', data.uuids)
+            // loadMaterials is on mixins
+            // https://github.com/huybuidac/vuex-extensions
+            dispatch('loadMaterials', {
+              uuids: data.uuids,
+              imgStyle: 'card_medium',
+              callBack: 'loadMaterialsCallBack'
+            })
+          }else{
+            commit('setNoresults')
+          }
         })
         .catch((error) => {
           console.warn('Issue with getResults', error)
           Promise.reject(error)
         })
     },
-    getItems ({ dispatch, commit, state }, uuids) {
-      const params = {
-        // include: 'images', // no needs to include thanks to consumers_image_styles module
-        // include: 'drupal_internal__nid',
-        'filter[uuids-groupe][group][conjunction]': 'OR'
-      }
-      for (let i = 0; i < uuids.length; i++) {
-        const uuid = uuids[i]
-        params[`filter[${uuid}][condition][path]`] = 'id'
-        params[`filter[${uuid}][condition][value]`] = uuid
-        params[`filter[${uuid}][condition][operator]`] = '='
-        params[`filter[${uuid}][condition][memberOf]`] = 'uuids-groupe'
-      }
-      // console.log('search JSONAPI params', params);
-      const q = qs.stringify(params)
-      return JSONAPI.get('node/materiau?' + q)
-        .then(({ data }) => {
-          console.log('search getItems data', data)
-          dispatch('parseItems', { data: data.data, uuids: uuids })
-          // commit('setItems', data.items)
-        })
-        .catch((error) => {
-          console.warn('Issue with getItems', error)
-          Promise.reject(error)
-        })
-    },
-    parseItems ({ dispatch, commit, state }, { data, uuids }) {
-      // data comes from jsonapi query
-      // uuids comes from solr search query (we loop from uuids to conserve the search results order)
-      console.log('search parseItems data, uuids', data, uuids)
-      const items = []
-      // for (var i = 0; i < data.length; i++) {
-      for (let i = 0; i < uuids.length; i++) {
-        const uuid = uuids[i]
-        // https://stackoverflow.com/questions/11258077/how-to-find-index-of-an-object-by-key-and-value-in-an-javascript-array
-        const item_index = data.findIndex(p => p.id == uuid)
-        // console.log('item_index', item_index);
-        if (item_index == -1) continue
-
-        const item_src = data[item_index]
-        const attrs = item_src.attributes
-        const relations = item_src.relationships
-
-        // get field values
-        const item = {
-          uuid: uuid,
-          title: attrs.title,
-          field_short_description: attrs.field_short_description,
-          body: attrs.body,
-          field_reference: attrs.field_reference
-        }
-
-        // get images included values
-        const img_src = relations.images.data
-        // console.log('img_src', img_src);
-        // this is a temporary deactivation of images
-        // img_src = [];
-        item.images = []
-        for (let j = 0; j < img_src.length; j++) {
-          if (img_src[j].meta.imageDerivatives) {
-            item.images.push({
-              title: img_src[j].meta.title,
-              // meta.imageDerivatives.style.href link is provided by drupal consumers_image_styles module
-              // BUG: missing all image derivative but first
-              url: img_src[j].meta.imageDerivatives.links.card_medium.href
-            })
-          } else {
-            console.warn('missing image derivative ' + j + '/' + img_src.length + ' for ' + attrs.title)
-          }
-        }
-
-        items.push(item)
-      }
-      console.log('items', items)
-      commit('setItems', items)
+    loadMaterialsCallBack ({ commit, state }, { items, callBackArgs }) {
+      console.log('search loadMaterialsCallBack', items)
+      commit('setMaterials', items)
       if (state.infiniteLoadingState) {
         if (state.offset + state.limit > state.count) {
           console.log('Search infinite completed')

+ 30 - 31
web/themes/custom/materiotheme/vuejs/store/modules/user.js

@@ -1,5 +1,5 @@
 import { REST } from 'vuejs/api/rest-axios'
-import { JSONAPI } from 'vuejs/api/json-axios'
+// import { JSONAPI } from 'vuejs/api/json-axios'
 import { MA } from 'vuejs/api/ma-axios'
 import qs from 'querystring-es3'
 
@@ -89,9 +89,15 @@ export default {
     openFlagColl (state, collid) {
       state.openedCollid = collid
     },
+    closeFlagColl (state) {
+      state.openedCollid = null
+    },
     setLoadedCollItems (state, data) {
       console.log('setLoadedCollItems', data)
-      state.flagcolls[data.collid].loadedItems = data.items
+      // if no data, we are just calling the mutation to trigger the component update
+      if (data) {
+        state.flagcolls[data.collid].loadedItems = data.items
+      }
     }
   },
 
@@ -270,38 +276,31 @@ export default {
           })
       })
     },
-    openFlagColl ({ commit, dispatch }, collid) {
+    openFlagColl ({ commit, dispatch, state }, collid) {
       console.log('user openFlagColl', collid)
       commit('openFlagColl', collid)
-      dispatch('loadFlagCollItems', collid)
-    },
-    loadFlagCollItems ({ commit, state }, collid) {
-      console.log('loadFlagCollItems', state.flagcolls[collid].items_uuids)
-      const params = {
-        'filter[uuids-groupe][group][conjunction]': 'OR'
-      }
-      const uuids = state.flagcolls[collid].items_uuids
-      // console.log('uuids', uuids)
-      for (let i = 0; i < uuids.length; i++) {
-        let uuid = uuids[i]
-        // console.log('uuid', uuid)
-        params[`filter[${uuid}][condition][path]`] = 'id'
-        params[`filter[${uuid}][condition][value]`] = uuid
-        params[`filter[${uuid}][condition][operator]`] = '='
-        params[`filter[${uuid}][condition][memberOf]`] = 'uuids-groupe'
-      }
-      console.log('search JSONAPI params', params);
-      const q = qs.stringify(params)
-      return JSONAPI.get('node/materiau?' + q)
-        .then(({ data }) => {
-          console.log('user loadFlagCollItems data', data)
-          // dispatch('parseItems', { data: data.data, uuids: uuids })
-          commit('setLoadedCollItems', {collid: collid, items: data.data})
-        })
-        .catch((error) => {
-          console.warn('Issue with loadFlagCollItems', error)
-          Promise.reject(error)
+      if (typeof state.flagcolls[collid].loadedItems === 'undefined') {
+        // if no loadedItems, load them
+        // loadMaterials is on mixins
+        // https://github.com/huybuidac/vuex-extensions
+        dispatch('loadMaterials', {
+          uuids: state.flagcolls[collid].items_uuids,
+          imgStyle: 'card_medium_half',
+          callBack: 'loadMaterialsCallBack',
+          callBackArgs: { collid: collid }
         })
+      } else {
+        // call the mutation without data to only trigger the FlagCollection component update
+        commit('setLoadedCollItems')
+      }
+    },
+    loadMaterialsCallBack ({ commit }, { items, callBackArgs }) {
+      console.log('user loadMaterialsCallBack', items)
+      commit('setLoadedCollItems', { collid: callBackArgs.collid, items: items })
+    },
+    closeFlagColl ({ commit, dispatch }) {
+      console.log('user closeFlagColl')
+      commit('closeFlagColl')
     },
     userLogout ({ commit, state }) {
       const credentials = qs.stringify({

Some files were not shown because too many files changed in this diff