Browse Source

[ADD] product cart

Gogs 7 years ago
parent
commit
c86e44fc8a

+ 3 - 0
src/App.vue

@@ -27,6 +27,9 @@
         methods: mapActions([
             'initPurchase'
         ]),
+        /**
+         * 
+         */
         mounted() {
             this.initPurchase()
         }

+ 0 - 13
src/components/cart/ProductItem.vue

@@ -1,13 +0,0 @@
-<template lang="pug">
-  
-</template>
-
-<script>
-    export default {
-    
-    }
-</script>
-
-<style lang="sass">
-
-</style>

+ 0 - 13
src/components/cart/ProductsGrid.vue

@@ -1,13 +0,0 @@
-<template lang="pug">
-  
-</template>
-
-<script>
-    export default {
-    
-    }
-</script>
-
-<style lang="sass">
-
-</style>

+ 47 - 0
src/components/product/Cart.vue

@@ -0,0 +1,47 @@
+<template lang="pug">
+    .cart
+        .cart-total
+            h2.currency-cart-total
+        .cart-items-wrapper
+            transition-group(name='list' tag='ul' class='cart-items')
+                cart-item(v-for='item in cartItems' :key='item.id' :item='item')
+</template>
+
+<script>
+    import { mapGetters } from 'vuex'
+    import CartItem from '@/components/product/CartItem'
+
+    export default {
+        components: {
+            CartItem
+        }
+    }
+</script>
+
+<style lang="sass">
+    .cart
+        width: 300px
+        height: 100%
+        border-left: 1px solid #d3d3d3
+        padding-left: 10px
+        display: inline-block
+        vertical-align: top
+        .cart-total
+            width: 100%
+            height: 50px
+            .currency-cart-total
+                width: 100%
+                height: 50px
+                margin: 0
+                font-size: 30pt
+        .cart-items-wrapper
+            width: 100%
+            height: calc(100% - 100px)
+            overflow-y: auto
+            overflow-x: hidden
+            .list-enter-active, .list-leave-active
+                transition: all 0.3s
+            .list-enter, .list-leave-to
+                opacity: 0
+                transform: translateX(300px)
+</style>

+ 84 - 0
src/components/product/CartItem.vue

@@ -0,0 +1,84 @@
+<template lang="pug">
+    li.cart-item
+        h3.item-name
+        input.item-quantity
+        span.item-x x
+        span.item-price
+        span.item-equals =
+        span.item-subtotal
+</template>
+
+<script>
+    import { mapGetters, mapActions } from 'vuex'
+
+    export default {
+        props: {
+            item: {
+                type: Object,
+                required: true,
+                default: {}
+            }
+        },
+        computed: {
+            quantity: {
+                get() {
+                    return this.item.qty || 1
+                },
+                set(value) {
+                    this.item.quantity = value || 1
+                }
+            }
+        },
+        mounted() {
+            this.$set(this.item, 'qty', 1)
+            this.$set(this.item, 'price', this.item.list_price)
+            this.$set(this.item, 'discount', 0)
+        }
+    }
+</script>
+
+<style lang="sass">
+    .cart-item
+        width: 100%
+        height: 90px
+        list-style: none outside none
+        border-bottom: 1px solid #d3d3d3
+        box-sizing: border-box
+        position: relative
+        &:nth-child(1)
+            border-top: 1px solid #d3d3d3
+        &:hover
+            transition-duration: 1000ms
+            border-bottom: 2px solid #7c7bad
+        .item-name
+            width: 100%
+            height: 20px
+            margin: 10px 0 5px 0
+            float: left
+            font-size: 8pt
+        .item-quantity
+            width: 50px
+            height: 28px
+            margin-top: 6px
+            text-align: right
+            float: left
+        .item-x
+            width: 80px
+            height: 20px
+            margin-top: 12px
+            text-align: right
+            float: left
+        .item-equals
+            width: 20px
+            height: 20px
+            margin-top: 12px
+            text-align: center
+            float: left
+        .item-subtotal
+            width: 100px
+            height: 20px
+            margin-top: 12px
+            padding-right: 15px
+            text-align: right
+            font-weight: bold
+</style>

