Refonte du système de notifications : passage aux notifications dérivées
Remplace le système de notifications stockées par un système de providers qui dérivent les notifications des données existantes (commentaires, réponses, demandes de projet, demandes de rendez-vous, validations de brief). - Ajout du NotificationCollector et de l'interface NotificationProvider - Création de 5 providers : Comment, Reply, ProjectRequest, AppointmentRequest, Content - Métadonnées de notifications stockées directement sur les entités source - Nouvelles routes mark-as-read et mark-all-read - Mise à jour du frontend pour le nouveau système - Route de migration pour les données existantes Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
c68b51f639
commit
a7d315942a
26 changed files with 1406 additions and 137 deletions
|
|
@ -163,6 +163,34 @@ export const useApiStore = defineStore("api", () => {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Marque une notification comme lue.
|
||||
* @param {Object} notification - L'objet notification complet (avec type, id, _file, _projectUri, etc.)
|
||||
*/
|
||||
async function markNotificationRead(notification) {
|
||||
const headers = {
|
||||
method: "POST",
|
||||
body: JSON.stringify(notification),
|
||||
};
|
||||
try {
|
||||
const response = await fetch("/mark-notification-read.json", headers);
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
const data = await response.json();
|
||||
if (data.status === "error") {
|
||||
throw new Error(data.message);
|
||||
}
|
||||
// Mettre à jour le store local
|
||||
userStore.markNotificationRead(notification.id, notification.project?.uri || notification._projectUri);
|
||||
return data;
|
||||
} catch (error) {
|
||||
console.error("Erreur lors du marquage de la notification:", error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// Ancienne fonction gardée pour rétro-compatibilité
|
||||
async function readNotification(notificationId, projectId) {
|
||||
const headers = {
|
||||
method: "POST",
|
||||
|
|
@ -215,6 +243,31 @@ export const useApiStore = defineStore("api", () => {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Marque toutes les notifications comme lues (nouveau système).
|
||||
*/
|
||||
async function markAllNotificationsRead() {
|
||||
try {
|
||||
const response = await fetch("/mark-all-notifications-read.json", {
|
||||
method: "POST",
|
||||
});
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
const data = await response.json();
|
||||
if (data.status === "error") {
|
||||
throw new Error(data.message);
|
||||
}
|
||||
userStore.markAllNotificationsRead();
|
||||
console.log("Toutes les notifications ont été marquées comme lues.");
|
||||
return data;
|
||||
} catch (error) {
|
||||
console.error("Erreur lors du marquage de toutes les notifications:", error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// Ancienne fonction gardée pour rétro-compatibilité
|
||||
async function readAllNotifications() {
|
||||
try {
|
||||
const response = await fetch("/read-all-notifications.json");
|
||||
|
|
@ -243,6 +296,10 @@ export const useApiStore = defineStore("api", () => {
|
|||
updateComment,
|
||||
deleteComment,
|
||||
replyComment,
|
||||
// Nouvelles fonctions
|
||||
markNotificationRead,
|
||||
markAllNotificationsRead,
|
||||
// Anciennes fonctions (rétro-compatibilité)
|
||||
readNotification,
|
||||
readAllNotifications,
|
||||
validateBrief,
|
||||
|
|
|
|||
|
|
@ -11,48 +11,76 @@ export const useUserStore = defineStore('user', () => {
|
|||
|
||||
const { projects } = storeToRefs(useProjectsStore());
|
||||
|
||||
/**
|
||||
* Liste des notifications agrégées depuis tous les projets.
|
||||
* Les notifications sont maintenant dérivées côté backend avec isRead pré-calculé.
|
||||
*/
|
||||
const notifications = computed(() => {
|
||||
return projects.value?.flatMap((project) => {
|
||||
if (!projects.value || !user.value) return [];
|
||||
|
||||
return projects.value.flatMap((project) => {
|
||||
if (!project.notifications) return [];
|
||||
|
||||
return project.notifications
|
||||
.filter((notification) => notification.author.uuid !== user.value.uuid)
|
||||
.map((notification) => ({
|
||||
...notification,
|
||||
project: project,
|
||||
isRead: notification.readby?.includes(user.value.uuid),
|
||||
}));
|
||||
return project.notifications.map((notification) => ({
|
||||
...notification,
|
||||
project: project,
|
||||
// isRead est maintenant fourni par le backend
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
||||
function readNotification(notificationId, projectId) {
|
||||
console.log('Read notification', notificationId, projectId);
|
||||
/**
|
||||
* Marque une notification comme lue dans le store local.
|
||||
* @param {string} notificationId - L'ID de la notification
|
||||
* @param {string} projectUri - L'URI du projet (optionnel, pour retrouver le projet)
|
||||
*/
|
||||
function markNotificationRead(notificationId, projectUri = null) {
|
||||
if (!user.value?.uuid) return;
|
||||
|
||||
projects.value = projects.value.map((project) => {
|
||||
// Si projectUri fourni, cibler le bon projet
|
||||
if (projectUri && project.uri !== projectUri && `/${project.uri}` !== projectUri) {
|
||||
return project;
|
||||
}
|
||||
|
||||
return {
|
||||
...project,
|
||||
notifications: (project.notifications || []).map((notification) =>
|
||||
notification.id === notificationId
|
||||
? {
|
||||
...notification,
|
||||
isRead: true,
|
||||
readby: [...new Set([...(notification.readby || []), user.value.uuid])],
|
||||
}
|
||||
: notification
|
||||
),
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Marque toutes les notifications comme lues dans le store local.
|
||||
*/
|
||||
function markAllNotificationsRead() {
|
||||
if (!user.value?.uuid) return;
|
||||
|
||||
projects.value = projects.value.map((project) => ({
|
||||
...project,
|
||||
notifications:
|
||||
project.uuid === projectId || project.uri === projectId
|
||||
? project.notifications.map((notification) =>
|
||||
notification.id === notificationId
|
||||
? {
|
||||
...notification,
|
||||
readby: [
|
||||
...new Set([...notification.readby, user.value.uuid]),
|
||||
],
|
||||
}
|
||||
: notification
|
||||
)
|
||||
: project.notifications,
|
||||
notifications: (project.notifications || []).map((notification) => ({
|
||||
...notification,
|
||||
isRead: true,
|
||||
readby: [...new Set([...(notification.readby || []), user.value.uuid])],
|
||||
})),
|
||||
}));
|
||||
}
|
||||
|
||||
// Anciennes fonctions gardées pour rétro-compatibilité
|
||||
function readNotification(notificationId, projectId) {
|
||||
markNotificationRead(notificationId, projectId);
|
||||
}
|
||||
|
||||
function readAllNotifications() {
|
||||
projects.value = projects.value.map((project) => ({
|
||||
...project,
|
||||
notifications: project.notifications.map((notification) => ({
|
||||
...notification,
|
||||
readby: [...new Set([...notification.readby, user.value.uuid])],
|
||||
})),
|
||||
}));
|
||||
markAllNotificationsRead();
|
||||
}
|
||||
|
||||
function canEditComment(comment) {
|
||||
|
|
@ -63,6 +91,10 @@ export const useUserStore = defineStore('user', () => {
|
|||
user,
|
||||
isLogged,
|
||||
notifications,
|
||||
// Nouvelles fonctions
|
||||
markNotificationRead,
|
||||
markAllNotificationsRead,
|
||||
// Anciennes fonctions (rétro-compatibilité)
|
||||
readNotification,
|
||||
readAllNotifications,
|
||||
canEditComment,
|
||||
|
|
|
|||
|
|
@ -119,14 +119,24 @@ function changeTab(newValue) {
|
|||
|
||||
function readAll() {
|
||||
try {
|
||||
api.readAllNotifications();
|
||||
api.markAllNotificationsRead();
|
||||
} catch (error) {
|
||||
console.log('Could not read all notifications : ', error);
|
||||
}
|
||||
}
|
||||
|
||||
// Functions
|
||||
function handleNotificationClick(notification) {
|
||||
async function handleNotificationClick(notification) {
|
||||
// Marquer la notification comme lue
|
||||
if (!notification.isRead) {
|
||||
try {
|
||||
await api.markNotificationRead(notification);
|
||||
} catch (error) {
|
||||
console.log('Could not mark notification as read:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// Naviguer vers la cible
|
||||
const href =
|
||||
notification.type === 'appointment-request'
|
||||
? getHref(notification) + '?tab=designToLight'
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue