#8193: Added filter in ClientNotes #1609
|
@ -4,7 +4,7 @@ import { ref, reactive, useAttrs, computed } from 'vue';
|
||||||
import { onBeforeRouteLeave } from 'vue-router';
|
import { onBeforeRouteLeave } from 'vue-router';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { useQuasar } from 'quasar';
|
import { useQuasar } from 'quasar';
|
||||||
|
import { useState } from 'src/composables/useState';
|
||||||
import { toDateHourMin } from 'src/filters';
|
import { toDateHourMin } from 'src/filters';
|
||||||
|
|
||||||
import VnPaginate from 'components/ui/VnPaginate.vue';
|
import VnPaginate from 'components/ui/VnPaginate.vue';
|
||||||
|
@ -23,9 +23,9 @@ const $attrs = computed(() => {
|
||||||
const { required, deletable, ...rest } = originalAttrs;
|
const { required, deletable, ...rest } = originalAttrs;
|
||||||
return rest;
|
return rest;
|
||||||
});
|
});
|
||||||
|
|
||||||
const $props = defineProps({
|
const $props = defineProps({
|
||||||
url: { type: String, default: null },
|
url: { type: String, default: null },
|
||||||
|
dataKey: { type: String, default: null },
|
||||||
saveUrl: { type: String, default: null },
|
saveUrl: { type: String, default: null },
|
||||||
userFilter: { type: Object, default: () => {} },
|
userFilter: { type: Object, default: () => {} },
|
||||||
filter: { type: Object, default: () => {} },
|
filter: { type: Object, default: () => {} },
|
||||||
|
@ -33,16 +33,17 @@ const $props = defineProps({
|
||||||
addNote: { type: Boolean, default: false },
|
addNote: { type: Boolean, default: false },
|
||||||
selectType: { type: Boolean, default: false },
|
selectType: { type: Boolean, default: false },
|
||||||
justInput: { type: Boolean, default: false },
|
justInput: { type: Boolean, default: false },
|
||||||
|
filterColumns: { type: Array, default: () => [] },
|
||||||
});
|
});
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const quasar = useQuasar();
|
const quasar = useQuasar();
|
||||||
const newNote = reactive({ text: null, observationTypeFk: null });
|
const newNote = reactive({ text: null, observationTypeFk: null });
|
||||||
const observationTypes = ref([]);
|
const observationTypes = ref([]);
|
||||||
const vnPaginateRef = ref();
|
const vnPaginateRef = ref();
|
||||||
|
const state = useState();
|
||||||
const defaultObservationType = computed(() =>
|
const user = state.getUser();
|
||||||
observationTypes.value.find(ot => ot.code === 'salesPerson')?.id
|
const defaultObservationType = computed(
|
||||||
|
() => observationTypes.value.find((ot) => ot.code === 'salesPerson')?.id,
|
||||||
);
|
);
|
||||||
|
|
||||||
let originalText;
|
let originalText;
|
||||||
|
@ -122,19 +123,38 @@ function fetchData([data]) {
|
||||||
emit('onFetch', data);
|
emit('onFetch', data);
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleObservationTypes = (data) => {
|
const handleObservationTypes = async (data) => {
|
||||||
observationTypes.value = data;
|
observationTypes.value = data;
|
||||||
if(defaultObservationType.value) {
|
|
||||||
newNote.observationTypeFk = defaultObservationType.value;
|
const { data: departments } = await axios.get('Departments');
|
||||||
}
|
const userDepartment = departments.find((ot) => ot.id === user.value.departmentFk);
|
||||||
|
|
||||||
|
const hasObservationType =
|
||||||
|
observationTypes.value.find(
|
||||||
|
(ot) => parseInt(ot.departmentFk) === userDepartment.id,
|
||||||
|
) ||
|
||||||
|
observationTypes.value.find(
|
||||||
|
(ot) => parseInt(ot.departmentFk) === userDepartment.parentFk,
|
||||||
|
);
|
||||||
|
|
||||||
|
newNote.observationTypeFk = hasObservationType
|
||||||
|
? hasObservationType.code
|
||||||
|
: defaultObservationType.value;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function exprBuilder(param, value) {
|
||||||
|
switch (param) {
|
||||||
|
case 'observationTypeFk':
|
||||||
|
case 'workerFk':
|
||||||
|
return { [param]: value };
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<FetchData
|
<FetchData
|
||||||
v-if="selectType"
|
v-if="selectType"
|
||||||
|
|||||||
url="ObservationTypes"
|
url="ObservationTypes"
|
||||||
:filter="{ fields: ['id', 'description', 'code'] }"
|
:filter="{ fields: ['id', 'description', 'code', 'departmentFk'] }"
|
||||||
auto-load
|
auto-load
|
||||||
@on-fetch="handleObservationTypes"
|
@on-fetch="handleObservationTypes"
|
||||||
/>
|
/>
|
||||||
|
@ -156,6 +176,7 @@ const handleObservationTypes = (data) => {
|
||||||
<QCardSection class="q-px-xs q-my-none q-py-none">
|
<QCardSection class="q-px-xs q-my-none q-py-none">
|
||||||
<VnRow class="full-width">
|
<VnRow class="full-width">
|
||||||
<VnSelect
|
<VnSelect
|
||||||
|
class="q-mr-xs"
|
||||||
:label="t('Observation type')"
|
:label="t('Observation type')"
|
||||||
v-if="selectType"
|
v-if="selectType"
|
||||||
url="ObservationTypes"
|
url="ObservationTypes"
|
||||||
|
@ -164,6 +185,8 @@ const handleObservationTypes = (data) => {
|
||||||
style="flex: 0.15"
|
style="flex: 0.15"
|
||||||
:required="'required' in originalAttrs"
|
:required="'required' in originalAttrs"
|
||||||
@keyup.enter.stop="insert"
|
@keyup.enter.stop="insert"
|
||||||
|
data-cy="VnNotes-observation-type"
|
||||||
|
filled
|
||||||
/>
|
/>
|
||||||
<VnInput
|
<VnInput
|
||||||
v-model.trim="newNote.text"
|
v-model.trim="newNote.text"
|
||||||
|
@ -171,10 +194,10 @@ const handleObservationTypes = (data) => {
|
||||||
:label="$props.justInput && newNote.text ? '' : t('Add note here...')"
|
:label="$props.justInput && newNote.text ? '' : t('Add note here...')"
|
||||||
filled
|
filled
|
||||||
autogrow
|
autogrow
|
||||||
jon marked this conversation as resolved
Outdated
alexm
commented
Esto no deberia estar en un componente generico, VnNotes se usa en claim, worker, etc Esto no deberia estar en un componente generico, VnNotes se usa en claim, worker, etc
|
|||||||
autofocus
|
|
||||||
@keyup.enter.stop="handleClick"
|
@keyup.enter.stop="handleClick"
|
||||||
:required="'required' in originalAttrs"
|
:required="'required' in originalAttrs"
|
||||||
clearable
|
clearable
|
||||||
|
data-cy="VnNotes-text-input"
|
||||||
>
|
>
|
||||||
<template #append>
|
<template #append>
|
||||||
<QBtn
|
<QBtn
|
||||||
|
@ -204,10 +227,9 @@ const handleObservationTypes = (data) => {
|
||||||
ref="vnPaginateRef"
|
ref="vnPaginateRef"
|
||||||
class="show"
|
class="show"
|
||||||
v-bind="$attrs"
|
v-bind="$attrs"
|
||||||
:search-url="false"
|
:search-url="$props.url"
|
||||||
@on-fetch="
|
@on-fetch="newNote.text = ''"
|
||||||
newNote.text = '';
|
:exprBuilder
|
||||||
"
|
|
||||||
>
|
>
|
||||||
<template #body="{ rows }">
|
<template #body="{ rows }">
|
||||||
<TransitionGroup name="list" tag="div" class="column items-center full-width">
|
<TransitionGroup name="list" tag="div" class="column items-center full-width">
|
||||||
|
@ -234,6 +256,7 @@ const handleObservationTypes = (data) => {
|
||||||
outline
|
outline
|
||||||
color="grey"
|
color="grey"
|
||||||
v-if="selectType && note.observationTypeFk"
|
v-if="selectType && note.observationTypeFk"
|
||||||
|
data-cy="VnNotes-observation-type-badge"
|
||||||
>
|
>
|
||||||
{{
|
{{
|
||||||
observationTypes.find(
|
observationTypes.find(
|
||||||
|
|
|
@ -1,15 +1,134 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
|
import { ref, computed, onMounted, onUnmounted } from 'vue';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
|
import { useStateStore } from 'stores/useStateStore';
|
||||||
|
|
||||||
|
import RightMenu from 'src/components/common/RightMenu.vue';
|
||||||
|
import VnSelect from 'src/components/common/VnSelect.vue';
|
||||||
|
import FetchData from 'src/components/FetchData.vue';
|
||||||
import VnNotes from 'src/components/ui/VnNotes.vue';
|
import VnNotes from 'src/components/ui/VnNotes.vue';
|
||||||
|
import VnTableFilter from 'src/components/VnTable/VnTableFilter.vue';
|
||||||
|
import VnAvatar from 'src/components/ui/VnAvatar.vue';
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
const url = 'clientObservations';
|
||||||
|
const stateStore = useStateStore();
|
||||||
|
const filteredWorkers = ref([]);
|
||||||
|
const columns = computed(() => [
|
||||||
|
{
|
||||||
|
name: 'observationTypeFk',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'workerFk',
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
const setWorkerObservations = (data) => {
|
||||||
|
const seen = new Set();
|
||||||
|
filteredWorkers.value = data;
|
||||||
|
filteredWorkers.value = data.filter((worker) => {
|
||||||
|
if (!seen.has(worker.workerFk)) {
|
||||||
|
seen.add(worker.workerFk);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
function exprBuilder(param, value) {
|
||||||
|
switch (param) {
|
||||||
|
case 'observationTypeFk':
|
||||||
|
case 'workerFk':
|
||||||
|
return { [param]: value };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
stateStore.rightDrawerChangeValue(true);
|
||||||
|
});
|
||||||
|
onUnmounted(() => {
|
||||||
|
stateStore.rightDrawer = false;
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
|
<FetchData
|
||||||
|
:url="url"
|
||||||
|
:filter="{ fields: ['id', 'workerFk'] }"
|
||||||
|
:where="{ clientFk: $route.params.id }"
|
||||||
|
auto-load
|
||||||
|
@on-fetch="setWorkerObservations"
|
||||||
|
/>
|
||||||
|
<RightMenu>
|
||||||
|
<template #right-panel>
|
||||||
|
<VnTableFilter
|
||||||
|
data-key="clientObservations"
|
||||||
|
:data-key
|
||||||
|
:columns="columns"
|
||||||
|
:redirect="false"
|
||||||
|
:exprBuilder
|
||||||
|
:search-url="url"
|
||||||
|
:showTagChips="false"
|
||||||
|
>
|
||||||
|
<template #filter-observationTypeFk="{ params, columnName, searchFn }">
|
||||||
|
<VnSelect
|
||||||
|
:label="t('Observation type')"
|
||||||
|
url="ObservationTypes"
|
||||||
|
v-model="params[columnName]"
|
||||||
|
option-label="description"
|
||||||
|
option-value="id"
|
||||||
|
@keyup.enter="searchFn"
|
||||||
|
@update:modelValue="() => searchFn()"
|
||||||
|
dense
|
||||||
|
filled
|
||||||
|
data-cy="VnNotes-observation-type-filter"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
<template #filter-workerFk="{ params, columnName, searchFn }">
|
||||||
|
<VnSelect
|
||||||
|
:label="t('globals.user')"
|
||||||
|
v-model="params[columnName]"
|
||||||
|
option-label="workerFk"
|
||||||
|
option-value="workerFk"
|
||||||
|
:options="filteredWorkers"
|
||||||
|
@keyup.enter="searchFn"
|
||||||
|
@update:modelValue="() => searchFn()"
|
||||||
|
hide-selected
|
||||||
|
dense
|
||||||
|
filled
|
||||||
|
data-cy="VnNotes-user-filter"
|
||||||
|
>
|
||||||
|
<template #option="{ opt, itemProps }">
|
||||||
|
<QItem v-bind="itemProps" class="q-pa-xs row items-center">
|
||||||
|
<QItemSection class="col-3 items-center">
|
||||||
|
<VnAvatar :worker-id="opt.worker.id" />
|
||||||
|
</QItemSection>
|
||||||
|
<QItemSection class="col-9 justify-center">
|
||||||
|
<span>{{ opt.worker?.user?.name }}</span>
|
||||||
|
<span class="text-grey">
|
||||||
|
{{ `#${opt.worker?.user?.id}` }}
|
||||||
|
</span>
|
||||||
|
</QItemSection>
|
||||||
|
</QItem>
|
||||||
|
</template>
|
||||||
|
</VnSelect>
|
||||||
|
</template>
|
||||||
|
</VnTableFilter>
|
||||||
|
</template>
|
||||||
|
</RightMenu>
|
||||||
<VnNotes
|
<VnNotes
|
||||||
url="clientObservations"
|
:url="url"
|
||||||
|
data-key="clientObservations"
|
||||||
:add-note="true"
|
:add-note="true"
|
||||||
:filter="{ where: { clientFk: $route.params.id } }"
|
:filter="{ where: { clientFk: $route.params.id } }"
|
||||||
:body="{ clientFk: $route.params.id }"
|
:body="{ clientFk: $route.params.id }"
|
||||||
style="overflow-y: auto"
|
style="overflow-y: auto"
|
||||||
:select-type="true"
|
:select-type="true"
|
||||||
|
:filter-columns="['workerFk', 'observationTypeFk']"
|
||||||
required
|
required
|
||||||
order="created DESC"
|
order="created DESC"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
<i18n>
|
||||||
|
es:
|
||||||
|
Observation type: Tipo de observación
|
||||||
|
</i18n>
|
||||||
|
|
|
@ -1,13 +1,37 @@
|
||||||
/// <reference types="cypress" />
|
/// <reference types="cypress" />
|
||||||
describe('Client notes', () => {
|
describe('Client notes', () => {
|
||||||
|
const obervationType = 'Packager';
|
||||||
|
const user = 'developer';
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.viewport(1280, 720);
|
cy.viewport(1920, 1080);
|
||||||
cy.login('developer');
|
cy.login('developer');
|
||||||
cy.visit('#/customer/1110/notes', {
|
cy.visit('#/customer/1102/notes');
|
||||||
timeout: 5000,
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
it('Should load layout', () => {
|
|
||||||
cy.get('.q-card').should('be.visible');
|
it('should add and filter notes by observation type', () => {
|
||||||
|
cy.selectOption("[data-cy='VnNotes-observation-type']", obervationType);
|
||||||
|
cy.dataCy('VnNotes-text-input').type('Test note {enter}');
|
||||||
|
|
||||||
|
cy.selectOption("[data-cy='VnNotes-observation-type-filter']", obervationType);
|
||||||
|
cy.get('.column.full-width')
|
||||||
|
.children()
|
||||||
|
.each(($el) => {
|
||||||
|
cy.dataCy('VnNotes-observation-type-badge').should(
|
||||||
|
'include.text',
|
||||||
|
obervationType,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should filter notes by user', () => {
|
||||||
|
cy.selectOption("[data-cy='VnNotes-user-filter']", user);
|
||||||
|
cy.get('.column.full-width')
|
||||||
|
.children()
|
||||||
|
.each(($el) => {
|
||||||
|
cy.dataCy('VnNotes-observation-type-badge').should(
|
||||||
|
'include.text',
|
||||||
|
obervationType,
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
describe('Vehicle Notes', () => {
|
describe('Vehicle Notes', () => {
|
||||||
const selectors = {
|
const selectors = {
|
||||||
addNoteInput: 'Add note here..._input',
|
addNoteInput: 'VnNotes-text-input',
|
||||||
saveNoteBtn: 'saveNote',
|
saveNoteBtn: 'saveNote',
|
||||||
deleteNoteBtn: 'notesRemoveNoteBtn',
|
deleteNoteBtn: 'notesRemoveNoteBtn',
|
||||||
noteCard: '.column.full-width > :nth-child(1) > .q-card__section--vert',
|
noteCard: '.column.full-width > :nth-child(1) > .q-card__section--vert',
|
||||||
|
|
Loading…
Reference in New Issue
Esta part no se gasta no?