Chamilo is a learning management system focused on ease of use and accessibility
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
chamilo-lms/assets/vue/views/message/MessageList.vue

433 lines
10 KiB

<template>
<div class="section-header section-header--h2">
<h2
class="mr-auto"
v-text="title"
/>
<BaseButton
icon="email-plus"
only-icon
type="black"
@click="goToCompose"
/>
<BaseButton
:disabled="isLoading"
icon="refresh"
only-icon
type="black"
@click="refreshMessages"
/>
<BaseButton
:disabled="0 === selectedItems.length || isLoading"
icon="delete"
only-icon
type="black"
@click="showDlgConfirmDeleteMultiple"
/>
<BaseButton
:disabled="0 === selectedItems.length || isLoading"
icon="multiple-marked"
only-icon
popup-identifier="course-messages-list-tmenu"
type="black"
@click="mToggleMessagesList"
/>
<BaseMenu
id="course-messages-list-tmenu"
ref="mMessageList"
:model="mItemsMarkAs"
/>
</div>
<hr />
<div class="message-container">
<div class="message-actions">
<BaseButton
:label="t('Inbox')"
icon="inbox"
type="black"
@click="showInbox"
/>
<BaseButton
:label="t('Unread')"
icon="email-unread"
type="black"
@click="showUnread"
/>
<BaseButton
:label="t('Sent')"
icon="sent"
type="black"
@click="showSent"
/>
<BaseButton
v-for="tag in tags"
:key="tag.id"
:label="tag.tag"
icon="tag-outline"
type="black"
@click="showInboxByTag(tag)"
/>
</div>
<DataTable
ref="dtMessages"
v-model:selection="selectedItems"
:loading="isLoading"
:row-class="rowClass"
:rows="initialRowsPerPage"
:rows-per-page-options="[10, 20, 50]"
:total-records="totalItems"
:value="items"
current-page-report-template="{first} to {last} of {totalRecords}"
data-key="@id"
lazy
paginator
paginator-template="RowsPerPageDropdown FirstPageLink PrevPageLink CurrentPageReport NextPageLink LastPageLink"
responsive-layout="scroll"
sort-field="sendDate"
:sort-order="-1"
@page="onPage($event)"
@row-click="onRowClick"
@sort="sortingChanged($event)"
>
<Column selection-mode="multiple" />
<Column :header="t('From')">
<template #body="slotProps">
<div
v-if="slotProps.data.sender"
class="flex items-center gap-2"
>
<BaseUserAvatar :image-url="slotProps.data.sender.illustrationUrl" />
{{ slotProps.data.sender.username }}
</div>
<div
v-else
v-t="'No sender'"
/>
</template>
</Column>
<Column :header="t('Title')" :sortable="true" field="title">
<template #body="slotProps">
<div class="flex gap-2 pb-2">
{{ slotProps.data.title }}
</div>
<BaseTag
v-for="tag in findMyReceiver(slotProps.data)?.tags"
:key="tag.id"
:label="tag.tag"
type="info"
/>
</template>
</Column>
<Column :header="t('Send date')" :sortable="true" field="sendDate">
<template #body="slotProps">
{{ relativeDatetime(slotProps.data.sendDate) }}
</template>
</Column>
<Column :header="t('Actions')">
<template #body="slotProps">
<BaseButton
icon="delete"
size="small"
type="danger"
@click="showDlgConfirmDeleteSingle(slotProps)"
/>
</template>
</Column>
</DataTable>
</div>
</template>
<script setup>
import { computed, onMounted, ref } from "vue"
import { useStore } from "vuex"
import { useI18n } from "vue-i18n"
import { useRoute, useRouter } from "vue-router"
import { useFormatDate } from "../../composables/formatDate"
import BaseButton from "../../components/basecomponents/BaseButton.vue"
import BaseMenu from "../../components/basecomponents/BaseMenu.vue"
import BaseUserAvatar from "../../components/basecomponents/BaseUserAvatar.vue"
import BaseTag from "../../components/basecomponents/BaseTag.vue"
import DataTable from "primevue/datatable"
import Column from "primevue/column"
import { useConfirm } from "primevue/useconfirm"
import { useQuery } from "@vue/apollo-composable"
import { MESSAGE_STATUS_DELETED, MESSAGE_TYPE_INBOX } from "../../components/message/constants"
import { GET_USER_MESSAGE_TAGS } from "../../graphql/queries/MessageTag"
import { useNotification } from "../../composables/notification"
import { useMessageRelUserStore } from "../../store/messageRelUserStore"
import SocialSideMenu from "../../components/social/SocialSideMenu.vue";
const route = useRoute()
const router = useRouter()
const store = useStore()
const { t } = useI18n()
const confirm = useConfirm()
const notification = useNotification()
const messageRelUserStore = useMessageRelUserStore()
const { relativeDatetime } = useFormatDate()
const user = computed(() => store.getters["security/getUser"])
const mItemsMarkAs = ref([
{
label: t("As read"),
command: () => {
const promises = selectedItems.value.map((message) => {
const myReceiver = findMyReceiver(message)
if (!myReceiver) {
return undefined
}
myReceiver.read = true
return store.dispatch("messagereluser/update", myReceiver)
})
Promise.all(promises)
.then(() => messageRelUserStore.findUnreadCount())
.catch((e) => notification.showErrorNotification(e))
.finally(() => (selectedItems.value = []))
},
},
{
label: t("As unread"),
command: async () => {
const promises = selectedItems.value.map((message) => {
const myReceiver = findMyReceiver(message)
if (!myReceiver) {
return undefined
}
myReceiver.read = false
return store.dispatch("messagereluser/update", myReceiver)
})
Promise.all(promises)
.then(() => messageRelUserStore.findUnreadCount())
.catch((e) => notification.showErrorNotification(e))
.finally(() => (selectedItems.value = []))
},
},
])
const mMessageList = ref(null)
const mToggleMessagesList = (event) => mMessageList.value.toggle(event)
const dtMessages = ref(null)
const initialRowsPerPage = 10
const goToCompose = () => {
router.push({
name: "MessageCreate",
query: route.query,
})
}
const { result: messageTagsResult } = useQuery(
GET_USER_MESSAGE_TAGS,
{ user: user.value["@id"] },
{ fetchPolicy: "cache-and-network" },
)
const tags = computed(() => messageTagsResult.value?.messageTags?.edges.map(({ node }) => node) ?? [])
const items = computed(() => store.getters["message/getRecents"])
const isLoading = computed(() => store.getters["message/isLoading"])
const totalItems = computed(() => store.getters["message/getTotalItems"])
const title = ref(null)
const selectedItems = ref([])
const rowClass = (data) => {
const myReceiver = findMyReceiver(data)
if (!myReceiver) {
return []
}
return [{ "font-semibold": !myReceiver.read }]
}
let fetchPayload = {}
function loadMessages(reset = true) {
if (reset) {
store.dispatch("message/resetList")
dtMessages.value.resetPage()
}
store.dispatch("message/fetchAll", fetchPayload)
}
function showInbox() {
title.value = t("Inbox")
fetchPayload = {
msgType: MESSAGE_TYPE_INBOX,
"receivers.receiver": user.value["@id"],
"order[sendDate]": "desc",
itemsPerPage: initialRowsPerPage,
page: 1,
}
loadMessages()
}
function showInboxByTag(tag) {
title.value = tag.tag
fetchPayload = {
msgType: MESSAGE_TYPE_INBOX,
"receivers.receiver": user.value["@id"],
"receivers.tags.tag": tag.tag,
"order[sendDate]": "desc",
itemsPerPage: initialRowsPerPage,
page: 1,
}
loadMessages()
}
function showUnread() {
title.value = t("Unread")
fetchPayload = {
msgType: MESSAGE_TYPE_INBOX,
"receivers.receiver": user.value["@id"],
"order[sendDate]": "desc",
"receivers.read": false,
itemsPerPage: initialRowsPerPage,
page: 1,
}
loadMessages()
}
function showSent() {
title.value = t("Sent")
fetchPayload = {
msgType: MESSAGE_TYPE_INBOX,
sender: user.value["@id"],
"order[sendDate]": "desc",
itemsPerPage: initialRowsPerPage,
page: 1,
}
loadMessages()
}
function refreshMessages() {
fetchPayload.itemsPerPage = initialRowsPerPage
fetchPayload.page = 1
loadMessages()
}
function onPage(event) {
delete fetchPayload["order[title]"]
delete fetchPayload["order[sendDate]"]
fetchPayload.page = event.page + 1
fetchPayload.itemsPerPage = event.rows
fetchPayload[`order[${event.sortField}]`] = event.sortOrder === -1 ? "desc" : "asc"
loadMessages(false)
}
function onRowClick({ data }) {
router.push({
name: "MessageShow",
query: {
id: data["@id"],
},
})
}
function sortingChanged(event) {
delete fetchPayload["order[title]"]
delete fetchPayload["order[sendDate]"]
fetchPayload[`order[${event.sortField}]`] = event.sortOrder === -1 ? "desc" : "asc"
loadMessages(true)
}
function findMyReceiver(message) {
const receivers = [...message.receiversTo, ...message.receiversCc]
return receivers.find(({ receiver }) => receiver["@id"] === user.value["@id"])
}
async function deleteMessage(message) {
if (message.sender["@id"] === user.value["@id"]) {
message.status = MESSAGE_STATUS_DELETED
await store.dispatch("message/update", message)
} else {
const myReceiver = findMyReceiver(message)
if (myReceiver) {
await store.dispatch("messagereluser/del", myReceiver)
}
}
}
function showDlgConfirmDeleteSingle({ data }) {
confirm.require({
header: t("Confirmation"),
message: t(`Are you sure you want to delete "${data.title}"?`),
accept: async () => {
await deleteMessage(data)
loadMessages()
notification.showSuccessNotification(t("Message deleted"))
},
})
}
function showDlgConfirmDeleteMultiple() {
confirm.require({
header: t("Confirmation"),
message: t("Are you sure you want to delete the selected items?"),
accept: async () => {
for (const message of selectedItems.value) {
await deleteMessage(message)
}
loadMessages()
notification.showSuccessNotification(t("Messages deleted"))
selectedItems.value = []
},
})
}
onMounted(() => {
showInbox()
})
</script>