From 7e26aa773cb0a5bca4cd66d8439047e84b91c341 Mon Sep 17 00:00:00 2001 From: Juan Ferrer Toribio Date: Fri, 9 Dec 2022 11:28:38 +0100 Subject: [PATCH] refs #4922 password recovery, app store, error handler, fixes --- package.json | 3 +- quasar.config.js | 8 +++- src/boot/app.js | 7 +++ src/boot/axios.js | 18 +++++--- src/boot/error-handler.js | 59 +++++++++++++++++++++++++ src/boot/i18n.js | 4 +- src/css/app.scss | 8 ++++ src/i18n/en-US/index.js | 7 ++- src/i18n/es-ES/index.js | 12 ++++++ src/i18n/index.js | 4 +- src/js/vn/json-connection.js | 10 ++++- src/layouts/MainLayout.vue | 20 +++++---- src/pages/{ => Cms}/Home.vue | 19 +++------ src/pages/Ecomerce/Orders.vue | 64 ++++++++++++++++++++++++++++ src/pages/ErrorNotFound.vue | 4 +- src/pages/Login/Login.vue | 16 +++---- src/pages/Login/RememberPassword.vue | 54 ++++++++++++++++++----- src/router/routes.js | 8 +++- src/stores/app.js | 17 ++++++++ src/stores/example-store.js | 15 ------- src/stores/user.js | 53 +++++++++++++++-------- 21 files changed, 314 insertions(+), 96 deletions(-) create mode 100644 src/boot/app.js create mode 100644 src/boot/error-handler.js create mode 100644 src/i18n/es-ES/index.js rename src/pages/{ => Cms}/Home.vue (75%) create mode 100644 src/pages/Ecomerce/Orders.vue create mode 100644 src/stores/app.js delete mode 100644 src/stores/example-store.js diff --git a/package.json b/package.json index 9ebf5068..2d7bd877 100644 --- a/package.json +++ b/package.json @@ -58,8 +58,7 @@ }, "scripts": { "front": "webpack serve --open", - "back": "cd ../salix && gulp backOnly", - "db": "cd ../vn-database && myvc run -d", + "back": "cd ../vn-database && myvc start && cd ../salix && gulp backOnly", "build": "rm -rf build/ ; webpack", "clean": "rm -rf build/", "lint": "eslint --ext .js,.vue ./" diff --git a/quasar.config.js b/quasar.config.js index d0fd8d6b..08fc8ee3 100644 --- a/quasar.config.js +++ b/quasar.config.js @@ -26,7 +26,9 @@ module.exports = configure(function (ctx) { // https://v2.quasar.dev/quasar-cli-webpack/boot-files boot: [ 'i18n', - 'axios' + 'axios', + 'error-handler', + 'app' ], // https://v2.quasar.dev/quasar-cli-webpack/quasar-config-js#Property%3A-css @@ -129,7 +131,9 @@ module.exports = configure(function (ctx) { // directives: [], // Quasar plugins - plugins: [] + plugins: [ + 'Notify' + ] }, // animations: 'all', // --- includes all animations diff --git a/src/boot/app.js b/src/boot/app.js new file mode 100644 index 00000000..08b64067 --- /dev/null +++ b/src/boot/app.js @@ -0,0 +1,7 @@ +import { boot } from 'quasar/wrappers' +import { appStore } from 'stores/app' + +export default boot(({ app }) => { + const myApp = appStore() + app.config.globalProperties.$app = myApp +}) diff --git a/src/boot/axios.js b/src/boot/axios.js index 079f1bed..150a8d8d 100644 --- a/src/boot/axios.js +++ b/src/boot/axios.js @@ -1,5 +1,6 @@ import { boot } from 'quasar/wrappers' import { Connection } from '../js/db/connection' +import { userStore } from 'stores/user' import axios from 'axios' // Be careful when using SSR for cross-request state pollution @@ -11,17 +12,20 @@ import axios from 'axios' const api = axios.create({ baseURL: `//${location.hostname}:${location.port}/api/` }) -api.interceptors.request.use(function addToken (config) { - const token = localStorage.getItem('vnToken') - if (token) { - config.headers.Authorization = token - } - return config -}) const jApi = new Connection() export default boot(({ app }) => { + const user = userStore() + function addToken (config) { + if (user.token) { + config.headers.Authorization = user.token + } + return config + } + api.interceptors.request.use(addToken) + jApi.use(addToken) + // for use inside Vue files (Options API) through this.$axios and this.$api app.config.globalProperties.$axios = axios diff --git a/src/boot/error-handler.js b/src/boot/error-handler.js new file mode 100644 index 00000000..cbf541d2 --- /dev/null +++ b/src/boot/error-handler.js @@ -0,0 +1,59 @@ + +export default async ({ app }) => { +/* + window.addEventListener('error', + e => onWindowError(e)); + window.addEventListener('unhandledrejection', + e => onWindowRejection(e)); + + ,onWindowError(event) { + errorHandler(event.error); + } + ,onWindowRejection(event) { + errorHandler(event.reason); + } +*/ + app.config.errorHandler = (err, vm, info) => { + errorHandler(err, vm) + } + + function errorHandler (err, vm) { + let message + let tMessage + const res = err.response + + if (res) { + const status = res.status + + if (status >= 400 && status < 500) { + switch (status) { + case 401: + tMessage = 'loginFailed' + break + case 403: + tMessage = 'authenticationRequired' + vm.$router.push('/login') + break + case 404: + tMessage = 'notFound' + break + default: + message = res.data.error.message + } + } else if (status >= 500) { + tMessage = 'internalServerError' + } + } else { + tMessage = 'somethingWentWrong' + console.error(err) + } + + if (tMessage) { + message = vm.$t(tMessage) + } + vm.$q.notify({ + message, + type: 'negative' + }) + } +} diff --git a/src/boot/i18n.js b/src/boot/i18n.js index e36a6ba2..3b264658 100644 --- a/src/boot/i18n.js +++ b/src/boot/i18n.js @@ -4,8 +4,10 @@ import messages from 'src/i18n' export default boot(({ app }) => { const i18n = createI18n({ - locale: 'en-US', + locale: 'es-ES', globalInjection: true, + silentTranslationWarn: true, + silentFallbackWarn: true, messages }) diff --git a/src/css/app.scss b/src/css/app.scss index e0d7afb3..5e320667 100644 --- a/src/css/app.scss +++ b/src/css/app.scss @@ -13,6 +13,14 @@ body { font-family: 'Poppins', 'Verdana', 'Sans'; background-color: #fafafa; } +a.link { + text-decoration: none; + color: #6a1; + + &:hover { + text-decoration: underline; + } +} .q-card { border-radius: 7px; box-shadow: 0 0 3px rgba(0, 0, 0, .1); diff --git a/src/i18n/en-US/index.js b/src/i18n/en-US/index.js index b70b80f0..0eaf5814 100644 --- a/src/i18n/en-US/index.js +++ b/src/i18n/en-US/index.js @@ -3,5 +3,10 @@ export default { failed: 'Action failed', - success: 'Action was successful' + success: 'Action was successful', + internalServerError: 'Internal server error', + somethingWentWrong: 'Something went wrong', + loginFailed: 'Login failed', + authenticationRequired: 'Authentication required', + notFound: 'Not found' } diff --git a/src/i18n/es-ES/index.js b/src/i18n/es-ES/index.js new file mode 100644 index 00000000..174bb108 --- /dev/null +++ b/src/i18n/es-ES/index.js @@ -0,0 +1,12 @@ +// This is just an example, +// so you can safely delete all default props below + +export default { + failed: 'Acción fallida', + success: 'Acción exitosa', + internalServerError: 'Error interno del servidor', + somethingWentWrong: 'Algo salió mal', + loginFailed: 'Usuario o contraseña incorrectos', + authenticationRequired: 'Autenticación requerida', + notFound: 'No encontrado' +} diff --git a/src/i18n/index.js b/src/i18n/index.js index 81e1ad08..136539a4 100644 --- a/src/i18n/index.js +++ b/src/i18n/index.js @@ -1,5 +1,7 @@ import enUS from './en-US' +import esES from './es-ES' export default { - 'en-US': enUS + 'en-US': enUS, + 'es-ES': esES } diff --git a/src/js/vn/json-connection.js b/src/js/vn/json-connection.js index de9cd0f6..9a3e4cb9 100644 --- a/src/js/vn/json-connection.js +++ b/src/js/vn/json-connection.js @@ -9,6 +9,11 @@ export class JsonConnection extends VnObject { _connected = false _requestsCount = 0 token = null + interceptors = [] + + use (fn) { + this.interceptors.push(fn) + } /** * Executes the specified REST service with the given params and calls @@ -70,8 +75,9 @@ export class JsonConnection extends VnObject { const request = new XMLHttpRequest() request.open(config.method, config.url, true) - const token = localStorage.getItem('vnToken') - if (token) { request.setRequestHeader('Authorization', token) } + for (const fn of this.interceptors) { + config = fn(config) + } const headers = config.headers if (headers) { diff --git a/src/layouts/MainLayout.vue b/src/layouts/MainLayout.vue index d8fa8510..061e9a9d 100644 --- a/src/layouts/MainLayout.vue +++ b/src/layouts/MainLayout.vue @@ -8,26 +8,22 @@ round icon="menu" aria-label="Menu" - @click="toggleLeftDrawer" - /> - + @click="toggleLeftDrawer"/> Home - + show-if-above>