Skip to content
1 change: 1 addition & 0 deletions packages/composables/nuxt/defaultConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@ export default {
cartCookieName: 'vsf-cart',
customerCookieName: 'vsf-customer',
storeCookieName: 'vsf-store',
messageCookieName: 'vsf-message',
},
};
2 changes: 1 addition & 1 deletion packages/composables/nuxt/plugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ export default integrationPlugin(({ app, res, req, integration }) => {
getLocale,
setLocale,
getCountry,
setCountry
setCountry,
},
}
});
Expand Down
7 changes: 0 additions & 7 deletions packages/theme/components/LoginModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,6 @@
class="form__element"
/>
</ValidationProvider>
<SfCheckbox
v-model="rememberMe"
v-e2e="'login-modal-remember-me'"
name="remember-me"
label="Remember me"
class="form__element checkbox"
/>
<div v-if="error.login">
{{ error.login }}
</div>
Expand Down
22 changes: 19 additions & 3 deletions packages/theme/composables/useUiNotification/index.ts
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -22,13 +23,18 @@ 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');

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

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

app.$cookies.remove(cookieNames.messageCookieName);
};

const newNotification = {
Expand All @@ -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),
Expand Down
1 change: 1 addition & 0 deletions packages/theme/enums/cookieNameEnum.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ module.exports = {
cartCookieName: 'vsf-cart',
customerCookieName: 'vsf-customer',
storeCookieName: 'vsf-store',
messageCookieName: 'vsf-message',
};
1 change: 1 addition & 0 deletions packages/theme/lang/en.js
Original file line number Diff line number Diff line change
Expand Up @@ -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'
};
1 change: 1 addition & 0 deletions packages/theme/nuxt.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,7 @@ export default {
},
},
plugins: [
'~/plugins/token-expired',
'~/plugins/i18n',
],
router: {
Expand Down
71 changes: 71 additions & 0 deletions packages/theme/plugins/__tests__/token-expired.spec.js
Original file line number Diff line number Diff line change
@@ -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);
});
});
27 changes: 27 additions & 0 deletions packages/theme/plugins/token-expired.js
Original file line number Diff line number Diff line change
@@ -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;
});
};
3 changes: 3 additions & 0 deletions packages/theme/test-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ const customRender = (component, options = {}, callback = null) => render(compon
context: {
app: {
localePath,
$cookies: {
get: jest.fn(),
},
},
},
},
Expand Down