Merge pull request 'fixes #4797 Seccion Worker/Notification' (!51) from 4797-worker-notification-selector into dev
gitea/salix-front/pipeline/head This commit looks good Details

Reviewed-on: #51
Reviewed-by: Alex Moreno <alexm@verdnatura.es>
This commit is contained in:
Alexandre Riera 2023-05-15 09:42:16 +00:00
commit a1ca8c822f
6 changed files with 294 additions and 1 deletions

View File

@ -361,6 +361,7 @@ export default {
list: 'List', list: 'List',
basicData: 'Basic data', basicData: 'Basic data',
summary: 'Summary', summary: 'Summary',
notifications: 'Notifications',
}, },
list: { list: {
name: 'Name', name: 'Name',
@ -394,6 +395,12 @@ export default {
role: 'Role', role: 'Role',
sipExtension: 'Extension', sipExtension: 'Extension',
}, },
notificationsManager: {
activeNotifications: 'Active notifications',
availableNotifications: 'Available notifications',
subscribed: 'Subscribed to the notification',
unsubscribed: 'Unsubscribed from the notification',
},
imageNotFound: 'Image not found', imageNotFound: 'Image not found',
}, },
wagon: { wagon: {

View File

@ -361,6 +361,7 @@ export default {
list: 'Listado', list: 'Listado',
basicData: 'Datos básicos', basicData: 'Datos básicos',
summary: 'Resumen', summary: 'Resumen',
notifications: 'Notificaciones',
}, },
list: { list: {
name: 'Nombre', name: 'Nombre',
@ -394,6 +395,12 @@ export default {
role: 'Rol', role: 'Rol',
sipExtension: 'Extensión', sipExtension: 'Extensión',
}, },
notificationsManager: {
activeNotifications: 'Notificaciones activas',
availableNotifications: 'Notificaciones disponibles',
subscribed: 'Se ha suscrito a la notificación',
unsubscribed: 'Se ha dado de baja de la notificación',
},
imageNotFound: 'No se ha encontrado la imagen', imageNotFound: 'No se ha encontrado la imagen',
}, },
wagon: { wagon: {

View File

@ -0,0 +1,142 @@
<script setup>
import axios from 'axios';
import { useQuasar } from 'quasar';
import { computed, onMounted, onUpdated, ref } from 'vue';
import { useI18n } from 'vue-i18n';
import { useRoute } from 'vue-router';
const $props = defineProps({
id: {
type: Number,
required: false,
default: null,
},
});
const entityId = computed(() => $props.id || route.params.id);
onMounted(() => fetch());
onUpdated(() => fetch());
const route = useRoute();
const { t } = useI18n();
const quasar = useQuasar();
const notifications = ref([]);
async function fetch() {
try {
await axios
.get(`NotificationSubscriptions/${entityId.value}/getList`)
.then(async (res) => {
if (res.data) {
notifications.value = res.data;
}
});
} catch (e) {
//
}
}
async function disableNotification(notification) {
await axios
.delete(`NotificationSubscriptions/${notification.id}`)
.catch(() => (notification.active = true))
.then((res) => {
if (res.data) {
notification.id = null;
notification.active = false;
quasar.notify({
type: 'positive',
message: t('worker.notificationsManager.unsubscribed'),
});
}
});
}
async function toggleNotification(notification) {
if (!notification.active) {
await disableNotification(notification);
} else {
await axios
.post(`NotificationSubscriptions`, {
notificationFk: notification.notificationFk,
userFk: entityId.value,
})
.catch(() => (notification.active = false))
.then((res) => {
if (res.data) {
notification.id = res.data.id;
quasar.notify({
type: 'positive',
message: t('worker.notificationsManager.subscribed'),
});
}
});
}
}
</script>
<template>
<QPage>
<QCard class="q-pa-md">
<QList>
<div
v-show="
notifications.filter(
(notification) => notification.active == true
).length
"
>
<QItemLabel header class="text-h6">
{{ t('worker.notificationsManager.activeNotifications') }}
</QItemLabel>
<QItem>
<div
v-for="notification in notifications.filter(
(notification) => notification.active == true
)"
:key="notification.id"
>
<QChip
:key="notification.id"
:label="notification.name"
text-color="white"
color="primary"
class="q-mr-sm"
removable
@remove="disableNotification(notification)"
/>
</div>
</QItem>
</div>
<div v-show="notifications.length">
<QItemLabel header class="text-h6">
{{ t('worker.notificationsManager.availableNotifications') }}
</QItemLabel>
<div class="row">
<QItem
class="col-3"
:key="notification.notificationFk"
v-for="notification in notifications"
>
<QItemSection>
<QItemLabel>{{ notification.name }}</QItemLabel>
<QItemLabel caption>{{
notification.description
}}</QItemLabel>
</QItemSection>
<QItemSection side top>
<QToggle
checked-icon="check"
unchecked-icon="close"
indeterminate-icon="block"
v-model="notification.active"
@update:model-value="toggleNotification(notification)"
/>
</QItemSection>
</QItem>
</div>
</div>
</QList>
</QCard>
</QPage>
</template>

View File

@ -11,7 +11,7 @@ export default {
redirect: { name: 'WorkerMain' }, redirect: { name: 'WorkerMain' },
menus: { menus: {
main: ['WorkerList'], main: ['WorkerList'],
card: [], card: ['WorkerNotificationsManager'],
}, },
children: [ children: [
{ {
@ -42,9 +42,19 @@ export default {
path: 'summary', path: 'summary',
meta: { meta: {
title: 'summary', title: 'summary',
icon: 'launch',
}, },
component: () => import('src/pages/Worker/Card/WorkerSummary.vue'), component: () => import('src/pages/Worker/Card/WorkerSummary.vue'),
}, },
{
name: 'WorkerNotificationsManager',
path: 'notifications',
meta: {
title: 'notifications',
icon: 'notifications',
},
component: () => import('src/pages/Worker/Card/WorkerNotificationsManager.vue'),
},
], ],
}, },
], ],

