Skip to content

Commit

Permalink
feat(the-cart): add TheCart component
Browse files Browse the repository at this point in the history
  • Loading branch information
Raullages committed Jun 8, 2020
1 parent ebd4896 commit feb9a9e
Show file tree
Hide file tree
Showing 6 changed files with 307 additions and 24 deletions.
9 changes: 5 additions & 4 deletions @ecomplus/storefront-app/src/views/Cart.vue
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
<template>
<div id="cart">
<ec-cart
<the-cart
:amount="amount"
@shippingService="selectShippingService"
:discountCoupon.sync="discountCoupon"
@setDiscountRule="setDiscountRule"
:discount-coupon.sync="discountCoupon"
:base-modules-request-data="baseModulesRequestData"
@shipping-service="selectShippingService"
@set-discount-rule="setDiscountRule"
/>
</div>
</template>
Expand Down
43 changes: 23 additions & 20 deletions @ecomplus/storefront-app/src/views/js/Cart.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,22 @@
import { mapGetters, mapMutations, mapActions } from 'vuex'
import {
mapGetters,
mapMutations,
mapActions
} from 'vuex'
import ecomCart from '@ecomplus/shopping-cart'
import baseModulesRequestData from './../../lib/base-modules-request-data'
import { upsertCart } from './../../lib/sync-cart-to-api'
import EcCart from './../../components/EcCart.vue'
import TheCart from '#components/TheCart.vue'

