added unread and read all function with endpoints for notifications

This commit is contained in:
2024-07-05 13:36:31 +00:00
committed by Julien Fastré
parent 2b09e1459c
commit 2d67843901
14 changed files with 805 additions and 377 deletions

View File

@@ -1,14 +1,16 @@
import {createApp} from "vue";
import { createApp } from "vue";
import NotificationReadToggle from "ChillMainAssets/vuejs/_components/Notification/NotificationReadToggle.vue";
import { _createI18n } from "ChillMainAssets/vuejs/_js/i18n";
import NotificationReadAllToggle from "ChillMainAssets/vuejs/_components/Notification/NotificationReadAllToggle.vue";
const i18n = _createI18n({});
window.addEventListener('DOMContentLoaded', function (e) {
document.querySelectorAll('.notification_toggle_read_status')
.forEach(function (el, i) {
createApp({
template: `<notification-read-toggle
window.addEventListener("DOMContentLoaded", function (e) {
document
.querySelectorAll(".notification_toggle_read_status")
.forEach(function (el, i) {
createApp({
template: `<notification-read-toggle
:notificationId="notificationId"
:buttonClass="buttonClass"
:buttonNoText="buttonNoText"
@@ -17,40 +19,45 @@ window.addEventListener('DOMContentLoaded', function (e) {
@markRead="onMarkRead"
@markUnread="onMarkUnread">
</notification-read-toggle>`,
components: {
NotificationReadToggle,
},
data() {
return {
notificationId: el.dataset.notificationId,
buttonClass: el.dataset.buttonClass,
buttonNoText: 'false' === el.dataset.buttonText,
showUrl: el.dataset.showButtonUrl,
isRead: 1 === Number.parseInt(el.dataset.notificationCurrentIsRead),
container: el.dataset.container
}
},
computed: {
getContainer() {
return document.querySelectorAll(`div.${this.container}`);
}
},
methods: {
onMarkRead() {
if (typeof this.getContainer[i] !== 'undefined') {
this.getContainer[i].classList.replace('read', 'unread');
} else { throw 'data-container attribute is missing' }
this.isRead = false;
},
onMarkUnread() {
if (typeof this.getContainer[i] !== 'undefined') {
this.getContainer[i].classList.replace('unread', 'read');
} else { throw 'data-container attribute is missing' }
this.isRead = true;
},
}
})
.use(i18n)
.mount(el);
});
components: {
NotificationReadToggle,
},
data() {
return {
notificationId: parseInt(el.dataset.notificationId),
buttonClass: el.dataset.buttonClass,
buttonNoText: "false" === el.dataset.buttonText,
showUrl: el.dataset.showButtonUrl,
isRead: 1 === Number.parseInt(el.dataset.notificationCurrentIsRead),
container: el.dataset.container,
};
},
computed: {
getContainer() {
return document.querySelectorAll(`div.${this.container}`);
},
},
methods: {
onMarkRead() {
if (typeof this.getContainer[i] !== "undefined") {
this.getContainer[i].classList.replace("read", "unread");
} else {
throw "data-container attribute is missing";
}
this.isRead = false;
},
onMarkUnread() {
if (typeof this.getContainer[i] !== "undefined") {
this.getContainer[i].classList.replace("unread", "read");
} else {
throw "data-container attribute is missing";
}
this.isRead = true;
},
},
})
.use(i18n)
.mount(el);
});
});

View File

@@ -0,0 +1,39 @@
import { createApp } from "vue";
import { _createI18n } from "../../vuejs/_js/i18n";
import NotificationReadAllToggle from "../../vuejs/_components/Notification/NotificationReadAllToggle.vue";
const i18n = _createI18n({});
document.addEventListener("DOMContentLoaded", function () {
const elements = document.querySelectorAll(".notification_all_read");
elements.forEach((element) => {
console.log('launch');
createApp({
template: `<notification-read-all-toggle @markAsRead="markAsRead" @markAsUnRead="markAsUnread"></notification-read-all-toggle>`,
components: {
NotificationReadAllToggle,
},
methods: {
markAsRead(id: number) {
const el = document.querySelector<HTMLDivElement>(`div.notification-status[data-notification-id="${id}"]`);
if (el === null) {
return;
}
el.classList.add('read');
el.classList.remove('unread');
},
markAsUnread(id: number) {
const el = document.querySelector<HTMLDivElement>(`div.notification-status[data-notification-id="${id}"]`);
if (el === null) {
return;
}
el.classList.remove('read');
el.classList.add('unread');
},
}
})
.use(i18n)
.mount(element);
});
});

View File

@@ -0,0 +1,50 @@
<template>
<div>
<button v-if="idsMarkedAsRead.length === 0"
class="btn btn-primary"
type="button"
@click="markAllRead"
>
<i class="fa fa-sm fa-envelope-open-o"></i> Marquer tout comme lu
</button>
<button v-else
class="btn btn-primary"
type="button"
@click="undo"
>
<i class="fa fa-sm fa-envelope-open-o"></i> Annuler
</button>
</div>
</template>
<script lang="ts" setup>
import { makeFetch } from "../../../lib/api/apiMethods";
import { ref } from "vue";
const emit = defineEmits<{
(e: 'markAsRead', id: number): void,
(e: 'markAsUnRead', id: number): void,
}>();
const idsMarkedAsRead = ref([] as number[]);
async function markAllRead() {
const ids: number[] = await makeFetch("POST", `/api/1.0/main/notification/mark/allread`, null);
for (let i of ids) {
idsMarkedAsRead.value.push(i);
emit('markAsRead', i);
}
}
async function undo() {
const touched: number[] = await makeFetch("POST", `/api/1.0/main/notification/mark/undoallread`, idsMarkedAsRead.value);
while (idsMarkedAsRead.value.length > 0) {
idsMarkedAsRead.value.pop();
}
for (let t of touched) {
emit('markAsUnRead', t);
}
};
</script>
<style lang="scss" scoped></style>

View File

@@ -1,47 +1,66 @@
<template>
<div :class="{'btn-group btn-group-sm float-end': isButtonGroup }"
role="group" aria-label="Notification actions">
<button v-if="isRead"
class="btn"
:class="overrideClass"
type="button"
:title="$t('markAsUnread')"
@click="markAsUnread"
>
<div
:class="{ 'btn-group btn-group-sm float-end': isButtonGroup }"
role="group"
aria-label="Notification actions"
>
<button
v-if="isRead"
class="btn"
:class="overrideClass"
type="button"
:title="$t('markAsUnread')"
@click="markAsUnread"
>
<i class="fa fa-sm fa-envelope-o"></i>
<span v-if="!buttonNoText" class="ps-2">
{{ $t('markAsUnread') }}
{{ $t("markAsUnread") }}
</span>
</button>
<button v-if="!isRead"
class="btn"
:class="overrideClass"
type="button"
:title="$t('markAsRead')"
@click="markAsRead"
>
<button
v-if="!isRead"
class="btn"
:class="overrideClass"
type="button"
:title="$t('markAsRead')"
@click="markAsRead"
>
<i class="fa fa-sm fa-envelope-open-o"></i>
<span v-if="!buttonNoText" class="ps-2">
{{ $t('markAsRead') }}
{{ $t("markAsRead") }}
</span>
</button>
<a v-if="isButtonGroup"
<a
v-if="isButtonGroup"
type="button"
class="btn btn-outline-primary"
:href="showUrl"
:title="$t('action.show')"
>
>
<i class="fa fa-sm fa-comment-o"></i>
</a>
<!-- "Mark All Read" button -->
<button
v-if="showMarkAllButton"
class="btn"
:class="overrideClass"
type="button"
:title="$t('markAllRead')"
@click="markAllRead"
>
<i class="fa fa-sm fa-envelope-o"></i>
<span v-if="!buttonNoText" class="ps-2">
{{ $t("markAllRead") }}
</span>
</button>
</div>
</template>
<script>
import { makeFetch } from 'ChillMainAssets/lib/api/apiMethods.ts';
import { makeFetch } from "ChillMainAssets/lib/api/apiMethods.ts";
export default {
name: "NotificationReadToggle",
@@ -57,7 +76,7 @@ export default {
// Optional
buttonClass: {
required: false,
type: String
type: String,
},
buttonNoText: {
required: false,
@@ -65,14 +84,14 @@ export default {
},
showUrl: {
required: false,
type: String
}
type: String,
},
},
emits: ['markRead', 'markUnread'],
emits: ["markRead", "markUnread"],
computed: {
/// [Option] override default button appearance (btn-misc)
overrideClass() {
return this.buttonClass ? this.buttonClass : 'btn-misc'
return this.buttonClass ? this.buttonClass : "btn-misc";
},
/// [Option] don't display text on button
buttonHideText() {
@@ -82,31 +101,48 @@ export default {
// When passed, the component return a button-group with 2 buttons.
isButtonGroup() {
return this.showUrl;
}
},
},
methods: {
markAsUnread() {
makeFetch('POST', `/api/1.0/main/notification/${this.notificationId}/mark/unread`, []).then(response => {
this.$emit('markRead', { notificationId: this.notificationId });
})
makeFetch(
"POST",
`/api/1.0/main/notification/${this.notificationId}/mark/unread`,
[]
).then((response) => {
this.$emit("markRead", {notificationId: this.notificationId});
});
},
markAsRead() {
makeFetch('POST', `/api/1.0/main/notification/${this.notificationId}/mark/read`, []).then(response => {
this.$emit('markUnread', { notificationId: this.notificationId });
})
makeFetch(
"POST",
`/api/1.0/main/notification/${this.notificationId}/mark/read`,
[]
).then((response) => {
this.$emit("markUnread", {
notificationId: this.notificationId,
});
});
},
markAllRead() {
makeFetch(
"POST",
`/api/1.0/main/notification/markallread`,
[]
).then((response) => {
this.$emit("markAllRead");
});
},
},
i18n: {
messages: {
fr: {
markAsUnread: 'Marquer comme non-lu',
markAsRead: 'Marquer comme lu'
}
}
}
}
markAsUnread: "Marquer comme non-lu",
markAsRead: "Marquer comme lu",
},
},
},
};
</script>
<style lang="scss">
</style>
<style lang="scss"></style>