View File

@ -0,0 +1,27 @@
describe('WorkerNotificationsManager', () => {
beforeEach(() => {
const workerId = 1110;
cy.viewport(1280, 720);
cy.login('salesBoss');
cy.visit(`/#/worker/${workerId}/notifications`);
});
it('should unsubscribe 2 notifications, check the unsubscription has been saved, subscribe to other one and should check the data has been saved', () => {
cy.get('.q-chip').should('have.length', 3);
cy.get('.q-toggle__thumb').eq(0).click();
cy.get('.q-notification__message').should('have.text', 'Unsubscribed from the notification');
cy.get('.q-chip > .q-icon').eq(0).click();
cy.reload();
cy.get('.q-chip').should('have.length', 1);
cy.get('.q-toggle__thumb').should('have.length', 3).eq(0).click();
cy.get('.q-notification__message').should('have.text', 'Subscribed to the notification');
cy.get('.q-toggle__thumb').should('have.length', 3).eq(1).click();
cy.get('.q-notification__message').should('have.text', 'Subscribed to the notification');
cy.reload();
cy.get('.q-chip').should('have.length', 3);
});
});

View File

@ -0,0 +1,100 @@
import { vi, describe, expect, it, beforeAll, afterEach } from 'vitest';
import { createWrapper, axios } from 'app/test/vitest/helper';
import WorkerNotificationsManager from 'src/pages/Worker/Card/WorkerNotificationsManager.vue';
describe('WorkerNotificationsManager', () => {
let vm;
const entityId = 1110;
beforeAll(() => {
vm = createWrapper(WorkerNotificationsManager, {
propsData: {
id: entityId,
},
}).vm;
});
afterEach(() => {
vi.clearAllMocks();
});
describe('fetch()', () => {
it('should fetch notification subscriptions and role mappings', async () => {
vi.spyOn(axios, 'get')
.mockResolvedValueOnce({
data: [
{
id: 1,
name: 'Name 1',
description: 'Description 1',
notificationFk: 1,
active: true
},
],
});
await vm.fetch();
expect(axios.get).toHaveBeenCalledWith(`NotificationSubscriptions/${entityId}/getList`);
expect(vm.notifications).toEqual([
{
id: 1,
notificationFk: 1,
name: 'Name 1',
description: 'Description 1',
active: true,
},
]);
});
});
describe('disableNotification()', () => {
it('should disable the notification', async () => {
vi.spyOn(axios, 'delete').mockResolvedValue({ data: { count: 1 } });
vi.spyOn(vm.quasar, 'notify');
const subscriptionId = 1;
vm.notifications = [{ id: 1, active: true }];
await vm.disableNotification(vm.notifications[0]);
expect(axios.delete).toHaveBeenCalledWith(
`NotificationSubscriptions/${subscriptionId}`
);
expect(vm.notifications[0].id).toBeNull();
expect(vm.notifications[0].id).toBeFalsy();
expect(vm.quasar.notify).toHaveBeenCalledWith(
expect.objectContaining({ type: 'positive' })
);
});
});
describe('toggleNotification()', () => {
it('should activate the notification', async () => {
vi.spyOn(axios, 'post').mockResolvedValue({
data: { id: 1, notificationFk: 1 },
});
vm.notifications = [{ id: null, active: true, notificationFk: 1 }];
await vm.toggleNotification(vm.notifications[0]);
expect(axios.post).toHaveBeenCalledWith('NotificationSubscriptions', {
notificationFk: 1,
userFk: entityId,
});
expect(vm.notifications[0].id).toBe(1);
expect(vm.notifications[0].active).toBeTruthy();
expect(vm.quasar.notify).toHaveBeenCalledWith(
expect.objectContaining({ type: 'positive' })
);
});
it('should disable the notification', async () => {
vi.spyOn(vm, 'disableNotification');
vm.notifications = [{ id: 1, active: false, notificationFk: 1 }];
await vm.toggleNotification(vm.notifications[0]);
expect(vm.notifications[0].id).toBe(null);
expect(vm.notifications[0].active).toBeFalsy();
});
});
});