diff --git a/.eslintignore b/.eslintignore index 2569aef9fe..2c1e5c7a43 100644 --- a/.eslintignore +++ b/.eslintignore @@ -10,6 +10,7 @@ dist/ dist-client/ apidoc_build/ content_cache/ +i18n_cache/ node_modules/ # Old migrations, disabled diff --git a/test/client/.babelrc b/test/client/.babelrc deleted file mode 100644 index 5fd9045a15..0000000000 --- a/test/client/.babelrc +++ /dev/null @@ -1,16 +0,0 @@ -{ - "env": { - "test": { - plugins: [ - ["istanbul"], - ], - }, - }, - "presets": [ - ["es2015", { modules: false }], - ], - "plugins": [ - "transform-object-rest-spread", - ], - "comments": false, -} \ No newline at end of file diff --git a/test/client/unit/index.js b/test/client/unit/index.js deleted file mode 100644 index 9a3f4b6f9a..0000000000 --- a/test/client/unit/index.js +++ /dev/null @@ -1,21 +0,0 @@ -/* eslint-disable */ -// TODO verify if it's needed, added because Axios require Promise in the global scope -// and babel-runtime doesn't affect external libraries -require('babel-polyfill'); - -// Automatically setup SinonJS' sandbox for each test -beforeEach(() => { - global.sandbox = sinon.createSandbox(); -}); - -afterEach(() => { - global.sandbox.restore(); -}); - -// require all test files -const testsContext = require.context('./specs', true, /\.js$/); -testsContext.keys().forEach(testsContext); - -// require all .vue and .js files except main.js for coverage. -const srcContext = require.context('../../../website/client', true, /^\.\/(?=(?!main(\.js)?$))(?=(.*\.(vue|js)$))/); -srcContext.keys().forEach(srcContext); diff --git a/test/client/unit/karma.conf.js b/test/client/unit/karma.conf.js deleted file mode 100644 index b12c5aac67..0000000000 --- a/test/client/unit/karma.conf.js +++ /dev/null @@ -1,40 +0,0 @@ -/* eslint-disable */ -// This is a karma config file. For more details see -// http://karma-runner.github.io/0.13/config/configuration-file.html -// we are also using it with karma-webpack -// https://github.com/webpack/karma-webpack - -// Necessary for babel to respect the env version of .babelrc which is necessary -// Because inject-loader does not work with ["es2015", { modules: false }] that we use -// in order to let webpack2 handle the imports -process.env.CHROME_BIN = require('puppeteer').executablePath(); -// eslint-disable-line no-process-env -process.env.BABEL_ENV = process.env.NODE_ENV; // eslint-disable-line no-process-env -const webpackConfig = require('../../../webpack/webpack.test.conf'); - -module.exports = function (config) { - config.set({ - // to run in additional browsers: - // 1. install corresponding karma launcher - // http://karma-runner.github.io/0.13/config/browsers.html - // 2. add it to the `browsers` array below. - browsers: ['ChromeHeadless'], - frameworks: ['mocha', 'sinon-stub-promise', 'sinon-chai', 'chai-as-promised', 'chai'], - reporters: ['spec', 'coverage'], - files: ['./index.js'], - preprocessors: { - './index.js': ['webpack', 'sourcemap'], - }, - webpack: webpackConfig, - webpackMiddleware: { - noInfo: true, - }, - coverageReporter: { - dir: '../../../coverage/client-unit', - reporters: [ - { type: 'lcov', subdir: '.' }, - { type: 'text-summary' }, - ], - }, - }); -}; diff --git a/website/client/src/app.vue b/website/client/src/app.vue index 0f9fb26081..6b5f7db865 100644 --- a/website/client/src/app.vue +++ b/website/client/src/app.vue @@ -297,7 +297,7 @@ export default { }; }, computed: { - ...mapState(['isUserLoggedIn', 'browserTimezoneOffset', 'isUserLoaded']), + ...mapState(['isUserLoggedIn', 'browserTimezoneOffset', 'isUserLoaded', 'notificationsRemoved']), ...mapState({ user: 'user.data' }), isStaticPage () { return this.$route.meta.requiresLogin === false; @@ -361,13 +361,55 @@ export default { showSpinner: false, }); - // Set up Error interceptors - axios.interceptors.response.use(response => { - if (this.user && response.data && response.data.notifications) { - this.$set(this.user, 'notifications', response.data.notifications); + axios.interceptors.response.use(response => { // Set up Response interceptors + // Verify that the user was not updated from another browser/app/client + // If it was, sync + const { url } = response.config; + const { method } = response.config; + + const isApiCall = url.indexOf('api/v4') !== -1; + const userV = response.data && response.data.userV; + const isCron = url.indexOf('/api/v4/cron') === 0 && method === 'post'; + + if (this.isUserLoaded && isApiCall && userV) { + const oldUserV = this.user._v; + this.user._v = userV; + + // Do not sync again if already syncing + const isUserSync = url.indexOf('/api/v4/user') === 0 && method === 'get'; + const isTasksSync = url.indexOf('/api/v4/tasks/user') === 0 && method === 'get'; + // exclude chat seen requests because with real time chat they would be too many + const isChatSeen = url.indexOf('/chat/seen') !== -1 && method === 'post'; + // exclude POST /api/v4/cron because the user is synced automatically after cron runs + + // Something has changed on the user object that was not tracked here, sync the user + if (userV - oldUserV > 1 && !isCron && !isChatSeen && !isUserSync && !isTasksSync) { + Promise.all([ + this.$store.dispatch('user:fetch', { forceLoad: true }), + this.$store.dispatch('tasks:fetchUserTasks', { forceLoad: true }), + ]); + } } + + // Store the app version from the server + const serverAppVersion = response.data && response.data.appVersion; + + if (serverAppVersion && this.$store.state.serverAppVersion !== response.data.appVersion) { + this.$store.state.serverAppVersion = serverAppVersion; + } + + // Store the notifications, filtering those that have already been read + // See store/index.js on why this is necessary + if (this.user && response.data && response.data.notifications) { + const filteredNotifications = response.data.notifications.filter(serverNotification => { + if (this.notificationsRemoved.includes(serverNotification.id)) return false; + return true; + }); + this.$set(this.user, 'notifications', filteredNotifications); + } + return response; - }, error => { + }, error => { // Set up Error interceptors if (error.response.status >= 400) { const isBanned = this.checkForBannedUser(error); if (isBanned === true) return null; // eslint-disable-line consistent-return @@ -425,51 +467,6 @@ export default { return Promise.reject(error); }); - axios.interceptors.response.use(response => { - // Verify that the user was not updated from another browser/app/client - // If it was, sync - const { url } = response.config; - const { method } = response.config; - - const isApiCall = url.indexOf('api/v4') !== -1; - const userV = response.data && response.data.userV; - const isCron = url.indexOf('/api/v4/cron') === 0 && method === 'post'; - - if (this.isUserLoaded && isApiCall && userV) { - const oldUserV = this.user._v; - this.user._v = userV; - - // Do not sync again if already syncing - const isUserSync = url.indexOf('/api/v4/user') === 0 && method === 'get'; - const isTasksSync = url.indexOf('/api/v4/tasks/user') === 0 && method === 'get'; - // exclude chat seen requests because with real time chat they would be too many - const isChatSeen = url.indexOf('/chat/seen') !== -1 && method === 'post'; - // exclude POST /api/v4/cron because the user is synced automatically after cron runs - - // Something has changed on the user object that was not tracked here, sync the user - if (userV - oldUserV > 1 && !isCron && !isChatSeen && !isUserSync && !isTasksSync) { - Promise.all([ - this.$store.dispatch('user:fetch', { forceLoad: true }), - this.$store.dispatch('tasks:fetchUserTasks', { forceLoad: true }), - ]); - } - } - - // Verify the client is updated - // const serverAppVersion = response.data.appVersion; - // let serverAppVersionState = this.$store.state.serverAppVersion; - // if (isApiCall && !serverAppVersionState) { - // this.$store.state.serverAppVersion = serverAppVersion; - // } else if (isApiCall && serverAppVersionState !== serverAppVersion) { - // if (document.activeElement.tagName !== 'INPUT' - // || confirm(this.$t('habiticaHasUpdated'))) { - // location.reload(true); - // } - // } - - return response; - }); - // Setup listener for title this.$store.watch(state => state.title, title => { document.title = title; diff --git a/website/client/src/components/achievements/chooseClass.vue b/website/client/src/components/achievements/chooseClass.vue index 913abb1b1d..5597f4328f 100644 --- a/website/client/src/components/achievements/chooseClass.vue +++ b/website/client/src/components/achievements/chooseClass.vue @@ -16,7 +16,7 @@