From c86c1cc0c0cb4701e63092d7b9d2936037a9cc4d Mon Sep 17 00:00:00 2001 From: wbuezas Date: Sat, 17 Aug 2024 19:59:35 -0300 Subject: [PATCH 1/7] General improvements --- src/css/app.scss | 9 ++++++++ src/pages/Account/AddressDetails.vue | 21 +++++++++++------- src/pages/Account/AddressList.vue | 22 +++++++++++++++++-- src/pages/Ecomerce/InvoicesView.vue | 10 ++++++++- src/pages/Ecomerce/OrdersView.vue | 13 +++++++++++ .../ui => pages/Ecomerce}/TicketDetails.vue | 0 src/pages/Ecomerce/TicketView.vue | 2 +- 7 files changed, 65 insertions(+), 12 deletions(-) rename src/{components/ui => pages/Ecomerce}/TicketDetails.vue (100%) diff --git a/src/css/app.scss b/src/css/app.scss index d802cb22..4a800f63 100644 --- a/src/css/app.scss +++ b/src/css/app.scss @@ -42,3 +42,12 @@ a.link { .no-padding { padding: 0 !important; } +input[type='number'] { + -moz-appearance: textfield; +} +input::-webkit-outer-spin-button, +input::-webkit-inner-spin-button { + appearance: none; + -webkit-appearance: none; + -moz-appearance: none; +} diff --git a/src/pages/Account/AddressDetails.vue b/src/pages/Account/AddressDetails.vue index 33bbcfb4..d706cfed 100644 --- a/src/pages/Account/AddressDetails.vue +++ b/src/pages/Account/AddressDetails.vue @@ -75,7 +75,7 @@ onMounted(() => getCountries()); }" :pks="pks" :isEditMode="isEditMode" - :title="t('addEditAddress')" + :title="t(isEditMode ? 'editAddress' : 'addAddress')" table="myAddress" schema="hedera" @onDataSaved="goBack()" @@ -114,7 +114,6 @@ onMounted(() => getCountries()); en-US: back: Back accept: Accept - addEditAddress: Add or edit address name: Consignee address: Address city: City @@ -122,21 +121,23 @@ en-US: country: Country province: Province addressChangedSuccessfully: Address changed successfully + addAddress: Add address + editAddress: Edit address es-ES: back: Volver accept: Aceptar - addEditAddress: Añadir o modificar dirección name: Consignatario - address: Morada + address: Dirección city: Ciudad postalCode: Código postal country: País - province: Distrito + province: Provincia addressChangedSuccessfully: Dirección modificada correctamente + addAddress: Añadir dirección + editAddress: Modificar dirección ca-ES: back: Tornar accept: Acceptar - addEditAddress: Afegir o modificar adreça name: Consignatari address: Direcció city: Ciutat @@ -144,10 +145,11 @@ ca-ES: country: País province: Província addressChangedSuccessfully: Adreça modificada correctament + addAddress: Afegir adreça + editAddress: Modificar adreça fr-FR: back: Retour accept: Accepter - addEditAddress: Ajouter ou modifier l'adresse name: Destinataire address: Numéro Rue city: Ville @@ -155,10 +157,11 @@ fr-FR: country: Pays province: Province addressChangedSuccessfully: Adresse modifié avec succès + addAddress: Ajouter adresse + editAddress: Modifier adresse pt-PT: back: Voltar accept: Aceitar - addEditAddress: Adicionar ou modificar morada name: Consignatario address: Morada city: Concelho @@ -166,4 +169,6 @@ pt-PT: country: País province: Distrito addressChangedSuccessfully: Morada modificada corretamente + addAddress: Adicionar morada + editAddress: Modificar morada diff --git a/src/pages/Account/AddressList.vue b/src/pages/Account/AddressList.vue index 812cf19a..974c5022 100644 --- a/src/pages/Account/AddressList.vue +++ b/src/pages/Account/AddressList.vue @@ -133,13 +133,21 @@ onMounted(async () => { () => removeAddress(address.id) ) " - /> + > + + {{ t('deleteAddress') }} + + + > + + {{ t('editAddress') }} + + @@ -151,20 +159,30 @@ en-US: addAddress: Add address defaultAddressModified: Default address modified confirmDeleteAddress: Are you sure you want to delete the address? + editAddress: Edit address + deleteAddress: Delete address es-ES: addAddress: Añadir dirección defaultAddressModified: Dirección por defecto modificada confirmDeleteAddress: ¿Estás seguro de que quieres borrar la dirección? + editAddress: Modificar dirección + deleteAddress: Borrar dirección ca-ES: addAddress: Afegir adreça defaultAddressModified: Adreça per defecte modificada confirmDeleteAddress: Estàs segur que vols esborrar l'adreça? + editAddress: Modificar adreça + deleteAddress: Esborrar adreça fr-FR: addAddress: Ajouter une adresse defaultAddressModified: Adresse par défaut modifiée confirmDeleteAddress: Êtes-vous sûr de vouloir supprimer l'adresse? + editAddress: Modifier adresse + deleteAddress: Supprimer adresse pt-PT: addAddress: Adicionar Morada defaultAddressModified: Endereço padrão modificado confirmDeleteAddress: Tem a certeza de que deseja excluir o endereço? + editAddress: Modificar morada + deleteAddress: Eliminar morada diff --git a/src/pages/Ecomerce/InvoicesView.vue b/src/pages/Ecomerce/InvoicesView.vue index c21ac9ce..5c49eb63 100644 --- a/src/pages/Ecomerce/InvoicesView.vue +++ b/src/pages/Ecomerce/InvoicesView.vue @@ -17,18 +17,26 @@ const years = ref([]); const invoices = ref([]); const columns = computed(() => [ - { name: 'ref', label: t('invoice'), field: 'ref', align: 'left' }, + { + name: 'ref', + label: t('invoice'), + field: 'ref', + align: 'left', + sortable: true + }, { name: 'issued', label: t('issued'), field: 'issued', align: 'left', + sortable: true, format: val => formatDate(val, 'D MMM YYYY') }, { name: 'amount', label: t('amount'), field: 'amount', + sortable: true, format: val => currency(val) }, { diff --git a/src/pages/Ecomerce/OrdersView.vue b/src/pages/Ecomerce/OrdersView.vue index 75eb6003..c010545c 100644 --- a/src/pages/Ecomerce/OrdersView.vue +++ b/src/pages/Ecomerce/OrdersView.vue @@ -7,12 +7,14 @@ import CardList from 'src/components/ui/CardList.vue'; import VnInput from 'src/components/common/VnInput.vue'; import VnConfirm from 'src/components/ui/VnConfirm.vue'; +import useNotify from 'src/composables/useNotify.js'; import { currency, formatDateTitle } from 'src/lib/filters.js'; import { tpvStore } from 'stores/tpv'; const { t } = useI18n(); const route = useRoute(); const jApi = inject('jApi'); +const { notify } = useNotify(); const showAmountToPayDialog = ref(null); const amountToPay = ref(null); @@ -36,6 +38,10 @@ const onPayClick = async () => { }; const onConfirmPay = async () => { + if (amountToPay.value <= 0) { + notify(t('amountError'), 'negative'); + return; + } if (amountToPay.value) { const amount = amountToPay.value.toString().replace('.', ','); amountToPay.value = parseFloat(amount); @@ -126,6 +132,8 @@ const onConfirmPay = async () => { v-model="amountToPay" :clearable="false" class="full-width" + type="number" + min="0" /> @@ -170,6 +178,7 @@ en-US: equal to or greater than 0. If you want to make a down payment, click the payment button, delete the suggested amount and enter the amount you want. amountToPay: 'Amount to pay (€):' + amountError: The amount must be a positive number less than or equal to the outstanding amount es-ES: startOrder: Empezar pedido noOrdersFound: No se encontrado pedidos @@ -183,6 +192,7 @@ es-ES: cuenta, pulsa el botón de pago, borra la cantidad sugerida e introduce la cantidad que desees. amountToPay: 'Cantidad a pagar (€):' + amountError: La cantidad debe ser un número positivo e inferior o igual al importe pendiente ca-ES: startOrder: Començar encàrrec noOrdersFound: No s'han trobat comandes @@ -196,6 +206,7 @@ ca-ES: lliurament a compte, prem el botó de pagament, esborra la quantitat suggerida e introdueix la quantitat que vulguis. amountToPay: 'Quantitat a pagar (€):' + amountError: La quantitat ha de ser un nombre positiu i inferior o igual a l'import pendent fr-FR: startOrder: Acheter noOrdersFound: Aucune commande trouvée @@ -209,6 +220,7 @@ fr-FR: voulez faire un versement, le montant suggéré effacé et entrez le montant que vous souhaitez. amountToPay: 'Montant à payer (€):' + amountError: La quantité doit être un neméro positif et inférieur ou égal à la somme restant à payer pt-PT: startOrder: Iniciar encomenda noOrdersFound: Nenhum pedido encontrado @@ -222,4 +234,5 @@ pt-PT: conta, clique no botão de pagamento, apague a quantidade sugerida e introduza a quantidade que deseje. amountToPay: 'Valor a pagar (€):' + amountError: A quantidade deve ser um número positivo e inferior ou igual ao importe pendiente diff --git a/src/components/ui/TicketDetails.vue b/src/pages/Ecomerce/TicketDetails.vue similarity index 100% rename from src/components/ui/TicketDetails.vue rename to src/pages/Ecomerce/TicketDetails.vue diff --git a/src/pages/Ecomerce/TicketView.vue b/src/pages/Ecomerce/TicketView.vue index 5aecfa35..637166bd 100644 --- a/src/pages/Ecomerce/TicketView.vue +++ b/src/pages/Ecomerce/TicketView.vue @@ -3,7 +3,7 @@ import { onMounted, inject, ref } from 'vue'; import { useRoute } from 'vue-router'; import { useI18n } from 'vue-i18n'; -import TicketDetails from 'src/components/ui/TicketDetails.vue'; +import TicketDetails from 'src/pages/Ecomerce/TicketDetails.vue'; import { userStore as useUserStore } from 'stores/user'; From 6e41548fdf5c2c61c18cb1107e29c9d895e3bd5f Mon Sep 17 00:00:00 2001 From: wbuezas Date: Sat, 17 Aug 2024 20:23:15 -0300 Subject: [PATCH 2/7] Create jApi error interceptor --- src/boot/axios.js | 7 ++ src/js/vn/json-connection.js | 178 ++++++++++++++++++----------------- 2 files changed, 100 insertions(+), 85 deletions(-) diff --git a/src/boot/axios.js b/src/boot/axios.js index 66b2ffe9..039d6235 100644 --- a/src/boot/axios.js +++ b/src/boot/axios.js @@ -35,6 +35,12 @@ const onResponseError = error => { return Promise.reject(error); }; +const jApiErrorInterceptor = error => { + if (error.message) { + notify(error.message, 'negative'); + } +}; + export default boot(({ app }) => { const user = userStore(); function addToken(config) { @@ -47,6 +53,7 @@ export default boot(({ app }) => { api.interceptors.response.use(response => response, onResponseError); jApi.use(addToken); + jApi.useErrorInterceptor(jApiErrorInterceptor); // for use inside Vue files (Options API) through this.$axios and this.$api diff --git a/src/js/vn/json-connection.js b/src/js/vn/json-connection.js index 21ea745e..51fabfe1 100644 --- a/src/js/vn/json-connection.js +++ b/src/js/vn/json-connection.js @@ -1,70 +1,75 @@ -import { VnObject } from './object' -import { JsonException } from './json-exception' +import { VnObject } from './object'; +import { JsonException } from './json-exception'; /** * Handler for JSON rest connections. */ export class JsonConnection extends VnObject { - _connected = false - _requestsCount = 0 - token = null - interceptors = [] + _connected = false; + _requestsCount = 0; + token = null; + interceptors = []; + errorInterceptor = null; - use (fn) { - this.interceptors.push(fn) + use(fn) { + this.interceptors.push(fn); + } + + useErrorInterceptor(fn) { + this.errorInterceptor = fn; } /** - * Executes the specified REST service with the given params and calls - * the callback when response is received. - * - * @param {String} url The service path - * @param {Object} params The params to pass to the service - * @return {Object} The parsed JSON response - */ - async send (url, params) { - if (!params) params = {} - params.srv = `json:${url}` - return this.sendWithUrl('POST', '.', params) + * Executes the specified REST service with the given params and calls + * the callback when response is received. + * + * @param {String} url The service path + * @param {Object} params The params to pass to the service + * @return {Object} The parsed JSON response + */ + async send(url, params) { + if (!params) params = {}; + params.srv = `json:${url}`; + return this.sendWithUrl('POST', '.', params); } - async sendForm (form) { - const params = {} - const elements = form.elements + async sendForm(form) { + const params = {}; + const elements = form.elements; for (let i = 0; i < elements.length; i++) { if (elements[i].name) { - params[elements[i].name] = elements[i].value + params[elements[i].name] = elements[i].value; } } - return this.sendWithUrl('POST', form.action, params) + return this.sendWithUrl('POST', form.action, params); } - async sendFormMultipart (form) { + async sendFormMultipart(form) { return this.request({ method: 'POST', url: form.action, data: new FormData(form) - }) + }); } - async sendFormData (formData) { + async sendFormData(formData) { return this.request({ method: 'POST', url: '', data: formData - }) + }); } /* - * Called when REST response is received. - */ - async sendWithUrl (method, url, params) { - const urlParams = new URLSearchParams() + * Called when REST response is received. + */ + async sendWithUrl(method, url, params) { + const urlParams = new URLSearchParams(); for (const key in params) { if (params[key] != null) { - urlParams.set(key, params[key]) + urlParams.set(key, params[key]); } } @@ -75,126 +80,129 @@ export class JsonConnection extends VnObject { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } - }) + }); } - async request (config) { - const request = new XMLHttpRequest() - request.open(config.method, config.url, true) + async request(config) { + const request = new XMLHttpRequest(); + request.open(config.method, config.url, true); for (const fn of this.interceptors) { - config = fn(config) + config = fn(config); } - const headers = config.headers + const headers = config.headers; if (headers) { for (const header in headers) { - request.setRequestHeader(header, headers[header]) + request.setRequestHeader(header, headers[header]); } } const promise = new Promise((resolve, reject) => { request.onreadystatechange = () => - this._onStateChange(request, resolve, reject) - }) + this._onStateChange(request, resolve, reject); + }); - request.send(config.data) + request.send(config.data); - this._requestsCount++ + this._requestsCount++; if (this._requestsCount === 1) { - this.emit('loading-changed', true) + this.emit('loading-changed', true); } - return promise + return promise; } - _onStateChange (request, resolve, reject) { + _onStateChange(request, resolve, reject) { if (request.readyState !== 4) { - return + return; } - this._requestsCount-- + this._requestsCount--; if (this._requestsCount === 0) { - this.emit('loading-changed', false) + this.emit('loading-changed', false); } - let data = null - let error = null + let data = null; + let error = null; try { if (request.status === 0) { - const err = new JsonException() + const err = new JsonException(); err.message = - 'The server does not respond, please check your Internet connection' - err.statusCode = request.status - throw err + 'The server does not respond, please check your Internet connection'; + err.statusCode = request.status; + throw err; } - let contentType = null + let contentType = null; try { contentType = request .getResponseHeader('Content-Type') .split(';')[0] - .trim() + .trim(); } catch (err) { - console.warn(err) + console.warn(err); } if (contentType !== 'application/json') { - const err = new JsonException() - err.message = request.statusText - err.statusCode = request.status - throw err + const err = new JsonException(); + err.message = request.statusText; + err.statusCode = request.status; + throw err; } - let json - let jsData + let json; + let jsData; if (request.responseText) { - json = JSON.parse(request.responseText) + json = JSON.parse(request.responseText); } if (json) { - jsData = json.data || json + jsData = json.data || json; } if (request.status >= 200 && request.status < 300) { - data = jsData + data = jsData; } else { - let exception = jsData.exception + let exception = jsData.exception; - const err = new JsonException() - err.statusCode = request.status + const err = new JsonException(); + err.statusCode = request.status; if (exception) { exception = exception .replace(/\\/g, '.') .replace(/Exception$/, '') - .replace(/^Vn\.Web\./, '') + .replace(/^Vn\.Web\./, ''); - err.exception = exception - err.message = jsData.message - err.code = jsData.code - err.file = jsData.file - err.line = jsData.line - err.trace = jsData.trace + err.exception = exception; + err.message = jsData.message; + err.code = jsData.code; + err.file = jsData.file; + err.line = jsData.line; + err.trace = jsData.trace; } else { - err.message = request.statusText + err.message = request.statusText; } - throw err + throw err; } } catch (e) { - data = null - error = e + data = null; + error = e; } if (error) { - this.emit('error', error) - reject(error) + if (this.errorInterceptor) { + this.errorInterceptor(error); + } + this.emit('error', error); + reject(error); } else { - resolve(data) + resolve(data); } } } From e47edb982776e5a0fb71004277f8f2dd5fd145df Mon Sep 17 00:00:00 2001 From: Javier Segarra Date: Mon, 19 Aug 2024 12:38:17 +0200 Subject: [PATCH 3/7] fix: eslint warnings --- .eslintrc.js | 17 ++++- .vscode/settings.json | 9 ++- quasar.config.js | 8 +- src/components/common/VnForm.vue | 17 ++++- src/components/common/VnInput.vue | 28 +++++-- src/components/common/VnSelect.vue | 11 ++- src/components/ui/CardList.vue | 5 +- src/components/ui/ChangePasswordForm.vue | 71 ++++++++++------- src/components/ui/VnConfirm.vue | 4 +- src/components/ui/VnImg.vue | 5 +- src/components/ui/VnTable.vue | 10 ++- src/layouts/MainLayout.vue | 46 ++++++++--- src/pages/Account/AccountConfig.vue | 6 +- src/pages/Account/AddressDetails.vue | 32 +++++--- src/pages/Account/AddressList.vue | 5 +- src/pages/Cms/HomeView.vue | 25 ++++-- src/pages/Ecomerce/Catalog.vue | 97 +++++++++++++++++------- src/pages/Ecomerce/PendingOrders.vue | 8 +- src/pages/Ecomerce/TicketDetails.vue | 29 +++++-- src/pages/Ecomerce/TicketView.vue | 5 +- src/pages/ErrorNotFound.vue | 9 ++- src/pages/Login/LoginView.vue | 84 ++++++++++++-------- src/pages/Login/RememberPassword.vue | 10 ++- src/pages/Login/ResetPassword.vue | 15 +++- 24 files changed, 402 insertions(+), 154 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index dabf8ae7..dd427155 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -22,8 +22,8 @@ module.exports = { // Uncomment any of the lines below to choose desired strictness, // but leave only one uncommented! // See https://eslint.vuejs.org/rules/#available-rules - 'plugin:vue/vue3-essential', // Priority A: Essential (Error Prevention) - // 'plugin:vue/vue3-strongly-recommended', // Priority B: Strongly Recommended (Improving Readability) + // 'plugin:vue/vue3-essential', // Priority A: Essential (Error Prevention) + 'plugin:vue/vue3-strongly-recommended', // Priority B: Strongly Recommended (Improving Readability) // 'plugin:vue/vue3-recommended', // Priority C: Recommended (Minimizing Arbitrary Choices and Cognitive Overhead) 'standard' @@ -66,7 +66,18 @@ module.exports = { 'prefer-promise-reject-errors': 'off', semi: 'off', // allow debugger during development only - 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off' + 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off', + 'vue/html-indent': [ + 'error', + 4, + { + attribute: 1, + baseIndent: 1, + closeBracket: 0, + alignAttributesVertically: true, + ignores: [] + } + ] }, overrides: [ { diff --git a/.vscode/settings.json b/.vscode/settings.json index 484a898f..0eda1dfd 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -3,8 +3,11 @@ "eslint.autoFixOnSave": true, "editor.bracketPairColorization.enabled": true, "editor.guides.bracketPairs": true, - "editor.formatOnSave": true, - "editor.defaultFormatter": "esbenp.prettier-vscode", + "editor.formatOnSave": false, + "editor.defaultFormatter": null, "editor.codeActionsOnSave": ["source.fixAll.eslint"], - "eslint.validate": ["javascript", "javascriptreact", "typescript", "vue"] + "eslint.validate": ["javascript", "javascriptreact", "typescript", "vue"], + "[sql]": { + "editor.formatOnSave": true + } } diff --git a/quasar.config.js b/quasar.config.js index 378b6e6d..abd52035 100644 --- a/quasar.config.js +++ b/quasar.config.js @@ -15,6 +15,12 @@ const { configure } = require('quasar/wrappers'); module.exports = configure(function (ctx) { return { + // fix: true, + // include = [], + // exclude = [], + // rawOptions = {}, + warnings: true, + errors: true, // https://v2.quasar.dev/quasar-cli-webpack/supporting-ts supportTS: false, @@ -102,7 +108,7 @@ module.exports = configure(function (ctx) { proxy: { '/api': 'http://localhost:3000', '/': { - target: 'http://localhost:3002', + target: 'http://localhost:3001', bypass: req => (req.path !== '/' ? req.path : null) } } diff --git a/src/components/common/VnForm.vue b/src/components/common/VnForm.vue index 418b8022..89ccbf78 100644 --- a/src/components/common/VnForm.vue +++ b/src/components/common/VnForm.vue @@ -179,7 +179,10 @@ defineExpose({ diff --git a/src/components/common/VnInput.vue b/src/components/common/VnInput.vue index f8af8001..025da5f1 100644 --- a/src/components/common/VnInput.vue +++ b/src/components/common/VnInput.vue @@ -56,10 +56,14 @@ defineExpose({ const inputRules = [ val => { - const { min } = vnInputRef.value.$attrs; + console.log('asd'); + const { min, max } = vnInputRef.value.$attrs; if (min >= 0) { if (Math.floor(val) < min) return t('inputMin', { value: min }); } + if (max > 0) { + if (Math.floor(val) > max) return t('inputMax', { value: max }); + } } ]; @@ -82,11 +86,17 @@ const inputRules = [ hide-bottom-space @keyup.enter="emit('keyup.enter')" > -