From 5e2f6a600eea6429c7820d86706b0adab7e2c537 Mon Sep 17 00:00:00 2001 From: Ritika-Patel08 Date: Mon, 11 Mar 2024 19:31:59 +0530 Subject: [PATCH 01/13] Implemented: app version component from dxp-components(#219) --- package-lock.json | 129 ++++++++++------------- package.json | 4 +- src/locales/en.json | 2 + src/locales/index.ts | 5 + src/main.ts | 4 +- src/store/modules/user/UserState.ts | 1 + src/store/modules/user/actions.ts | 4 + src/store/modules/user/getters.ts | 3 + src/store/modules/user/index.ts | 4 + src/store/modules/user/mutation-types.ts | 3 +- src/store/modules/user/mutations.ts | 4 + src/views/SelectProduct.vue | 6 +- src/views/Settings.vue | 23 ++-- tsconfig.json | 1 + 14 files changed, 94 insertions(+), 99 deletions(-) create mode 100644 src/locales/index.ts diff --git a/package-lock.json b/package-lock.json index 2ca99776..989aab09 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,8 +14,8 @@ "@casl/ability": "^6.0.0", "@casl/vue": "^2.2.0", "@hotwax/app-version-info": "^1.0.0", - "@hotwax/apps-theme": "^1.1.0", - "@hotwax/dxp-components": "1.11.0", + "@hotwax/apps-theme": "^1.2.6", + "@hotwax/dxp-components": "1.12.1", "@hotwax/oms-api": "^1.10.0", "@ionic/core": "6.7.5", "@ionic/vue": "6.7.5", @@ -2815,29 +2815,66 @@ "integrity": "sha512-PnJTqTbFvvl9N23yi1DjL4aNmTkpYFrayyoJyfH1qDJXADFbQ9kB7gJmKcfiPpyYMGR86Yf3Is5ct0+wReUJGQ==" }, "node_modules/@hotwax/apps-theme": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/@hotwax/apps-theme/-/apps-theme-1.2.5.tgz", - "integrity": "sha512-3Vec4pGWJVs6vDbL/pO5hYqoF1zn2w8liXuleqDJ7waI2R5JuF2eaJmYcUQETnk/DZIg47bDdyOSxihQltB2Ow==" + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@hotwax/apps-theme/-/apps-theme-1.2.6.tgz", + "integrity": "sha512-zpUjGoY7LBlKeiP0V7tonrmoey8HQ5THQmyixQ+IDtrjmEJNBjynW/Ef3gC0FUNNPuVqxWPZdT5CVgaETLGTwg==" }, "node_modules/@hotwax/dxp-components": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@hotwax/dxp-components/-/dxp-components-1.11.0.tgz", - "integrity": "sha512-z9UNzi1veT8Aj8Y1WWAGBGOR+I0s6A58qrsFj+L3LkpxTkq6zGN/JS80tTv29obEeeOfONm6XyLHvNOM6TFKyA==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@hotwax/dxp-components/-/dxp-components-1.12.1.tgz", + "integrity": "sha512-5soKaVBFd7klZnHBCi68j4CZwTlrBCzvPsyd+wHMbenezU+lOwMK0ftdWXrQcQPedeGdVtQXvvgSPWnLL310bg==", "dependencies": { "@hotwax/oms-api": "^1.8.1", - "@ionic/core": "^6.7.5", - "@ionic/vue": "^6.7.5", - "@types/vue-barcode-reader": "^0.0.0", + "@ionic/core": "^7.6.0", + "@ionic/vue": "^7.6.0", "firebase": "^10.3.1", "luxon": "^3.3.0", "pinia": "2.0.36", "pinia-plugin-persistedstate": "^3.1.0", "register-service-worker": "^1.7.2", "vue": "^3.3.4", - "vue-barcode-reader": "^1.0.3", "vue-i18n": "^9.2.2" } }, + "node_modules/@hotwax/dxp-components/node_modules/@ionic/core": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@ionic/core/-/core-7.7.4.tgz", + "integrity": "sha512-zThio3ZfbTu+3eM6QBdyeEk5OBc7M0ApFwSlP/G7rrFVcTPm12FNvG9VPD+aN5NwnYy0EsV3hlMkxbawoqjVLw==", + "dependencies": { + "@stencil/core": "^4.12.2", + "ionicons": "^7.2.2", + "tslib": "^2.1.0" + } + }, + "node_modules/@hotwax/dxp-components/node_modules/@ionic/vue": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@ionic/vue/-/vue-7.7.4.tgz", + "integrity": "sha512-THrMMoQHU2Ym+JaTj/dm/FV8FyB7ZXmc6kierZ/+BSvOncIekla8Afe6Qk2c2U1afOPos0MBINf9xXkwxnHfIw==", + "dependencies": { + "@ionic/core": "7.7.4", + "ionicons": "^7.0.0" + } + }, + "node_modules/@hotwax/dxp-components/node_modules/@stencil/core": { + "version": "4.12.5", + "resolved": "https://registry.npmjs.org/@stencil/core/-/core-4.12.5.tgz", + "integrity": "sha512-vSyFjY7XSEx0ufa9SebOd437CvnneaTXlCpuGDhjUDxAjGBlu6ie5qHyubobVGBth//aErc6wZPHc6W75Vp3iQ==", + "bin": { + "stencil": "bin/stencil" + }, + "engines": { + "node": ">=16.0.0", + "npm": ">=7.10.0" + } + }, + "node_modules/@hotwax/dxp-components/node_modules/ionicons": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/ionicons/-/ionicons-7.2.2.tgz", + "integrity": "sha512-I3iYIfc9Q9FRifWyFSwTAvbEABWlWY32i0sAVDDPGYnaIZVugkLCZFbEcrphW6ixVPg8tt1oLwalo/JJwbEqnA==", + "dependencies": { + "@stencil/core": "^4.0.3" + } + }, "node_modules/@hotwax/dxp-components/node_modules/luxon": { "version": "3.4.4", "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.4.4.tgz", @@ -2846,6 +2883,11 @@ "node": ">=12" } }, + "node_modules/@hotwax/dxp-components/node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" + }, "node_modules/@hotwax/dxp-components/node_modules/vue-i18n": { "version": "9.8.0", "resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-9.8.0.tgz", @@ -3882,33 +3924,6 @@ "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", "dev": true }, - "node_modules/@types/vue-barcode-reader": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/@types/vue-barcode-reader/-/vue-barcode-reader-0.0.0.tgz", - "integrity": "sha512-yngQhd35qGjCxMXWIqsAtF7qmxe0qUYRVd9qW5I/CcRPWDdBpqVkHnQSh6ro5BIBl3NQ3ppky7kMKS4pr+XwCQ==", - "dependencies": { - "vue": "^2.0.0" - } - }, - "node_modules/@types/vue-barcode-reader/node_modules/@vue/compiler-sfc": { - "version": "2.7.15", - "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-2.7.15.tgz", - "integrity": "sha512-FCvIEevPmgCgqFBH7wD+3B97y7u7oj/Wr69zADBf403Tui377bThTjBvekaZvlRr4IwUAu3M6hYZeULZFJbdYg==", - "dependencies": { - "@babel/parser": "^7.18.4", - "postcss": "^8.4.14", - "source-map": "^0.6.1" - } - }, - "node_modules/@types/vue-barcode-reader/node_modules/vue": { - "version": "2.7.15", - "resolved": "https://registry.npmjs.org/vue/-/vue-2.7.15.tgz", - "integrity": "sha512-a29fsXd2G0KMRqIFTpRgpSbWaNBK3lpCTOLuGLEDnlHWdjB8fwl6zyYZ8xCrqkJdatwZb4mGHiEfJjnw0Q6AwQ==", - "dependencies": { - "@vue/compiler-sfc": "2.7.15", - "csstype": "^3.1.0" - } - }, "node_modules/@types/webpack-env": { "version": "1.18.4", "resolved": "https://registry.npmjs.org/@types/webpack-env/-/webpack-env-1.18.4.tgz", @@ -5348,26 +5363,6 @@ "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", "dev": true }, - "node_modules/@zxing/library": { - "version": "0.19.3", - "resolved": "https://registry.npmjs.org/@zxing/library/-/library-0.19.3.tgz", - "integrity": "sha512-RUv5svewpDoD0ymXleOP8yVTO5BLkR0zn5coGC/Vs1671u0OBJ4xdtR8WVWf08OcvrieEMHdSfQY3ZKtqII/hg==", - "dependencies": { - "ts-custom-error": "^3.2.1" - }, - "engines": { - "node": ">= 10.4.0" - }, - "optionalDependencies": { - "@zxing/text-encoding": "~0.9.0" - } - }, - "node_modules/@zxing/text-encoding": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/@zxing/text-encoding/-/text-encoding-0.9.0.tgz", - "integrity": "sha512-U/4aVJ2mxI0aDNI8Uq0wEhMgY+u4CNtEb0om3+y3+niDAsoTCOB33UF0sxpzqzdqXLqmvc+vZyAt4O8pPdfkwA==", - "optional": true - }, "node_modules/abbrev": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-2.0.0.tgz", @@ -15876,14 +15871,6 @@ "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", "dev": true }, - "node_modules/ts-custom-error": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/ts-custom-error/-/ts-custom-error-3.3.1.tgz", - "integrity": "sha512-5OX1tzOjxWEgsr/YEUWSuPrQ00deKLh6D7OTWcvNHm12/7QPyRh8SYpyWvA4IZv8H/+GQWQEh/kwo95Q9OVW1A==", - "engines": { - "node": ">=14.0.0" - } - }, "node_modules/ts-loader": { "version": "9.5.1", "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.5.1.tgz", @@ -16435,14 +16422,6 @@ } } }, - "node_modules/vue-barcode-reader": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/vue-barcode-reader/-/vue-barcode-reader-1.0.3.tgz", - "integrity": "sha512-z4mv7+ai/8vECppBTb00tHnyFMMx6W1rAaQe+v214ihoaWK9iGrn8ZZsmgSxf3lwnrtGaibLdkonTtMrGsO+dA==", - "dependencies": { - "@zxing/library": "^0.19.1" - } - }, "node_modules/vue-cli-plugin-i18n": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/vue-cli-plugin-i18n/-/vue-cli-plugin-i18n-1.0.1.tgz", diff --git a/package.json b/package.json index 716c9117..1cda8406 100644 --- a/package.json +++ b/package.json @@ -18,8 +18,8 @@ "@casl/ability": "^6.0.0", "@casl/vue": "^2.2.0", "@hotwax/app-version-info": "^1.0.0", - "@hotwax/apps-theme": "^1.1.0", - "@hotwax/dxp-components": "1.11.0", + "@hotwax/apps-theme": "^1.2.6", + "@hotwax/dxp-components": "1.12.1", "@hotwax/oms-api": "^1.10.0", "@ionic/core": "6.7.5", "@ionic/vue": "6.7.5", diff --git a/src/locales/en.json b/src/locales/en.json index c9315ea0..da8b1691 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -5,6 +5,7 @@ "Are you sure you want to change the time zone to?": "Are you sure you want to change the time zone to?", "Authenticating": "Authenticating", "Blank": "Blank", + "Built: ": "Built: {builtDateTime}", "Cancel": "Cancel", "CANCEL": "CANCEL", "Canceling this job will cancel this occurrence and all following occurrences. This job will have to be re-enabled manually to run it again.": "Canceling this job will cancel this occurrence and all following occurrences. This job will have to be re-enabled manually to run it again.", @@ -162,6 +163,7 @@ "Username": "Username", "virtual, ": "virtual, ", "variants": "variants", + "Version: ": "Version: {appVersion}", "You can also download the products, locations and safety stock you selected in a CSV to upload in other systems": "You can also download the products, locations and safety stock you selected in a CSV to upload in other systems", "You do not have permission to access this page": "You do not have permission to access this page", "You do not have permission to access the app.": "You do not have permission to access the app." diff --git a/src/locales/index.ts b/src/locales/index.ts new file mode 100644 index 00000000..83e39f0d --- /dev/null +++ b/src/locales/index.ts @@ -0,0 +1,5 @@ +import en from "./en.json" + +export default { + "en-US": en +}; \ No newline at end of file diff --git a/src/main.ts b/src/main.ts index 3115cfc7..a1c97d4c 100644 --- a/src/main.ts +++ b/src/main.ts @@ -35,6 +35,7 @@ import permissionActions from '@/authorization/Actions'; import { dxpComponents } from '@hotwax/dxp-components' import { login, logout, loader } from './user-utils'; import { getConfig, initialise } from '@/adapter' +import localeMessages from './locales'; const app = createApp(App) @@ -58,7 +59,8 @@ const app = createApp(App) loader, appLoginUrl: process.env.VUE_APP_LOGIN_URL as string, getConfig, - initialise + initialise, + localeMessages }); // Filters are removed in Vue 3 and global filter introduced https://v3.vuejs.org/guide/migration/filters.html#global-filters diff --git a/src/store/modules/user/UserState.ts b/src/store/modules/user/UserState.ts index 077e20ba..07feebae 100644 --- a/src/store/modules/user/UserState.ts +++ b/src/store/modules/user/UserState.ts @@ -1,5 +1,6 @@ export default interface UserState { permissions: any; + pwaState: any; token: string; current: object | null; instanceUrl: string; diff --git a/src/store/modules/user/actions.ts b/src/store/modules/user/actions.ts index 89626abb..c5d49e25 100644 --- a/src/store/modules/user/actions.ts +++ b/src/store/modules/user/actions.ts @@ -187,6 +187,10 @@ const actions: ActionTree = { commit(types.USER_INSTANCE_URL_UPDATED, payload) updateInstanceUrl(payload) }, + + updatePwaState({ commit }, payload) { + commit(types.USER_PWA_STATE_UPDATED, payload); + } } export default actions; \ No newline at end of file diff --git a/src/store/modules/user/getters.ts b/src/store/modules/user/getters.ts index fcc52248..b6c22f67 100644 --- a/src/store/modules/user/getters.ts +++ b/src/store/modules/user/getters.ts @@ -30,5 +30,8 @@ const getters: GetterTree = { getUserPermissions (state) { return state.permissions; }, + getPwaState(state) { + return state.pwaState; + }, } export default getters; \ No newline at end of file diff --git a/src/store/modules/user/index.ts b/src/store/modules/user/index.ts index 6796b71b..3ba85293 100644 --- a/src/store/modules/user/index.ts +++ b/src/store/modules/user/index.ts @@ -13,6 +13,10 @@ const userModule: Module = { current: {}, instanceUrl: '', currentEComStore: {}, + pwaState: { + updateExists: false, + registration: null, + } }, getters, actions, diff --git a/src/store/modules/user/mutation-types.ts b/src/store/modules/user/mutation-types.ts index 20ef2012..95162856 100644 --- a/src/store/modules/user/mutation-types.ts +++ b/src/store/modules/user/mutation-types.ts @@ -4,4 +4,5 @@ export const USER_END_SESSION = SN_USER + '/END_SESSION' export const USER_INFO_UPDATED = SN_USER + '/INFO_UPDATED' export const USER_INSTANCE_URL_UPDATED = SN_USER + '/INSTANCE_URL_UPDATED' export const USER_CURRENT_ECOM_STORE_UPDATED = SN_USER + '/CURRENT_ECOM_STORE_UPDATED' -export const USER_PERMISSIONS_UPDATED = SN_USER + '/PERMISSIONS_UPDATED' \ No newline at end of file +export const USER_PERMISSIONS_UPDATED = SN_USER + '/PERMISSIONS_UPDATED' +export const USER_PWA_STATE_UPDATED = SN_USER + '/PWA_STATE_UPDATED' \ No newline at end of file diff --git a/src/store/modules/user/mutations.ts b/src/store/modules/user/mutations.ts index fb7c75e0..2fafc6aa 100644 --- a/src/store/modules/user/mutations.ts +++ b/src/store/modules/user/mutations.ts @@ -24,5 +24,9 @@ const mutations: MutationTree = { [types.USER_PERMISSIONS_UPDATED] (state, payload) { state.permissions = payload }, + [types.USER_PWA_STATE_UPDATED](state, payload) { + state.pwaState.registration = payload.registration; + state.pwaState.updateExists = payload.updateExists; + }, } export default mutations; \ No newline at end of file diff --git a/src/views/SelectProduct.vue b/src/views/SelectProduct.vue index a9f92793..9089a218 100644 --- a/src/views/SelectProduct.vue +++ b/src/views/SelectProduct.vue @@ -120,7 +120,7 @@
- + {{ variant.productName }} @@ -163,7 +163,7 @@ \ No newline at end of file diff --git a/src/components/JobConfiguration.vue b/src/components/JobConfiguration.vue deleted file mode 100644 index 3584b8e7..00000000 --- a/src/components/JobConfiguration.vue +++ /dev/null @@ -1,378 +0,0 @@ - - - - - \ No newline at end of file diff --git a/src/components/JobHistoryModal.vue b/src/components/JobHistoryModal.vue deleted file mode 100644 index 48dc5f66..00000000 --- a/src/components/JobHistoryModal.vue +++ /dev/null @@ -1,131 +0,0 @@ - - - \ No newline at end of file diff --git a/src/components/JobReorderModal.vue b/src/components/JobReorderModal.vue deleted file mode 100644 index 7cb80517..00000000 --- a/src/components/JobReorderModal.vue +++ /dev/null @@ -1,193 +0,0 @@ - - - - - \ No newline at end of file diff --git a/src/components/Menu.vue b/src/components/Menu.vue index 7390808d..0eeba0d4 100644 --- a/src/components/Menu.vue +++ b/src/components/Menu.vue @@ -20,33 +20,12 @@ - - - - -

{{ instanceUrl }}

-
- {{ userProfile?.userTimeZone }} -
- - - {{ store.storeName }} - - - - - {{ eComStore.storeName }} - - -
-
\ No newline at end of file diff --git a/src/components/ProductListItem.vue b/src/components/ProductListItem.vue deleted file mode 100644 index e312f8f5..00000000 --- a/src/components/ProductListItem.vue +++ /dev/null @@ -1,49 +0,0 @@ - - - \ No newline at end of file diff --git a/src/components/SafetyStockModal.vue b/src/components/SafetyStockModal.vue deleted file mode 100644 index 53d3d78f..00000000 --- a/src/components/SafetyStockModal.vue +++ /dev/null @@ -1,104 +0,0 @@ - - - \ No newline at end of file diff --git a/src/main.ts b/src/main.ts index a1c97d4c..89a4e5bb 100644 --- a/src/main.ts +++ b/src/main.ts @@ -29,13 +29,6 @@ import './theme/variables.css'; import i18n from './i18n' import store from './store' -import permissionPlugin from '@/authorization'; -import permissionRules from '@/authorization/Rules'; -import permissionActions from '@/authorization/Actions'; -import { dxpComponents } from '@hotwax/dxp-components' -import { login, logout, loader } from './user-utils'; -import { getConfig, initialise } from '@/adapter' -import localeMessages from './locales'; const app = createApp(App) @@ -47,21 +40,7 @@ const app = createApp(App) }) .use(router) .use(i18n) - .use(store) - .use(permissionPlugin, { - rules: permissionRules, - actions: permissionActions - }) - .use(dxpComponents, { - defaultImgUrl: require("@/assets/images/defaultImage.png"), - login, - logout, - loader, - appLoginUrl: process.env.VUE_APP_LOGIN_URL as string, - getConfig, - initialise, - localeMessages - }); + .use(store); // Filters are removed in Vue 3 and global filter introduced https://v3.vuejs.org/guide/migration/filters.html#global-filters app.config.globalProperties.$filters = { diff --git a/src/router/index.ts b/src/router/index.ts index 6b8910cc..372e5fdc 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -1,20 +1,12 @@ import { createRouter, createWebHistory } from '@ionic/vue-router'; import { RouteRecordRaw } from 'vue-router'; -import SelectFacility from '@/views/SelectFacility.vue' -import SelectFacilityCSVUpload from '@/views/SelectFacilityCSVUpload.vue' -import SelectProduct from '@/views/SelectProduct.vue' -import SelectProductCSVUpload from '@/views/SelectProductCSVUpload.vue' -import ThresholdUpdates from '@/views/ThresholdUpdates.vue' import Settings from "@/views/Settings.vue" import store from '@/store' -import ScheduleThreshold from '@/views/ScheduleThreshold.vue' - -import { hasPermission } from '@/authorization'; import { showToast } from '@/utils' import { translate } from '@/i18n' +import Login from '@/views/Login.vue' import 'vue-router' -import { DxpLogin, useAuthStore } from '@hotwax/dxp-components'; import { loader } from '@/user-utils'; // Defining types for the meta values @@ -25,77 +17,30 @@ declare module 'vue-router' { } const authGuard = async (to: any, from: any, next: any) => { - const authStore = useAuthStore() - if (!authStore.isAuthenticated || !store.getters['user/isAuthenticated']) { - await loader.present('Authenticating') - // TODO use authenticate() when support is there - const redirectUrl = window.location.origin + '/login' - window.location.href = `${process.env.VUE_APP_LOGIN_URL}?redirectUrl=${redirectUrl}` - loader.dismiss() + if (store.getters["user/isAuthenticated"]) { + next() + } else { + next("/login") } - next() }; const loginGuard = (to: any, from: any, next: any) => { - const authStore = useAuthStore() - if (authStore.isAuthenticated && !to.query?.token && !to.query?.oms) { - next('/') + if (!store.getters["user/isAuthenticated"]) { + next() + } else { + next("/") } - next(); }; const routes: Array = [ { path: '/', - redirect: '/select-product' - }, - { - path: '/select-product', - name: 'SelectProduct', - component: SelectProduct, - beforeEnter: authGuard, - meta: { - permissionId: "APP_SELECT_PRODUCT_VIEW" - } - }, - { - path: '/select-product-csv-upload', - name: 'SelectProductCSVUpload', - component: SelectProductCSVUpload, - meta: { - permissionId: "" - } - }, - { - path: '/select-facility', - name: 'SelectFacility', - component: SelectFacility, - beforeEnter: authGuard, - meta: { - permissionId: "" - } - }, - { - path: '/select-facility-csv-upload', - name: 'SelectFacilityCSVUpload', - component: SelectFacilityCSVUpload, - meta: { - permissionId: "" - } - }, - { - path: '/threshold-updates', - name: 'ThresholdUpdates', - component: ThresholdUpdates, - beforeEnter: authGuard, - meta: { - permissionId: "APP_THRESHOLD_UPDATES_VIEW" - } + redirect: '/settings' }, { path: '/login', name: 'DxpLogin', - component: DxpLogin, + component: Login, beforeEnter: loginGuard }, { @@ -103,16 +48,7 @@ const routes: Array = [ name: "Settings", component: Settings, beforeEnter: authGuard - }, - { - path: '/schedule-threshold', - name: 'ScheduleThreshold', - component: ScheduleThreshold, - beforeEnter: authGuard, - meta: { - permissionId: "APP_SAVE_THRESHOLD_VIEW" - } - }, + } ] const router = createRouter({ @@ -120,18 +56,4 @@ const router = createRouter({ routes }) -router.beforeEach((to, from) => { - if (to.meta.permissionId && !hasPermission(to.meta.permissionId)) { - let redirectToPath = from.path; - // If the user has navigated from Login page or if it is page load, redirect user to settings page without showing any toast - if (redirectToPath == "/login" || redirectToPath == "/") redirectToPath = "/settings"; - else { - showToast(translate('You do not have permission to access this page')); - } - return { - path: redirectToPath, - } - } -}) - export default router \ No newline at end of file diff --git a/src/services/JobService.ts b/src/services/JobService.ts deleted file mode 100644 index 0f4e9469..00000000 --- a/src/services/JobService.ts +++ /dev/null @@ -1,94 +0,0 @@ -import { api } from '@/adapter'; -import store from "@/store"; -import { hasError } from '@/utils'; -import logger from "@/logger"; - -const fetchJob = async (payload: any): Promise => { - let resp; - const params = { - "inputFields": { - "productStoreId": payload.eComStoreId, - "productStoreId_op": "equals", - "jobId": payload.jobId.toString(), - "jobId_op": "equals" - }, - "fieldList": [ "systemJobEnumId", "runTime", "tempExprId", "parentJobId", "serviceName", "jobId", "jobName", "statusId", "cancelDateTime", "finishDateTime", "startDateTime", "runtimeDataId", "productStoreId" ], - "noConditionFind": "Y", - } - try { - resp = await fetchJobInformation(params) - if (resp.status === 200 && resp.data.docs?.length > 0 && !hasError(resp)) { - const job = resp.data.docs[0]; - job['statusDesc'] = store.state.util.statusDesc[job.statusId]; - await store.dispatch('job/fetchTemporalExpression', [job.tempExprId]); - await store.dispatch('job/fetchJobDescription', [job.systemJobEnumId]); - if (job.runtimeData && job.runtimeData.searchPreferenceId) await store.dispatch('job/fetchThresholdRules', [job.runtimeData.searchPreferenceId]) - return job; - } else { - logger.error(resp); - return {}; - } - } catch (err) { - logger.error(err); - return {} - } -} - -const fetchJobInformation = async (payload: any, cache = false): Promise => { - return api({ - url: "/findJobs", - method: "post", - data: payload, - cache - }); -} -const fetchJobDescription = async (payload: any): Promise => { - return api({ - url: "performFind", - method: "post", - data: payload - }); -} - -const updateJob = async (payload: any): Promise => { - return api({ - url: "service/updateJobSandbox", - method: "post", - data: payload - }); -} - -const scheduleJob = async (payload: any): Promise => { - return api({ - url: "scheduleService", - method: "post", - data: payload - }); -} - -const fetchTemporalExpression = async (payload: any): Promise => { - return api({ - url: "performFind", - method: "post", - data: payload - }); -} - -const fetchThresholdRules = async (payload: any): Promise => { - return api({ - url: "performFind", - method: "post", - data: payload - }); -} - - -export const JobService = { - fetchJobDescription, - fetchJobInformation, - fetchTemporalExpression, - fetchThresholdRules, - updateJob, - scheduleJob, - fetchJob -} \ No newline at end of file diff --git a/src/services/ProductService.ts b/src/services/ProductService.ts deleted file mode 100644 index 2d2261ab..00000000 --- a/src/services/ProductService.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { api } from '@/adapter'; - -const fetchProducts = async (query: any): Promise => { - return api({ - // TODO: We can replace this with any API - url: "searchProducts", - method: "post", - data: query, - cache: true - }); -} - -const getProducts = async (payload: any): Promise => { - return api({ - url: "/solr-query", - method: "POST", - data: payload - }) -} - -const updateSearchPreference = async (payload: any): Promise => { - return api({ - url: "service/updateSearchPreference", - method: "post", - data: payload - }); -} - -const createSearchPreference = async (payload: any): Promise => { - return api({ - url: "service/createSearchPreference", - method: "post", - data: payload - }); -} - -const fetchFacets = async (payload: any): Promise => { - return api({ - url: "/AutoCompleteSolrFacet", - method: "get", - params: payload - }); -} - -const associateSearchPrefToUser = async (payload: any): Promise => { - return api({ - url: "service/createUserSearchPreference", - method: "post", - data: payload - }); -} - -export const ProductService = { - associateSearchPrefToUser, - fetchFacets, - createSearchPreference, - fetchProducts, - getProducts, - updateSearchPreference -} \ No newline at end of file diff --git a/src/services/UserService.ts b/src/services/UserService.ts index 9c012a11..7aa87e0c 100644 --- a/src/services/UserService.ts +++ b/src/services/UserService.ts @@ -1,263 +1,95 @@ -import { api, client } from '@/adapter'; -import store from '@/store'; -import { hasError } from '@/utils' +import api, {client} from '@/api'; +import store from "@/store"; +import { hasError } from "@/utils"; const login = async (username: string, password: string): Promise => { - return api({ - url: "login", - method: "post", - data: { - 'USERNAME': username, - 'PASSWORD': password + let token = "" + try { + const resp = await api({ + url: "login", + method: "post", + data: { + username, + password + } + }) as any; + + if(!hasError(resp) && resp.data.token) { + token = resp.data.token + } else { + throw "Sorry, login failed. Please try again"; } - }); + } catch(err) { + return Promise.reject("Sorry, login failed. Please try again"); + } + return Promise.resolve(token) } const getUserProfile = async (token: any): Promise => { - const baseURL = store.getters['user/getBaseUrl']; + console.log('sdo'); + const baseURL = store.getters["user/getBaseUrl"]; + console.log(baseURL); + try { const resp = await client({ - url: "user-profile", - method: "get", + url: "user/profile", + method: "GET", baseURL, headers: { - Authorization: 'Bearer ' + token, - 'Content-Type': 'application/json' + "api_key": token, + "Content-Type": "application/json" } }); - if(hasError(resp)) return Promise.reject("Error getting user profile: " + JSON.stringify(resp.data)); + if(hasError(resp)) throw "Error getting user profile"; return Promise.resolve(resp.data) } catch(error: any) { return Promise.reject(error) } } -const getAvailableTimeZones = async (): Promise => { - return api({ - url: "getAvailableTimeZones", - method: "get", - cache: true - }); -} -const setUserTimeZone = async (payload: any): Promise => { - return api({ - url: "setUserTimeZone", - method: "post", - data: payload - }); -} -const getEComStores = async (token: any, partyId: any): Promise => { +const getEComStores = async (token: any): Promise => { try { - const params = { - "inputFields": { - "storeName_op": "not-empty", - partyId - }, - "fieldList": ["productStoreId", "storeName"], - "entityName": "ProductStoreAndRole", - "distinct": "Y", - "noConditionFind": "Y", - "filterByDate": 'Y', - } - const baseURL = store.getters['user/getBaseUrl']; + const baseURL = store.getters["user/getBaseUrl"]; const resp = await client({ - url: "performFind", - method: "get", + url: "user/productStore", + method: "GET", baseURL, - params, headers: { - Authorization: 'Bearer ' + token, - 'Content-Type': 'application/json' + "api_key": token, + "Content-Type": "application/json" } }); // Disallow login if the user is not associated with any product store - if (hasError(resp) || resp.data.docs.length === 0) { - return Promise.reject(resp.data); - } else { - return Promise.resolve(resp.data.docs); - } - } catch(error: any) { - return Promise.reject(error) - } -} -const getEcommerceCatalog = async (token: any, productStoreId: any): Promise => { - try { - const params = { - "inputFields": { - productStoreId - }, - "fieldList": ["productStoreId", "prodCatalogId"], - "entityName": "ProductStoreCatalog", - "distinct": "Y", - "noConditionFind": "Y", - "filterByDate": 'Y', - } - const baseURL = store.getters['user/getBaseUrl']; - const resp = await client({ - url: "performFind", - method: "get", - baseURL, - params, - headers: { - Authorization: 'Bearer ' + token, - 'Content-Type': 'application/json' - } - }); - if (hasError(resp) || resp.data.docs?.length == 0) { - // if has error or not catalog found - return Promise.reject(resp.data.docs); + if (hasError(resp) || resp.data.length === 0) { + throw resp.data; } else { - return Promise.resolve(resp.data.docs[0]); + return Promise.resolve(resp.data); } } catch(error: any) { return Promise.reject(error) } } - -const setUserPreference = async (payload: any): Promise => { +const getAvailableTimeZones = async (): Promise => { return api({ - url: "service/setUserPreference", - method: "post", - data: payload + url: "user/getAvailableTimeZones", + method: "get", + cache: true }); } -const getUserPreference = async (payload: any): Promise => { +const setUserTimeZone = async (payload: any): Promise => { return api({ - url: "service/getUserPreference", - //TODO Due to security reasons service model of OMS 1.0 does not support sending parameters in get request that's why we use post here + url: "setUserTimeZone", method: "post", - data: payload, + data: payload }); } -const getPreferredStore = async (token: any): Promise => { - const baseURL = store.getters['user/getBaseUrl']; - try { - const resp = await client({ - url: "service/getUserPreference", - //TODO Due to security reasons service model of OMS 1.0 does not support sending parameters in get request that's why we use post here - method: "post", - baseURL, - headers: { - Authorization: 'Bearer ' + token, - 'Content-Type': 'application/json' - }, - data: { - 'userPrefTypeId': 'SELECTED_BRAND' - }, - }); - if (hasError(resp)) { - return Promise.reject(resp.data); - } else { - return Promise.resolve(resp.data.userPrefValue); - } - } catch(error: any) { - return Promise.reject(error) - } - -} - -const getUserPermissions = async (payload: any, token: any): Promise => { - const baseURL = store.getters['user/getBaseUrl']; - let serverPermissions = [] as any; - - // If the server specific permission list doesn't exist, getting server permissions will be of no use - // It means there are no rules yet depending upon the server permissions. - if (payload.permissionIds && payload.permissionIds.length == 0) return serverPermissions; - // TODO pass specific permissionIds - let resp; - // TODO Make it configurable from the environment variables. - // Though this might not be an server specific configuration, - // we will be adding it to environment variable for easy configuration at app level - const viewSize = 200; - - try { - const params = { - "viewIndex": 0, - viewSize, - permissionIds: payload.permissionIds - } - resp = await client({ - url: "getPermissions", - method: "post", - baseURL, - data: params, - headers: { - Authorization: 'Bearer ' + token, - 'Content-Type': 'application/json' - } - }) - if(resp.status === 200 && resp.data.docs?.length && !hasError(resp)) { - serverPermissions = resp.data.docs.map((permission: any) => permission.permissionId); - const total = resp.data.count; - const remainingPermissions = total - serverPermissions.length; - if (remainingPermissions > 0) { - // We need to get all the remaining permissions - const apiCallsNeeded = Math.floor(remainingPermissions / viewSize) + ( remainingPermissions % viewSize != 0 ? 1 : 0); - const responses = await Promise.all([...Array(apiCallsNeeded).keys()].map(async (index: any) => { - const response = await client({ - url: "getPermissions", - method: "post", - baseURL, - data: { - "viewIndex": index + 1, - viewSize, - permissionIds: payload.permissionIds - }, - headers: { - Authorization: 'Bearer ' + token, - 'Content-Type': 'application/json' - } - }) - if(!hasError(response)){ - return Promise.resolve(response); - } else { - return Promise.reject(response); - } - })) - const permissionResponses = { - success: [], - failed: [] - } - responses.reduce((permissionResponses: any, permissionResponse: any) => { - if (permissionResponse.status !== 200 || hasError(permissionResponse) || !permissionResponse.data?.docs) { - permissionResponses.failed.push(permissionResponse); - } else { - permissionResponses.success.push(permissionResponse); - } - return permissionResponses; - }, permissionResponses) - - serverPermissions = permissionResponses.success.reduce((serverPermissions: any, response: any) => { - serverPermissions.push(...response.data.docs.map((permission: any) => permission.permissionId)); - return serverPermissions; - }, serverPermissions) - - // If partial permissions are received and we still allow user to login, some of the functionality might not work related to the permissions missed. - // Show toast to user intimiting about the failure - // Allow user to login - // TODO Implement Retry or improve experience with show in progress icon and allowing login only if all the data related to user profile is fetched. - if (permissionResponses.failed.length > 0) Promise.reject("Something went wrong while getting complete user permissions."); - } - } - return serverPermissions; - } catch(error: any) { - return Promise.reject(error); - } -} - - export const UserService = { - getEcommerceCatalog, - getPreferredStore, - getUserPermissions, - getUserProfile, - login, - getAvailableTimeZones, - setUserTimeZone, - setUserPreference, - getUserPreference, - getEComStores + getAvailableTimeZones, + getEComStores, + getUserProfile, + login, + setUserTimeZone } \ No newline at end of file diff --git a/src/services/UtilService.ts b/src/services/UtilService.ts deleted file mode 100644 index 9cd4f276..00000000 --- a/src/services/UtilService.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { api } from '@/adapter'; - -const getServiceStatusDesc = async (payload: any): Promise => { - return api({ - url: "performFind", - method: "post", - data: payload, - cache: true - }); -} - -const getShopifyConfig = async (payload: any): Promise => { - return api({ - url: "performFind", - method: "post", - data: payload - }); -} - -const fetchFacilitiesByProductStore = async (payload: any): Promise => { - return api({ - url: "performFind", - method: "post", - data: payload - }); -} - - -const fetchChannels = async (payload: any): Promise => { - return api({ - url: "performFind", - method: "POST", - data: payload - }) -} - -export const UtilService = { - fetchFacilitiesByProductStore, - getServiceStatusDesc, - getShopifyConfig, - fetchChannels -} \ No newline at end of file diff --git a/src/store/index.ts b/src/store/index.ts index 707a438e..579b6808 100644 --- a/src/store/index.ts +++ b/src/store/index.ts @@ -5,10 +5,6 @@ import actions from './actions' import RootState from './RootState' import createPersistedState from "vuex-persistedstate"; import userModule from './modules/user'; -import productModule from "./modules/product" -import jobModule from './modules/job' -import utilModule from "./modules/util" -import { setPermissions } from '@/authorization' // TODO check how to register it from the components only @@ -21,7 +17,7 @@ const state: any = { } const persistState = createPersistedState({ - paths: ['user', 'util'], + paths: ['user'], fetchBeforeUse: true }) @@ -33,15 +29,10 @@ const store = createStore({ getters, plugins: [ persistState ], modules: { - 'user': userModule, - 'product': productModule, - 'job': jobModule, - 'util': utilModule + 'user': userModule }, }) -setPermissions(store.getters['user/getUserPermissions']); - export default store export function useStore(): typeof store { return useVuexStore() diff --git a/src/store/modules/job/JobState.ts b/src/store/modules/job/JobState.ts deleted file mode 100644 index ffe78fcc..00000000 --- a/src/store/modules/job/JobState.ts +++ /dev/null @@ -1,17 +0,0 @@ -export default interface JobState { - pending: { - list: any, - total: 0 - } - running: { - list: any, - total: 0 - } - history: { - list: any, - total: 0 - } - temporalExp: any; - enumIds: any; - thresholdRules: any; -} \ No newline at end of file diff --git a/src/store/modules/job/actions.ts b/src/store/modules/job/actions.ts deleted file mode 100644 index 7c6bce6a..00000000 --- a/src/store/modules/job/actions.ts +++ /dev/null @@ -1,331 +0,0 @@ -import { ActionTree } from 'vuex' -import RootState from '@/store/RootState' -import JobState from './JobState' -import * as types from './mutation-types' -import { getResponseError, hasError, showToast } from '@/utils' -import { JobService } from '@/services/JobService' -import { translate } from '@/i18n' -import { DateTime } from 'luxon'; -import logger from "@/logger"; - -const actions: ActionTree = { - async fetchJobDescription({ commit, state }, payload){ - const enumIds = [] as any; - const cachedEnumIds = Object.keys(state.enumIds); - payload.map((id: any) => { - if(!cachedEnumIds.includes(id) && id){ - enumIds.push(id); - } - }); - if(enumIds.length <= 0) return enumIds.map((id: any) => state.enumIds[id]); - - const resp = await JobService.fetchJobDescription({ - "inputFields": { - "enumId": enumIds, - "enumId_op": "in" - }, - "fieldList": ['enumId', 'description', 'enumName'], - "entityName": "Enumeration", - "noConditionFind": "Y", - "viewSize": payload.length - }) - if (resp.status === 200 && resp.data?.count > 0 && !hasError(resp)) { - const enumInformation = resp.data.docs; - if (resp.data.docs) { - commit(types.JOB_DESCRIPTION_UPDATED, enumInformation); - } - } - return resp; - }, - - async fetchJobHistory({ commit, dispatch, state }, payload){ - await JobService.fetchJobInformation({ - "inputFields": { - "systemJobEnumId_fld0_value": payload.jobEnums[0], - "systemJobEnumId_fld0_grp": "1", - "systemJobEnumId_fld0_op": "equals", - "systemJobEnumId_fld1_value": payload.jobEnums[1], - "systemJobEnumId_fld1_grp": "2", - "systemJobEnumId_fld1_op": "equals", - "productStoreId": this.state.user.currentEComStore.productStoreId, - "productStoreId_grp": "2", - "statusId": ["SERVICE_CANCELLED", "SERVICE_CRASHED", "SERVICE_FAILED", "SERVICE_FINISHED"], - "statusId_op": "in", - "systemJobEnumId_op": "not-empty" - }, - "fieldList": [ "systemJobEnumId", "runTime", "tempExprId", "parentJobId", "serviceName", "jobId", "jobName", "statusId", "cancelDateTime", "finishDateTime", "startDateTime", "runtimeDataId" ], - "entityName": "JobSandbox", - "noConditionFind": "Y", - "viewSize": payload.viewSize, - "viewIndex": payload.viewIndex, - "orderBy": "runTime DESC" - }).then((resp) => { - if (resp.status === 200 && resp.data.docs?.length > 0 && !hasError(resp)) { - if (resp.data.docs) { - const total = resp.data.count; - let jobs = resp.data.docs; - if(payload.viewIndex && payload.viewIndex > 0){ - jobs = state.history.list.concat(resp.data.docs); - } - jobs.map((job: any) => { - job['statusDesc'] = this.state.util.statusDesc[job.statusId]; - }) - commit(types.JOB_HISTORY_UPDATED, { jobs, total }); - const tempExprList = [] as any; - const enumIds = [] as any; - const searchPreferenceIds = [] as any; - resp.data.docs.map((item: any) => { - enumIds.push(item.systemJobEnumId); - tempExprList.push(item.tempExprId); - if (item.runtimeData && item.runtimeData.searchPreferenceId) searchPreferenceIds.push(item.runtimeData.searchPreferenceId) - }) - const tempExpr = [...new Set(tempExprList)]; - dispatch('fetchTemporalExpression', tempExpr); - dispatch('fetchJobDescription', enumIds); - dispatch('fetchThresholdRules', [...new Set(searchPreferenceIds)]) - } - } else { - commit(types.JOB_HISTORY_UPDATED, { jobs: [], total: 0 }); - } - }).catch((err) => { - commit(types.JOB_HISTORY_UPDATED, { jobs: [], total: 0 }); - logger.error(err); - showToast(translate("Something went wrong"), err); - }) - }, - - async fetchRunningJobs({ commit, dispatch, state }, payload){ - await JobService.fetchJobInformation({ - "inputFields": { - "systemJobEnumId_fld0_value": payload.jobEnums[0], - "systemJobEnumId_fld0_grp": "1", - "systemJobEnumId_fld0_op": "equals", - "systemJobEnumId_fld1_value": payload.jobEnums[1], - "systemJobEnumId_fld1_grp": "2", - "systemJobEnumId_fld1_op": "equals", - "productStoreId": this.state.user.currentEComStore.productStoreId, - "productStoreId_grp": "2", - "statusId": ["SERVICE_RUNNING", "SERVICE_QUEUED"], - "statusId_op": "in", - "systemJobEnumId_op": "not-empty", - }, - "fieldList": [ "systemJobEnumId", "runTime", "tempExprId", "parentJobId", "serviceName", "jobId", "jobName", "statusId", "runtimeDataId" ], - "entityName": "JobSandbox", - "noConditionFind": "Y", - "viewSize": payload.viewSize, - "viewIndex": payload.viewIndex, - "orderBy": "runTime DESC" - }).then((resp) => { - if (resp.status === 200 && resp.data.docs?.length > 0 && !hasError(resp)) { - if (resp.data.docs) { - const total = resp.data.count; - let jobs = resp.data.docs; - if(payload.viewIndex && payload.viewIndex > 0){ - jobs = state.running.list.concat(resp.data.docs); - } - jobs.map((job: any) => { - job['statusDesc'] = this.state.util.statusDesc[job.statusId]; - }) - commit(types.JOB_RUNNING_UPDATED, { jobs, total }); - const tempExprList = [] as any; - const enumIds = [] as any; - const searchPreferenceIds = [] as any; - resp.data.docs.map((item: any) => { - enumIds.push(item.systemJobEnumId); - tempExprList.push(item.tempExprId); - if (item.runtimeData && item.runtimeData.searchPreferenceId) searchPreferenceIds.push(item.runtimeData.searchPreferenceId) - }) - const tempExpr = [...new Set(tempExprList)]; - dispatch('fetchTemporalExpression', tempExpr); - dispatch('fetchJobDescription', enumIds); - dispatch('fetchThresholdRules', [...new Set(searchPreferenceIds)]) - } - } else { - commit(types.JOB_RUNNING_UPDATED, { jobs: [], total: 0 }); - } - }).catch((err) => { - commit(types.JOB_RUNNING_UPDATED, { jobs: [], total: 0 }); - logger.error(err); - showToast(translate("Something went wrong"), err); - }) - }, - - async fetchPendingJobs({ commit, dispatch, state }, payload){ - await JobService.fetchJobInformation({ - "inputFields": { - "systemJobEnumId_fld0_value": payload.jobEnums[0], - "systemJobEnumId_fld0_grp": "1", - "systemJobEnumId_fld0_op": "equals", - "systemJobEnumId_fld1_value": payload.jobEnums[1], - "systemJobEnumId_fld1_grp": "2", - "systemJobEnumId_fld1_op": "equals", - "productStoreId": this.state.user.currentEComStore.productStoreId, - "productStoreId_grp": "2", - "statusId": "SERVICE_PENDING", - "systemJobEnumId_op": "not-empty" - }, - "fieldList": [ "systemJobEnumId", "runTime", "tempExprId", "parentJobId", "serviceName", "jobId", "jobName", "currentRetryCount", "statusId", "runtimeDataId", "productStoreId" ], - "entityName": "JobSandbox", - "noConditionFind": "Y", - "viewSize": payload.viewSize, - "viewIndex": payload.viewIndex, - "orderBy": "runTime ASC" - }).then((resp) => { - if (resp.status === 200 && resp.data.docs?.length > 0 && !hasError(resp)) { - if (resp.data.docs) { - const total = resp.data.count; - let jobs = resp.data.docs; - if(payload.viewIndex && payload.viewIndex > 0){ - jobs = state.pending.list.concat(resp.data.docs); - } - - commit(types.JOB_PENDING_UPDATED, { jobs, total }); - const tempExprList = [] as any; - const enumIds = [] as any; - const searchPreferenceIds = [] as any; - resp.data.docs.map((item: any) => { - enumIds.push(item.systemJobEnumId); - tempExprList.push(item.tempExprId); - if (item.runtimeData && item.runtimeData.searchPreferenceId) searchPreferenceIds.push(item.runtimeData.searchPreferenceId) - }) - const tempExpr = [...new Set(tempExprList)]; - dispatch('fetchTemporalExpression', tempExpr); - dispatch('fetchJobDescription', enumIds); - dispatch('fetchThresholdRules', [...new Set(searchPreferenceIds)]) - } - } else { - commit(types.JOB_PENDING_UPDATED, { jobs: [], total: 0 }); - } - }).catch((err) => { - commit(types.JOB_PENDING_UPDATED, { jobs: [], total: 0 }); - logger.error(err); - showToast(translate("Something went wrong"), err); - }) - }, - async fetchTemporalExpression({ state, commit }, tempExprIds){ - const tempIds = [] as any; - const cachedTempExprId = Object.keys(state.temporalExp); - tempExprIds.map((id: any) => { - if(!cachedTempExprId.includes(id) && id){ - tempIds.push(id); - } - }); - if(tempIds.length <= 0) return tempExprIds.map((id: any) => state.temporalExp[id]); - - const resp = await JobService.fetchTemporalExpression({ - "inputFields": { - "tempExprId": tempIds, - "temoExprId_op": "in" - }, - "viewSize": tempIds.length, - "fieldList": [ "tempExprId", "description","integer1", "integer2" ], - "entityName": "TemporalExpression", - "noConditionFind": "Y", - }) - if (resp.status === 200 && !hasError(resp)) { - commit(types.JOB_TEMPORAL_EXPRESSION_UPDATED, resp.data.docs); - } - return resp; - }, - async fetchThresholdRules({ state, commit }, thresholdRuleIds){ - const tempIds = [] as any; - const cachedThresholdRuleIds = Object.keys(state.thresholdRules); - thresholdRuleIds.map((id: any) => { - if(!cachedThresholdRuleIds.includes(id) && id){ - tempIds.push(id); - } - }); - if(tempIds.length <= 0) return thresholdRuleIds.map((id: any) => state.temporalExp[id]); - try { - const resp = await JobService.fetchThresholdRules({ - "inputFields": { - "searchPrefId": tempIds, - "searchPrefId_op": "in" - }, - "viewSize": tempIds.length, - "fieldList": [ "searchPrefId", "searchPrefValue"], - "entityName": "SearchPreference", - "noConditionFind": "Y", - }) - if (resp.status === 200 && !hasError(resp)) { - commit(types.JOB_THRESHOLD_RULES_UPDATED, resp.data.docs); - } - return resp; - } catch(err: any){ - logger.error(err); - return Promise.reject(new Error(err)) - } - }, - - removeThresholdRule({ commit }, id){ - commit(types.JOB_THRESHOLD_RULE_REMOVED, id); - }, - - clearJobState({commit}) { - commit(types.JOB_PENDING_UPDATED, {jobs: [], total: 0}); - commit(types.JOB_HISTORY_UPDATED, {jobs: [], total: 0}); - commit(types.JOB_RUNNING_UPDATED, {jobs: [], total: 0}); - }, - - async skipJob({ getters }, job) { - let skipTime = {}; - const integer1 = getters['getTemporalExpr'](job.tempExprId).integer1; - const integer2 = getters['getTemporalExpr'](job.tempExprId).integer2 - if(integer1 === 12) { - skipTime = { minutes: integer2 } - } else if (integer1 === 10) { - skipTime = { hours: integer2 } - } else if (integer1 === 5) { - skipTime = { days: integer2 } - } else { - showToast(translate("This job schedule cannot be skipped")); - return; - } - const time = DateTime.fromMillis(job.runTime).diff(DateTime.local()).plus(skipTime); - const updatedRunTime = time.toMillis() + DateTime.local().toMillis() - const payload = { - 'jobId': job.jobId, - 'runTime': updatedRunTime, - 'systemJobEnumId': job.systemJobEnumId, - 'recurrenceTimeZone': this.state.user.current.userTimeZone, - 'statusId': "SERVICE_PENDING" - } as any - - const resp = await JobService.updateJob(payload) - if (resp.status === 200 && !hasError(resp) && resp.data.successMessage) { - // TODO: improve the condition to store the current job in state. - // returning the updated runTime on success as, the job configuration component does not get updated when - // skipping a job from there. - return { updatedRunTime: payload.runTime } - } - return resp; - }, - - async cancelJob({ dispatch }, job) { - let resp; - - try { - resp = await JobService.updateJob({ - jobId: job.jobId, - systemJobEnumId: job.systemJobEnumId, - statusId: "SERVICE_CANCELLED", - recurrenceTimeZone: this.state.user.current.userTimeZone, - cancelDateTime: DateTime.now().toMillis() - }); - if (resp.status == 200 && !hasError(resp)) { - showToast(translate('Service updated successfully')) - } else { - showToast(translate('Something went wrong'), getResponseError(resp)) - } - } catch (err) { - showToast(translate('Something went wrong'), err) - logger.error(err) - // TODO: explore around handling error, so that we can directly access the response status code - // This is returned so that response is handled in catch instead of then - // err is string and when trying to access status it gives error - return Promise.reject(err) - } - return resp; - }, -} -export default actions; \ No newline at end of file diff --git a/src/store/modules/job/getters.ts b/src/store/modules/job/getters.ts deleted file mode 100644 index 44605b1e..00000000 --- a/src/store/modules/job/getters.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { GetterTree } from 'vuex' -import JobState from './JobState' -import RootState from '../../RootState' -import parser from 'boolean-parser' - -const getters: GetterTree = { - getPendingJobs (state){ - return state.pending.list; - }, - getTemporalExpr: (state) => (id: string): any => { - return state.temporalExp[id]; - }, - getEnumDescription: (state) => (id: string): any => { - return state.enumIds[id]?.description; - }, - getEnumName: (state) => (id: string): any => { - return state.enumIds[id] ? state.enumIds[id]?.enumName : ''; - }, - isPendingJobsScrollable: (state) => { - return state.pending.list?.length > 0 && state.pending.list?.length < state.pending.total - }, - isRunningJobsScrollable: (state) => { - return state.running.list?.length > 0 && state.running.list?.length < state.running.total - }, - getRunningJobs (state){ - return state.running.list; - }, - isHistoryJobsScrollable: (state) => { - return state.history.list?.length > 0 && state.history.list?.length < state.history.total - }, - getJobHistory (state){ - return state.history.list; - }, - getTagsAndOperator: (state, getters) => (id: string, type: string): any => { - const tagString = getters.getTags(id, type); - const operator = tagString.indexOf(' AND ') > 0 ? 'AND' : 'OR' - if(tagString){ - let tags = parser.removeOuterBrackets(tagString.trim()); - //Need to parse as it is returned in json format - tags = tags.split(` ${operator} `).map((tag: any) => JSON.parse(tag)) - return { tags, operator } - } - return { tags: [], operator }; - }, - getTags: (state) => (id: string, type: string): any => { - const thresholdRule = state.thresholdRules[id]; - if (!thresholdRule) return ""; - const tags = thresholdRule.json.filter.find((filter: any) => filter.startsWith(type === 'included' ? 'tags:' : '-tags:')) - return tags ? tags.substring(tags.indexOf(":") + 1) : ""; - }, - getThresholdRule: (state) => (id: string): any => { - return state.thresholdRules[id]; - } - } - - export default getters; \ No newline at end of file diff --git a/src/store/modules/job/index.ts b/src/store/modules/job/index.ts deleted file mode 100644 index 0d414713..00000000 --- a/src/store/modules/job/index.ts +++ /dev/null @@ -1,35 +0,0 @@ -import actions from './actions' -import getters from './getters' -import mutations from './mutations' -import { Module } from 'vuex' -import JobState from './JobState' -import RootState from '../../RootState' - -const jobModule: Module = { - namespaced: true, - state: { - pending: { - list: [], - total: 0 - }, - running: { - list: [], - total: 0 - }, - history: { - list: [], - total: 0 - }, - temporalExp: [], - enumIds: {}, - thresholdRules: {} - }, - getters, - actions, - mutations, -} - -export default jobModule; - -// TODO -// store.registerModule('job', jobModule); diff --git a/src/store/modules/job/mutation-types.ts b/src/store/modules/job/mutation-types.ts deleted file mode 100644 index 8505d657..00000000 --- a/src/store/modules/job/mutation-types.ts +++ /dev/null @@ -1,8 +0,0 @@ -export const SN_JOB = 'job' -export const JOB_PENDING_UPDATED = SN_JOB + '/PENDING_UPDATED' -export const JOB_TEMPORAL_EXPRESSION_UPDATED = SN_JOB + '/TEMPORAL_EXPRESSION_UPDATED' -export const JOB_THRESHOLD_RULES_UPDATED = SN_JOB + '/THRESHOLD_RULES_UPDATED' -export const JOB_DESCRIPTION_UPDATED = SN_JOB + '/DESCRIPTION_UPDATED' -export const JOB_HISTORY_UPDATED = SN_JOB + '/HISTORY_UPDATED' -export const JOB_RUNNING_UPDATED = SN_JOB + '/RUNNING_UPDATED' -export const JOB_THRESHOLD_RULE_REMOVED = SN_JOB + 'THRESHOLD_RULE_REMOVED' \ No newline at end of file diff --git a/src/store/modules/job/mutations.ts b/src/store/modules/job/mutations.ts deleted file mode 100644 index b394ab19..00000000 --- a/src/store/modules/job/mutations.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { MutationTree } from 'vuex' -import JobState from './JobState' -import * as types from './mutation-types' -import logger from "@/logger"; - -const mutations: MutationTree = { - [types.JOB_PENDING_UPDATED] (state, payload) { - state.pending.list = payload.jobs; - state.pending.total = payload.total; - }, - [types.JOB_RUNNING_UPDATED] (state, payload) { - state.running.list = payload.jobs; - state.running.total = payload.total; - }, - [types.JOB_HISTORY_UPDATED] (state, payload) { - state.history.list = payload.jobs; - state.history.total = payload.total; - }, - [types.JOB_TEMPORAL_EXPRESSION_UPDATED] (state, temporalExpressions) { - if(temporalExpressions){ - temporalExpressions.forEach((temporalExpression: any) => { - state.temporalExp[temporalExpression.tempExprId] = temporalExpression; - }) - } - }, - [types.JOB_THRESHOLD_RULES_UPDATED] (state, thresholdRules) { - if(thresholdRules){ - state.thresholdRules = thresholdRules.reduce((thresholdRules: any, thresholdRule: any) => { - // Try catch to handle when parsing fails - try { - thresholdRules[thresholdRule.searchPrefId] = JSON.parse(thresholdRule.searchPrefValue); - } catch(err) { - logger.error(err); - } - return thresholdRules; - }, state.thresholdRules) - } - }, - [types.JOB_DESCRIPTION_UPDATED] (state, enums) { - if (enums) { - enums.forEach((enumInfo: any) => { - state.enumIds[enumInfo.enumId] = enumInfo - }); - } - }, - [types.JOB_THRESHOLD_RULE_REMOVED] (state, id) { - if(id) { - delete state.thresholdRules[id] - } - } -} -export default mutations; \ No newline at end of file diff --git a/src/store/modules/product/ProductState.ts b/src/store/modules/product/ProductState.ts deleted file mode 100644 index 072ae303..00000000 --- a/src/store/modules/product/ProductState.ts +++ /dev/null @@ -1,25 +0,0 @@ -export default interface ProductState { - products: { - list: any; - total: { - variant: number; - virtual: number; - } - }; - appliedFilters: { - included: { - tags: { - list: any; - operator: string; - }; - }, - excluded: { - tags: { - list: any; - operator: string; - }; - } - }; - query: any; - threshold: number; -} \ No newline at end of file diff --git a/src/store/modules/product/actions.ts b/src/store/modules/product/actions.ts deleted file mode 100644 index daa11bdc..00000000 --- a/src/store/modules/product/actions.ts +++ /dev/null @@ -1,157 +0,0 @@ -import { ProductService } from "@/services/ProductService"; -import { ActionTree } from 'vuex' -import RootState from '@/store/RootState' -import ProductState from './ProductState' -import * as types from './mutation-types' -import { hasError, showToast, getFeature } from '@/utils' -import { translate } from '@/i18n' -import logger from "@/logger"; - -const actions: ActionTree = { - - async getProducts({ commit, state }) { - let resp; - - const query = state.query - - try { - resp = await ProductService.getProducts(query); - - if (resp.status === 200 && resp.data.grouped.groupId?.ngroups > 0 && !hasError(resp)) { - let products = resp.data.grouped.groupId?.groups; - let totalVirtual = resp.data.grouped.groupId.ngroups; - let totalVariant = resp.data.grouped.groupId.matches; - products = products.map((product: any) => { - return { - productId: product.groupValue, - productName: product.doclist.docs[0]?.parentProductName, - variants: product.doclist.docs.map((variant: any) => { - return { - ...variant, - 'color': getFeature(variant.featureHierarchy, '1/COLOR/'), - 'size': getFeature(variant.featureHierarchy, '1/SIZE/') - } - }) - } - }) - - if(query.json.params.start && query.json.params.start > 0) products = state.products.list.concat(products); - if(query.json.query !== "*:*"){ - totalVirtual = state.products.total.virtual - totalVariant = state.products.total.variant - } - commit(types.PRODUCT_LIST_UPDATED, { products, totalVirtual, totalVariant }); - } else { - showToast(translate("Products not found")); - commit(types.PRODUCT_LIST_UPDATED, { products: [], totalVirtual: query.json.query === "*:*" ? 0 : state.products.total.virtual, totalVariant: query.json.query === "*:*" ? 0 : state.products.total.variant }); - } - } catch (error) { - logger.error(error); - showToast(translate("Something went wrong"), error); - } - return resp; - }, - - setAppliedfiltersAndOperator({ commit, dispatch }, payload){ - commit(types.PRODUCT_ALL_FILTERS_UPDATED, payload) - dispatch('updateQuery'); - }, - - async updateAppliedFilters({ commit, state, dispatch }, payload) { - commit(types.PRODUCT_FILTER_UPDATED, { id: payload.id, type: payload.type, value: payload.value }) - dispatch('updateQuery') - }, - - async updateAppliedFilterOperator({ commit, state, dispatch }, payload) { - const appliedFilters = JSON.parse(JSON.stringify((state.appliedFilters as any)[payload.type][payload.id])) - appliedFilters.operator = payload.value; - commit(types.PRODUCT_FILTER_UPDATED, {id: payload.id, type: payload.type, value: appliedFilters}) - // If we have list items then only apply filters again - if(appliedFilters.list.length) dispatch('updateQuery') - }, - - async updateQuery({ commit, dispatch, state }, payload) { - // initializing the filter always on updateQuery call because we are adding values in the filter - // as string and if some value is removed then we need to do multiple operations on the filter string - // to remove that value from the query filter - state.query.json['filter'] = ["docType: PRODUCT", "groupId: *", `prodCatalogIds: ${this.state.user.currentEComStore.prodCatalogId}`] - state.query.json['params'] = { - "group": true, - "group.field": "groupId", - "group.limit": 10000, - "group.ngroups": true - } - state.query.json['query'] = "*:*" - - if(payload && payload.queryString) { - state.query.json.params.defType = 'edismax' - state.query.json.params.qf = 'productId productName upc sku internalName brandName parentProductName' - state.query.json.query = `${payload.queryString}` - } - - if (payload) { - state.query.json.params.rows = payload.viewSize - state.query.json.params.start = payload.viewSize * payload.viewIndex - } - state.query.json['filter'] = Object.keys(state.appliedFilters.included).reduce((filter, value) => { - const filterValues = (state.appliedFilters.included as any)[value] - if (filterValues.list.length > 0) { - filter.push(`${value}: ("${filterValues.list.join('" ' + filterValues.operator + ' "')}")`) - } - return filter - }, state.query.json['filter']) - - state.query.json['filter'] = Object.keys(state.appliedFilters.excluded).reduce((filter, value) => { - const filterValues = (state.appliedFilters.excluded as any)[value] - if (filterValues.list.length > 0) { - filter.push(`-${value}: ("${filterValues.list.join('" ' + filterValues.operator + ' "')}")`) - } - return filter - }, state.query.json['filter']) - - commit(types.PRODUCT_QUERY_UPDATED, state.query) - await dispatch('getProducts') - }, - - async resetFilters({ commit, state, dispatch }, payload) { - const appliedFilters = JSON.parse(JSON.stringify((state.appliedFilters as any)[payload.type])) - const value = Object.keys(appliedFilters).reduce((value: any, filter: any) => { - value[filter] = { - list: [], - operator: "OR" - } - return value - }, {}) - commit(types.PRODUCT_FILTERS_UPDATED, {type: payload.type, value}) - await dispatch('updateQuery') - }, - - async clearAllFilters({ commit, state }) { - const appliedFilters = JSON.parse(JSON.stringify(state.appliedFilters)) - const value = Object.keys(appliedFilters).reduce((value: any, type: any) => { - const val = Object.keys(appliedFilters[type]).reduce((val: any, filter: any) => { - val[filter] = { - list: [], - operator: 'OR' - } - return val - }, {}) - value[type] = val - return value - }, {}) - commit(types.PRODUCT_ALL_FILTERS_UPDATED, value) - }, - - async clearFilters({ commit, dispatch }, payload) { - commit(types.PRODUCT_FILTER_UPDATED, {id: payload.id, type: payload.type, value: payload.value}) - await dispatch('updateQuery') - }, - clearProductList({ commit }){ - commit(types.PRODUCT_LIST_UPDATED, { products: [], totalVirtual: 0, totalVariant: 0 }); - }, - - async updateThreshold({ commit }, value) { - commit(types.PRODUCT_THRESHOLD_UPDATED, value) - } -} -export default actions; \ No newline at end of file diff --git a/src/store/modules/product/getters.ts b/src/store/modules/product/getters.ts deleted file mode 100644 index 86754f8f..00000000 --- a/src/store/modules/product/getters.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { GetterTree } from "vuex"; -import ProductState from "./ProductState"; -import RootState from "../../RootState"; - -const getters: GetterTree = { - getSearchProducts(state) { - return state.products.list; - }, - isScrollable(state) { - return ( - state.products.list.length > 0 && - state.products.list.length < state.products.total.virtual - ); - }, - getProducts(state) { - return state.products; - }, - getAppliedFilters(state) { - return state.appliedFilters; - }, - getQuery(state) { - return state.query; - }, - getThreshold(state) { - return state.threshold; - } -}; -export default getters; \ No newline at end of file diff --git a/src/store/modules/product/index.ts b/src/store/modules/product/index.ts deleted file mode 100644 index 20146854..00000000 --- a/src/store/modules/product/index.ts +++ /dev/null @@ -1,51 +0,0 @@ -import actions from './actions' -import getters from './getters' -import mutations from './mutations' -import { Module } from 'vuex' -import ProductState from './ProductState' -import RootState from '../../RootState' - -const productModule: Module = { - namespaced: true, - state: { - products: { - list: [], - total: { - virtual: 0, - variant: 0 - } - }, - appliedFilters: { - included: { - tags: { - list: [], - operator: "OR" - }, - }, - excluded: { - tags: { - list: [], - operator: "OR" - }, - } - }, - query: { - "json": { - "params": { - "group": true, - "group.field": "groupId", - "group.limit": 10000, - "group.ngroups": true - } as any, - "query": "*:*", - "filter": ["docType: PRODUCT"] - } - }, - threshold: 0 - }, - getters, - actions, - mutations, -} - -export default productModule; \ No newline at end of file diff --git a/src/store/modules/product/mutation-types.ts b/src/store/modules/product/mutation-types.ts deleted file mode 100644 index 58af0ada..00000000 --- a/src/store/modules/product/mutation-types.ts +++ /dev/null @@ -1,7 +0,0 @@ -export const SN_PRODUCT = 'product' -export const PRODUCT_LIST_UPDATED = SN_PRODUCT + '/LIST_UPDATED' -export const PRODUCT_FILTER_UPDATED = SN_PRODUCT + '/FILTER_UPDATED' -export const PRODUCT_QUERY_UPDATED = SN_PRODUCT + '/QUERY_UPDATED' -export const PRODUCT_FILTERS_UPDATED = SN_PRODUCT + '/FILTERS_UPDATED' -export const PRODUCT_ALL_FILTERS_UPDATED = SN_PRODUCT + '/ALL_FILTERS_UPDATED' -export const PRODUCT_THRESHOLD_UPDATED = SN_PRODUCT + '/THRESHOLD_UPDATED' diff --git a/src/store/modules/product/mutations.ts b/src/store/modules/product/mutations.ts deleted file mode 100644 index 3ba78c8a..00000000 --- a/src/store/modules/product/mutations.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { MutationTree } from 'vuex' -import ProductState from './ProductState' -import * as types from './mutation-types' - -const mutations: MutationTree = { - [types.PRODUCT_LIST_UPDATED] (state, payload) { - state.products.list = payload.products; - state.products.total.variant = payload.totalVariant; - state.products.total.virtual = payload.totalVirtual; - }, - [types.PRODUCT_FILTER_UPDATED] (state, payload) { - (state.appliedFilters as any)[payload.type][payload.id] = payload.value - }, - [types.PRODUCT_QUERY_UPDATED] (state, payload) { - state.query = payload - }, - [types.PRODUCT_FILTERS_UPDATED] (state, payload) { - (state.appliedFilters as any)[payload.type] = payload.value - }, - [types.PRODUCT_ALL_FILTERS_UPDATED] (state, payload) { - state.appliedFilters = payload - }, - [types.PRODUCT_THRESHOLD_UPDATED] (state, payload) { - state.threshold = payload - } -} -export default mutations; \ No newline at end of file diff --git a/src/store/modules/user/UserState.ts b/src/store/modules/user/UserState.ts index 07feebae..afbd45ce 100644 --- a/src/store/modules/user/UserState.ts +++ b/src/store/modules/user/UserState.ts @@ -1,6 +1,4 @@ export default interface UserState { - permissions: any; - pwaState: any; token: string; current: object | null; instanceUrl: string; diff --git a/src/store/modules/user/actions.ts b/src/store/modules/user/actions.ts index a12e9609..d424752c 100644 --- a/src/store/modules/user/actions.ts +++ b/src/store/modules/user/actions.ts @@ -3,90 +3,44 @@ import { ActionTree } from 'vuex' import RootState from '@/store/RootState' import UserState from './UserState' import * as types from './mutation-types' -import { hasError, showToast } from '@/utils' +import { showToast } from '@/utils' import { translate } from '@/i18n' -import { Settings } from 'luxon'; import logger from "@/logger"; -import { - getServerPermissionsFromRules, - prepareAppPermissions, - resetPermissions, - setPermissions -} from '@/authorization' -import { logout, updateInstanceUrl, updateToken, resetConfig } from '@/adapter' -import { useAuthStore } from '@hotwax/dxp-components' import emitter from '@/event-bus' - - +import { Settings } from "luxon" const actions: ActionTree = { /** * Login user and return token */ - async login ({ commit, dispatch }, payload) { - + async login ({ commit }, { username, password }) { try { - const {token, oms} = payload; - dispatch("setUserInstanceUrl", oms); - - // Getting the permissions list from server - const permissionId = process.env.VUE_APP_PERMISSION_ID; - // Prepare permissions list - const serverPermissionsFromRules = getServerPermissionsFromRules(); - if (permissionId) serverPermissionsFromRules.push(permissionId); - - const serverPermissions = await UserService.getUserPermissions({ - permissionIds: [...new Set(serverPermissionsFromRules)] - }, token); - const appPermissions = prepareAppPermissions(serverPermissions); - - - // Checking if the user has permission to access the app - // If there is no configuration, the permission check is not enabled - if (permissionId) { - // As the token is not yet set in the state passing token headers explicitly - // TODO Abstract this out, how token is handled should be part of the method not the callee - const hasPermission = appPermissions.some((appPermission: any) => appPermission.action === permissionId ); // If there are any errors or permission check fails do not allow user to login - if (!hasPermission) { - const permissionError = 'You do not have permission to access the app.'; - showToast(translate(permissionError)); - logger.error("error", permissionError); - return Promise.reject(new Error(permissionError)); - } + if(!username.length || !password.length) { + return Promise.reject('') } + emitter.emit("presentLoader", { message: "Logging in...", backdropDismiss: false }) + // TODO: implement support for permission check + const token = await UserService.login(username, password) + const userProfile = await UserService.getUserProfile(token); - userProfile.stores = await UserService.getEComStores(token, userProfile.partyId); - let preferredStore = userProfile.stores.length ? userProfile.stores[0] : {}; + // TODO: fetch only associated product stores for user, currently api does not support this + userProfile.stores = await UserService.getEComStores(token); - const preferredStoreId = await UserService.getPreferredStore(token); - if (preferredStoreId) { - const store = userProfile.stores.find((store: any) => store.productStoreId === preferredStoreId); - store && (preferredStore = store) + if (userProfile.timeZone) { + Settings.defaultZone = userProfile.timeZone; } - // prodCatalogId will be used getting the products instead of productStoreIds as the productStoreIds is tokenized - // For STORE, the results will have X_STORE results as well - preferredStore.prodCatalogId = (await UserService.getEcommerceCatalog(token, preferredStore.productStoreId))?.prodCatalogId; - /* ---- Guard clauses ends here --- */ - setPermissions(appPermissions); - if (userProfile.userTimeZone) { - Settings.defaultZone = userProfile.userTimeZone; - } - updateToken(token) - - // TODO user single mutation - commit(types.USER_INFO_UPDATED, userProfile); - commit(types.USER_CURRENT_ECOM_STORE_UPDATED, preferredStore); - commit(types.USER_PERMISSIONS_UPDATED, appPermissions); commit(types.USER_TOKEN_CHANGED, { newToken: token }) - + emitter.emit("dismissLoader") + commit(types.USER_INFO_UPDATED, userProfile); + commit(types.USER_CURRENT_ECOM_STORE_UPDATED, userProfile.stores.length ? userProfile.stores[0] : {}); + return Promise.resolve({ token }) } catch (err: any) { - // If any of the API call in try block has status code other than 2xx it will be handled in common catch block. - // TODO Check if handling of specific status codes is required. - showToast(translate('Something went wrong while login. Please contact administrator')); + emitter.emit("dismissLoader") + showToast(translate(err)); logger.error("error", err); return Promise.reject(new Error(err)) } @@ -95,88 +49,22 @@ const actions: ActionTree = { /** * Logout user */ - async logout ({ commit }, payload) { - // store the url on which we need to redirect the user after logout api completes in case of SSO enabled - let redirectionUrl = '' - - emitter.emit('presentLoader', { message: 'Logging out', backdropDismiss: false }) - - // Calling the logout api to flag the user as logged out, only when user is authorised - // if the user is already unauthorised then not calling the logout api as it returns 401 again that results in a loop, thus there is no need to call logout api if the user is unauthorised - if(!payload?.isUserUnauthorised) { - let resp; - - // wrapping the parsing logic in try catch as in some case the logout api makes redirection, and then we are unable to parse the resp and thus the logout process halts - try { - resp = await logout(); - - // Added logic to remove the `//` from the resp as in case of get request we are having the extra characters and in case of post we are having 403 - resp = JSON.parse(resp.startsWith('//') ? resp.replace('//', '') : resp) - } catch(err) { - logger.error('Error parsing data', err) - } - - if(resp?.logoutAuthType == 'SAML2SSO') { - redirectionUrl = resp.logoutUrl - } - } - - const authStore = useAuthStore() - + async logout ({ commit }) { // TODO add any other tasks if need commit(types.USER_END_SESSION) - this.dispatch('product/clearAllFilters') - this.dispatch('product/clearProductList'); - this.dispatch('util/clearFacilitiesByProductStore') - this.dispatch('util/clearShopifyConfig') - this.dispatch('job/clearJobState'); - resetPermissions(); - resetConfig(); - - // reset plugin state on logout - authStore.$reset() - - // If we get any url in logout api resp then we will redirect the user to the url - if(redirectionUrl) { - window.location.href = redirectionUrl - } - - emitter.emit('dismissLoader') - return redirectionUrl; - }, - - /** - * update current eComStore information - */ - async setEcomStore({ commit }, payload) { - let productStore = payload.productStore; - if(!productStore) { - productStore = this.state.user.current.stores.find((store: any) => store.productStoreId === payload.productStoreId); - } - // prodCatalogId will be used getting the products instead of productStoreIds as the productStoreIds is tokenized - // For STORE, the results will have X_STORE results as well - productStore.prodCatalogId = (await UserService.getEcommerceCatalog(undefined, productStore.productStoreId))?.prodCatalogId; - - commit(types.USER_CURRENT_ECOM_STORE_UPDATED, productStore); - this.dispatch('product/clearAllFilters') - this.dispatch('product/clearProductList'); - this.dispatch('job/clearJobState'); - await UserService.setUserPreference({ - 'userPrefTypeId': 'SELECTED_BRAND', - 'userPrefValue': productStore.productStoreId - }); }, + /** - * Update user timeZone - */ - async setUserTimeZone ( { state, commit }, payload) { - const resp = await UserService.setUserTimeZone(payload) - if (resp.status === 200 && !hasError(resp)) { - const current: any = state.current; - current.userTimeZone = payload.tzId; + * Update user timeZone + */ + async setUserTimeZone({ state, commit }, payload) { + const current: any = state.current; + // TODO: add support to change the user time on server, currently api to update user is not available + if(current.timeZone !== payload.tzId) { + current.timeZone = payload.tzId; commit(types.USER_INFO_UPDATED, current); - Settings.defaultZone = current.userTimeZone; + Settings.defaultZone = current.timeZone; showToast(translate("Time zone updated successfully")); } }, @@ -184,11 +72,14 @@ const actions: ActionTree = { // Set User Instance Url setUserInstanceUrl ({ commit }, payload){ commit(types.USER_INSTANCE_URL_UPDATED, payload) - updateInstanceUrl(payload) }, - updatePwaState({ commit }, payload) { - commit(types.USER_PWA_STATE_UPDATED, payload); + setEcomStore({ commit, state }, payload) { + let productStore = payload.productStore; + if(!productStore) { + productStore = (state.current as any).stores.find((store: any) => store.productStoreId === payload.productStoreId); + } + commit(types.USER_CURRENT_ECOM_STORE_UPDATED, productStore); } } diff --git a/src/store/modules/user/getters.ts b/src/store/modules/user/getters.ts index b6c22f67..ce5192c8 100644 --- a/src/store/modules/user/getters.ts +++ b/src/store/modules/user/getters.ts @@ -6,7 +6,7 @@ const getters: GetterTree = { getBaseUrl (state) { let baseURL = process.env.VUE_APP_BASE_URL; if (!baseURL) baseURL = state.instanceUrl; - return baseURL.startsWith('http') ? baseURL : `https://${baseURL}.hotwax.io/api/`; + return baseURL.startsWith('http') ? baseURL : `https://${baseURL}.hotwax.io/rest/s1/order-routing/`; }, isAuthenticated (state) { return !!state.token; @@ -27,11 +27,5 @@ const getters: GetterTree = { getCurrentEComStore(state) { return state.currentEComStore }, - getUserPermissions (state) { - return state.permissions; - }, - getPwaState(state) { - return state.pwaState; - }, } export default getters; \ No newline at end of file diff --git a/src/store/modules/user/index.ts b/src/store/modules/user/index.ts index 3ba85293..1d2cbb56 100644 --- a/src/store/modules/user/index.ts +++ b/src/store/modules/user/index.ts @@ -9,14 +9,9 @@ const userModule: Module = { namespaced: true, state: { token: '', - permissions: [], current: {}, instanceUrl: '', - currentEComStore: {}, - pwaState: { - updateExists: false, - registration: null, - } + currentEComStore: {} }, getters, actions, diff --git a/src/store/modules/user/mutation-types.ts b/src/store/modules/user/mutation-types.ts index 95162856..e7c812f4 100644 --- a/src/store/modules/user/mutation-types.ts +++ b/src/store/modules/user/mutation-types.ts @@ -3,6 +3,4 @@ export const USER_TOKEN_CHANGED = SN_USER + '/TOKEN_CHANGED' export const USER_END_SESSION = SN_USER + '/END_SESSION' export const USER_INFO_UPDATED = SN_USER + '/INFO_UPDATED' export const USER_INSTANCE_URL_UPDATED = SN_USER + '/INSTANCE_URL_UPDATED' -export const USER_CURRENT_ECOM_STORE_UPDATED = SN_USER + '/CURRENT_ECOM_STORE_UPDATED' -export const USER_PERMISSIONS_UPDATED = SN_USER + '/PERMISSIONS_UPDATED' -export const USER_PWA_STATE_UPDATED = SN_USER + '/PWA_STATE_UPDATED' \ No newline at end of file +export const USER_CURRENT_ECOM_STORE_UPDATED = SN_USER + '/CURRENT_ECOM_STORE_UPDATED' \ No newline at end of file diff --git a/src/store/modules/user/mutations.ts b/src/store/modules/user/mutations.ts index 2fafc6aa..e91a0dee 100644 --- a/src/store/modules/user/mutations.ts +++ b/src/store/modules/user/mutations.ts @@ -10,7 +10,6 @@ const mutations: MutationTree = { state.token = '' state.current = {} state.currentEComStore = {} - state.permissions = [] }, [types.USER_INFO_UPDATED] (state, payload) { state.current = payload @@ -18,15 +17,11 @@ const mutations: MutationTree = { [types.USER_INSTANCE_URL_UPDATED] (state, payload) { state.instanceUrl = payload; }, + [types.USER_INFO_UPDATED] (state, payload) { + state.current = payload + }, [types.USER_CURRENT_ECOM_STORE_UPDATED] (state, payload) { state.currentEComStore = payload; }, - [types.USER_PERMISSIONS_UPDATED] (state, payload) { - state.permissions = payload - }, - [types.USER_PWA_STATE_UPDATED](state, payload) { - state.pwaState.registration = payload.registration; - state.pwaState.updateExists = payload.updateExists; - }, } export default mutations; \ No newline at end of file diff --git a/src/store/modules/util/UtilState.ts b/src/store/modules/util/UtilState.ts deleted file mode 100644 index bdc6415f..00000000 --- a/src/store/modules/util/UtilState.ts +++ /dev/null @@ -1,6 +0,0 @@ -export default interface UtilState { - statusDesc: any; - shopifyConfig: any; - facilitiesByProductStore: any; - channels: []; -} \ No newline at end of file diff --git a/src/store/modules/util/actions.ts b/src/store/modules/util/actions.ts deleted file mode 100644 index 04d0b31e..00000000 --- a/src/store/modules/util/actions.ts +++ /dev/null @@ -1,120 +0,0 @@ -import { UtilService } from '@/services/UtilService' -import { ActionTree } from 'vuex' -import RootState from '@/store/RootState' -import UtilState from './UtilState' -import * as types from './mutation-types' -import { hasError } from '@/utils' -import logger from "@/logger"; - -const actions: ActionTree = { - /** - * Status Description - */ - async getServiceStatusDesc ({ commit }) { - try{ - const resp = await UtilService.getServiceStatusDesc({ - "inputFields": { - "statusTypeId": "SERVICE_STATUS", - "statusTypeId_op": "equals" - }, - "entityName": "StatusItem", - "fieldList": ["statusId", "description"], - "noConditionFind": "Y", - "viewSize": 20 - }) - if (resp.status === 200 && !hasError(resp) && resp.data.count) { - commit(types.UTIL_SERVICE_STATUS_DESC_UPDATED, resp.data.docs); - } - } catch(err) { - logger.error(err) - } - }, - - async getShopifyConfig({ state, commit }, payload) { - // TODO: for now passing view size as 1 by considering that one product store id is associated with only - // one shopify config - const resp = await UtilService.getShopifyConfig({ - "inputFields": { - "productStoreId": payload - }, - "entityName": "ShopifyConfig", - "distinct": "Y", - "noConditionFind": "Y", - "fieldList": ["shopifyConfigId", "productStoreId"], - "viewSize": 1 - }) - - if (resp.status === 200 && !hasError(resp) && resp.data?.docs?.length > 0) { - const shopifyConfig = resp.data.docs[0] - - const shopifyConfigs = JSON.parse(JSON.stringify(state.shopifyConfig)) - shopifyConfigs[shopifyConfig.productStoreId] = shopifyConfig.shopifyConfigId - - commit(types.UTIL_SHOPIFY_CONFIG_UPDATED, shopifyConfigs); - return shopifyConfig; - } - return {}; - }, - - async fetchFacilitiesByProductStore({ state, commit }, payload) { - - try { - const resp = await UtilService.fetchFacilitiesByProductStore(payload); - - if (resp.status === 200 && !hasError(resp) && resp.data?.count > 0) { - const facilities = resp.data.docs.reduce((facilities: any, data: any) => { - if(!facilities[data.productStoreId]) { - facilities[data.productStoreId] = [] - } - - facilities[data.productStoreId].push(data.facilityId) - return facilities - }, {}) - commit(types.UTIL_PRODUCT_STORE_FACILITY_UPDATED, { - ...state.facilitiesByProductStore, - ...facilities - }); - return facilities; - } - } catch (err) { - logger.error(err) - } - return {}; - }, - - async fetchChannels({ commit }) { - let channels = [] - const params = { - entityName: "FacilityGroup", - inputFields: { - facilityGroupTypeId: 'CHANNEL_FAC_GROUP' - }, - noConditionFind: 'Y', - orderBy: "facilityGroupName ASC", - fieldList: ["facilityGroupId", "facilityGroupTypeId", "facilityGroupName", "description"], - viewSize: 50 - } - - try { - const resp = await UtilService.fetchChannels(params) - if (!hasError(resp)) { - channels = resp.data.docs - } else { - throw resp.data - } - } catch (error) { - logger.error(error) - } - commit(types.UTIL_CHANNELS_UPDATED, channels) - }, - - async clearFacilitiesByProductStore({ commit }) { - commit(types.UTIL_PRODUCT_STORE_FACILITY_UPDATED, {}) - }, - - async clearShopifyConfig({ commit }) { - commit(types.UTIL_SHOPIFY_CONFIG_UPDATED, {}) - } -} - -export default actions; \ No newline at end of file diff --git a/src/store/modules/util/getters.ts b/src/store/modules/util/getters.ts deleted file mode 100644 index 46ed083d..00000000 --- a/src/store/modules/util/getters.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { GetterTree } from 'vuex' -import UtilState from './UtilState' -import RootState from '@/store/RootState' - -const getters: GetterTree = { - getStatusDesc: (state) => (statusId: any) => { - return state.statusDesc[statusId] ? state.statusDesc[statusId] : "-"; - }, - getShopifyConfig(state) { - return state.shopifyConfig - }, - getFacilityByProductStore(state) { - return state.facilitiesByProductStore - }, - getChannels(state) { - return state.channels; - } -} -export default getters; \ No newline at end of file diff --git a/src/store/modules/util/index.ts b/src/store/modules/util/index.ts deleted file mode 100644 index 0846d1ec..00000000 --- a/src/store/modules/util/index.ts +++ /dev/null @@ -1,21 +0,0 @@ -import actions from './actions' -import getters from './getters' -import mutations from './mutations' -import { Module } from 'vuex' -import UtilState from './UtilState' -import RootState from '@/store/RootState' - -const utilModule: Module = { - namespaced: true, - state: { - statusDesc: {}, - shopifyConfig: {}, - facilitiesByProductStore: {}, - channels: [] - }, - getters, - actions, - mutations, -} - -export default utilModule; \ No newline at end of file diff --git a/src/store/modules/util/mutation-types.ts b/src/store/modules/util/mutation-types.ts deleted file mode 100644 index a7dc3abd..00000000 --- a/src/store/modules/util/mutation-types.ts +++ /dev/null @@ -1,5 +0,0 @@ -export const SN_UTIL = 'util' -export const UTIL_SERVICE_STATUS_DESC_UPDATED = SN_UTIL + '/SERVICE_STATUS_DESC_UPDATED' -export const UTIL_SHOPIFY_CONFIG_UPDATED = SN_UTIL + '/SHOPIFY_CONFIG_UPDATED' -export const UTIL_PRODUCT_STORE_FACILITY_UPDATED = SN_UTIL + '/PRODUCT_STORE_FACILITY_UPDATED' -export const UTIL_CHANNELS_UPDATED = SN_UTIL + '/CHANNELS_UPDATED' diff --git a/src/store/modules/util/mutations.ts b/src/store/modules/util/mutations.ts deleted file mode 100644 index 0e0ad324..00000000 --- a/src/store/modules/util/mutations.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { MutationTree } from 'vuex' -import UtilState from './UtilState' -import * as types from './mutation-types' - -const mutations: MutationTree = { - [types.UTIL_SERVICE_STATUS_DESC_UPDATED] (state, payload) { - payload.map((status: any) => { - state.statusDesc[status.statusId] = status.description; - }) - }, - [types.UTIL_SHOPIFY_CONFIG_UPDATED] (state, payload) { - state.shopifyConfig = payload; - }, - [types.UTIL_PRODUCT_STORE_FACILITY_UPDATED] (state, payload) { - state.facilitiesByProductStore = payload - }, - [types.UTIL_CHANNELS_UPDATED](state, payload) { - state.channels = payload - } -} -export default mutations; \ No newline at end of file diff --git a/src/utils/index.ts b/src/utils/index.ts index 6e08b98b..7226d8df 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -1,6 +1,4 @@ -import { modalController, toastController } from '@ionic/vue'; -import { DateTime } from "luxon"; -import ErrorMessageModal from "@/components/ErrorMessageModal.vue"; +import { toastController } from '@ionic/vue'; // TODO Use separate files for specific utilities @@ -9,54 +7,14 @@ const hasError = (response: any) => { return typeof response.data != "object" || !!response.data._ERROR_MESSAGE_ || !!response.data._ERROR_MESSAGE_LIST_ || !!response.data.error; } -const showToast = async (message: string, err?: any) => { - const config = { - message, - duration: 3000, - position: 'bottom' - } as any - if (err) { - config.buttons = [ - { - text: 'view', - side: 'end', - handler: async () => { - const errorMessageModal = await modalController.create({ - component: ErrorMessageModal, - componentProps: { - errorMessage: err, - }, - initialBreakpoint: 0.08, - breakpoints: [0, 0.10, 0.5, 0.75] - }); - return errorMessageModal.present(); - } - } - ] - } - const toast = await toastController.create(config) +const showToast = async (message: string) => { + const toast = await toastController + .create({ + message, + duration: 3000, + position: "top", + }) return toast.present(); } -const getFeature = (featureHierarchy: any, featureKey: string) => { - let featureValue = '' - if (featureHierarchy) { - const feature = featureHierarchy.find((featureItem: any) => featureItem.startsWith(featureKey)) - const featureSplit = feature ? feature.split('/') : []; - featureValue = featureSplit[2] ? featureSplit[2] : ''; - } - return featureValue; -} - -const handleDateTimeInput = (dateTimeValue: any) => { - // TODO Handle it in a better way - // Remove timezone and then convert to timestamp - // Current date time picker picks browser timezone and there is no supprt to change it - const dateTime = DateTime.fromISO(dateTimeValue, { setZone: true}).toFormat("yyyy-MM-dd'T'HH:mm:ss") - return DateTime.fromISO(dateTime).toMillis() -} - -const getResponseError = (resp: any) => { - return resp.data.error || resp.data._ERROR_MESSAGE_ || resp.data._ERROR_MESSAGE_LIST_ || resp.data.errorMessage || resp.data.errorMessageList || ""; -} -export { handleDateTimeInput, showToast, hasError, getFeature, getResponseError } +export { showToast, hasError } diff --git a/src/views/Login.vue b/src/views/Login.vue new file mode 100644 index 00000000..bd3a19ea --- /dev/null +++ b/src/views/Login.vue @@ -0,0 +1,79 @@ + + + + + diff --git a/src/views/ScheduleThreshold.vue b/src/views/ScheduleThreshold.vue deleted file mode 100644 index 9e0edc48..00000000 --- a/src/views/ScheduleThreshold.vue +++ /dev/null @@ -1,721 +0,0 @@ - - - - - \ No newline at end of file diff --git a/src/views/SelectFacility.vue b/src/views/SelectFacility.vue deleted file mode 100644 index 664f83bd..00000000 --- a/src/views/SelectFacility.vue +++ /dev/null @@ -1,225 +0,0 @@ - - - - - diff --git a/src/views/SelectFacilityCSVUpload.vue b/src/views/SelectFacilityCSVUpload.vue deleted file mode 100644 index ffdd5e5d..00000000 --- a/src/views/SelectFacilityCSVUpload.vue +++ /dev/null @@ -1,100 +0,0 @@ - - - - - \ No newline at end of file diff --git a/src/views/SelectProduct.vue b/src/views/SelectProduct.vue deleted file mode 100644 index 9089a218..00000000 --- a/src/views/SelectProduct.vue +++ /dev/null @@ -1,604 +0,0 @@ - - - - - diff --git a/src/views/SelectProductCSVUpload.vue b/src/views/SelectProductCSVUpload.vue deleted file mode 100644 index 3bd6ef40..00000000 --- a/src/views/SelectProductCSVUpload.vue +++ /dev/null @@ -1,93 +0,0 @@ - - - - - diff --git a/src/views/Settings.vue b/src/views/Settings.vue index 24eb5ba4..d92647e9 100644 --- a/src/views/Settings.vue +++ b/src/views/Settings.vue @@ -18,24 +18,34 @@ is added on sides from ion-item and ion-padding-vertical to compensate the removed vertical padding --> - {{ userProfile.userLoginId }} - {{ userProfile?.partyName }} + {{ userProfile.userId }} + {{ userProfile?.userFullName }}
{{ $t("Logout") }} - - {{ $t("Go to Launchpad") }} - - - -

