Skip to content

Commit

Permalink
Merge fe2dae9 into 785c738
Browse files Browse the repository at this point in the history
  • Loading branch information
lukaszjedrasik committed Mar 17, 2021
2 parents 785c738 + fe2dae9 commit d19a83b
Show file tree
Hide file tree
Showing 12 changed files with 156 additions and 36 deletions.
4 changes: 3 additions & 1 deletion packages/commercetools/theme/lang/de.js
Original file line number Diff line number Diff line change
Expand Up @@ -118,5 +118,7 @@ export default {
'Let’s start now – we’ll help you': 'Fangen wir jetzt an - wir helfen Ihnen.',
'Search results': 'Suchergebnisse',
'Product suggestions': 'Produktvorschläge',
'Search for items': 'Nach Artikeln suchen'
'Search for items': 'Nach Artikeln suchen',
'Go to Checkout': 'Zum Checkout gehen',
'Successfully added {PRODUCT_NAME} to the cart': '{PRODUCT_NAME} wurde erfolgreich in den Warenkorb gelegt'
};
2 changes: 2 additions & 0 deletions packages/commercetools/theme/lang/en.js
Original file line number Diff line number Diff line change
Expand Up @@ -119,4 +119,6 @@ export default {
'Search results': 'Search results',
'Product suggestions': 'Product suggestions',
'Search for items': 'Search for items',
'Go to Checkout': 'Go to Checkout',
'Successfully added {PRODUCT_NAME} to the cart': 'Successfully added {PRODUCT_NAME} to the cart'
};
8 changes: 8 additions & 0 deletions packages/core/docs/changelog/5378.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
module.exports = {
description: 'added add to cart error/success handling',
link: 'https://github.com/vuestorefront/vue-storefront/issues/5378',
isBreaking: false,
breakingChanges: [],
author: 'Łukasz Jędrasik',
linkToGitHubAccount: 'https://github.com/lukaszjedrasik'
};
38 changes: 38 additions & 0 deletions packages/core/docs/guide/theme.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,3 +94,41 @@ Below you can find a list of the most important Nuxt Modules and libraries that

