diff --git a/packages/core/docs/contributing/changelog.md b/packages/core/docs/contributing/changelog.md index c902210c5f8..de2f34081a3 100644 --- a/packages/core/docs/contributing/changelog.md +++ b/packages/core/docs/contributing/changelog.md @@ -1,5 +1,8 @@ # Changelog +## 2.3.0 (not relased) +- added useUiNotification composable ([#5363](https://github.com/vuestorefront/vue-storefront/issues/5363)) + ## 2.2.0 - added bottom margin to fix visibility of last footer category ([#5253](https://github.com/DivanteLtd/vue-storefront/issues/5253)) - [BREAKING] refactored names of many factory methods and composable methods, details in linked PR ([#5299](https://github.com/DivanteLtd/vue-storefront/pull/5299)) diff --git a/packages/core/docs/general/error-handling.md b/packages/core/docs/general/error-handling.md index 4751157799a..4fdd31d9c7c 100644 --- a/packages/core/docs/general/error-handling.md +++ b/packages/core/docs/general/error-handling.md @@ -79,9 +79,10 @@ Let's imagine you have some global components for error notifications. You want ```ts const { cart, error } = useCart() +const { send } = useUiNotification(); watch(error, (error, prevError) => { - if (error.value.addItem && error.value.addItem !== prevError.value.addItem) sendInAppNotification('error', error.value.addItem.message) - if (error.value.removeItem && error.value.removeItem !== prevError.value.removeItem) sendInAppNotification('error', error.value.removeItem.message) + if (error.value.addItem && error.value.addItem !== prevError.value.addItem) send({ type: 'danger', message: error.value.addItem.message }) + if (error.value.removeItem && error.value.removeItem !== prevError.value.removeItem) send({ type: 'danger', message: error.value.removeItem.message }) }) ``` diff --git a/packages/core/nuxt-theme-module/theme/components/CartSidebar.vue b/packages/core/nuxt-theme-module/theme/components/CartSidebar.vue index 19be02bd895..f7fc7a5e020 100644 --- a/packages/core/nuxt-theme-module/theme/components/CartSidebar.vue +++ b/packages/core/nuxt-theme-module/theme/components/CartSidebar.vue @@ -75,9 +75,9 @@ - {{ $t('Go to checkout') }} @@ -87,7 +87,7 @@ {{ $t('Go back shopping') }}{{ $t('Go back shopping') }} diff --git a/packages/core/nuxt-theme-module/theme/components/Notification.vue b/packages/core/nuxt-theme-module/theme/components/Notification.vue new file mode 100644 index 00000000000..75b186e14fd --- /dev/null +++ b/packages/core/nuxt-theme-module/theme/components/Notification.vue @@ -0,0 +1,105 @@ + + + + + diff --git a/packages/core/nuxt-theme-module/theme/composables/index.ts b/packages/core/nuxt-theme-module/theme/composables/index.ts index 74bd181c0c9..1d414b562dd 100644 --- a/packages/core/nuxt-theme-module/theme/composables/index.ts +++ b/packages/core/nuxt-theme-module/theme/composables/index.ts @@ -1,7 +1,9 @@ import useUiHelpers from './useUiHelpers'; import useUiState from './useUiState'; +import useUiNotification from './useUiNotification'; export { useUiHelpers, - useUiState + useUiState, + useUiNotification }; diff --git a/packages/core/nuxt-theme-module/theme/composables/useUiNotification/index.ts b/packages/core/nuxt-theme-module/theme/composables/useUiNotification/index.ts new file mode 100644 index 00000000000..56e546a6b06 --- /dev/null +++ b/packages/core/nuxt-theme-module/theme/composables/useUiNotification/index.ts @@ -0,0 +1,53 @@ +import { computed, reactive } from '@vue/composition-api'; + +interface UiNotification { + message: string; + action: { text: string; onClick: Function }; + type: 'danger' | 'success' | 'info'; + icon: string; + persist: boolean; + id: symbol; + dismiss: () => void; +} + +interface Notifications { + notifications: Array; +} + +const state = reactive({ + notifications: [] +}); + +const useUiNotification = () => { + const send = (notification: UiNotification) => { + const id = Symbol(); + + const dismiss = () => { + const index = state.notifications.findIndex(notification => notification.id === id); + + if (index !== -1) state.notifications.splice(index, 1); + }; + + const newNotification = { + ...notification, + id, + dismiss + }; + + state.notifications.push(newNotification); + if (state.notifications.length > 3) state.notifications.shift(); + + if (!notification.persist) { + setTimeout(() => { + dismiss(); + }, 3000); + } + }; + + return { + send, + notifications: computed(() => state.notifications) + }; +}; + +export default useUiNotification; diff --git a/packages/core/nuxt-theme-module/theme/layouts/default.vue b/packages/core/nuxt-theme-module/theme/layouts/default.vue index 0c352a57f6b..592197550a3 100644 --- a/packages/core/nuxt-theme-module/theme/layouts/default.vue +++ b/packages/core/nuxt-theme-module/theme/layouts/default.vue @@ -22,6 +22,7 @@ + @@ -35,6 +36,7 @@ import CartSidebar from '~/components/CartSidebar.vue'; import WishlistSidebar from '~/components/WishlistSidebar.vue'; import LoginModal from '~/components/LoginModal.vue'; import LazyHydrate from 'vue-lazy-hydration'; +import Notification from '~/components/Notification'; export default { components: { @@ -45,7 +47,8 @@ export default { AppFooter, CartSidebar, WishlistSidebar, - LoginModal + LoginModal, + Notification } };