From ccf31570439f3c9bc4b501e40c48ca7dbc904de3 Mon Sep 17 00:00:00 2001 From: Javier Segarra Date: Wed, 23 Apr 2025 13:13:04 +0200 Subject: [PATCH 01/27] fix: use popup evt to handle loading --- src/components/common/VnSelect.vue | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/components/common/VnSelect.vue b/src/components/common/VnSelect.vue index 0cbe541fc..70167229a 100644 --- a/src/components/common/VnSelect.vue +++ b/src/components/common/VnSelect.vue @@ -161,7 +161,7 @@ const arrayData = useArrayData(arrayDataKey, { searchUrl: false, mapKey: $attrs['map-key'], }); - +const isMenuOpened = ref(false); const computedSortBy = computed(() => { return $props.sortBy || $props.optionLabel + ' ASC'; }); @@ -186,7 +186,9 @@ onMounted(() => { if ($props.focusOnMount) setTimeout(() => vnSelectRef.value.showPopup(), 300); }); -const someIsLoading = computed(() => isLoading.value || !!arrayData?.isLoading?.value); +const someIsLoading = computed( + () => (isLoading.value || !!arrayData?.isLoading?.value) && !isMenuOpened.value, +); function findKeyInOptions() { if (!$props.options) return; return filter($props.modelValue, $props.options)?.length; @@ -370,6 +372,8 @@ function getCaption(opt) { :loading="someIsLoading" :disable="someIsLoading" @virtual-scroll="onScroll" + @popup-hide="isMenuOpened = false" + @popup-show="isMenuOpened = true" @keydown="handleKeyDown" :data-cy="$attrs.dataCy ?? $attrs.label + '_select'" :data-url="url" From 2fb794727874ac05a9e4428306e3a8fb410eefb4 Mon Sep 17 00:00:00 2001 From: Javier Segarra Date: Fri, 25 Apr 2025 09:43:43 +0200 Subject: [PATCH 02/27] feat: add error handling and append slot to VnMultiCheck component --- src/components/common/VnCheckbox.vue | 1 + src/components/common/VnMultiCheck.vue | 90 +++++++++++++++++--------- 2 files changed, 62 insertions(+), 29 deletions(-) diff --git a/src/components/common/VnCheckbox.vue b/src/components/common/VnCheckbox.vue index daaf891dc..c2c93d7e9 100644 --- a/src/components/common/VnCheckbox.vue +++ b/src/components/common/VnCheckbox.vue @@ -43,5 +43,6 @@ const checkboxModel = computed({ {{ info }} + diff --git a/src/components/common/VnMultiCheck.vue b/src/components/common/VnMultiCheck.vue index 19b93ffa9..fe8c52603 100644 --- a/src/components/common/VnMultiCheck.vue +++ b/src/components/common/VnMultiCheck.vue @@ -15,7 +15,6 @@ const props = defineProps({ }, url: { type: String, - default: null, required: true, }, searchUrl: { @@ -24,6 +23,8 @@ const props = defineProps({ }, }); const value = ref(false); +const menuRef = ref(null); +const errorMessage = ref(null); const rows = ref(0); const onClick = () => { if (value.value) { @@ -37,7 +38,11 @@ const onClick = () => { .then(({ data }) => { rows.value = data; }) - .catch(console.error); + .catch(({ response }) => { + if (response.data.error.name === 'UserError') { + errorMessage.value = t('tooManyResults'); + } else errorMessage.value = response.data.error.message; + }); } }; defineEmits(['update:selected', 'select:all']); @@ -45,36 +50,63 @@ defineEmits(['update:selected', 'select:all']); en: - Select all: 'Select all ({rows})' -fr: - Select all: 'Sélectionner tout ({rows})' + tooManyResults: Too many results. Please narrow down your search. + records: '{rows} records' es: - Select all: 'Seleccionar todo ({rows})' -de: - Select all: 'Alle auswählen ({rows})' -it: - Select all: 'Seleziona tutto ({rows})' -pt: - Select all: 'Selecionar tudo ({rows})' + Select all: Seleccionar todo + tooManyResults: Demasiados registros. Restringe la búsqueda. + records: '{rows} registros' From 28c59f16b9d53befad9dae183ee9dab0785e37a7 Mon Sep 17 00:00:00 2001 From: Javier Segarra Date: Fri, 25 Apr 2025 09:43:56 +0200 Subject: [PATCH 03/27] fix: remove unused promise prop from CustomerNotificationsCampaignConsumption --- src/pages/Customer/Notifications/CustomerNotifications.vue | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pages/Customer/Notifications/CustomerNotifications.vue b/src/pages/Customer/Notifications/CustomerNotifications.vue index 02792182c..84babe24d 100644 --- a/src/pages/Customer/Notifications/CustomerNotifications.vue +++ b/src/pages/Customer/Notifications/CustomerNotifications.vue @@ -89,7 +89,6 @@ const columns = computed(() => [ From 82a1d451ef9e450865b6a88b5494e8caf2cdb6c3 Mon Sep 17 00:00:00 2001 From: Javier Segarra Date: Fri, 25 Apr 2025 10:12:17 +0200 Subject: [PATCH 04/27] fix: update campaign consumption message format to include record count --- .../CustomerNotificationsCampaignConsumption.vue | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/Customer/Notifications/CustomerNotificationsCampaignConsumption.vue b/src/pages/Customer/Notifications/CustomerNotificationsCampaignConsumption.vue index 141a02bfc..36157082b 100644 --- a/src/pages/Customer/Notifications/CustomerNotificationsCampaignConsumption.vue +++ b/src/pages/Customer/Notifications/CustomerNotificationsCampaignConsumption.vue @@ -142,13 +142,13 @@ onMounted(async () => { valentinesDay: Valentine's Day mothersDay: Mother's Day allSaints: All Saints' Day - Campaign consumption: Campaign consumption ({rows}) + Campaign consumption: Campaign consumption - {rows} records es: params: valentinesDay: Día de San Valentín mothersDay: Día de la Madre allSaints: Día de Todos los Santos - Campaign consumption: Consumo campaña ({rows}) + Campaign consumption: Consumo campaña - {rows} registros Campaign: Campaña From: Desde To: Hasta From 36102aff0021dbf35f3936d03e1918a2e4a70bec Mon Sep 17 00:00:00 2001 From: Javier Segarra Date: Fri, 25 Apr 2025 13:52:05 +0200 Subject: [PATCH 05/27] style: adjust column alignment and add class for improved layout --- src/pages/Ticket/TicketAdvance.vue | 23 +++++++++++++++-------- src/pages/Ticket/TicketFuture.vue | 21 ++++++++++++++++++--- 2 files changed, 33 insertions(+), 11 deletions(-) diff --git a/src/pages/Ticket/TicketAdvance.vue b/src/pages/Ticket/TicketAdvance.vue index bf3593acd..c0b6c2bb4 100644 --- a/src/pages/Ticket/TicketAdvance.vue +++ b/src/pages/Ticket/TicketAdvance.vue @@ -101,7 +101,7 @@ const ticketColumns = computed(() => [ format: (row, dashIfEmpty) => dashIfEmpty(row.lines), }, { - align: 'left', + align: 'right', label: t('advanceTickets.import'), name: 'totalWithVat', hidden: true, @@ -169,15 +169,17 @@ const ticketColumns = computed(() => [ label: t('advanceTickets.notMovableLines'), headerClass: 'horizontal-separator', name: 'notMovableLines', + class: 'shrink', }, { align: 'left', label: t('advanceTickets.futureLines'), headerClass: 'horizontal-separator', name: 'futureLines', + class: 'shrink', }, { - align: 'left', + align: 'right', label: t('advanceTickets.futureImport'), name: 'futureTotalWithVat', hidden: true, @@ -332,7 +334,12 @@ watch( if (!$el) return; const head = $el.querySelector('thead'); const firstRow = $el.querySelector('thead > tr'); - + const headSelectionCol = $el.querySelector( + 'thead tr.bg-header th.q-table--col-auto-width', + ); + if (headSelectionCol) { + headSelectionCol.classList.add('horizontal-separator'); + } const newRow = document.createElement('tr'); destinationElRef.value = document.createElement('th'); originElRef.value = document.createElement('th'); @@ -341,8 +348,10 @@ watch( destinationElRef.value.classList.add('text-uppercase', 'color-vn-label'); originElRef.value.classList.add('text-uppercase', 'color-vn-label'); - destinationElRef.value.setAttribute('colspan', '7'); - originElRef.value.setAttribute('colspan', '9'); + originElRef.value.classList.add('advance-icon'); + + destinationElRef.value.setAttribute('colspan', '9'); + originElRef.value.setAttribute('colspan', '11'); destinationElRef.value.textContent = `${t( 'advanceTickets.destination', @@ -453,10 +462,8 @@ watch( selection: 'multiple', }" v-model:selected="selectedTickets" - :pagination="{ rowsPerPage: 0 }" - :no-data-label="t('globals.noResults')" :right-search="false" - :order="['futureTotalWithVat ASC']" + :order="['futureTotalWithVat ASC']" auto-load :disable-option="{ card: true }" > diff --git a/src/pages/Ticket/TicketFuture.vue b/src/pages/Ticket/TicketFuture.vue index 6ed3afcc6..0939708c1 100644 --- a/src/pages/Ticket/TicketFuture.vue +++ b/src/pages/Ticket/TicketFuture.vue @@ -85,6 +85,7 @@ const ticketColumns = computed(() => [ label: t('advanceTickets.liters'), name: 'liters', align: 'left', + class: 'shrink', headerClass: 'horizontal-separator', }, { @@ -177,7 +178,12 @@ watch( if (!$el) return; const head = $el.querySelector('thead'); const firstRow = $el.querySelector('thead > tr'); - + const headSelectionCol = $el.querySelector( + 'thead tr.bg-header th.q-table--col-auto-width', + ); + if (headSelectionCol) { + headSelectionCol.classList.add('horizontal-separator'); + } const newRow = document.createElement('tr'); destinationElRef.value = document.createElement('th'); originElRef.value = document.createElement('th'); @@ -185,9 +191,10 @@ watch( newRow.classList.add('bg-header'); destinationElRef.value.classList.add('text-uppercase', 'color-vn-label'); originElRef.value.classList.add('text-uppercase', 'color-vn-label'); + originElRef.value.classList.add('advance-icon'); - destinationElRef.value.setAttribute('colspan', '7'); - originElRef.value.setAttribute('colspan', '9'); + destinationElRef.value.setAttribute('colspan', '9'); + originElRef.value.setAttribute('colspan', '7'); originElRef.value.textContent = `${t('advanceTickets.origin')}`; destinationElRef.value.textContent = `${t('advanceTickets.destination')}`; @@ -371,4 +378,12 @@ watch( :deep(.horizontal-bottom-separator) { border-bottom: 4px solid white !important; } +:deep(th.advance-icon::after) { + content: '>>'; + font-size: larger; + position: absolute; + text-align: center; + float: 0; + left: 0; +} From 797a48b04cb16131b32611550c4d1ee942ad9a95 Mon Sep 17 00:00:00 2001 From: Javier Segarra Date: Fri, 25 Apr 2025 15:40:06 +0200 Subject: [PATCH 06/27] feat(TicketAdvance): add futurePreparation column to ticket table --- src/pages/Ticket/TicketAdvance.vue | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/pages/Ticket/TicketAdvance.vue b/src/pages/Ticket/TicketAdvance.vue index c0b6c2bb4..aa78fe7f0 100644 --- a/src/pages/Ticket/TicketAdvance.vue +++ b/src/pages/Ticket/TicketAdvance.vue @@ -145,6 +145,15 @@ const ticketColumns = computed(() => [ headerClass: 'horizontal-separator', name: 'futureLiters', }, + { + label: t('advanceTickets.preparation'), + name: 'futurePreparation', + field: 'futurePreparation', + align: 'left', + sortable: true, + headerClass: 'horizontal-separator', + columnFilter: false, + }, { align: 'left', label: t('advanceTickets.futureZone'), From 70ceee988cf4a2795e767d45a3546b25c1db02cd Mon Sep 17 00:00:00 2001 From: pablone Date: Sun, 27 Apr 2025 16:16:33 +0200 Subject: [PATCH 07/27] fix(VnTable): replace click event with mousedown for editable rows --- src/components/VnTable/VnTable.vue | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/components/VnTable/VnTable.vue b/src/components/VnTable/VnTable.vue index 8915500fc..60d2dbcff 100644 --- a/src/components/VnTable/VnTable.vue +++ b/src/components/VnTable/VnTable.vue @@ -214,7 +214,7 @@ onBeforeMount(() => { }); onMounted(async () => { - if ($props.isEditable) document.addEventListener('click', clickHandler); + if ($props.isEditable) document.addEventListener('mousedown', mousedownHandler); mode.value = quasar.platform.is.mobile && !$props.disableOption?.card ? CARD_MODE @@ -237,7 +237,7 @@ onMounted(async () => { }); onUnmounted(async () => { - if ($props.isEditable) document.removeEventListener('click', clickHandler); + if ($props.isEditable) document.removeEventListener('mousedown', mousedownHandler); }); watch( @@ -385,7 +385,7 @@ function hasEditableFormat(column) { if (isEditableColumn(column)) return 'editable-text'; } -const clickHandler = async (event) => { +const mousedownHandler = async (event) => { const clickedElement = event.target.closest('td'); const isDateElement = event.target.closest('.q-date'); const isTimeElement = event.target.closest('.q-time'); @@ -408,6 +408,7 @@ const clickHandler = async (event) => { } if (isEditableColumn(column)) { + event.preventDefault(); await renderInput(Number(rowIndex), colField, clickedElement); } }; From 5e27f56796602f85109ffdb27bfac71b27decf30 Mon Sep 17 00:00:00 2001 From: alexm Date: Mon, 28 Apr 2025 11:28:13 +0200 Subject: [PATCH 08/27] fix(useArrayData): ensure options are set correctly on mount --- src/composables/useArrayData.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/composables/useArrayData.js b/src/composables/useArrayData.js index 9f95d639c..b046dfada 100644 --- a/src/composables/useArrayData.js +++ b/src/composables/useArrayData.js @@ -19,7 +19,7 @@ export function useArrayData(key, userOptions) { let canceller = null; onMounted(() => { - setOptions(); + setOptions(userOptions ?? {}); reset(['skip']); const query = route.query; @@ -39,9 +39,8 @@ export function useArrayData(key, userOptions) { setCurrentFilter(); }); - if (key && userOptions) setOptions(); - - function setOptions(params = userOptions) { + function setOptions(params) { + if (!params) return; const allowedOptions = [ 'url', 'filter', From 91a8b9dcffc3cd458a5eee09b868c2f513262e18 Mon Sep 17 00:00:00 2001 From: Javier Segarra Date: Mon, 28 Apr 2025 11:54:29 +0200 Subject: [PATCH 09/27] refactor: remove unused slot from VnCheckbox component --- src/components/common/VnCheckbox.vue | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/common/VnCheckbox.vue b/src/components/common/VnCheckbox.vue index c2c93d7e9..daaf891dc 100644 --- a/src/components/common/VnCheckbox.vue +++ b/src/components/common/VnCheckbox.vue @@ -43,6 +43,5 @@ const checkboxModel = computed({ {{ info }} - From 34aa1282466729655cd6d67028a9463ab704a3a8 Mon Sep 17 00:00:00 2001 From: Javier Segarra Date: Mon, 28 Apr 2025 11:54:47 +0200 Subject: [PATCH 10/27] refactor: replace VnMultiCheck with VnCheckboxMenu component --- src/components/VnTable/VnTable.vue | 6 +- src/components/common/VnCheckboxMenu.vue | 113 +++++++++++++++++++++++ src/components/common/VnMultiCheck.vue | 112 ---------------------- 3 files changed, 116 insertions(+), 115 deletions(-) create mode 100644 src/components/common/VnCheckboxMenu.vue delete mode 100644 src/components/common/VnMultiCheck.vue diff --git a/src/components/VnTable/VnTable.vue b/src/components/VnTable/VnTable.vue index 8915500fc..a177e6e4b 100644 --- a/src/components/VnTable/VnTable.vue +++ b/src/components/VnTable/VnTable.vue @@ -34,7 +34,7 @@ import VnTableFilter from './VnTableFilter.vue'; import { getColAlign } from 'src/composables/getColAlign'; import RightMenu from '../common/RightMenu.vue'; import VnScroll from '../common/VnScroll.vue'; -import VnMultiCheck from '../common/VnMultiCheck.vue'; +import VnCheckboxMenu from '../common/VnCheckboxMenu.vue'; const arrayData = useArrayData(useAttrs()['data-key']); const $props = defineProps({ @@ -724,14 +724,14 @@ const handleSelectedAll = (data) => { :data-cy > -