+ 7 - 2
src/components/product/ProductCard.vue

@@ -1,5 +1,5 @@
 <template lang="pug">
-    .product-card
+    .product-card(@click='selectProduct(item)')
         h2.product-name {{ item.name }}
         img.product-image(:src="item.imageMedium ? 'data:image/png;base64,' + item.imageMedium : '/web/static/src/img/placeholder.png'")
         .product-price
@@ -7,6 +7,8 @@
 </template>
 
 <script>
+    import { mapActions } from 'vuex'
+
     export default {
         props: {
             item: {
@@ -17,7 +19,10 @@
         methods: {
             getPrice() {
                 return 0
-            }
+            },
+            ...mapActions([
+                'selectProduct'
+            ])
         }
     }
 </script>

+ 4 - 2
src/components/product/ProductsStep.vue

@@ -3,17 +3,19 @@
         .products-selector
             product-searcher
             products-grid
-        .cart-viewer
+        cart
 </template>
 
 <script>
     import ProductSearcher from '@/components/product/ProductSearcher'
     import ProductsGrid from '@/components/product/ProductsGrid'
+    import Cart from '@/components/product/Cart'
 
     export default {
         components: {
             ProductSearcher,
-            ProductsGrid
+            ProductsGrid,
+            Cart
         }
     }
 </script>

+ 15 - 1
src/components/supplier/SupplierCard.vue

@@ -1,5 +1,5 @@
 <template lang="pug">
-    .supplier-card
+    .supplier-card(@click='selectSupplier(item)' :class="{ 'supplier-selected': isSupplierSelected() }")
         h2.supplier-name {{ item.name }}
         img.supplier-image(:src="!!item.imageMedium ? 'data:image/png;base64,' + item.imageMedium : 'base/static/src/img/avatar.png'")
 </template>
@@ -13,6 +13,20 @@
                 type: Object,
                 default: {}
             }
+        },
+        computed: mapGetters([
+            'supplierSelected'
+        ]),
+        methods: {
+            /**
+             * 
+             */
+            isSupplierSelected() {
+                return !!this.supplierSelected && this.item.id === this.supplierSelected.id
+            },
+            ...mapActions([
+                'selectSupplier'
+            ])
         }
     }
 </script>

+ 45 - 3
src/components/supplier/SupplierDetails.vue

@@ -1,13 +1,55 @@
 <template lang="pug">
-  
+    .supplier-details
+        form.supplier-form
+            .form-separator
+                h3 Detalles generales
+                hr
+            .form-item
+                label.form-label Nombre
+                input.form-input(:value="supplierSelected.name || ''" readonly)
+            .form-item
+                label.form-label Celular
+                input.form-input(:value="supplierSelected.mobile || ''" readonly)
+            .form-item
+                label.form-label Teléfono
+                input.form-input(:value="supplierSelected.phone || ''" readonly)
+            .form-item
+                label.form-label Email
+                input.form-input(:value="supplierSelected.email || ''" readonly)
 </template>
 
 <script>
+    import { mapGetters } from 'vuex'
+
     export default {
-    
+        computed: mapGetters([
+            'supplierSelected'
+        ])
     }
 </script>
 
 <style lang="sass">
-
+    .supplier-details
+        width: 100%
+        height: 100%
+        .supplier-form
+            width: 100%
+            height: 100%
+            .form-separator
+                h3
+                    color: #9e9e9e
+                    font-size: 8pt
+                hr
+                    margin-top: 5px
+            .form-item
+                width: 100%
+                height: 35px
+                margin-bottom: 5px
+                .form-label
+                    width: 65px
+                    height: 35px
+                .form-input
+                    width: 210px
+                    height: 35px
+                    border-radius: 0
 </style>

+ 1 - 0
src/components/supplier/SupplierForm.vue