{{ $t('OMS') }}

- + + + + {{ $t('OMS instance') }} + + + {{ oms }} + + + + {{ $t('This is the name of the OMS you are connected to right now. Make sure that you are connected to the right instance before proceeding.') }} + + + {{ $t('Go to OMS') }} + + + @@ -59,7 +69,13 @@

- +
+

+ {{ translate("App") }} +

{{ translate("Version:") + appVersion }}

+

+

{{ translate("Built:") + getDateTime(appInfo.builtTime) }}

+
@@ -72,7 +88,7 @@ {{ $t('The timezone you select is used to ensure automations you schedule are always accurate to the time you select.') }} - {{ userProfile && userProfile.userTimeZone ? userProfile.userTimeZone : '-' }} + {{ userProfile && userProfile.timeZone ? userProfile.timeZone : '-' }} {{ $t("Change") }} @@ -89,6 +105,8 @@ import { mapGetters, useStore } from 'vuex'; import { useRouter } from 'vue-router'; import TimeZoneModal from '@/views/TimezoneModal.vue'; import Image from '@/components/Image.vue' +import { DateTime } from "luxon"; +import { translate } from '@/i18n'; export default defineComponent({ name: 'Settings', @@ -115,13 +133,17 @@ export default defineComponent({ }, data() { return { - baseURL: process.env.VUE_APP_BASE_URL + baseURL: process.env.VUE_APP_BASE_URL, + appVersion: '', + appInfo: process.env.VUE_APP_VERSION_INFO ? JSON.parse(process.env.VUE_APP_VERSION_INFO) : {} as any }; }, computed: { ...mapGetters({ userProfile: 'user/getUserProfile', - currentEComStore: 'user/getCurrentEComStore' + currentEComStore: 'user/getCurrentEComStore', + oms: 'user/getInstanceUrl', + token: 'user/user/getUserToken', }) }, methods: { @@ -143,18 +165,24 @@ export default defineComponent({ }); return timeZoneModal.present(); }, - logout () { - this.store.dispatch('user/logout', { isUserUnauthorised: false }).then((redirectionUrl) => { - // if not having redirection url then redirect the user to launchpad - if(!redirectionUrl) { - const redirectUrl = window.location.origin + '/login' - window.location.href = `${process.env.VUE_APP_LOGIN_URL}?isLoggedOut=true&redirectUrl=${redirectUrl}` - } + logout() { + this.store.dispatch("user/logout").then(() => { + this.router.push("/login"); }) }, goToLaunchpad() { window.location.href = `${process.env.VUE_APP_LOGIN_URL}` }, + getDateTime(time: any) { + return time ? DateTime.fromMillis(time).toLocaleString(DateTime.DATETIME_MED) : ""; + }, + goToOms() { + const link = (this.oms.startsWith('http') ? this.oms.replace(/\/api\/?|\/$/, "") : `https://${this.oms}.hotwax.io`) + `/qapps?token=${this.token}` + window.open(link, '_blank', 'noopener, noreferrer') + } + }, + mounted() { + this.appVersion = this.appInfo.branch ? (this.appInfo.branch + "-" + this.appInfo.revision) : this.appInfo.tag; }, setup(){ const store = useStore(); @@ -169,6 +197,7 @@ export default defineComponent({ store, router, timeOutline, + translate, openOutline } } diff --git a/src/views/ThresholdUpdates.vue b/src/views/ThresholdUpdates.vue deleted file mode 100644 index c440a784..00000000 --- a/src/views/ThresholdUpdates.vue +++ /dev/null @@ -1,688 +0,0 @@ - - - - diff --git a/src/views/TimezoneModal.vue b/src/views/TimezoneModal.vue index 0e8918a1..8cfed970 100644 --- a/src/views/TimezoneModal.vue +++ b/src/views/TimezoneModal.vue @@ -6,40 +6,45 @@ - {{ $t("Select time zone") }} + {{ translate("Select time zone") }} - + - -
-

{{ $t("No time zone found")}}

+
+ + + {{ translate("Fetching time zones") }} + +
+
+

{{ translate("No time zone found") }}

- + {{ timeZone.label }} ({{ timeZone.id }}) - +
- + - From 89a54166f26655a7bac4606cb76132c8779c4d05 Mon Sep 17 00:00:00 2001 From: amansinghbais Date: Fri, 5 Apr 2024 16:59:16 +0530 Subject: [PATCH 07/13] Improved: code for better login flow (#246) --- src/components/Menu.vue | 35 +++++++++++++++++++++++++++++ src/services/UserService.ts | 35 +++++++++++++---------------- src/store/modules/user/actions.ts | 1 + src/store/modules/user/mutations.ts | 3 --- src/views/TimezoneModal.vue | 2 +- 5 files changed, 53 insertions(+), 23 deletions(-) diff --git a/src/components/Menu.vue b/src/components/Menu.vue index 0eeba0d4..d5294143 100644 --- a/src/components/Menu.vue +++ b/src/components/Menu.vue @@ -20,12 +20,33 @@ + + + + +

{{ instanceUrl }}

+
+ {{ userProfile?.timeZone }} +
+ + + {{ store.storeName }} + + + + + {{ eComStore.storeName }} + + +
+