Browse Source

Adding distributor form component, form reactivity and some functionality

Herton 7 years ago
parent
commit
fccf2414a5

+ 1 - 0
package.json

@@ -12,6 +12,7 @@
   "dependencies": {
     "axios": "^0.18.0",
     "bootstrap-vue": "^2.0.0-rc.9",
+    "lodash": "^4.17.10",
     "octicons": "^7.2.0",
     "vue": "^2.5.11",
     "vue-router": "^3.0.1",

+ 91 - 36
src/components/Distributor-form.vue

@@ -1,88 +1,143 @@
 <template>
   <div id="distributor-form">
-    <b-form @submit="onSubmit" @reset="onReset" v-if="show">
-      <b-form-group label="Title:"
+    <b-form @submit="onSubmit">
+      <!-- Title Field -->
+      <b-form-group :label="labels.title"
                     label-for="distributor_title">
         <b-form-input id="distributor_title"
                       type="email"
-                      v-model="distributor(id).title"
+                      v-model="distributor.title"
                       required
-                      placeholder="Enter title">
+                      :placeholder="labels.titlePlaceholder">
         </b-form-input>
       </b-form-group>
-      <b-form-group label="Notes:"
+       <!-- Notes Field -->
+      <b-form-group :label="labels.notes"
                       label-for="distributor_notes">
         <b-form-textarea id="distributor_notes"
-                      v-model="distributor(id).notes"
-                      placeholder="Enter something"
+                      v-model="distributor.notes"
+                      :placeholder="labels.notesPlaceholder"
                       :rows="3"
                       :max-rows="6">
         </b-form-textarea>
       </b-form-group>
-      <b-form-group>
-        <b-table :items="contacts(id)" :fields="names(id)">
+       <!-- Contacts Fields -->
+      <b-form-group :label="labels.contacts">
+        <!-- If there are any contacts -->
+        <b-table v-if="names" :items="contacts" :fields="names">
           <template slot="actions" slot-scope="row">
-            <!-- we use @click.stop here to prevent emitting of a 'row-clicked' event  -->
             <b-button size="sm" @click.stop="onDelete(row.item)" class="mr-1">
-              delete
+              {{labels.delete}}
             </b-button>
           </template>            
         </b-table>
+        <!-- Inline contacts form -->
+        <b-form inline v-for="(contact, key) in distributor.contacts" :key="contact.id">
+          <b-input class="mb-3 mr-sm-3" 
+              v-model="contact.name"
+              :placeholder="labels.name" />
+
+          <b-input class="mb-3 mr-sm-3" 
+              v-model="contact.email" 
+              :placeholder="labels.email" />
+
+          <b-input class="mb-3 mr-sm-3" 
+              v-model="contact.phone" 
+              :placeholder="labels.phone"/>
+              
+          <b-button @click.stop="onDelete(key)" class="mb-3 mr-sm-3"  variant="primary">{{labels.delete}}</b-button>
+        
+        </b-form>
+
+        <b-form-group>
+          <b-button @click.stop="onAddContact()" class="mb-12 mr-sm-12"  variant="primary">{{labels.add}}</b-button>
+        </b-form-group>
+    
+        <b-form-group class="text-right">
+          <b-button  type="submit" variant="primary">{{labels.submit}}</b-button>
+          <b-button @click.stop="onCancel()" type="reset" variant="danger">{{labels.cancel}}</b-button>
+        </b-form-group>
       </b-form-group>
-      <b-button type="submit" variant="primary">Submit</b-button>
-      <b-button type="reset" variant="danger">Reset</b-button>
     </b-form>
-
   </div>
 </template>
 
 <script>
-import {mapGetters, mapState, mapActions} from 'vuex';
+import {mapGetters, mapActions} from 'vuex';
 import * as types from '../store/types';
+import {store} from '../store/store';
 
 export default {
   props: {
     id: {
-      type: Number,
       default: null
-    }
+    },
   },
   data () {
     return {
-      show: true,
-      translations: {
-        title: 'Distributor page',
-        add_distributor: 'Add distributor',
-      },
+      labels: {
+        title: 'Title:',
+        notes: 'Notes:',
+        contacts: 'Contacts:',
+        delete: 'Delete',
+        submit: 'Save',
+        cancel: 'Cancel',
+        titlePlaceholder: 'Enter title',
+        notesPlaceholder: 'Enter something',
+        add: 'Add',
+        name: 'Name',
+        email: 'Email',
+        phone: 'Phone',
+      }
     }
   },
   computed: {
-    
-  },
-  methods: {
     ...mapGetters({
-          distributor: types.GET_DISTRIBUTOR,
           contacts: types.GET_CONTACTS,
           names: types.GET_CONTACT_FIELDS,
       }),
-    onSubmit () {
-      console.log(distributor);
+      distributor: {
+        get() {
+          return this.$store.getters['distributor/GET_DISTRIBUTOR'](this.id)
+        },
+        set(val) {
+          //Placeholder
+        },
+      }
+  },
+  watch: {
+    distributor: {
+      handler(val){
+        this.saveDistributor({
+          id: val.id, 
+          distributor: val
+        });
+      },
+      deep: true
+    }
+  },
+  methods: {
+    ...mapActions({
+          saveDistributor: types.SET_DISTRIBUTOR,
+      }),
+    onSubmit (ev) {
+      console.log(ev);
     },
-    onReset () {
-      console.log('onReset');
+    onAddContact () {
+      console.log('add');
     },
     onDelete(item) {
       console.log('delete', item);
+    },
+    onCancel() {
+      console.log('onCancel');
     }
   },
-  created() {
-    console.log(this.id);
-    let t = this.contacts(this.id)
-    debugger
-  }
 }
 </script>
 
 <style lang="scss">
-
+  #distributor-form{
+    text-align: left;
+  }
 </style>

+ 48 - 0
src/components/Distributor-modal-form.vue

@@ -0,0 +1,48 @@
+<template>
+  <div class="distributor-modal-form-wrapper">
+    <!-- Info modal -->
+      <b-modal id="distributor_modal_form" 
+            :title="modalTitle"
+            size="lg"
+            @hide="resetModal" hideFooter>
+        <!-- Distributor Form -->
+        <distributor-form 
+            :id="distributorId"/>
+      </b-modal>
+  </div>
+</template>
+
+<script>
+
+import DistributorForm from './Distributor-form.vue';
+import {mapGetters, mapState, mapActions} from 'vuex';
+import * as types from '../store/types';
+
+export default {
+  components: {
+      'distributor-form': DistributorForm,
+  },
+  props: {
+    distributorId: {
+        default: null,
+    },
+  },
+  data () {
+    return {
+    }
+  },
+  computed: {
+      modalTitle() {
+          return this.distributorId ? 'Edit distributor' : 'Add a distributor';
+      },
+  },
+  methods: {
+    resetModal () {
+      this.$emit('closeItem');
+    },
+  },
+}
+</script>
+
+<style lang="scss">
+</style>

+ 26 - 21
src/components/Distributor.vue

@@ -1,27 +1,32 @@
 <template>
   <div class="distributor">
+    
     <header class="header container mb-5">
-      <h1>{{translations.title}}</h1>
+      <h1>{{labels.title}}</h1>
     </header>
+
     <section class="container">
-      <!-- Info modal -->
-      <b-modal id="modal_edit_form" @hide="resetModal" :title="modalTitle" ok-only>
-        <b-card>
-          <distributor-form 
-            :id="selectedId"/>
-        </b-card>
-      </b-modal>
+      <!-- Distributor modal -->
+      <distributor-modal-form
+          :distributorId="selectedId"
+          @resetModal="resetModal">
+      </distributor-modal-form>
+
       <div class="row mb-3">
         <b-table :items="items" :fields="fields">
+
+           <!-- Action to edit Distributor-->
           <template slot="actions" slot-scope="row">
-            <!-- we use @click.stop here to prevent emitting of a 'row-clicked' event  -->
             <b-button size="sm" @click.stop="editDistributor(row.item)" class="mr-1">
-              {{translations.edit_distributor}} 
+              {{labels.edit_distributor}} 
             </b-button>
-          </template>            
+          </template>      
+
         </b-table>
+
+        <!-- Button to add Distributor-->
         <b-button :pressed.sync="addDistributor" variant="primary">
-          {{translations.add_distributor}}
+          {{labels.add_distributor}}
         </b-button>
       </div>
     </section>
@@ -30,21 +35,21 @@
 
 <script>
 
-import DistributorForm from './Distributor-form.vue';
+import DistributorModalForm from './Distributor-modal-form.vue';
 import {mapGetters, mapState, mapActions} from 'vuex';
 import * as types from '../store/types';
 
 export default {
   components: {
-      'distributor-form': DistributorForm,
+      'distributor-modal-form': DistributorModalForm,
   },
   data () {
     return {
       addDistributor: true,
-      translations: {
+      labels: {
         title: 'Distributor page',
         add_distributor: 'Add distributor',
-        edit_distributor: 'Edit distributor',
+        edit_distributor: 'Edit',
       },
       selectedId: null,
       rowShowing: null,
@@ -57,17 +62,17 @@ export default {
           items: types.GET_ITEMS,
       }),
       modalTitle() {
-        return this.translations.add_distributor;
+        return this.labels.add_distributor;
       },
   },
   methods: {
     editDistributor(item) {
-      console.log(item);
-      this.selectedId = item.id;
-      this.$root.$emit('bv::show::modal', 'modal_edit_form', item)
+      this.selectedId = parseInt(item.id);
+      this.$root.$emit('bv::show::modal', 'distributor_modal_form')
     },
     resetModal () {
-      this.modalInfo.title = ''
+      this.selectedId = null;
+      console.log('Modal resets');
     },
     ...mapActions({
       loadMockedDistributors: types.FETCH_DISTRIBUTORS,

+ 21 - 2
src/store/modules/distributor/actions.js

@@ -42,7 +42,26 @@ export default {
     [types.CLEAR_DISTRIBUTORS]: ({commit}) => {
         commit(types.UPDATE_DISTRIBUTORS, []);
     },
-    [types.GET_DISTRIBUTOR]: ({commit}, payload) => {
-        commit(types.UPDATE_DISTRIBUTOR, payload);
+    /**
+     * Expected payload: {id, distributor}
+     */
+    [types.SET_DISTRIBUTOR]: ({commit, getters}, payload) => {
+        if (payload.id) {
+            // Update server with what changed
+            // api call
+            commit(types.UPDATE_DISTRIBUTOR, payload.distributor);
+        } else {
+            // Add new distributor
+            // api call
+            let distributor = {
+                id: Math.floor(Math.random() * 9000),
+            }
+            commit(types.UPDATE_DISTRIBUTOR, 
+                Object.assign(
+                    distributor, 
+                    payload.distributor
+                )
+            );
+        }
     },
 };

+ 38 - 9
src/store/modules/distributor/getters.js

@@ -1,25 +1,54 @@
 import * as types from '../../types';
 
+const UUID = '44490103-92B7-4712-B494'; //A starting client side id
+
+class DistributorClass {
+    constructor() {
+        //Setting a random client side contact id
+        let uuid = uuid || `${UUID}-${Math.floor(Math.random() * 9000)}`;
+        //Setting the basic properties
+        this.title = '';
+        this.notes = '';
+        this.contacts = [{
+                uuid: uuid,
+                name: '',
+                email: '',
+                phone: '',
+            }];
+    }
+};
+
 export default {
     [types.GET_CONTACTS]: state => (id) => {
-        return state.distributors.find(distributor => distributor.id === id).contacts || [];
+        let contacts = [];
+        if (id) {
+            const dist = state.distributors.find(distributor => distributor.id === id)
+            contacts = (dist && dist.contacts) ? dist.contacts : [];
+        }
+        return contacts;
     },
-    [types.GET_CONTACT_FIELDS]: state => (id) => {
-        let dist = state.distributors.find(distributor => distributor.id === id);
-        let keys = Object.keys(dist);
-        keys.push('actions'); //Adding Action column
+    [types.GET_CONTACT_FIELDS]: state => {
+        let dist = new DistributorClass();
+        let keys = Object.keys(dist.contacts[0]);
+        keys = keys.slice(1); //Removing uuid column
+        keys.push(''); //Adding empty Action column
         return keys;
     },
     [types.GET_DISTRIBUTORS]: state => {
         return state.distributors;
     },
-    [types.GET_DISTRIBUTOR]: state => (id) => {
-        return state.distributors.find(distributor => distributor.id === id) || {};
+    [types.GET_DISTRIBUTOR]: (state) => (id) => {
+        let distributor;
+        if (id) {
+            distributor = state.distributors.find(distributor => distributor.id === id) || {};
+        } else {
+            distributor = new DistributorClass();
+        }
+        return distributor;
     },
     [types.GET_FIELDS]: state => {
-        let keys = Object.keys(state.distributors[0]);
+        let keys = Object.keys(new DistributorClass());
         keys.push('actions'); //Adding Action column
-        keys = keys.slice(1); //Removing the title
         return keys;
     },
     [types.GET_ITEMS]: state => {

+ 2 - 1
src/store/types.js

@@ -13,4 +13,5 @@ export const UPDATE_DISTRIBUTOR = 'distributor/UPDATE_DISTRIBUTOR';
 
 // Actions
 export const FETCH_DISTRIBUTORS = 'distributor/FETCH_DISTRIBUTORS';
-export const CLEAR_DISTRIBUTORS = 'distributor/CLEAR_DISTRIBUTORS';
+export const CLEAR_DISTRIBUTORS = 'distributor/CLEAR_DISTRIBUTORS';
+export const SET_DISTRIBUTOR = 'distributor/SET_DISTRIBUTOR';

+ 2 - 1
webpack.config.js

@@ -71,7 +71,8 @@ module.exports = {
   },
   resolve: {
     alias: {
-      'vue$': 'vue/dist/vue.esm.js'
+      'vue$': 'vue/dist/vue.esm.js',
+      'components': path.resolve('./src/components'),
     },
     extensions: ['*', '.js', '.vue', '.json']
   },