0
0
Fork 0

refs 6105 claimNotes and VnNotes created

This commit is contained in:
Jorge Penadés 2023-08-16 09:03:41 +02:00
parent 96cfea8a41
commit ee7c2389b5
8 changed files with 342 additions and 11 deletions

View File

@ -0,0 +1,36 @@
<script setup>
import { useSession } from 'src/composables/useSession';
const $props = defineProps({
worker: { type: Number, required: true },
description: { type: String, default: null },
});
const session = useSession();
const token = session.getToken();
</script>
<template>
<div class="avatar-picture">
<QAvatar color="orange">
<QImg
:src="`/api/Images/user/160x160/${$props.worker}/download?access_token=${token}`"
spinner-color="white"
/>
</QAvatar>
<div class="description">
<slot name="description">
<p>
{{ $props.description }}
</p>
</slot>
</div>
</div>
</template>
<style lang="scss" scoped>
.avatar-picture {
display: flex;
flex-direction: column;
align-items: center;
.description {
text-align: center;
}
}
</style>

View File

@ -0,0 +1,156 @@
<script setup>
import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue';
import AvatarPicture from 'src/components/ui/AvatarPicture.vue';
import { toDateHour } from 'src/filters';
import { ref } from 'vue';
import axios from 'axios';
import FetchData from 'components/FetchData.vue';
import { useI18n } from 'vue-i18n';
const $props = defineProps({
id: { type: String, required: true },
url: { type: String, default: null },
filter: { type: Object, default: () => {} },
body: { type: Object, default: () => {} },
addNote: { type: Boolean, default: false },
});
const { t } = useI18n();
const notes = ref([]);
const noteModal = ref(false);
const newNote = ref('');
const claimObservationRef = ref();
function setNotes(data) {
notes.value = data;
}
async function fetch() {
const body = $props.body;
Object.assign(body, { text: newNote.value });
await axios.post($props.url, body);
claimObservationRef.value.fetch();
}
</script>
<template>
<FetchData
:url="$props.url"
:filter="$props.filter"
@on-fetch="setNotes"
auto-load
ref="claimObservationRef"
/>
<div class="notes" ref="notesContainer">
<QDialog v-model="noteModal" persistent>
<QCard class="note-dialog q-pa-sm">
<QCardSection class="note-dialog__header">
<div class="note-dialog__title">
<QIcon name="draft" class="note-dialog__title-icon" />
<div class="text-h6 note-dialog__title-text">
{{ t('Add note') }}
</div>
</div>
<QBtn icon="close" flat round dense v-close-popup />
</QCardSection>
<QCardSection class="note-dialog__content">
<QInput
autofocus
type="textarea"
:hint="t('Add note here...')"
filled
autogrow
v-model="newNote"
></QInput>
</QCardSection>
<QCardActions class="note-dialog__actions q-mr-md">
<QBtn
flat
:label="t('globals.close')"
color="primary"
v-close-popup
/>
<QBtn
:label="t('globals.save')"
color="primary"
v-close-popup
@click="fetch"
/>
</QCardActions>
</QCard>
</QDialog>
<QCard class="q-pa-md" v-for="(note, index) in notes" :key="index">
<div class="picture q-pa-sm">
<slot name="picture">
<AvatarPicture :worker="note.workerFk">
<template #description>
<span class="link">
{{ `${note.worker.firstName} ${note.worker.lastName}` }}
</span>
<WorkerDescriptorProxy :id="note.worker.id" />
</template>
</AvatarPicture>
</slot>
</div>
<div class="text">
<slot name="text">
{{ note.text }}
</slot>
</div>
<div class="actions">
<slot name="actions">
<div>
{{ toDateHour(note.created) }}
</div>
</slot>
</div>
</QCard>
<QBtn
v-if="addNote"
class="add-btn"
color="primary"
round
@click="noteModal = true"
>
<QIcon name="add" size="md"></QIcon>
</QBtn>
</div>
</template>
<style lang="scss" scoped>
.q-card {
min-width: 350px;
}
.note-dialog {
display: flex;
flex-direction: column;
.note-dialog__header {
width: 100%;
align-self: flex-start;
display: flex;
justify-content: space-between;
}
.note-dialog__title {
display: flex;
align-items: center;
gap: 5px;
color: $primary;
font-size: large;
}
.note-dialog__content {
width: 95%;
}
.note-dialog__actions {
align-self: flex-end;
}
}
.add-btn {
width: 70px;
height: 70px;
position: sticky;
left: 95%;
bottom: 2%;
}
</style>
<i18n>
es:
Add note here...: Añadir nota aquí...
Add note: Añadir nota
</i18n>

View File