- [`@storefront-ui/vue`](https://storefrontui.io)
- [`wee-validate`](https://vee-validate.logaretm.com/v3)

## In-app Notifications

In Vue Storefront we're providing Notifications system based on composable `useUiNotification`.

There are three types of notifications: `danger`, `success` and `info`.

### How to send notification?

To send a new notification you need to only import `useUiNotification` from composables and pass `type` and `message` to `send` function. Rest parameters are optional.

Also, we have prepared repetitive notification messages. You can find them inside the assets directory.

```js
import { useUiNotification } from '~/composables';

setup() {
const { send } = useUiNotification();

send({
type: 'success',
message: 'Successfully added product to the cart'
})
}
```

```ts
type SendUiNotificationParams = {
message: string;
type: 'danger' | 'success' | 'info';
action?: { text: string; onClick: () => void };
icon?: string;
persist?: boolean;
dismiss?: () => void;
}
```
Also we have prepared
28 changes: 28 additions & 0 deletions packages/core/nuxt-theme-module/theme/assets/notifications/cart.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { useUiNotification } from '../../composables';

export const cart = ({ i18n, router }) => {
const addItem = ({ productName, error }) => {
const { send } = useUiNotification();

if (error) {
send({
type: 'danger',
message: error
});
} else {
send({
type: 'success',
message: productName ? i18n.t('Successfully added {PRODUCT_NAME} to the cart', { PRODUCT_NAME: productName }) : i18n.t('Successfully added product to the cart'),
persist: true,
action: {
text: i18n.t('Go to Checkout'),
onClick: () => router.push('/checkout/shipping')
}
});
}
};

return {
addItem
};
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { cart } from './cart';
import { useContext } from '@nuxtjs/composition-api';

const sendNotification = () => {
const { app } = useContext();
const { i18n, router } = app;

return {
cart: cart({ i18n, router })
};
};

export default sendNotification;
16 changes: 11 additions & 5 deletions packages/core/nuxt-theme-module/theme/components/Notification.vue
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export default {
};
</script>

<style scoped lang="scss">
<style lang="scss">
.notifications {
position: fixed;
width: 100%;
Expand All @@ -50,26 +50,30 @@ export default {
left: auto;
bottom: auto;
right: 5%;
width: 320px;
width: 360px;
}
}
.sf-notification {
max-width: 100%;
margin: var(--spacer-xs) auto 0 auto;
--notification-font-size: var(--font-size--sm);
&:first-child {
margin-top: 0;
}
&__message {
margin: 0 var(--spacer-base) var(--spacer-2xs) 0;
}
@include for-mobile {
background: var(--c-link);
--notification-border-radius: 0;
--notification-max-width: 100%;
--notification-background: var(--c-link);
--notification-font-size: var(--font-size--sm);
--notification-font-family: var(--font-family--primary);
--notification-font-weight: var(--font-weight--normal);
--notification-padding: var(--spacer-base) var(--spacer-lg);
--notification-padding: var(--spacer-base);
}
@include for-desktop {
margin: 0 0 var(--spacer-xs) 0;
--notification-close-top: var(--spacer-sm);
}
}
.slide-fade-enter-active,
Expand All @@ -83,12 +87,14 @@ export default {
transform: translateY(40px);
@include for-desktop {
opacity: 0;
transform: translateY(0);
}
}
.slide-fade-leave-to {
transform: translateY(80px);
@include for-desktop {
opacity: 0;
transform: translateY(0);
}
}
</style>
Original file line number Diff line number Diff line change
@@ -1,33 +1,29 @@
import { computed, reactive } from '@vue/composition-api';
import { reactive } from '@vue/composition-api';

interface UiNotification {
interface UseUiNotification {
message: string;
action: { text: string; onClick: (...args: any) => void };
type: 'danger' | 'success' | 'info';
icon: string;
persist: boolean;
id: symbol;
dismiss: () => void;
action?: { text: string; onClick: () => void };
icon?: string;
persist?: boolean;
id?: symbol;
dismiss?: () => void;
}

interface Notifications {
notifications: Array<UiNotification>;
}
type SendUiNotificationParams = Omit<UseUiNotification, 'id'>;

const state = reactive<Notifications>({
notifications: []
});
const notifications = reactive<Array<UseUiNotification>>([]);
const maxVisibleNotifications = 3;
const timeToLive = 3000;

const useUiNotification = () => {
const send = (notification: UiNotification) => {
const send = (notification: SendUiNotificationParams) => {
const id = Symbol();

const dismiss = () => {
const index = state.notifications.findIndex(notification => notification.id === id);
const index = notifications.findIndex(notification => notification.id === id);

if (index !== -1) state.notifications.splice(index, 1);
if (index !== -1) notifications.splice(index, 1);
};

const newNotification = {
Expand All @@ -36,8 +32,8 @@ const useUiNotification = () => {
dismiss
};

state.notifications.push(newNotification);
if (state.notifications.length > maxVisibleNotifications) state.notifications.shift();
notifications.push(newNotification);
if (notifications.length > maxVisibleNotifications) notifications.shift();

if (!notification.persist) {
setTimeout(dismiss, timeToLive);
Expand All @@ -46,7 +42,7 @@ const useUiNotification = () => {

return {
send,
notifications: computed(() => state.notifications)
notifications
};
};

Expand Down
5 changes: 4 additions & 1 deletion packages/core/nuxt-theme-module/theme/lang/de.js
Original file line number Diff line number Diff line change
Expand Up @@ -118,5 +118,8 @@ export default {
'Let’s start now – we’ll help you': 'Fangen wir jetzt an - wir helfen Ihnen.',
'Search results': 'Suchergebnisse',
'Product suggestions': 'Produktvorschläge',
'Search for items': 'Nach Artikeln suchen'
'Search for items': 'Nach Artikeln suchen',
'Go to Checkout': 'Zum Checkout gehen',
'Successfully added {PRODUCT_NAME} to the cart': '{PRODUCT_NAME} wurde erfolgreich in den Warenkorb gelegt',
'Successfully added product to the cart': 'Produkt wurde erfolgreich in den Warenkorb gelegt'
};
5 changes: 4 additions & 1 deletion packages/core/nuxt-theme-module/theme/lang/en.js
Original file line number Diff line number Diff line change
Expand Up @@ -118,5 +118,8 @@ export default {
'Let’s start now – we’ll help you': 'Let’s start now – we’ll help you.',
'Search results': 'Search results',
'Product suggestions': 'Product suggestions',
'Search for items': 'Search for items'
'Search for items': 'Search for items',
'Go to Checkout': 'Go to Checkout',
'Successfully added {PRODUCT_NAME} to the cart': 'Successfully added {PRODUCT_NAME} to the cart',
'Successfully added product to the cart': 'Successfully added product to the cart'
};
21 changes: 16 additions & 5 deletions packages/core/nuxt-theme-module/theme/pages/Category.vue
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@
:link="localePath(`/p/${productGetters.getId(product)}/${productGetters.getSlug(product)}`)"
class="products__product-card"
@click:wishlist="addItemToWishlist({ product })"
@click:add-to-cart="addItemToCart({ product, quantity: 1 })"
@click:add-to-cart="addToCart(product, 1)"
/>
</transition-group>
<transition-group
Expand All @@ -199,7 +199,7 @@
:is-on-wishlist="false"
class="products__product-card-horizontal"
@click:wishlist="addItemToWishlist({ product })"
@click:add-to-cart="addItemToCart({ product, quantity: 1 })"
@click:add-to-cart="addToCart(product, 1)"
:link="localePath(`/p/${productGetters.getId(product)}/${productGetters.getSlug(product)}`)"
>
<template #configuration>
Expand Down Expand Up @@ -363,18 +363,20 @@ import {
import { ref, computed, onMounted } from '@vue/composition-api';
import { useCart, useWishlist, productGetters, useFacet, facetGetters } from '<%= options.generate.replace.composables %>';
import { useUiHelpers, useUiState } from '~/composables';
import sendNotification from '~/assets/notifications';
import { onSSR } from '@vue-storefront/core';
import LazyHydrate from 'vue-lazy-hydration';
import Vue from 'vue';
// TODO(addToCart qty, horizontal): https://github.com/vuestorefront/storefront-ui/issues/1606
export default {
transition: 'fade',
setup(props, context) {
setup(_, context) {
const th = useUiHelpers();
const uiState = useUiState();
const { addItem: addItemToCart, isInCart } = useCart();
const { addItem: addItemToCart, isInCart, error } = useCart();
const { addItem: addItemToWishlist } = useWishlist();
const { cart: sendCartNotification } = sendNotification();
const { result, search, loading } = useFacet();
const products = computed(() => facetGetters.getProducts(result.value));
Expand Down Expand Up @@ -440,6 +442,14 @@ export default {
changeFilters(selectedFilters.value);
};
const addToCart = async (product, quantity) => {
await addItemToCart({ product, quantity });
sendCartNotification.addItem({
productName: product._name,
error: error.value.addItem ? error.value.addItem.message : false
});
};
return {
...uiState,
th,
Expand All @@ -460,7 +470,8 @@ export default {
isFilterSelected,
selectedFilters,
clearFilters,
applyFilters
applyFilters,
addToCart
};
},
components: {
Expand Down
18 changes: 14 additions & 4 deletions packages/core/nuxt-theme-module/theme/pages/Product.vue
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@
:disabled="loading"
:canAddToCart="stock > 0"
class="product__add-to-cart"
@click="addItem({ product, quantity: parseInt(qty) })"
@click="addToCart(product, parseInt(qty))"
/>
</div>

Expand Down Expand Up @@ -188,19 +188,21 @@ import InstagramFeed from '~/components/InstagramFeed.vue';
import RelatedProducts from '~/components/RelatedProducts.vue';
import { ref, computed } from '@vue/composition-api';
import { useProduct, useCart, productGetters, useReview, reviewGetters } from '<%= options.generate.replace.composables %>';
import sendNotification from '~/assets/notifications';
import { onSSR } from '@vue-storefront/core';
import MobileStoreBanner from '~/components/MobileStoreBanner.vue';
import LazyHydrate from 'vue-lazy-hydration';
export default {
name: 'Product',
transition: 'fade',
setup(props, context) {
setup(_, context) {
const qty = ref(1);
const { id } = context.root.$route.params;
const { products, search } = useProduct('products');
const { products: relatedProducts, search: searchRelatedProducts, loading: relatedLoading } = useProduct('relatedProducts');
const { addItem, loading } = useCart();
const { addItem, loading, error } = useCart();
const { cart: sendCartNotification } = sendNotification();
const { reviews: productReviews, search: searchReviews } = useReview('productReviews');
const product = computed(() => productGetters.getFiltered(products.value, { master: true, attributes: context.root.$route.query })[0]);
Expand Down Expand Up @@ -234,6 +236,14 @@ export default {
});
};
const addToCart = async (product, quantity) => {
await addItem({ product, quantity });
sendCartNotification.addItem({
productName: product._name,
error: error.value.addItem ? error.value.addItem.message : false
});
};
return {
updateFilter,
configuration,
Expand All @@ -246,7 +256,7 @@ export default {
relatedLoading,
options,
qty,
addItem,
addToCart,
loading,
productGetters,
productGallery
Expand Down

0 comments on commit d19a83b

Please sign in to comment.