@@ -14,6 +14,7 @@
                 console.log(value)
                 if (!value) {
                     this.$modal.hide('supplier-modal')
+                    return
                 }
 
                 this.supplier.name = ''

+ 5 - 3
src/components/supplier/SupplierStep.vue

@@ -5,8 +5,7 @@
                 supplier-searcher
                 supplier-grid
             transition(name='slide-fade')
-                .supplier-details
-                    supplier-details
+                supplier-details(v-if='!!supplierSelected')
 </template>
 
 <script>
@@ -21,7 +20,10 @@
             SupplierSearcher,
             SupplierGrid,
             SupplierDetails
-        }
+        },
+        computed: mapGetters([
+            'supplierSelected'
+        ])
     }
 </script>
 

+ 0 - 4
src/store/actions.js

@@ -25,10 +25,6 @@ const actions = {
         Object.keys(payload).forEach(key => {
             commit(`set${key[0].toLocaleUpperCase()}${key.slice(1)}`, payload[key])
         })
-
-        setTimeout(() => {
-            dispatch('resetPurchase')
-        }, 5000)
     },
     /**
      * Send data to create concrete purchase

+ 2 - 0
src/store/index.js

@@ -9,6 +9,7 @@ import currency from '@/store/modules/currency'
 import journal from '@/store/modules/journal'
 import supplier from '@/store/modules/supplier'
 import product from '@/store/modules/product'
+import cart from '@/store/modules/cart'
 import picking from '@/store/modules/picking'
 import payment from '@/store/modules/payment'
 
@@ -23,6 +24,7 @@ const store = new Vuex.Store({
         journal,
         supplier,
         product,
+        cart,
         picking,
         payment
     }

+ 104 - 0
src/store/modules/cart.js

@@ -0,0 +1,104 @@
+const state = {
+    cartItems: {
+        default: [],
+        values: []
+    },
+    cartTotal: {
+        default: 0,
+        value: 0
+    }
+}
+
+const getters = {
+    /**
+     * 
+     * @param {*} state 
+     */
+    cartItems(state) {
+        return state.cartItems.values
+    },
+    /**
+     * 
+     * @param {*} state 
+     */
+    total(state) {
+        return state.cartTotal.value
+    }
+}
+
+const mutations = {
+    /**
+     * 
+     * @param {*} state 
+     * @param {*} payload 
+     */
+    setCartItems(state, payload) {
+        state.cartItems.values = [...payload]
+    },
+    /**
+     * 
+     * @param {*} state 
+     * @param {*} payload 
+     */
+    setTotal(state, payload) {
+        state.cartTotal.value = payload
+    },
+    /**
+     * 
+     * @param {*} state 
+     * @param {*} payload 
+     */
+    addToCart(state, payload) {
+        let productFound = state.cartItems.values.find(item => item.id === payload.id)
+
+        if(productFound) {
+            payload.qty = payload.qty + 1
+            return
+        }
+
+        state.cartItems.values = [payload, ...state.cartItems.values]
+    },
+    /**
+     * 
+     * @param {*} state 
+     */
+    computeTotal(state) {
+        console.log(state.cartTotal)
+        state.cartTotal.value = state.cartItems.values.reduce((total, value) => total + ((value.price || value.listPrice) * (value.qty || 1)), 0)
+    }
+}
+
+const actions = {
+    /**
+     * Add item to cart or increment item quantity if exist
+     * @param {*} param0 
+     * @param {*} payload 
+     */
+    addToCart({ commit }, payload) {
+        commit('addToCart', payload)
+        commit('computeTotal')
+    },
+    /**
+     * Remove item from cart
+     * @param {*} param0 
+     * @param {*} payload 
+     */
+    removeFromCart({ commit }, payload) {
+        console.log(payload)
+    },
+    /**
+     * Decrement item quantity from cart
+     * @param {*} param0 
+     * @param {*} payload 
+     */
+    decrementFromCart({ commit }, payload) {
+        console.log(payload)
+    }
+}
+
+export default {
+    state,
+    getters,
+    mutations,
+    actions
+}

+ 44 - 0
src/store/modules/product.js