@ -1,6 +1,7 @@
import toLowerCase from './toLowerCase';
import toDate from './toDate';
import toDateString from './toDateString';
import toDateHour from './toDateHour';
import toCurrency from './toCurrency';
import toPercentage from './toPercentage';
import toLowerCamel from './toLowerCamel';
@ -11,6 +12,7 @@ export {
toLowerCamel,
toDate,
toDateString,
toDateHour,
toCurrency,
toPercentage,
dashIfEmpty,

12
src/filters/toDateHour.js Normal file
View File

@ -0,0 +1,12 @@
export default function toDateHour(date) {
const dateHour = new Date(date).toLocaleDateString('es-ES', {
timeZone: 'Europe/Madrid',
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
});
return dateHour;
}

View File

@ -3,11 +3,12 @@ import LeftMenu from 'components/LeftMenu.vue';
import { getUrl } from 'composables/getUrl';
import VnSearchbar from 'src/components/ui/VnSearchbar.vue';
import { useStateStore } from 'stores/useStateStore';
import { computed, onMounted } from 'vue';
import { computed } from 'vue';
import { useI18n } from 'vue-i18n';
import { useRoute } from 'vue-router';
import ClaimDescriptor from './ClaimDescriptor.vue';
import { onMounted } from 'vue';
const stateStore = useStateStore();
const { t } = useI18n();
const route = useRoute();
@ -21,11 +22,6 @@ const $props = defineProps({
const entityId = computed(() => {
return $props.id || route.params.id;
});
const claimSections = [
{ name: 'Notes', url: '/note/index', icon: 'draft' },
{ name: 'Development', url: '/development', icon: 'vn:traceability' },
{ name: 'Action', url: '/action', icon: 'vn:actions' },
];
let salixUrl;
onMounted(async () => {
@ -49,17 +45,35 @@ onMounted(async () => {
<QSeparator />
<QList>
<QItem
v-for="section in claimSections"
:key="section.name"
active-class="text-primary"
:href="salixUrl + section.url"
:to="`/claim/${entityId}/notes`"
clickable
v-ripple
>
<QItemSection avatar>
<QIcon :name="section.icon" />
<QIcon name="draft" />
</QItemSection>
<QItemSection> {{ t(section.name) }} </QItemSection>
<QItemSection> {{ t('Notes') }} </QItemSection>
</QItem>
<QItem
active-class="text-primary"
clickable
v-ripple
:href="`${salixUrl}/development`"
>
<QItemSection avatar>
<QIcon name="vn:traceability"></QIcon>
</QItemSection>
<QItemSection>{{ t('Development') }}</QItemSection>
</QItem>
<QItem
active-class="text-primary"
clickable
v-ripple
:href="`${salixUrl}/action`"
>
<QItemSection avatar><QIcon name="vn:actions"></QIcon></QItemSection>
<QItemSection>{{ t('Action') }}</QItemSection>
</QItem>
</QList>
</QScrollArea>

View File

@ -0,0 +1,86 @@
<script setup>
import { useRoute } from 'vue-router';
import { useState } from 'src/composables/useState';
import VnNotes from 'src/components/ui/VnNotes.vue';
const route = useRoute();
const state = useState();
const user = state.getUser();
const id = route.params.id;
const claimFilter = {
order: 'created DESC',
where: { claimFk: id },
fields: ['created', 'workerFk', 'text'],
include: {
relation: 'worker',
scope: {
fields: ['id', 'firstName', 'lastName'],
},
},
};
const body = {
claimFk: id,
workerFk: user.value.id,
};
</script>
<template>
<div class="claim-notes">
<VnNotes
:add-note="true"
:id="id"
url="claimObservations"
:filter="claimFilter"
:body="body"
/>
</div>
</template>
<style lang="scss">
.q-card {
width: 100%;
max-width: 70em;
display: flex;
justify-content: space-between;
align-items: center;
flex-wrap: wrap;
}
.claim-notes {
.notes {
display: flex;
flex-direction: column;
align-items: center;
> * {
margin: 10px;
}
.text {
flex: 70%;
padding: 10px;
}
.picture {
flex: 15%;
.avatar-picture {
width: 70px;
}
}
.actions {
flex: 15%;
align-self: baseline;
text-align: center;
}
}
}
@media (max-width: 1150px) {
.claim-notes {
.text {
margin-top: 20px;
order: 3;
flex: 100%;
}
.actions {
text-align: end;
}
}
}
</style>

View File

@ -103,6 +103,15 @@ export default {
},
component: () => import('src/pages/Claim/Card/ClaimLog.vue'),
},
{
name: 'ClaimNotes',
path: 'notes',
meta: {
title: 'notes',
icon: 'vn:details',
},
component: () => import('src/pages/Claim/Card/ClaimNotes.vue'),
},
],
},
],

View File

@ -0,0 +1,16 @@
/// <reference types="cypress" />
describe('ClaimNotes', () => {
beforeEach(() => {
const claimId = 2;
cy.login('developer');
cy.visit(`/#/claim/${claimId}/notes`);
});
it('should add a new note', () => {
const message = 'This is a new message.';
cy.get('.add-btn').click();
cy.get('.note-dialog__content').type(message);
cy.get('.note-dialog__actions .q-btn:nth-child(2)').click();
cy.get('.notes > :nth-child(1) > .text').should('have.text', message);
});
});