diff --git a/packages/composables/nuxt/defaultConfig.js b/packages/composables/nuxt/defaultConfig.js
index 2decfc05b..dee433b45 100644
--- a/packages/composables/nuxt/defaultConfig.js
+++ b/packages/composables/nuxt/defaultConfig.js
@@ -6,5 +6,6 @@ export default {
cartCookieName: 'vsf-cart',
customerCookieName: 'vsf-customer',
storeCookieName: 'vsf-store',
+ messageCookieName: 'vsf-message',
},
};
diff --git a/packages/composables/nuxt/plugin.js b/packages/composables/nuxt/plugin.js
index 966fb3ad1..00a24f3f1 100644
--- a/packages/composables/nuxt/plugin.js
+++ b/packages/composables/nuxt/plugin.js
@@ -62,7 +62,7 @@ export default integrationPlugin(({ app, res, req, integration }) => {
getLocale,
setLocale,
getCountry,
- setCountry
+ setCountry,
},
}
});
diff --git a/packages/theme/components/LoginModal.vue b/packages/theme/components/LoginModal.vue
index e5ce4c637..512ad4a68 100644
--- a/packages/theme/components/LoginModal.vue
+++ b/packages/theme/components/LoginModal.vue
@@ -56,13 +56,6 @@
class="form__element"
/>
-
{{ error.login }}
diff --git a/packages/theme/composables/useUiNotification/index.ts b/packages/theme/composables/useUiNotification/index.ts
index ab1f52d90..eab0583dd 100644
--- a/packages/theme/composables/useUiNotification/index.ts
+++ b/packages/theme/composables/useUiNotification/index.ts
@@ -1,4 +1,5 @@
-import { computed, reactive } from '@nuxtjs/composition-api';
+import { computed, reactive, useContext} from '@nuxtjs/composition-api';
+import cookieNames from '~/enums/cookieNameEnum';
interface UiNotification {
message: string;
@@ -22,6 +23,9 @@ const maxVisibleNotifications = 3;
const timeToLive = 3000;
const useUiNotification = () => {
+ const { app } = useContext();
+ const cookieMessage: UiNotification = app.$cookies.get(cookieNames.messageCookieName);
+
const send = (notification: UiNotification) => {
const id = Symbol('id');
@@ -29,6 +33,8 @@ const useUiNotification = () => {
const index = state.notifications.findIndex((n) => n.id === id);
if (index !== -1) state.notifications.splice(index, 1);
+
+ app.$cookies.remove(cookieNames.messageCookieName);
};
const newNotification = {
@@ -37,14 +43,24 @@ const useUiNotification = () => {
dismiss,
};
- state.notifications.push(newNotification);
- if (state.notifications.length > maxVisibleNotifications) state.notifications.shift();
+ if (!state.notifications.some((stateNotification) => stateNotification.message === notification.message)) {
+ state.notifications.push(newNotification);
+ }
+
+ if (state.notifications.length > maxVisibleNotifications) {
+ state.notifications.shift();
+ }
if (!notification.persist) {
setTimeout(dismiss, timeToLive);
}
};
+
+ if (cookieMessage) {
+ send(cookieMessage);
+ }
+
return {
send,
notifications: computed(() => state.notifications),
diff --git a/packages/theme/enums/cookieNameEnum.js b/packages/theme/enums/cookieNameEnum.js
index 0943fab16..18ead2de4 100644
--- a/packages/theme/enums/cookieNameEnum.js
+++ b/packages/theme/enums/cookieNameEnum.js
@@ -5,4 +5,5 @@ module.exports = {
cartCookieName: 'vsf-cart',
customerCookieName: 'vsf-customer',
storeCookieName: 'vsf-store',
+ messageCookieName: 'vsf-message',
};
diff --git a/packages/theme/lang/en.js b/packages/theme/lang/en.js
index 3692e34fb..b1a6c3e4c 100644
--- a/packages/theme/lang/en.js
+++ b/packages/theme/lang/en.js
@@ -168,5 +168,6 @@ export default {
subscribeToNewsletterModalContent: 'After signing up for the newsletter, you will receive special offers and messages from VSF via email. We will not sell or distribute your email to any third party at any time. Please see our {0}.',
'Default Shipping Address': 'Default Shipping Address',
'Default Billing Address': 'Default Billing Address',
+ 'You are not authorized, please log in': 'You are not authorized, please log in',
'Out of stock': 'Out of stock'
};
diff --git a/packages/theme/nuxt.config.js b/packages/theme/nuxt.config.js
index 8cfa8419a..b1baaf02c 100755
--- a/packages/theme/nuxt.config.js
+++ b/packages/theme/nuxt.config.js
@@ -226,6 +226,7 @@ export default {
},
},
plugins: [
+ '~/plugins/token-expired',
'~/plugins/i18n',
],
router: {
diff --git a/packages/theme/plugins/__tests__/token-expired.spec.js b/packages/theme/plugins/__tests__/token-expired.spec.js
new file mode 100644
index 000000000..1c8a868f9
--- /dev/null
+++ b/packages/theme/plugins/__tests__/token-expired.spec.js
@@ -0,0 +1,71 @@
+import tokenExpiredPlugin from '../token-expired';
+import cookieNames from '~/enums/cookieNameEnum';
+
+const callbackResponse = {
+ data: {
+ message: 'The current customer isn\'t authorized.',
+ },
+};
+
+
+const appMock = {
+ $vsf: {
+ $magento: {
+ client: {
+ interceptors: {
+ response: {
+ use: (callback) => {
+ callback(callbackResponse);
+ },
+ },
+ },
+ },
+ },
+ },
+ $cookies: {
+ remove: jest.fn(),
+ set: jest.fn(),
+ },
+ localePath: (t) => t,
+ i18n: {
+ t: (t) => t,
+ },
+};
+
+const redirectMock = jest.fn();
+
+describe('Token Expired plugin', () => {
+ beforeEach(() => {
+ jest.resetAllMocks();
+ });
+
+ it('should work only when the current customer is not authorized', async () => {
+ // eslint-disable-next-line @typescript-eslint/await-thenable
+ await tokenExpiredPlugin({ app: appMock, redirect: redirectMock });
+
+ expect(redirectMock).toHaveBeenCalledWith('/');
+ });
+
+ it('should set message cookie', async () => {
+ // eslint-disable-next-line @typescript-eslint/await-thenable
+ await tokenExpiredPlugin({ app: appMock, redirect: redirectMock });
+
+ const messageMock = {
+ icon: null,
+ message: 'You are not authorized, please log in.',
+ persist: true,
+ title: null,
+ type: 'warning',
+ };
+
+ expect(appMock.$cookies.set).toHaveBeenCalledWith('vsf-message', messageMock);
+ });
+
+ it('should clear customer token and clear cart id', async () => {
+ // eslint-disable-next-line @typescript-eslint/await-thenable
+ await tokenExpiredPlugin({ app: appMock, redirect: redirectMock });
+
+ expect(appMock.$cookies.remove).toHaveBeenCalledTimes(2);
+ expect(appMock.$cookies.remove).toHaveBeenCalledWith(cookieNames.customerCookieName);
+ });
+});
diff --git a/packages/theme/plugins/token-expired.js b/packages/theme/plugins/token-expired.js
new file mode 100644
index 000000000..d3c8773a1
--- /dev/null
+++ b/packages/theme/plugins/token-expired.js
@@ -0,0 +1,27 @@
+import cookieNames from '~/enums/cookieNameEnum';
+
+export default ({ app, redirect }) => {
+ let once = true;
+
+
+ app.$vsf.$magento.client.interceptors.response.use(async (r) => {
+
+ if (r.data.message === 'The current customer isn\'t authorized.' && once) {
+ once = false;
+ app.$cookies.remove(cookieNames.customerCookieName);
+ app.$cookies.remove(cookieNames.cartCookieName);
+
+ await app.$cookies.set(cookieNames.messageCookieName, {
+ message: app.i18n.t('You are not authorized, please log in.'),
+ type: 'warning',
+ icon: null,
+ persist: true,
+ title: null,
+ });
+
+ redirect(app.localePath('/'));
+ }
+
+ return r;
+ });
+};
diff --git a/packages/theme/test-utils.js b/packages/theme/test-utils.js
index db04f2a9c..b724dee36 100644
--- a/packages/theme/test-utils.js
+++ b/packages/theme/test-utils.js
@@ -13,6 +13,9 @@ const customRender = (component, options = {}, callback = null) => render(compon
context: {
app: {
localePath,
+ $cookies: {
+ get: jest.fn(),
+ },
},
},
},