export default {
name: 'cart',

components: {
EcCart
TheCart
},

computed: {
...mapGetters([
'amount'
]),
...mapGetters(['amount']),

discountCoupon: {
get () {
Expand All @@ -22,6 +25,9 @@ export default {
set (couponCode) {
this.setDiscountCoupon(couponCode)
}
},
baseModulesRequestData () {
return baseModulesRequestData
}
},

Expand All @@ -32,25 +38,22 @@ export default {
'selectShippingService'
]),

...mapActions([
'fetchCartItems'
])
...mapActions(['fetchCartItems'])
},

created () {
this.fetchCartItems({}).then(() => {
upsertCart()
.then(() => {
ecomCart.on('change', upsertCart)
const fetchAddedItem = ({ item }) => {
this.fetchCartItems({ items: [item] })
}
ecomCart.on('addItem', fetchAddedItem)
this.$once('hook:beforeDestroy', () => {
ecomCart.off('change', upsertCart)
ecomCart.off('addItem', fetchAddedItem)
})
upsertCart().then(() => {
ecomCart.on('change', upsertCart)
const fetchAddedItem = ({ item }) => {
this.fetchCartItems({ items: [item] })
}
ecomCart.on('addItem', fetchAddedItem)
this.$once('hook:beforeDestroy', () => {
ecomCart.off('change', upsertCart)
ecomCart.off('addItem', fetchAddedItem)
})
})
})
}
}
3 changes: 3 additions & 0 deletions @ecomplus/storefront-components/src/TheCart.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<script src="./js/TheCart.js"></script>
<template lang="html" src="./html/TheCart.html"></template>
<style lang="scss" src="./scss/TheCart.scss"></style>
135 changes: 135 additions & 0 deletions @ecomplus/storefront-components/src/html/TheCart.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
<div class="cart">
<transition-group enter-active-class="animated fadeInDown">
<div
class="row"
v-if="cart.items.length"
key="list">
<div class="col-md-7 col-lg-8">
<div class="cart__list">
<slot
name="list"
v-bind="{ items: cart.items }">
<transition-group
enter-active-class="animated fadeInDown"
leave-active-class="animated fadeOutUp faster position-absolute"
>
<cart-item
v-for="item in cart.items"
:key="item._id"
:item="item"
:name-max-length="80"
/>
</transition-group>
</slot>
</div>

<recommended-items col-class-name="col-6 col-lg-3"/>

<slot name="back-shopping">
<div class="cart__back d-none d-md-block my-4">
<a
class="cart__btn-back btn btn-link"
role="button"
href="/"
>
<i class="fas fa-arrow-left mr-1"></i>
{{ i19continueShopping }}
</a>
</div>
</slot>
</div>

<div class="col-md-5 col-lg-4 mt-3 mt-md-0">
<div class="cart__info">
<slot name="info">
<div class="cart__summary-row">
<span>Subtotal</span>
<div>{{ formatMoney(cart.subtotal) }}</div>
</div>

<transition enter-active-class="animated fadeInDown">
<div
class="cart__summary-row mt-1"
v-if="amount.discount">
<span>
<i class="fas fa-tag mr-1"></i>
{{ i19discount }}
</span>
<div>{{ formatMoney(amount.discount) }}</div>
</div>
</transition>

<shipping-calculator
class="cart__shipping"
:can-select-services="true"
:shipped-items="cart.items"
@select-service="val => $emit('shipping-service', val)"
@update:zip-code="val => $emit('update:zipCode', val)"
/>

<div class="cart__summary-row cart__total">
<span>Total</span>
<a-prices
:product="{ price: amount.total || cart.subtotal }"
:discount-option="{ value: amount.discount }"
:is-literal="true"
/>
</div>

<slot name="checkout">
<a
class="cart__btn-checkout btn btn-lg btn-block btn-success"
role="button"
:href="checkoutUrl"
>
<span class="mr-1">
<i class="fas fa-shopping-bag"></i>
</span>
{{ i19checkout }}
</a>

<a
class="cart__btn-back btn btn-block btn-outline-secondary d-md-none"
role="button"
href="/"
>
<i class="fas fa-arrow-left mr-1"></i>
{{ i19continueShopping }}
</a>
</slot>
</slot>
</div>

<slot name="discount-applier">
<discount-applier
class="cart__discount"
:amount="amount"
:coupon-code.sync="localDiscountCoupon"
:is-coupon-applied="Boolean(discountCoupon && amount.discount)"
@set-discount-rule="discountRule => $emit('set-discount-rule', discountRule)"
:modules-payload="modulesPayload"
/>
</slot>
</div>
</div>

<div
v-else
class="cart__empty"
key="empty"
>
<slot name="empty">
<p class="lead text-muted">
{{ i19emptyCart }} ...
</p>
<a class="btn btn-primary" href="/">
<span class="mr-1">
<i class="fas fa-arrow-left"></i>
</span>
{{ i19continueShopping }}
</a>
</slot>
</div>
</transition-group>
</div>

86 changes: 86 additions & 0 deletions @ecomplus/storefront-components/src/js/TheCart.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import {
$ecomConfig,
i18n,
formatMoney
} from '@ecomplus/utils'

import ecomCart from '@ecomplus/shopping-cart'
import APrices from './../APrices.vue'
import CartItem from './../CartItem.vue'
import DiscountApplier from './../DiscountApplier.vue'
import ShippingCalculator from './../ShippingCalculator.vue'
import RecommendedItems from './../RecommendedItems.vue'

import {
i19checkout,
i19continueShopping,
i19discount,
i19emptyCart
} from '@ecomplus/i18n'

export default {
name: 'TheCart',

components: {
APrices,
CartItem,
DiscountApplier,
ShippingCalculator,
RecommendedItems
},

props: {
ecomCart: {
type: Object,
default () {
return ecomCart
}
},
lang: {
type: String,
default: $ecomConfig.get('lang')
},
checkoutUrl: {
type: String,
default: '/app/#/checkout'
},
amount: {
type: Object,
default () {
return {}
}
},
discountCoupon: String,
baseModulesRequestData: {
type: Object,
default () {
return {}
}
}
},

computed: {
i19checkout: () => i18n(i19checkout),
i19continueShopping: () => i18n(i19continueShopping),
i19discount: () => i18n(i19discount),
i19emptyCart: () => i18n(i19emptyCart),
modulesPayload () {
return this.baseModulesRequestData
},
cart () {
return this.ecomCart.data
},
localDiscountCoupon: {
get () {
return this.discountCoupon
},
set (couponCode) {
this.$emit('update:discountCoupon', couponCode)
}
}
},

methods: {
formatMoney
}
}
55 changes: 55 additions & 0 deletions @ecomplus/storefront-components/src/scss/TheCart.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
.cart {
&__empty {
width: 100%;
text-align: center;
}

.cart-item {
padding-top: 1rem;
border-top: 1px dotted var(--gray);

&__name {
margin-bottom: .5rem;
}
}

&__discount {
margin: 1.5rem 0 1rem;

@media (max-width: 575.98px) {
margin: .5rem 0;
}
}

&__info {
border-radius: .25rem;
padding: 1rem;
background: var(--light);
}

&__summary-row {
display: flex;
justify-content: space-between;
align-items: center;
text-align: right;

> span {
color: var(--gray);
}
}

&__shipping {
margin: 1rem 0;
}

&__total {
margin: 1rem 0;

.prices {
&__value {
font-size: 1.5rem;
}
}
}
}

0 comments on commit feb9a9e

Please sign in to comment.