diff --git a/src/boot/vnDate.js b/src/boot/vnDate.js index 33d5ac27f..8f18e2400 100644 --- a/src/boot/vnDate.js +++ b/src/boot/vnDate.js @@ -1,4 +1,6 @@ import { boot } from 'quasar/wrappers'; +import { date as quasarDate } from 'quasar'; +const { formatDate } = quasarDate; export default boot(() => { Date.vnUTC = () => { @@ -25,4 +27,34 @@ export default boot(() => { const date = new Date(Date.vnUTC()); return new Date(date.getFullYear(), date.getMonth() + 1, 0); }; + + Date.getCurrentDateTimeFormatted = ( + options = { + startOfDay: false, + endOfDay: true, + iso: true, + mask: 'DD-MM-YYYY HH:mm', + }, + ) => { + const date = Date.vnUTC(); + if (options.startOfDay) { + date.setHours(0, 0, 0); + } + if (options.endOfDay) { + date.setHours(23, 59, 0); + } + if (options.iso) { + return date.toISOString(); + } + return formatDate(date, options.mask); + }; + + Date.convertToISODateTime = (dateTimeStr) => { + const [datePart, timePart] = dateTimeStr.split(' '); + const [day, month, year] = datePart.split('-'); + const [hours, minutes] = timePart.split(':'); + + const isoDate = new Date(year, month - 1, day, hours, minutes); + return isoDate.toISOString(); + }; }); diff --git a/src/components/EditPictureForm.vue b/src/components/EditPictureForm.vue index 1f158e785..29377b559 100644 --- a/src/components/EditPictureForm.vue +++ b/src/components/EditPictureForm.vue @@ -140,7 +140,7 @@ const updatePhotoPreview = (value) => { img.onerror = () => { notify( t("This photo provider doesn't allow remote downloads"), - 'negative' + 'negative', ); }; } @@ -219,11 +219,7 @@ const makeRequest = async () => { color="primary" class="cursor-pointer" @click="rotateLeft()" - > - - + />
@@ -233,11 +229,7 @@ const makeRequest = async () => { color="primary" class="cursor-pointer" @click="rotateRight()" - > - - + />
@@ -265,7 +257,6 @@ const makeRequest = async () => { class="cursor-pointer q-mr-sm" @click="openInputFile()" > - {{ diff --git a/src/components/NavBar.vue b/src/components/NavBar.vue index 7329ddae2..65139e1e5 100644 --- a/src/components/NavBar.vue +++ b/src/components/NavBar.vue @@ -69,7 +69,7 @@ const refresh = () => window.location.reload(); 'no-visible': !stateQuery.isLoading().value, }" size="sm" - data-cy="loading-spinner" + data-cy="navBar-spinner" /> diff --git a/src/components/VnTable/VnTable.vue b/src/components/VnTable/VnTable.vue index 644bc1caf..2f3bbd2bd 100644 --- a/src/components/VnTable/VnTable.vue +++ b/src/components/VnTable/VnTable.vue @@ -751,6 +751,7 @@ const rowCtrlClickFunction = computed(() => { withFilters " :column="col" + :data-cy="`column-filter-${col.name}`" :show-title="true" :data-key="$attrs['data-key']" v-model="params[columnName(col)]" diff --git a/src/components/common/VnAccountNumber.vue b/src/components/common/VnAccountNumber.vue index 8bff3e261..5bce49459 100644 --- a/src/components/common/VnAccountNumber.vue +++ b/src/components/common/VnAccountNumber.vue @@ -8,7 +8,8 @@ const model = defineModel({ prop: 'modelValue' }); diff --git a/src/components/common/VnInputDateTime.vue b/src/components/common/VnInputDateTime.vue new file mode 100644 index 000000000..b239d528a --- /dev/null +++ b/src/components/common/VnInputDateTime.vue @@ -0,0 +1,79 @@ + + + + + es: + Open date: Abrir fecha + diff --git a/src/components/common/__tests__/VnInputDateTime.spec.js b/src/components/common/__tests__/VnInputDateTime.spec.js new file mode 100644 index 000000000..23132d77d --- /dev/null +++ b/src/components/common/__tests__/VnInputDateTime.spec.js @@ -0,0 +1,81 @@ +import { createWrapper } from 'app/test/vitest/helper.js'; +import { describe, it, expect, beforeAll } from 'vitest'; +import VnInputDateTime from 'components/common/VnInputDateTime.vue'; +import vnDateBoot from 'src/boot/vnDate'; + +let vm; +let wrapper; + +beforeAll(() => { + // Initialize the vnDate boot + vnDateBoot(); +}); +function generateWrapper(date, outlined, showEvent) { + wrapper = createWrapper(VnInputDateTime, { + props: { + modelValue: date, + isOutlined: outlined, + showEvent: showEvent, + }, + }); + wrapper = wrapper.wrapper; + vm = wrapper.vm; +} + +describe('VnInputDateTime', () => { + describe('selectedDate', () => { + it('formats a valid datetime correctly', async () => { + generateWrapper('2023-12-25T10:30:00', false, true); + await vm.$nextTick(); + expect(vm.selectedDate).toBe('25-12-2023 10:30'); + }); + + it('handles null date value', async () => { + generateWrapper(null, false, true); + await vm.$nextTick(); + expect(vm.selectedDate).toBeInstanceOf(Date); + }); + + it('updates the model value when a new datetime is set', async () => { + vm.selectedDate = '31-12-2023 15:45'; + await vm.$nextTick(); + expect(wrapper.emitted()['update:modelValue']).toBeTruthy(); + }); + }); + + describe('styleAttrs', () => { + it('should return empty styleAttrs when isOutlined is false', async () => { + generateWrapper('2023-12-25T10:30:00', false, true); + await vm.$nextTick(); + expect(vm.styleAttrs).toEqual({}); + }); + + it('should set styleAttrs when isOutlined is true', async () => { + generateWrapper('2023-12-25T10:30:00', true, true); + await vm.$nextTick(); + expect(vm.styleAttrs).toEqual({ + dense: true, + outlined: true, + rounded: true, + }); + }); + }); + + describe('component rendering', () => { + it('should render date and time icons', async () => { + generateWrapper('2023-12-25T10:30:00', false, true); + await vm.$nextTick(); + const icons = wrapper.findAllComponents({ name: 'QIcon' }); + expect(icons.length).toBe(2); + expect(icons[0].props('name')).toBe('today'); + expect(icons[1].props('name')).toBe('access_time'); + }); + + it('should render popup proxies for date and time', async () => { + generateWrapper('2023-12-25T10:30:00', false, true); + await vm.$nextTick(); + const popups = wrapper.findAllComponents({ name: 'QPopupProxy' }); + expect(popups.length).toBe(2); + }); + }); +}); diff --git a/src/components/ui/EntityDescriptor.vue b/src/components/ui/EntityDescriptor.vue index a5dced551..e6adaa5f7 100644 --- a/src/components/ui/EntityDescriptor.vue +++ b/src/components/ui/EntityDescriptor.vue @@ -44,7 +44,8 @@ onBeforeMount(async () => { }); // It enables to load data only once if the module is the same as the dataKey - if (!isSameDataKey.value || !route.params.id) await getData(); + if (!isSameDataKey.value || !route.params.id || $props.id !== route.params.id) + await getData(); watch( () => [$props.url, $props.filter], async () => { @@ -58,7 +59,8 @@ async function getData() { store.filter = $props.filter ?? {}; isLoading.value = true; try { - const { data } = await arrayData.fetch({ append: false, updateRouter: false }); + await arrayData.fetch({ append: false, updateRouter: false }); + const { data } = store; state.set($props.dataKey, data); emit('onFetch', data); } finally { diff --git a/src/components/ui/VnFilterPanel.vue b/src/components/ui/VnFilterPanel.vue index dc9e4e776..6460499b0 100644 --- a/src/components/ui/VnFilterPanel.vue +++ b/src/components/ui/VnFilterPanel.vue @@ -212,6 +212,7 @@ const getLocale = (label) => { color="primary" style="position: fixed; z-index: 1; right: 0; bottom: 0" icon="search" + data-cy="vnFilterPanel_search" @click="search()" > @@ -229,6 +230,7 @@ const getLocale = (label) => { { diff --git a/src/pages/Customer/components/CustomerSamplesCreate.vue b/src/pages/Customer/components/CustomerSamplesCreate.vue index 1294a5d25..dfa944748 100644 --- a/src/pages/Customer/components/CustomerSamplesCreate.vue +++ b/src/pages/Customer/components/CustomerSamplesCreate.vue @@ -41,7 +41,6 @@ const sampleType = ref({ hasPreview: false }); const initialData = reactive({}); const entityId = computed(() => route.params.id); const customer = computed(() => useArrayData('Customer').store?.data); -const filterEmailUsers = { where: { userFk: user.value.id } }; const filterClientsAddresses = { include: [ { relation: 'province', scope: { fields: ['name'] } }, @@ -73,7 +72,7 @@ onBeforeMount(async () => { const setEmailUser = (data) => { optionsEmailUsers.value = data; - initialData.replyTo = data[0]?.email; + initialData.replyTo = data[0]?.notificationEmail; }; const setClientsAddresses = (data) => { @@ -182,10 +181,12 @@ const toCustomerSamples = () => {