diff --git a/packages/api-client/src/helpers/apiClient/defaultSettings.ts b/packages/api-client/src/helpers/apiClient/defaultSettings.ts index e0bccc073..c2133a6e2 100644 --- a/packages/api-client/src/helpers/apiClient/defaultSettings.ts +++ b/packages/api-client/src/helpers/apiClient/defaultSettings.ts @@ -23,6 +23,9 @@ export const defaultSettings: ClientConfig = { setLocale: () => {}, getCountry: () => '', setCountry: () => {}, + setMessage: () => {}, + // @ts-ignore + getMessage: () => ({}), }, externalCheckout: { enable: false, diff --git a/packages/api-client/src/types/setup.ts b/packages/api-client/src/types/setup.ts index 2ab1f599a..cebc7b295 100644 --- a/packages/api-client/src/types/setup.ts +++ b/packages/api-client/src/types/setup.ts @@ -38,16 +38,25 @@ export type Store = { export type ConfigState = { getCartId(): string; setCartId(id?: string | null): void; + removeCartId(): void; getCustomerToken(): string; setCustomerToken(token?: string | null): void; + removeCustomerToken(): void; getStore(): string; setStore(id?: string | null): void; + removeStore(): void; getCurrency(): string; setCurrency(id?: string | null): void; + removeCurrency(): void; getLocale(): string; setLocale(id?: string | null): void; + removeLocale(): void; getCountry(): string; setCountry(id?: string | null): void; + removeCountry(): void; + getMessage(): T; + setMessage(id?: T | null): void; + removeMessage(): void; }; export interface ClientConfig { diff --git a/packages/theme/composables/useApi/index.ts b/packages/theme/composables/useApi/index.ts index e4fc2feea..010a7bd35 100644 --- a/packages/theme/composables/useApi/index.ts +++ b/packages/theme/composables/useApi/index.ts @@ -1,12 +1,11 @@ import { useContext } from '@nuxtjs/composition-api'; import { request as graphQLRequest, GraphQLClient } from 'graphql-request'; -import cookieNames from '~/enums/cookieNameEnum'; export const useApi = () => { const { app } = useContext(); - const customerToken = app.$cookies.get(cookieNames.customerCookieName); - const storeCode = app.$cookies.get(cookieNames.storeCookieName); - const currency = app.$cookies.get(cookieNames.currencyCookieName); + const customerToken = app.$vsf.$magento.config.state.getCustomerToken(); + const storeCode = app.$vsf.$magento.config.state.getStore(); + const currency = app.$vsf.$magento.config.state.getCurrency(); const magentoConfig = app.$vsf.$magento.config; // TODO remove once we remove apollo client const { useGETForQueries } = magentoConfig.customApolloHttpLinkOptions; diff --git a/packages/theme/composables/useMagentoConfiguration.ts b/packages/theme/composables/useMagentoConfiguration.ts index 3c19472e3..d92520892 100644 --- a/packages/theme/composables/useMagentoConfiguration.ts +++ b/packages/theme/composables/useMagentoConfiguration.ts @@ -2,7 +2,6 @@ import { computed, ComputedRef, useContext } from '@nuxtjs/composition-api'; import { StoreConfig } from '~/modules/GraphQL/types'; import { storeConfigGetters } from '~/getters'; -import cookieNames from '~/enums/cookieNameEnum'; import { useConfig } from '~/composables'; type UseMagentoConfiguration = () => { @@ -13,20 +12,19 @@ type UseMagentoConfiguration = () => { loadConfiguration: (params: { updateCookies: boolean; updateLocale: boolean; }) => Promise; }; -// @ts-ignore export const useMagentoConfiguration: UseMagentoConfiguration = () => { - const { app } = useContext(); + const { app: { i18n, $vsf: { $magento: { config } } } } = useContext(); const { config: storeConfig, load: loadConfig, } = useConfig(); - const selectedCurrency = computed(() => app.$cookies.get(cookieNames.currencyCookieName)); - const selectedLocale = computed(() => app.$cookies.get(cookieNames.localeCookieName)); - const selectedStore = computed(() => app.$cookies.get(cookieNames.storeCookieName)); + const selectedCurrency = computed(() => config.state.getCurrency()); + const selectedLocale = computed(() => config.state.getLocale()); + const selectedStore = computed(() => config.state.getStore()); - const loadConfiguration: (params: { updateCookies: boolean; updateLocale: boolean; }) => void = (params = { + const loadConfiguration: (params: { updateCookies: boolean; updateLocale: boolean; }) => Promise = async (params = { updateCookies: false, updateLocale: false, }) => { @@ -35,34 +33,23 @@ export const useMagentoConfiguration: UseMagentoConfiguration = () => { updateLocale, } = params; - // eslint-disable-next-line promise/catch-or-return - loadConfig().then(() => { - if (!app.$cookies.get(cookieNames.storeCookieName) || updateCookies) { - app.$cookies.set( - cookieNames.storeCookieName, - storeConfigGetters.getCode(storeConfig.value as StoreConfig), - ); - } + await loadConfig(); + if (config.state.getStore() || updateCookies) { + config.state.setStore(storeConfigGetters.getCode(storeConfig.value)); + } - if (!app.$cookies.get(cookieNames.localeCookieName) || updateCookies) { - app.$cookies.set( - cookieNames.localeCookieName, - storeConfigGetters.getCode(storeConfig.value as StoreConfig), - ); - } + if (!config.state.getLocale() || updateCookies) { + config.state.setLocale(storeConfigGetters.getLocale(storeConfig.value)); + } - if (!app.$cookies.get(cookieNames.currencyCookieName) || updateCookies) { - app.$cookies.set( - cookieNames.currencyCookieName, - storeConfigGetters.getCurrency(storeConfig.value as StoreConfig), - ); - } + if (!config.state.getCurrency() || updateCookies) { + config.state.setCurrency(storeConfigGetters.getCurrency(storeConfig.value)); + } - if (updateLocale) { - app.i18n.setLocale(storeConfigGetters.getLocale(storeConfig.value as StoreConfig)); - } - return true; - }); + // eslint-disable-next-line promise/always-return + if (updateLocale) { + i18n.setLocale(storeConfigGetters.getLocale(storeConfig.value)); + } }; return { diff --git a/packages/theme/composables/useUiNotification/index.ts b/packages/theme/composables/useUiNotification/index.ts index e70d705f3..350b99f05 100644 --- a/packages/theme/composables/useUiNotification/index.ts +++ b/packages/theme/composables/useUiNotification/index.ts @@ -1,17 +1,17 @@ import { computed, reactive, useContext } from '@nuxtjs/composition-api'; -import cookieNames from '~/enums/cookieNameEnum'; -interface UiNotification { +type UiNotificationType = 'secondary' | 'info' | 'success' | 'warning' | 'danger'; + +export interface UiNotification { message: string; title?: string; action?: { text: string; onClick: (...args: any) => void }; - type: 'danger' | 'success' | 'info'; + type: UiNotificationType; icon: string; persist?: boolean; id: symbol; dismiss?: () => void; } - interface Notifications { notifications: Array; } @@ -24,7 +24,7 @@ const timeToLive = 3000; const useUiNotification = () => { const { app } = useContext(); - const cookieMessage: UiNotification = app.$cookies.get(cookieNames.messageCookieName); + const cookieMessage = app.$vsf.$magento.config.state.getMessage(); const send = (notification: UiNotification) => { const id = Symbol('id'); @@ -34,7 +34,7 @@ const useUiNotification = () => { if (index !== -1) state.notifications.splice(index, 1); - app.$cookies.remove(cookieNames.messageCookieName); + app.$vsf.$magento.config.state.removeMessage(); }; const newNotification = { @@ -58,7 +58,7 @@ const useUiNotification = () => { if (cookieMessage) { send(cookieMessage); - app.$cookies.remove(cookieNames.messageCookieName); + app.$vsf.$magento.config.state.removeMessage(); } return { diff --git a/packages/theme/composables/useWishlist/index.ts b/packages/theme/composables/useWishlist/index.ts index 3d7ae145b..85c8795ed 100644 --- a/packages/theme/composables/useWishlist/index.ts +++ b/packages/theme/composables/useWishlist/index.ts @@ -1,6 +1,5 @@ import { ref, useContext } from '@nuxtjs/composition-api'; import { Logger } from '~/helpers/logger'; -import cookieNames from '~/enums/cookieNameEnum'; import { CustomQuery } from '~/composables/types'; import { useCustomerStore } from '~/stores/customer'; import { findItemOnWishlist } from '~/composables/useWishlist/helpers'; @@ -156,7 +155,7 @@ export const useWishlist = (): UseWishlist => { }); } - if (!app.context.$cookies.get(cookieNames.customerCookieName)) { // TODO: replace by value from pinia store after sueCart composable will be refactored + if (!app.$vsf.$magento.config.state.getCustomerToken()) { // TODO: replace by value from pinia store after sueCart composable will be refactored Logger.error('Need to be authenticated to add a product to wishlist'); } diff --git a/packages/theme/helpers/integrationPlugin/index.ts b/packages/theme/helpers/integrationPlugin/index.ts index 129b2b84f..47645a394 100644 --- a/packages/theme/helpers/integrationPlugin/index.ts +++ b/packages/theme/helpers/integrationPlugin/index.ts @@ -1,10 +1,17 @@ -import { Context as NuxtContext, Plugin as NuxtPlugin } from '@nuxt/types'; +import { Context as NuxtContext } from '@nuxt/types'; +import { Inject } from '@nuxt/types/app'; import axios from 'axios'; import { createExtendIntegrationInCtx, createAddIntegrationToCtx } from './context'; import { getIntegrationConfig, createProxiedApi } from './_proxyUtils'; -type InjectFn = (key: string, value: any) => void; -export type IntegrationPlugin = (pluginFn: NuxtPlugin) => NuxtPlugin; +interface IntegrationContext { + integration: { + configure: (tag: string, configuration: any) => void; + extend: (tag: string, integrationProperties: any) => void; + } +} + +type NuxtPluginWithIntegration = (ctx: NuxtContext & IntegrationContext, inject: Inject) => void | Promise; const parseCookies = (cookieString: string): Record => Object.fromEntries(cookieString .split(';') @@ -22,8 +29,8 @@ const setCookieValues = (cookieValues: Record, cookieString = '' return Object.entries(parsed).map(([name, value]) => `${name}=${value}`).join('; '); }; -export const integrationPlugin = (pluginFn: NuxtPlugin) => (nuxtCtx: NuxtContext, inject: InjectFn) => { - const configure = (tag, configuration) => { +export const integrationPlugin = (pluginFn: NuxtPluginWithIntegration) => (nuxtCtx: NuxtContext, inject: Inject) => { + const configure = (tag: string, configuration) => { const injectInContext = createAddIntegrationToCtx({ tag, nuxtCtx, inject }); const config = getIntegrationConfig(nuxtCtx, configuration); const { middlewareUrl, ssrMiddlewareUrl } = (nuxtCtx as any).$config; @@ -51,5 +58,5 @@ export const integrationPlugin = (pluginFn: NuxtPlugin) => (nuxtCtx: NuxtContext const integration = { configure, extend }; - pluginFn({ ...nuxtCtx, integration } as NuxtContext, inject); + pluginFn({ ...nuxtCtx, integration }, inject); }; diff --git a/packages/theme/middleware/checkout.js b/packages/theme/middleware/checkout.ts similarity index 68% rename from packages/theme/middleware/checkout.js rename to packages/theme/middleware/checkout.ts index 9ff45aecc..dfe9c9acb 100644 --- a/packages/theme/middleware/checkout.js +++ b/packages/theme/middleware/checkout.ts @@ -1,5 +1,8 @@ +import { Middleware } from '@nuxt/types'; import { Logger } from '~/helpers/logger'; -export default () => { +const middleware : Middleware = () => { Logger.error('Please implement vendor-specific checkout.js middleware in the \'middleware\' directory to block access to checkout steps when customer did not yet complete previous steps'); }; + +export default middleware; diff --git a/packages/theme/middleware/is-authenticated.js b/packages/theme/middleware/is-authenticated.js deleted file mode 100644 index 9405859d8..000000000 --- a/packages/theme/middleware/is-authenticated.js +++ /dev/null @@ -1,5 +0,0 @@ -export default async ({ app, redirect }) => { - if (!app.$cookies.get('vsf-customer')) { - return redirect('/'); - } -}; diff --git a/packages/theme/middleware/is-authenticated.ts b/packages/theme/middleware/is-authenticated.ts new file mode 100644 index 000000000..dfd38d5ce --- /dev/null +++ b/packages/theme/middleware/is-authenticated.ts @@ -0,0 +1,8 @@ +import { Middleware } from '@nuxt/types'; + +const middleware : Middleware = (context) => { + if (!context.app.$vsf.$magento.config.state.getCustomerToken()) { + context.redirect('/'); + } +}; +export default middleware; diff --git a/packages/theme/modules/magento/defaultConfig.ts b/packages/theme/modules/magento/defaultConfig.ts index b02ba5409..c73080c9e 100644 --- a/packages/theme/modules/magento/defaultConfig.ts +++ b/packages/theme/modules/magento/defaultConfig.ts @@ -1,4 +1,4 @@ -export const defaultConfig : Record = { +export const defaultConfig = { cookies: { currencyCookieName: 'vsf-currency', countryCookieName: 'vsf-country', @@ -8,4 +8,7 @@ export const defaultConfig : Record = { storeCookieName: 'vsf-store', messageCookieName: 'vsf-message', }, -}; + locale: undefined, + country: undefined, + currency: undefined, +} as const; diff --git a/packages/theme/modules/magento/helpers/index.ts b/packages/theme/modules/magento/helpers/index.ts index 279be965a..d629284c2 100644 --- a/packages/theme/modules/magento/helpers/index.ts +++ b/packages/theme/modules/magento/helpers/index.ts @@ -1,26 +1,24 @@ import { defaultConfig } from '~/modules/magento/defaultConfig'; -export const getLocaleSettings = (app, moduleOptions) => { - let localeSettings : Record = {}; - - if (moduleOptions.cookies) { - localeSettings = { - locale: app.$cookies.get(moduleOptions.cookies.localeCookieName), - country: app.$cookies.get(moduleOptions.cookies.countryCookieName), - currency: app.$cookies.get(moduleOptions.cookies.currencyCookieName), - }; - } +export const getLocaleSettings = (app, moduleOptions, additionalProperties) => { + const localeSettings = moduleOptions.cookies + ? { + currency: additionalProperties.state.getCurrency(), + locale: additionalProperties.state.getLocale(), + country: additionalProperties.state.getCountry(), + } + : {}; return { - locale: app.i18n.locale || (localeSettings.locale || moduleOptions.locale || defaultConfig.locale || undefined), - country: localeSettings.country || moduleOptions.country || defaultConfig.country || undefined, currency: localeSettings.currency || moduleOptions.currency || defaultConfig.currency || undefined, + locale: app.i18n.locale || localeSettings.locale || moduleOptions.locale || defaultConfig.locale || undefined, + country: localeSettings.country || moduleOptions.country || defaultConfig.country || undefined, }; }; -export const mapConfigToSetupObject = ({ moduleOptions, app, additionalProperties = {} }) => ({ +export const mapConfigToSetupObject = ({ app, moduleOptions, additionalProperties = {} }) => ({ ...defaultConfig, ...moduleOptions, ...additionalProperties, - ...getLocaleSettings(app, moduleOptions), + ...getLocaleSettings(app, moduleOptions, additionalProperties), }); diff --git a/packages/theme/modules/magento/plugin.ts b/packages/theme/modules/magento/plugin.ts index cb3bc5668..c8916d726 100644 --- a/packages/theme/modules/magento/plugin.ts +++ b/packages/theme/modules/magento/plugin.ts @@ -1,62 +1,113 @@ +import type { NuxtCookies, GetOptions } from 'cookie-universal-nuxt'; +import type { CookieSerializeOptions } from 'cookie'; import { integrationPlugin } from '~/helpers/integrationPlugin'; import { mapConfigToSetupObject } from '~/modules/magento/helpers'; import { defaultConfig } from '~/modules/magento/defaultConfig'; const moduleOptions = JSON.parse('<%= JSON.stringify(options) %>'); -// TODO should be moved to THEME and expose consistent cookie management API export default integrationPlugin((plugin) => { - const cartCookieName : string = moduleOptions.cookies?.cartCookieName || defaultConfig.cookies.cartCookieName; - const customerCookieName : string = moduleOptions.cookies?.customerCookieName || defaultConfig.cookies.customerCookieName; - const storeCookieName : string = moduleOptions.cookies?.storeCookieName || defaultConfig.cookies.storeCookieName; - const currencyCookieName : string = moduleOptions.cookies?.currencyCookieName || defaultConfig.cookies.currencyCookieName; - const localeCookieName : string = moduleOptions.cookies?.localeCookieName || defaultConfig.cookies.localeCookieName; - const countryCookieName : string = moduleOptions.cookies?.countryCookieName || defaultConfig.cookies.countryCookieName; + const getCookieName = (property: string) : string => moduleOptions.cookies?.[property] ?? defaultConfig.cookies[property]; + + const cookieNames = { + cart: getCookieName('cartCookieName'), + customer: getCookieName('customerCookieName'), + currency: getCookieName('currencyCookieName'), + store: getCookieName('storeCookieName'), + locale: getCookieName('localeCookieName'), + country: getCookieName('countryCookieName'), + message: getCookieName('messageCookieName'), + }; const { $cookies } = plugin.app; - const getCartId = () => $cookies.get(cartCookieName); - const setCartId = (id: string) => (!id ? $cookies.remove(cartCookieName) : $cookies.set(cartCookieName, id)); + const createCookieOperationsInstance = (cookies: NuxtCookies) => (cookieName: string) => ({ + get: (opts?: GetOptions) => cookies.get(cookieName, opts), + set: (value: TValue, opts?: CookieSerializeOptions) => cookies.set(cookieName, value, opts), + remove: (opts?: CookieSerializeOptions) => cookies.remove(cookieName, opts), + }); + + const createCookieOperations = createCookieOperationsInstance($cookies); + + // TODO Refactor to separate containers (state.cart.get() .set() .remove()) - this requires a breaking change in api-client types + + const { + get: getCartId, + set: setCartId, + remove: removeCartId, + } = createCookieOperations(cookieNames.cart); + + const { + get: getCustomerToken, + set: setCustomerToken, + remove: removeCustomerToken, + } = createCookieOperations(cookieNames.customer); - const getCustomerToken = () => $cookies.get(customerCookieName); - const setCustomerToken = (token: string) => (!token ? $cookies.remove(customerCookieName) : $cookies.set(customerCookieName, token)); + const { + get: getStore, + set: setStore, + remove: removeStore, + } = createCookieOperations(cookieNames.store); - const getStore = () => $cookies.get(storeCookieName); - const setStore = (store: string) => (!store ? $cookies.remove(storeCookieName) : $cookies.set(storeCookieName, store)); + const { + get: getCurrency, + set: setCurrency, + remove: removeCurrency, + } = createCookieOperations(cookieNames.currency); - const getCurrency = () => $cookies.get(currencyCookieName); - const setCurrency = (currency: string) => (!currency ? $cookies.remove(currencyCookieName) : $cookies.set(currencyCookieName, currency)); + const { + get: getLocale, + set: setLocale, + remove: removeLocale, + } = createCookieOperations(cookieNames.locale); - const getLocale = () => $cookies.get(localeCookieName); - const setLocale = (locale: string) => (!locale ? $cookies.remove(localeCookieName) : $cookies.set(localeCookieName, locale)); + const { + get: getCountry, + set: setCountry, + remove: removeCountry, + } = createCookieOperations(cookieNames.country); - const getCountry = () => $cookies.get(countryCookieName); - const setCountry = (country: string) => (!country ? $cookies.remove(countryCookieName) : $cookies.set(countryCookieName, country)); + const { + get: getMessage, + set: setMessage, + remove: removeMessage, + } = createCookieOperations(cookieNames.message); const settings = mapConfigToSetupObject({ moduleOptions, app: plugin.app, additionalProperties: { state: { - // Cart getCartId, setCartId, - // Customer + removeCartId, + getCustomerToken, setCustomerToken, - // Store + removeCustomerToken, + getStore, setStore, + removeStore, + getCurrency, setCurrency, + removeCurrency, + getLocale, setLocale, + removeLocale, + getCountry, setCountry, + removeCountry, + + getMessage, + setMessage, + removeMessage, }, }, }); - // @ts-ignore - not typed in core plugin.integration.configure('magento', settings); }); diff --git a/packages/theme/plugins/__tests__/i18n.spec.js b/packages/theme/plugins/__tests__/i18n.spec.js index 6d2daeed4..2d166594d 100644 --- a/packages/theme/plugins/__tests__/i18n.spec.js +++ b/packages/theme/plugins/__tests__/i18n.spec.js @@ -33,12 +33,9 @@ const callbackRequest = { }; const routeMock = { - path: 'https://domain/german', + path: '/german', }; const appMock = { - $cookies: { - get: jest.fn(), - }, i18n: { defaultLocale: 'en', defaultCurrency: 'EUR', @@ -61,7 +58,9 @@ const appMock = { state: { ...apiStateMock, setStore: jest.fn(), + getStore: jest.fn(), setLocale: jest.fn(), + getLocale: jest.fn(), setCurrency: jest.fn(), }, axios: { @@ -82,24 +81,22 @@ describe('i18n plugin', () => { it('Should read vsf-store cookie value', () => { i18nPlugin({ app: appMock, route: routeMock }); - expect(appMock.$cookies.get).toHaveBeenCalledWith('vsf-store'); + expect(appMock.$vsf.$magento.config.state.getStore).toHaveBeenCalled(); }); it('Should find locale based on magento store code', () => { - appMock.$cookies.get.mockReturnValue('default'); + appMock.$vsf.$magento.config.state.getStore.mockReturnValue('default'); i18nPlugin({ app: appMock, route: routeMock }); expect(appMock.i18n.setLocale).not.toHaveBeenCalled(); }); it('Should set default locale when there is no locale that match given magento store code', () => { - appMock.$cookies.get.mockReturnValue('pl_PL'); - - expect(appMock.i18n.setLocale).not.toHaveBeenCalledTimes(1); + appMock.$vsf.$magento.config.state.getStore('pl_PL'); + expect(appMock.i18n.setLocale).not.toHaveBeenCalled(); }); - it('Should set default locale when vsf-store cookie is not exist', () => { - appMock.$cookies.get.mockReturnValue(null); + it('Should set default locale when vsf-store cookie doesn\'t exist', () => { i18nPlugin({ app: appMock, route: routeMock }); expect(appMock.i18n.setLocale).toHaveBeenCalledWith('en'); @@ -114,7 +111,7 @@ describe('i18n plugin', () => { }, }; - testCaseAppMock.$cookies.get.mockReturnValueOnce('de_DE').mockReturnValueOnce('default'); + testCaseAppMock.$vsf.$magento.config.state.getStore.mockReturnValueOnce('de_DE').mockReturnValueOnce('default'); i18nPlugin({ app: testCaseAppMock, route: routeMock }); diff --git a/packages/theme/plugins/__tests__/token-expired.spec.js b/packages/theme/plugins/__tests__/token-expired.spec.js index 1974440b5..3712848fa 100644 --- a/packages/theme/plugins/__tests__/token-expired.spec.js +++ b/packages/theme/plugins/__tests__/token-expired.spec.js @@ -1,5 +1,4 @@ import tokenExpiredPlugin from '../token-expired'; -import cookieNames from '~/enums/cookieNameEnum'; const errRes = { data: { @@ -31,6 +30,13 @@ const appMockFactory = (callbackResponse) => ({ }, }, }, + config: { + state: { + setCustomerToken: jest.fn(), + setCartId: jest.fn(), + setMessage: jest.fn(), + }, + }, }, }, $cookies: { @@ -38,11 +44,11 @@ const appMockFactory = (callbackResponse) => ({ set: jest.fn(), }, router: { - go: jest.fn(), + push: jest.fn(), }, - localePath: (t) => t, + localePath: jest.fn(), i18n: { - t: (t) => t, + t: jest.fn(), }, }); @@ -54,36 +60,25 @@ describe('Token Expired plugin', () => { it('should be executed only if there is the "graphql-authorization" error', async () => { const appMock = appMockFactory(validRes); - // eslint-disable-next-line @typescript-eslint/await-thenable await tokenExpiredPlugin({ app: appMock }); - expect(appMock.router.go).toHaveBeenCalledTimes(0); + expect(appMock.router.push).toHaveBeenCalledTimes(0); }); it('should set message cookie', async () => { const appMock = appMockFactory(errRes); - // eslint-disable-next-line @typescript-eslint/await-thenable await tokenExpiredPlugin({ app: appMock }); - 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); + expect(appMock.$vsf.$magento.config.state.setMessage).toHaveBeenCalledWith(expect.any(Object)); }); it('should clear customer token and clear cart id', async () => { const appMock = appMockFactory(errRes); - // eslint-disable-next-line @typescript-eslint/await-thenable await tokenExpiredPlugin({ app: appMock }); - expect(appMock.$cookies.remove).toHaveBeenCalledTimes(2); - expect(appMock.$cookies.remove).toHaveBeenCalledWith(cookieNames.customerCookieName); + expect(appMock.$vsf.$magento.config.state.setCustomerToken).toHaveBeenCalled(); + expect(appMock.$vsf.$magento.config.state.setCustomerToken).toHaveBeenCalledWith(); }); }); diff --git a/packages/theme/plugins/fcPlugin.ts b/packages/theme/plugins/fcPlugin.ts index 07457e1a9..ffdfde86a 100644 --- a/packages/theme/plugins/fcPlugin.ts +++ b/packages/theme/plugins/fcPlugin.ts @@ -1,5 +1,5 @@ -import cookieNames from '~/enums/cookieNameEnum'; import formatCurrency from '~/helpers/formatCurrency'; +import { Plugin } from '@nuxt/types'; declare module 'vue/types/vue' { interface Vue { @@ -9,12 +9,14 @@ declare module 'vue/types/vue' { } } -export default ({ i18n, app }, inject) => { +const plugin : Plugin = (context, inject) => { inject('fc', (value: number | string, locale?: string, options = {}): string => { // eslint-disable-next-line no-param-reassign - locale = locale || i18n?.localeProperties?.iso.replace('_', '-'); + locale = locale || context.i18n?.localeProperties?.iso.replace('_', '-'); // eslint-disable-next-line no-param-reassign - options = { currency: app.$cookies.get(cookieNames.currencyCookieName) || i18n?.localeProperties?.defaultCurrency, ...options }; + options = { currency: context.app.$vsf.$magento.config.state.getCurrency() || context.i18n?.localeProperties?.defaultCurrency, ...options }; return formatCurrency(value, locale, options); }); }; + +export default plugin; diff --git a/packages/theme/plugins/i18n.ts b/packages/theme/plugins/i18n.ts index 417a56c51..d10e6d1a5 100644 --- a/packages/theme/plugins/i18n.ts +++ b/packages/theme/plugins/i18n.ts @@ -1,89 +1,37 @@ -import { Context, NuxtAppOptions } from '@nuxt/types'; +import { Context } from '@nuxt/types'; import { LocaleObject } from 'nuxt-i18n'; -import cookieNames from '~/enums/cookieNameEnum'; -export declare type ConfigState = { - getCartId(): string; - setCartId(id?: string | null): void; - getCustomerToken(): string; - setCustomerToken(token?: string | null): void; - getStore(): string; - setStore(id?: string | null): void; - getCurrency(): string; - setCurrency(id?: string | null): void; - getLocale(): string; - setLocale(id?: string | null): void; - getCountry(): string; - setCountry(id?: string | null): void; -}; - -/** - * Read vsf-store cookie value. - * - * @param app {NuxtAppOptions} - Nuxt App options object - * @returns {string} - vsf-store cookie value - */ -const readStoreCookie = (app: NuxtAppOptions) => app.$cookies.get(cookieNames.storeCookieName); - -/** - * Find locale code based on magento store code - * @param storeCode {string} - magento store code - * @param locales {array} - array with locales - * @returns string - */ -const findLocaleBasedOnStoreCode = (storeCode: string, locales: string[] | LocaleObject[]) => { - if (locales.some((l) => typeof l !== 'string')) { - return (locales as LocaleObject[]).find((locale) => locale.code === storeCode); - } - - return (locales as string[]).find((locale) => locale === storeCode); -}; - -/** - * Find defaultCurrency code based on magento store code - * @param storeCode {string} - magento store code - * @param locales {array} - array with locales - * @returns string - */ -const findCurrencyBasedOnStoreCode = (storeCode: string, locales: string[] | LocaleObject[]): string => { - const match = (locales as LocaleObject[]).find((locale) => locale.code === storeCode); +const findLocaleBasedOnMagentoStoreCode = (storeCode: string, locales: Array) => locales.find((locale) => ((typeof locale === 'object' ? locale.code : locale) === storeCode)); - return match.defaultCurrency; +const findCurrencyBasedOnMagentoStoreCode = (storeCode: string, locales: Array): string => { + const match = locales.find((locale) => typeof locale === 'object' && locale.code === storeCode) as LocaleObject | undefined; + return match?.defaultCurrency; }; -/** - * Set default locale - * @param i18n {i18n} i18n API - * @returns {Promise} - */ -const setDefaultLocale = async (i18n) => { - await i18n.setLocale(i18n.defaultLocale); -}; - -export default async ({ app, route }: Context) => { - await app.$vsf.$magento.client.interceptors.request.use(async (request) => { - const { i18n } = app; - const currentStoreCode = readStoreCookie(app) ?? route.path.split('/').find((element) => String(element)); - // eslint-disable-next-line @typescript-eslint/no-unsafe-argument - if (!currentStoreCode || !findLocaleBasedOnStoreCode(currentStoreCode, i18n.locales)) { - await setDefaultLocale(i18n); +export default ({ app, route }: Context) => app.$vsf.$magento.client.interceptors.request.use(async (request) => { + const { + $vsf: { $magento: { config: { state } } }, + i18n, + } = app; - return request; - } + const currentStoreCode = app.$vsf.$magento.config.state.getStore() ?? route.path.split('/')[0]; // localhost:3000/default + const shouldSetDefaultLocale = !currentStoreCode || !findLocaleBasedOnMagentoStoreCode(currentStoreCode, i18n.locales); - const i18nCurrentLocaleCode = i18n.locale; + if (shouldSetDefaultLocale) { + await i18n.setLocale(i18n.defaultLocale); + return request; + } - const localeCookie = app.$cookies.get(cookieNames.localeCookieName); + const i18nCurrentLocaleCode = i18n.locale; + const shouldLocaleBeRefreshed = i18nCurrentLocaleCode !== state.getLocale(); - if (i18nCurrentLocaleCode !== localeCookie) { - const apiState = app.$vsf.$magento.config.state as ConfigState; - const currency = findCurrencyBasedOnStoreCode(i18nCurrentLocaleCode, i18n.locales); + if (shouldLocaleBeRefreshed) { + const currency = findCurrencyBasedOnMagentoStoreCode(currentStoreCode, i18n.locales); + state.setCurrency(currency); - apiState.setStore(i18nCurrentLocaleCode); - apiState.setLocale(i18nCurrentLocaleCode); - apiState.setCurrency(currency); - } + state.setStore(i18nCurrentLocaleCode); + state.setLocale(i18nCurrentLocaleCode); + } - return request; - }); -}; + return request; +}); diff --git a/packages/theme/plugins/token-expired.ts b/packages/theme/plugins/token-expired.ts index b39a15efc..5d937232f 100644 --- a/packages/theme/plugins/token-expired.ts +++ b/packages/theme/plugins/token-expired.ts @@ -1,6 +1,8 @@ -import cookieNames from '~/enums/cookieNameEnum'; +import type { Plugin } from '@nuxt/types'; +import type { AxiosResponse } from 'axios'; +import type { UiNotification } from '~/composables/useUiNotification'; -const hasAuthorizationError = (res): boolean => { +const hasAuthorizationError = (res: AxiosResponse): boolean => { if (!res?.data?.errors) { return false; } @@ -20,25 +22,26 @@ const hasAuthorizationError = (res): boolean => { return isAuthErr; }; -export default ({ app }) => { - app.$vsf.$magento.client.interceptors.response.use(async (res): Promise => { +const plugin : Plugin = ({ app }) => { + app.$vsf.$magento.client.interceptors.response.use((res) => { if (!hasAuthorizationError(res)) { return res; } - - 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.'), + app.$vsf.$magento.config.state.setCustomerToken(); + app.$vsf.$magento.config.state.setCartId(); + app.$vsf.$magento.config.state.setMessage({ + id: Symbol(''), + message: app.i18n.t('You are not authorized, please log in.') as string, type: 'warning', icon: null, persist: true, title: null, }); - app.router.go(app.localePath('/')); + app.router.push(app.localePath('/')); return false; }); }; + +export default plugin;