From dcbc154caac51780ad3b185704e2d71a2e9e3da2 Mon Sep 17 00:00:00 2001 From: wbuezas Date: Mon, 22 Jul 2024 11:17:56 -0300 Subject: [PATCH 1/7] Components creation: AddressDetails, VnForm, VnInput and VnSelect --- src/components/common/VnForm.vue | 214 +++++++++++++++++++++++++++ src/components/common/VnInput.vue | 124 ++++++++++++++++ src/components/common/VnSelect.vue | 188 +++++++++++++++++++++++ src/i18n/en-US/index.js | 3 +- src/i18n/es-ES/index.js | 3 +- src/pages/Account/AddressDetails.vue | 148 +++++++++++++++++- src/router/routes.js | 2 +- 7 files changed, 673 insertions(+), 9 deletions(-) create mode 100644 src/components/common/VnForm.vue create mode 100644 src/components/common/VnInput.vue create mode 100644 src/components/common/VnSelect.vue diff --git a/src/components/common/VnForm.vue b/src/components/common/VnForm.vue new file mode 100644 index 00000000..02785dad --- /dev/null +++ b/src/components/common/VnForm.vue @@ -0,0 +1,214 @@ + + + + + diff --git a/src/components/common/VnInput.vue b/src/components/common/VnInput.vue new file mode 100644 index 00000000..62984159 --- /dev/null +++ b/src/components/common/VnInput.vue @@ -0,0 +1,124 @@ + + + + + +en-US: + inputMin: Must be more than {value} +es-ES: + inputMin: Must be more than {value} +ca-ES: + inputMin: Ha de ser més gran que {value} +fr-FR: + inputMin: Doit être supérieur à {value} +pt-PT: + inputMin: Deve ser maior que {value} + diff --git a/src/components/common/VnSelect.vue b/src/components/common/VnSelect.vue new file mode 100644 index 00000000..24b82017 --- /dev/null +++ b/src/components/common/VnSelect.vue @@ -0,0 +1,188 @@ + + + + + diff --git a/src/i18n/en-US/index.js b/src/i18n/en-US/index.js index 723cfc3b..ebd6fc58 100644 --- a/src/i18n/en-US/index.js +++ b/src/i18n/en-US/index.js @@ -74,5 +74,6 @@ export default { user: 'User', addresses: 'Addresses', addressEdit: 'Edit address', - dataSaved: 'Data saved' + dataSaved: 'Data saved', + save: 'Save' }; diff --git a/src/i18n/es-ES/index.js b/src/i18n/es-ES/index.js index 0ecd8706..bae2d4b5 100644 --- a/src/i18n/es-ES/index.js +++ b/src/i18n/es-ES/index.js @@ -74,5 +74,6 @@ export default { user: 'Usuario', addresses: 'Direcciones', addressEdit: 'Editar dirección', - dataSaved: 'Datos guardados' + dataSaved: 'Datos guardados', + save: 'Guardar' }; diff --git a/src/pages/Account/AddressDetails.vue b/src/pages/Account/AddressDetails.vue index 6a68eb78..067a47a5 100644 --- a/src/pages/Account/AddressDetails.vue +++ b/src/pages/Account/AddressDetails.vue @@ -1,33 +1,169 @@ - + en-US: back: Back accept: Accept + addEditAddress: Add or edit address + name: Consignee + address: Address + city: City + postalCode: Zip code + country: Country + province: Province + addressChangedSuccessfully: Address changed successfully es-ES: back: Volver accept: Aceptar + addEditAddress: Añadir o modificar dirección + name: Consignatario + address: Morada + city: Ciudad + postalCode: Código postal + country: País + province: Distrito + addressChangedSuccessfully: Dirección modificada correctamente ca-ES: back: Tornar accept: Acceptar + addEditAddress: Afegir o modificar adreça + name: Consignatari + address: Direcció + city: Ciutat + postalCode: Codi postal + country: País + province: Província + addressChangedSuccessfully: Adreça modificada correctament fr-FR: back: Retour accept: Accepter + addEditAddress: Ajouter ou modifier l'adresse + name: Destinataire + address: Numéro Rue + city: Ville + postalCode: Code postal + country: Pays + province: Province + addressChangedSuccessfully: Adresse modifié avec succès pt-PT: back: Voltar accept: Aceitar + addEditAddress: Adicionar ou modificar morada + name: Consignatario + address: Morada + city: Concelho + postalCode: Código postal + country: País + province: Distrito + addressChangedSuccessfully: Morada modificada corretamente diff --git a/src/router/routes.js b/src/router/routes.js index 1ab82dcc..94592ef0 100644 --- a/src/router/routes.js +++ b/src/router/routes.js @@ -60,7 +60,7 @@ const routes = [ component: () => import('pages/Account/AccountConf.vue') }, { - name: 'Addresses', + name: 'AddressesList', path: '/account/address-list', component: () => import('pages/Account/AddressList.vue') }, From 07c5f64265e4f391c878fddf4adf2f50dc7acdc7 Mon Sep 17 00:00:00 2001 From: wbuezas Date: Mon, 22 Jul 2024 13:51:54 -0300 Subject: [PATCH 2/7] improvements --- src/components/common/VnForm.vue | 87 ++++++++++++---------------- src/js/db/sqlService.js | 42 ++++++++++++++ src/pages/Account/AddressDetails.vue | 4 +- 3 files changed, 80 insertions(+), 53 deletions(-) create mode 100644 src/js/db/sqlService.js diff --git a/src/components/common/VnForm.vue b/src/components/common/VnForm.vue index 02785dad..4e5447ba 100644 --- a/src/components/common/VnForm.vue +++ b/src/components/common/VnForm.vue @@ -3,6 +3,10 @@ import { ref, inject, onMounted, computed } from 'vue'; import { useI18n } from 'vue-i18n'; import useNotify from 'src/composables/useNotify.js'; +import { + generateUpdateSqlQuery, + generateInsertSqlQuery +} from 'src/js/db/sqlService.js'; const props = defineProps({ title: { @@ -17,9 +21,11 @@ const props = defineProps({ type: String, default: '' }, + // Objeto que define las pks de la tabla. Usado para generar las queries sql correspondientes. + // Debe ser definido como un objeto de pares key-value, donde la clave es el nombre de la columna de la pk. pks: { type: Object, - default: () => {} // definidas como key: value, donde key es el nombre de la pk + default: () => {} }, createModelDefault: { type: Object, @@ -28,29 +34,33 @@ const props = defineProps({ value: '' }) }, + // Objeto que contiene la consulta SQL y los parámetros necesarios para obtener los datos iniciales del formulario. + // `query` debe ser una cadena de texto que representa la consulta SQL. + // `params` es un objeto que mapea los parámetros de la consulta a sus valores. fetchFormDataSql: { type: Object, default: () => ({ - // Objeto con query y params para obtener los datos iniciales del form query: '', params: {} }) }, + // Objeto con los datos iniciales del form, si este objeto es definido, no se ejecuta la query fetchFormDataSql formInitialData: { type: Object, - default: () => {} // Objeto con los datos iniciales del form + default: () => {} }, + // Array de columnas que no se deben actualizar columnsToIgnoreUpdate: { type: Array, - default: () => [] // Array de columnas que no se deben actualizar + default: () => [] }, autoLoad: { type: Boolean, default: true }, - mode: { - type: String, - default: 'update' + isEditMode: { + type: Boolean, + default: true }, defaultActions: { type: Boolean, @@ -73,7 +83,7 @@ const tableColumns = computed( () => modelInfo.value?.columns.map(col => col.name) || [] ); // Array de nombre de columnas que fueron actualizadas y no estan en columnsToIgnoreUpdate -const columnsUpdated = computed(() => { +const updatedColumns = computed(() => { return tableColumns.value.filter( colName => modelInfo.value?.data[0][colName] !== formData.value[colName] && @@ -106,7 +116,7 @@ const fetchFormData = async () => { const submit = async () => { try { - const sqlQuery = generateSqlQuery(props.table, props.schema, props.pks); + const sqlQuery = generateSqlQuery(); await jApi.execQuery(sqlQuery, props.pks); emit('onDataSaved'); notify(t('dataSaved'), 'positive'); @@ -116,51 +126,26 @@ const submit = async () => { } }; -const generateSqlQuery = (table, schema, pks) => { - if (props.mode === 'update') { - return generateUpdateSqlQuery(table, schema, pks); +const generateSqlQuery = () => { + if (props.isEditMode) { + return generateUpdateSqlQuery( + props.schema, + props.table, + props.pks, + updatedColumns.value, + formData.value + ); } else { - return generateCreateSqlQuery(table, schema, pks); + return generateInsertSqlQuery( + props.schema, + props.table, + formData.value, + updatedColumns.value, + props.createModelDefault + ); } }; -const generateUpdateSqlQuery = (table, schema, pks) => { - if (!columnsUpdated.value.length) return ''; - - const setClauses = columnsUpdated.value - .map(colName => `${colName} = '${formData.value[colName]}'`) - .join(', '); - const whereClause = Object.keys(props.pks) - .map(pk => `${pk} = ${pks[pk]}`) - .join(' AND '); - return ` - START TRANSACTION; - UPDATE ${schema}.${table} SET ${setClauses} WHERE (${whereClause}); - SELECT ${columnsUpdated.value.join(', ')} FROM ${schema}.${table} WHERE (${whereClause}); - COMMIT; - `; -}; - -const generateCreateSqlQuery = (table, schema) => { - if (!columnsUpdated.value.length) return ''; - - const columns = [ - props.createModelDefault.field, - ...columnsUpdated.value - ].join(', '); - const values = [ - props.createModelDefault.value, - ...columnsUpdated.value.map(colName => `'${formData.value[colName]}'`) - ].join(', '); - - return ` - START TRANSACTION; - INSERT INTO ${schema}.${table} (${columns}) VALUES (${values}); - SELECT id, ${columnsUpdated.value.join(', ')} FROM ${schema}.${table} WHERE ((id = LAST_INSERT_ID())); - COMMIT; - `; -}; - onMounted(async () => { if (!props.formInitialData && props.autoLoad) { fetchFormData(); @@ -182,7 +167,7 @@ defineExpose({ icon="check" rounded no-caps - :disabled="!columnsUpdated.length" + :disabled="!updatedColumns.length" @click="addressFormRef.submit()" /> diff --git a/src/js/db/sqlService.js b/src/js/db/sqlService.js new file mode 100644 index 00000000..375e2f74 --- /dev/null +++ b/src/js/db/sqlService.js @@ -0,0 +1,42 @@ +export const generateUpdateSqlQuery = ( + schema, + table, + pks, + columnsUpdated, + formData +) => { + const setClauses = columnsUpdated + .map(colName => `${colName} = '${formData[colName]}'`) + .join(', '); + const whereClause = Object.keys(pks) + .map(pk => `${pk} = ${pks[pk]}`) + .join(' AND '); + + return ` + START TRANSACTION; + UPDATE ${schema}.${table} SET ${setClauses} WHERE (${whereClause}); + SELECT ${columnsUpdated.join(', ')} FROM ${schema}.${table} WHERE (${whereClause}); + COMMIT; + `; +}; + +export const generateInsertSqlQuery = ( + schema, + table, + formData, + columnsUpdated, + createModelDefault +) => { + const columns = [createModelDefault.field, ...columnsUpdated].join(', '); + const values = [ + createModelDefault.value, + ...columnsUpdated.map(colName => `'${formData[colName]}'`) + ].join(', '); + + return ` + START TRANSACTION; + INSERT INTO ${schema}.${table} (${columns}) VALUES (${values}); + SELECT id, ${columnsUpdated.join(', ')} FROM ${schema}.${table} WHERE (id = LAST_INSERT_ID()); + COMMIT; + `; +}; diff --git a/src/pages/Account/AddressDetails.vue b/src/pages/Account/AddressDetails.vue index 067a47a5..c41b47e9 100644 --- a/src/pages/Account/AddressDetails.vue +++ b/src/pages/Account/AddressDetails.vue @@ -16,7 +16,7 @@ const vnFormRef = ref(null); const countriesOptions = ref([]); const provincesOptions = ref([]); const pks = { id: route.params.id }; -const formMode = route.params.id === '0' ? 'create' : 'update'; +const isEditMode = route.params.id !== '0'; const fetchAddressDataSql = { query: ` SELECT a.id, a.street, a.nickname, a.city, a.postalCode, a.provinceFk, p.countryFk @@ -74,7 +74,7 @@ onMounted(() => getCountries()); value: 'account.myUser_getId()' }" :pks="pks" - :mode="formMode" + :isEditMode="isEditMode" :title="t('addEditAddress')" table="myAddress" schema="hedera" From 2cbbaf619c6127b5291e71f291d06b316b4442e4 Mon Sep 17 00:00:00 2001 From: wbuezas Date: Tue, 23 Jul 2024 11:02:39 -0300 Subject: [PATCH 3/7] small change --- src/components/common/VnForm.vue | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/common/VnForm.vue b/src/components/common/VnForm.vue index 4e5447ba..e4ff648c 100644 --- a/src/components/common/VnForm.vue +++ b/src/components/common/VnForm.vue @@ -111,7 +111,6 @@ const fetchFormData = async () => { formData.value = { ...modelInfo.value.data[0] }; loading.value = false; - console.log('modelInfo: ', modelInfo.value); }; const submit = async () => { From 61062c1418d353371b54b3f43f0bc6bcd38e3d41 Mon Sep 17 00:00:00 2001 From: wbuezas Date: Tue, 23 Jul 2024 11:26:12 -0300 Subject: [PATCH 4/7] Add app.provide api --- src/boot/axios.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/boot/axios.js b/src/boot/axios.js index b5758897..1f384ff3 100644 --- a/src/boot/axios.js +++ b/src/boot/axios.js @@ -38,6 +38,7 @@ export default boot(({ app }) => { app.config.globalProperties.$jApi = jApi; app.provide('jApi', jApi); + app.provide('api', api); }); export { api, jApi }; From 83e3e034a82fe90ace2b3f4b6432a1627fd28fc0 Mon Sep 17 00:00:00 2001 From: wbuezas Date: Tue, 23 Jul 2024 16:37:24 -0300 Subject: [PATCH 5/7] Show Addresses list actions always --- src/pages/Account/AddressList.vue | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/pages/Account/AddressList.vue b/src/pages/Account/AddressList.vue index 5d39dcda..a5ad2b14 100644 --- a/src/pages/Account/AddressList.vue +++ b/src/pages/Account/AddressList.vue @@ -128,7 +128,7 @@ onMounted(async () => { -