-
-
-
-
-
-
+
diff --git a/src/components/ui/VnFilterPanel.vue b/src/components/ui/VnFilterPanel.vue
index fd508cea3..218e28600 100644
--- a/src/components/ui/VnFilterPanel.vue
+++ b/src/components/ui/VnFilterPanel.vue
@@ -4,11 +4,11 @@ import { useI18n } from 'vue-i18n';
import { useArrayData } from 'composables/useArrayData';
import { useRoute } from 'vue-router';
import toDate from 'filters/toDate';
-import useRedirect from 'src/composables/useRedirect';
import VnFilterPanelChip from 'components/ui/VnFilterPanelChip.vue';
const { t } = useI18n();
-const props = defineProps({
+const params = defineModel({ default: {}, required: true, type: Object });
+const $props = defineProps({
dataKey: {
type: String,
required: true,
@@ -18,11 +18,6 @@ const props = defineProps({
required: false,
default: false,
},
- params: {
- type: Object,
- required: false,
- default: null,
- },
showAll: {
type: Boolean,
default: true,
@@ -40,12 +35,20 @@ const props = defineProps({
},
hiddenTags: {
type: Array,
- default: () => [],
+ default: () => ['filter'],
},
customTags: {
type: Array,
default: () => [],
},
+ disableSubmitEvent: {
+ type: Boolean,
+ default: false,
+ },
+ searchUrl: {
+ type: String,
+ default: 'params',
+ },
redirect: {
type: Boolean,
default: true,
@@ -54,61 +57,64 @@ const props = defineProps({
const emit = defineEmits(['refresh', 'clear', 'search', 'init', 'remove']);
-const arrayData = useArrayData(props.dataKey, {
- exprBuilder: props.exprBuilder,
+const arrayData = useArrayData($props.dataKey, {
+ exprBuilder: $props.exprBuilder,
+ searchUrl: $props.searchUrl,
+ navigate: {},
});
const route = useRoute();
const store = arrayData.store;
-const userParams = ref({});
-const { navigate } = useRedirect();
onMounted(() => {
- if (props.params) userParams.value = JSON.parse(JSON.stringify(props.params));
- if (Object.keys(store.userParams).length > 0) {
- userParams.value = JSON.parse(JSON.stringify(store.userParams));
- }
- emit('init', { params: userParams.value });
+ emit('init', { params: params.value });
});
+function setUserParams(watchedParams) {
+ if (!watchedParams) return;
+
+ if (typeof watchedParams == 'string') watchedParams = JSON.parse(watchedParams);
+ watchedParams = { ...watchedParams, ...watchedParams.filter?.where };
+ delete watchedParams.filter;
+ params.value = { ...params.value, ...watchedParams };
+}
+
watch(
- () => route.query.params,
- (val) => {
- if (!val) {
- userParams.value = {};
- } else {
- const parsedParams = JSON.parse(val);
- userParams.value = { ...parsedParams };
- }
- }
+ () => route.query[$props.searchUrl],
+ (val) => setUserParams(val)
+);
+
+watch(
+ () => arrayData.store.userParams,
+ (val) => setUserParams(val)
);
const isLoading = ref(false);
-async function search() {
+async function search(evt) {
+ if (evt && $props.disableSubmitEvent) return;
+
store.filter.where = {};
isLoading.value = true;
- const params = { ...userParams.value };
+ const filter = { ...params.value };
store.userParamsChanged = true;
store.filter.skip = 0;
store.skip = 0;
- const { params: newParams } = await arrayData.addFilter({ params });
- userParams.value = newParams;
+ const { params: newParams } = await arrayData.addFilter({ params: params.value });
+ params.value = newParams;
- if (!props.showAll && !Object.values(params).length) store.data = [];
+ if (!$props.showAll && !Object.values(filter).length) store.data = [];
isLoading.value = false;
emit('search');
- if (props.redirect) navigate(store.data, {});
}
async function reload() {
isLoading.value = true;
- const params = Object.values(userParams.value).filter((param) => param);
+ const params = Object.values(params.value).filter((param) => param);
await arrayData.fetch({ append: false });
- if (!props.showAll && !params.length) store.data = [];
+ if (!$props.showAll && !params.length) store.data = [];
isLoading.value = false;
emit('refresh');
- if (props.redirect) navigate(store.data, {});
}
async function clearFilters() {
@@ -117,18 +123,19 @@ async function clearFilters() {
store.filter.skip = 0;
store.skip = 0;
// Filtrar los params no removibles
- const removableFilters = Object.keys(userParams.value).filter((param) =>
- props.unremovableParams.includes(param)
+ const removableFilters = Object.keys(params.value).filter((param) =>
+ $props.unremovableParams.includes(param)
);
const newParams = {};
// Conservar solo los params que no son removibles
for (const key of removableFilters) {
- newParams[key] = userParams.value[key];
+ newParams[key] = params.value[key];
}
- userParams.value = { ...newParams }; // Actualizar los params con los removibles
- await arrayData.applyFilter({ params: userParams.value });
+ params.value = {};
+ params.value = { ...newParams }; // Actualizar los params con los removibles
+ await arrayData.applyFilter({ params: params.value });
- if (!props.showAll) {
+ if (!$props.showAll) {
store.data = [];
}
@@ -136,36 +143,32 @@ async function clearFilters() {
emit('clear');
}
-const tagsList = computed(() =>
- Object.entries(userParams.value)
- .filter(([key, value]) => value && !(props.hiddenTags || []).includes(key))
- .map(([key, value]) => ({
- label: key,
- value: value,
- }))
-);
+const tagsList = computed(() => {
+ const tagList = [];
+ for (const key of Object.keys(params.value)) {
+ const value = params.value[key];
+ if (value == null || ($props.hiddenTags || []).includes(key)) continue;
+ tagList.push({ label: key, value });
+ }
+ return tagList;
+});
-const tags = computed(() =>
- tagsList.value.filter((tag) => !(props.customTags || []).includes(tag.label))
-);
+const tags = computed(() => {
+ return tagsList.value.filter((tag) => !($props.customTags || []).includes(tag.key));
+});
const customTags = computed(() =>
- tagsList.value.filter((tag) => (props.customTags || []).includes(tag.label))
+ tagsList.value.filter((tag) => ($props.customTags || []).includes(tag.key))
);
async function remove(key) {
- userParams.value[key] = null;
- await arrayData.applyFilter({ params: userParams.value });
+ params.value[key] = undefined;
+ search();
emit('remove', key);
}
function formatValue(value) {
- if (typeof value === 'boolean') {
- return value ? t('Yes') : t('No');
- }
-
- if (isNaN(value) && !isNaN(Date.parse(value))) {
- return toDate(value);
- }
+ if (typeof value === 'boolean') return value ? t('Yes') : t('No');
+ if (isNaN(value) && !isNaN(Date.parse(value))) return toDate(value);
return `"${value}"`;
}
@@ -226,14 +229,14 @@ function formatValue(value) {
{{ chip.label }}:
- "{{ chip.value }}"
+ "{{ formatValue(chip.value) }}"
-
+
-
+
@@ -269,7 +272,6 @@ function formatValue(value) {
color="primary"
/>
-
diff --git a/src/pages/Customer/ExtendedList/CustomerExtendedList.vue b/src/pages/Customer/ExtendedList/CustomerExtendedList.vue
deleted file mode 100644
index 79459d1a1..000000000
--- a/src/pages/Customer/ExtendedList/CustomerExtendedList.vue
+++ /dev/null
@@ -1,619 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- navigateToTravelId(row.id)"
- >
-
-
- {{ value }}
-
-
-
-
-
-
-
-
-
-
-
-
- {{ props.row.id }}
-
-
-
-
-
-
-
- {{ props.row.salesPerson }}
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/pages/Customer/ExtendedList/CustomerExtendedListActions.vue b/src/pages/Customer/ExtendedList/CustomerExtendedListActions.vue
deleted file mode 100644
index 8355c7560..000000000
--- a/src/pages/Customer/ExtendedList/CustomerExtendedListActions.vue
+++ /dev/null
@@ -1,60 +0,0 @@
-
-
-
-
-
-
- {{ t('Client ticket list') }}
-
-
-
-
- {{ t('Preview') }}
-
-
-
-
-
-
-es:
- Client ticket list: Listado de tickets del cliente
- Preview: Vista previa
-
diff --git a/src/pages/Customer/ExtendedList/CustomerExtendedListFilter.vue b/src/pages/Customer/ExtendedList/CustomerExtendedListFilter.vue
deleted file mode 100644
index 1be20f26c..000000000
--- a/src/pages/Customer/ExtendedList/CustomerExtendedListFilter.vue
+++ /dev/null
@@ -1,571 +0,0 @@
-
-
-
- (clients = data)"
- auto-load
- />
- (workers = data)"
- auto-load
- />
- (workers = data)"
- auto-load
- />
- (countriesOptions = data)"
- auto-load
- />
- (provincesOptions = data)"
- auto-load
- url="Provinces"
- />
- (paymethodsOptions = data)"
- auto-load
- />
- (businessTypesOptions = data)"
- auto-load
- />
- (sageTaxTypesOptions = data)"
- />
- (sageTransactionTypesOptions = data)"
- />
-
-
-
- {{ t(`customer.extendedList.tableVisibleColumns.${tag.label}`) }}:
-
- {{ formatFn(tag.value) }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-es:
- Social name: Razón social
-
diff --git a/src/pages/InvoiceIn/Card/InvoiceInDueDay.vue b/src/pages/InvoiceIn/Card/InvoiceInDueDay.vue
index 9325a5b41..d2b43c57a 100644
--- a/src/pages/InvoiceIn/Card/InvoiceInDueDay.vue
+++ b/src/pages/InvoiceIn/Card/InvoiceInDueDay.vue
@@ -10,8 +10,10 @@ import FetchData from 'src/components/FetchData.vue';
import VnSelect from 'src/components/common/VnSelect.vue';
import VnCurrency from 'src/components/common/VnCurrency.vue';
import { toCurrency } from 'src/filters';
+import useNotify from 'src/composables/useNotify.js';
const route = useRoute();
+const { notify } = useNotify();
const { t } = useI18n();
const arrayData = useArrayData();
const invoiceIn = computed(() => arrayData.store.data);
@@ -69,6 +71,7 @@ const isNotEuro = (code) => code != 'EUR';
async function insert() {
await axios.post('/InvoiceInDueDays/new', { id: +invoiceId });
await invoiceInFormRef.value.reload();
+ notify(t('globals.dataSaved'), 'positive');
}
const getTotalAmount = (rows) => rows.reduce((acc, { amount }) => acc + +amount, 0);
diff --git a/src/pages/Worker/Card/WorkerNotificationsManager.vue b/src/pages/Worker/Card/WorkerNotificationsManager.vue
index 44573adca..8699392e0 100644
--- a/src/pages/Worker/Card/WorkerNotificationsManager.vue
+++ b/src/pages/Worker/Card/WorkerNotificationsManager.vue
@@ -20,8 +20,8 @@ const { t } = useI18n();
const quasar = useQuasar();
const entityId = computed(() => $props.id || route.params.id);
const URL_KEY = 'NotificationSubscriptions';
-const active = ref();
-const available = ref();
+const active = ref(new Map());
+const available = ref(new Map());
async function toggleNotification(notification) {
try {
@@ -56,6 +56,7 @@ const swapEntry = (from, to, key) => {
};
function setNotifications(data) {
+ console.log('data: ', data);
active.value = new Map(data.active);
available.value = new Map(data.available);
}
diff --git a/src/router/modules/customer.js b/src/router/modules/customer.js
index 092d60639..3aece0dfe 100644
--- a/src/router/modules/customer.js
+++ b/src/router/modules/customer.js
@@ -14,7 +14,6 @@ export default {
main: [
'CustomerList',
'CustomerPayments',
- 'CustomerExtendedList',
'CustomerNotifications',
'CustomerDefaulter',
],
@@ -70,18 +69,6 @@ export default {
component: () =>
import('src/pages/Customer/Payments/CustomerPayments.vue'),
},
- {
- path: 'extendedList',
- name: 'CustomerExtendedList',
- meta: {
- title: 'extendedList',
- icon: 'vn:client',
- },
- component: () =>
- import(
- 'src/pages/Customer/ExtendedList/CustomerExtendedList.vue'
- ),
- },
{
path: 'notifications',
name: 'CustomerNotifications',
diff --git a/src/stores/useArrayDataStore.js b/src/stores/useArrayDataStore.js
index 115c161dd..ebe32f8d0 100644
--- a/src/stores/useArrayDataStore.js
+++ b/src/stores/useArrayDataStore.js
@@ -21,6 +21,8 @@ export const useArrayDataStore = defineStore('arrayDataStore', () => {
isLoading: false,
userParamsChanged: false,
exprBuilder: null,
+ searchUrl: 'params',
+ navigate: null,
};
}
diff --git a/test/cypress/integration/invoiceIn/invoiceInDueDay.spec.js b/test/cypress/integration/invoiceIn/invoiceInDueDay.spec.js
index 124b60c34..5a5becd22 100644
--- a/test/cypress/integration/invoiceIn/invoiceInDueDay.spec.js
+++ b/test/cypress/integration/invoiceIn/invoiceInDueDay.spec.js
@@ -22,7 +22,7 @@ describe('InvoiceInDueDay', () => {
cy.waitForElement('thead');
cy.get(addBtn).click();
- cy.saveCard();
+ cy.get('tbody > :nth-child(1)').should('exist');
cy.get('.q-notification__message').should('have.text', 'Data saved');
});
});
diff --git a/test/vitest/__tests__/composables/useArrayData.spec.js b/test/vitest/__tests__/composables/useArrayData.spec.js
index ae0ca7368..5e4d12560 100644
--- a/test/vitest/__tests__/composables/useArrayData.spec.js
+++ b/test/vitest/__tests__/composables/useArrayData.spec.js
@@ -1,31 +1,98 @@
-import { describe, expect, it, beforeAll } from 'vitest';
-import { axios } from 'app/test/vitest/helper';
+import { describe, expect, it, beforeEach, afterEach, vi } from 'vitest';
+import { axios, flushPromises } from 'app/test/vitest/helper';
import { useArrayData } from 'composables/useArrayData';
+import { useRouter } from 'vue-router';
+import * as vueRouter from 'vue-router';
describe('useArrayData', () => {
- let arrayData;
- beforeAll(() => {
- axios.get.mockResolvedValue({ data: [] });
- arrayData = useArrayData('InvoiceIn', { url: 'invoice-in/list' });
- Object.defineProperty(window.location, 'href', {
- writable: true,
- value: 'localhost:9000/invoice-in/list',
+ const filter = '{"order":"","limit":10,"skip":0}';
+ const params = { supplierFk: 2 };
+ beforeEach(() => {
+ vi.spyOn(useRouter(), 'replace');
+ vi.spyOn(useRouter(), 'push');
+ });
+
+ afterEach(() => {
+ vi.clearAllMocks();
+ });
+
+ it('should fetch and repalce url with new params', async () => {
+ vi.spyOn(axios, 'get').mockReturnValueOnce({ data: [] });
+
+ const arrayData = useArrayData('ArrayData', { url: 'mockUrl' });
+
+ arrayData.store.userParams = params;
+ arrayData.fetch({});
+
+ await flushPromises();
+ const routerReplace = useRouter().replace.mock.calls[0][0];
+
+ expect(axios.get.mock.calls[0][1].params).toEqual({
+ filter,
+ supplierFk: 2,
+ });
+ expect(routerReplace.path).toEqual('mockSection/list');
+ expect(JSON.parse(routerReplace.query.params)).toEqual(
+ expect.objectContaining(params)
+ );
+ });
+
+ it('Should get data and send new URL without keeping parameters, if there is only one record', async () => {
+ vi.spyOn(axios, 'get').mockReturnValueOnce({ data: [{ id: 1 }] });
+
+ const arrayData = useArrayData('ArrayData', { url: 'mockUrl', navigate: {} });
+
+ arrayData.store.userParams = params;
+ arrayData.fetch({});
+
+ await flushPromises();
+ const routerPush = useRouter().push.mock.calls[0][0];
+
+ expect(axios.get.mock.calls[0][1].params).toEqual({
+ filter,
+ supplierFk: 2,
+ });
+ expect(routerPush.path).toEqual('mockName/1');
+ expect(routerPush.query).toBeUndefined();
+ });
+
+ it('Should get data and send new URL keeping parameters, if you have more than one record', async () => {
+ vi.spyOn(axios, 'get').mockReturnValueOnce({ data: [{ id: 1 }, { id: 2 }] });
+
+ vi.spyOn(vueRouter, 'useRoute').mockReturnValue({
+ matched: [],
+ query: {},
+ params: {},
+ meta: { moduleName: 'mockName' },
+ path: 'mockName/1',
+ });
+ vi.spyOn(vueRouter, 'useRouter').mockReturnValue({
+ push: vi.fn(),
+ replace: vi.fn(),
+ currentRoute: {
+ value: {
+ params: {
+ id: 1,
+ },
+ meta: { moduleName: 'mockName' },
+ matched: [{ path: 'mockName/:id' }],
+ },
+ },
});
- // Mock the window.history.pushState method within useArrayData
- window.history.pushState = (data, title, url) => (window.location.href = url);
+ const arrayData = useArrayData('ArrayData', { url: 'mockUrl', navigate: {} });
- // Mock the URL constructor within useArrayData
- global.URL = class URL {
- constructor(url) {
- this.hash = url.split('localhost:9000/')[1];
- }
- };
- });
+ arrayData.store.userParams = params;
+ arrayData.fetch({});
- it('should add the params to the url', async () => {
- arrayData.store.userParams = { supplierFk: 2 };
- arrayData.updateStateParams();
- expect(window.location.href).contain('params=%7B%22supplierFk%22%3A2%7D');
+ await flushPromises();
+ const routerPush = useRouter().push.mock.calls[0][0];
+
+ expect(axios.get.mock.calls[0][1].params).toEqual({
+ filter,
+ supplierFk: 2,
+ });
+ expect(routerPush.path).toEqual('mockName/');
+ expect(routerPush.query.params).toBeDefined();
});
});
diff --git a/test/vitest/__tests__/composables/useRedirect.spec.js b/test/vitest/__tests__/composables/useRedirect.spec.js
deleted file mode 100644
index ce56189b9..000000000
--- a/test/vitest/__tests__/composables/useRedirect.spec.js
+++ /dev/null
@@ -1,52 +0,0 @@
-import { vi, describe, expect, it, beforeEach, beforeAll } from 'vitest';
-import useRedirect from 'src/composables/useRedirect';
-import { useRouter } from 'vue-router';
-
-vi.mock('vue-router');
-
-describe('useRedirect', () => {
- useRouter.mockReturnValue({
- push: vi.fn(),
- currentRoute: {
- value: {
- matched: [
- { path: '/' },
- { path: '/customer' },
- { path: '/customer/:id' },
- { path: '/customer/:id/basic-data' },
- ],
- },
- },
- });
- const data = [];
- let navigate;
- let spy;
-
- beforeAll(() => {
- const { navigate: navigateFn } = useRedirect();
- navigate = navigateFn;
- spy = useRouter().push;
- });
-
- beforeEach(() => {
- data.length = 0;
- spy.mockReset();
- });
-
- it('should redirect to list page if there are several results', async () => {
- data.push({ id: 1, name: 'employee' }, { id: 2, name: 'boss' });
- navigate(data, {});
- expect(spy).toHaveBeenCalledWith({ path: '/customer/' });
- });
-
- it('should redirect to list page if there is no results', async () => {
- navigate(data, {});
- expect(spy).toHaveBeenCalledWith({ path: '/customer/' });
- });
-
- it('should redirect to basic-data page if there is only one result', async () => {
- data.push({ id: 1, name: 'employee' });
- navigate(data, {});
- expect(spy).toHaveBeenCalledWith({ path: '/customer/1/basic-data' });
- });
-});
diff --git a/test/vitest/helper.js b/test/vitest/helper.js
index 4eeea25a8..d6721d817 100644
--- a/test/vitest/helper.js
+++ b/test/vitest/helper.js
@@ -15,16 +15,19 @@ installQuasarPlugin({
});
const pinia = createTestingPinia({ createSpy: vi.fn, stubActions: false });
const mockPush = vi.fn();
+const mockReplace = vi.fn();
vi.mock('vue-router', () => ({
useRouter: () => ({
push: mockPush,
+ replace: mockReplace,
currentRoute: {
value: {
params: {
id: 1,
},
meta: { moduleName: 'mockName' },
+ matched: [{ path: 'mockName/list' }],
},
},
}),
@@ -33,6 +36,7 @@ vi.mock('vue-router', () => ({
query: {},
params: {},
meta: { moduleName: 'mockName' },
+ path: 'mockSection/list',
}),
}));