@@ -6,6 +6,10 @@ const state = {
     products: {
         default: [],
         values: []
+    },
+    productVariant: {
+        default: null,
+        value: null
     }
 }
 
@@ -16,6 +20,13 @@ const getters = {
      */
     products(state) {
         return state.products.values
+    },
+    /**
+     * 
+     * @param {*} state 
+     */
+    selectedProduct(state) {
+        return state.selectedProduct.value
     }
 }
 
@@ -27,6 +38,14 @@ const mutations = {
      */
     setProducts(state, payload) {
         state.products.values = [...payload]
+    },
+    /**
+     * 
+     * @param {*} state 
+     * @param {*} payload 
+     */
+    setProductVariant(state, payload) {
+        state.productVariant.value = value
     }
 }
 
@@ -38,6 +57,31 @@ const actions = {
      */
     setProducts({ commit }, payload) {
         commit('setProducts', payload)
+    },
+    /**
+     * 
+     * @param {*} param0 
+     * @param {*} payload 
+     */
+    selectProduct({ commit, dispatch }, payload) {
+        if (payload.variantCount > 1) {
+            commit('setProductVariant', payload)
+            return
+        }
+
+        dispatch('addToCart', payload)
+    },
+    /**
+     * 
+     * @param {*} param0 
+     * @param {*} payload 
+     */
+    selectProductVariant({ commit, dispatch }, payload) {
+        commit('setProductVariant', null)
+
+        if (!payload) return
+
+        dispatch('addToCart', payload)
     }
 }
 

+ 16 - 30
src/store/modules/supplier.js

@@ -1,19 +1,19 @@
 const state = {
     suppliers: {
         default: [],
-        values: this.default
+        values: []
     },
     filteredSuppliers: {
         default: [],
-        values: this.default
+        values: []
     },
-    selectedSupplier: {
+    supplierSelected: {
         default: null,
-        value: this.default
+        value: null
     },
     addSupplier: {
         default: false,
-        value: this.default
+        value: false
     }
 }
 
@@ -29,15 +29,8 @@ const getters = {
      * 
      * @param {*} state 
      */
-    hasSelectedSupplier(state) {
-        return !!state.selectedSupplier.value
-    },
-    /**
-     * 
-     * @param {*} state 
-     */
-    selectedSupplier(state) {
-        return state.selectedSupplier.value
+    supplierSelected(state) {
+        return state.supplierSelected.value
     },
     /**
      * 
@@ -62,8 +55,8 @@ const mutations = {
      * @param {*} state 
      * @param {*} payload 
      */
-    setSelectedSupplier(state, payload) {
-        state.selectedSupplier.value = payload
+    setSupplierSelected(state, payload) {
+        state.supplierSelected.value = payload
     },
     /**
      * 
@@ -78,41 +71,34 @@ const mutations = {
      * @param {*} state 
      */
     setAddSupplier(state, payload) {
-        state.addSupplier.value = payload
+        state.addSupplier.value = !!payload
     }
 }
 
 const actions = {
-    /**
-     * 
-     * @param {*} param0 
-     */
-    setSuppliers({ commit }, payload) {
-        commit('setSuppliers', payload)
-    },
     /**
      * 
      * @param {*} param0 
      * @param {*} payload 
      */
-    setSelectSupplier({ commit }, payload) {
-        commit('selectSupplier', payload)
+    selectSupplier({ commit }, payload) {
+        commit('setSupplierSelected', payload)
     },
     /**
      * 
      * @param {*} param0 
      * @param {*} payload 
      */
-    setFilteredSuppliers({ commit }, payload) {
-        commit('filterSuppliers', payload)
+    filterSuppliers({ commit }, payload) {
+        commit('setFilteredSuppliers', payload)
     },
     /**
      * 
      * @param {*} param0 
      * @param {*} payload 
      */
-    setAddSupplier({ commit }) {
-        commit('addSupplier')
+    addSupplier({ commit }) {
+        commit('setAddSupplier', true)
     },
     /**
      *