From 90b4fa6ad3aac81cb6dbd547db0060f5fda322b3 Mon Sep 17 00:00:00 2001 From: Aditya Waghamare Date: Tue, 6 Oct 2026 20:09:29 +0530 Subject: [PATCH] fix(notifications): add filtering support for notifications in NotificationBox - Closes #201 - Files: web/app/components/NotificationBox.vue Signed-off-by: Aditya Waghamare --- web/app/components/NotificationBox.vue | 358 ++++++++----------------- 1 file changed, 115 insertions(+), 243 deletions(-) diff --git a/web/app/components/NotificationBox.vue b/web/app/components/NotificationBox.vue index 1c460768..6d6325e5 100644 --- a/web/app/components/NotificationBox.vue +++ b/web/app/components/NotificationBox.vue @@ -21,16 +21,25 @@ const { fetchDocumentTree } = useDocumentAPI() const wsState = useWebSocketStateStore() let unsubWsNotifications: (() => void) | null | undefined = null +const filterMode = ref<"all" | "unread" | "read">("all") + const { fetchOrganization } = useAuthSession() const fetchNotificationCount = useFetchNotificationCount({ read: false }) const fetchNotifications = useFetchManyNotifications({ limit: 100, page: 1 }) // static for now -const notifications = computed( - () => fetchNotifications.data.value?.notifications ?? [], -) +const notifications = computed(() => { + const all = fetchNotifications.data.value?.notifications ?? [] + if (filterMode.value === "unread") { + return all.filter((n) => !n.read) + } + if (filterMode.value === "read") { + return all.filter((n) => n.read) + } + return all +}) const hasUnreadNotifications = computed(() => - notifications.value.some((n) => !n.read), + (fetchNotifications.data.value?.notifications ?? []).some((n) => !n.read), ) onMounted(() => { @@ -95,8 +104,7 @@ async function buildNotificationHref(notification: Notification) { return metadata.blockId ? `${baseHref}#${metadata.blockId}` : baseHref } case NotificationCode.DocumentNewComment: { - const metadata = - notification.metadata as NotificationMetadataDocumentNewComment + const metadata = notification.metadata as NotificationMetadataDocumentNewComment const documentName = findDocumentName(metadata.documentId) || "" const docSlug = createNameSlugWithId(documentName, metadata.documentId) @@ -123,265 +131,129 @@ async function buildNotificationHref(notification: Notification) { } } -function findNotificationDocumentName(notification: Notification) { - return ( - findDocumentName(notification.metadata.documentId) || - t("notification.document-fallback") - ) -} - -function findNotificationIcon(notification: Notification) { - switch (notification.code) { - case NotificationCode.DocumentReviewRequest: - return "lucide:file-user" - case NotificationCode.DocumentHookTrigerred: - case NotificationCode.DocumentHookNeedsAttention: - switch ( - (notification.metadata as NotificationMetadataDocumentHookTriggered) - .type - ) { - case DocumentHookType.URLWatcher: - return "mingcute:earth-2-line" - case DocumentHookType.GitHubTracking: - return "simple-icons:github" - case DocumentHookType.ScheduledReminder: - return "lucide:timer" - case DocumentHookType.ContainerImageWatcher: - return "lucide:container" - default: - // a newer server may send a hook type this build does - // not know - return "lucide:file-exclamation-point" - } - case NotificationCode.DocumentNewComment: - return "mingcute:message-4-fill" - case NotificationCode.DocumentNewCommentReply: - return "mingcute:message-4-fill" - default: - return "lucide:file-exclamation-point" - } -} - -function buildNotificationDescription(notification: Notification) { - switch (notification.code) { - case NotificationCode.DocumentReviewRequest: { - return t("notification.messages.document-review-request-description") - } - case NotificationCode.DocumentHookTrigerred: - case NotificationCode.DocumentHookNeedsAttention: { - const metadata = - notification.metadata as NotificationMetadataDocumentHookTriggered - let hook = t("notification.hook-fallback") - - switch (metadata.type) { - case DocumentHookType.URLWatcher: - hook = t("editor.hooks.url-watcher.title") - break - case DocumentHookType.GitHubTracking: - hook = t("editor.hooks.github-tracking.title") - break - case DocumentHookType.ScheduledReminder: - hook = t("editor.hooks.scheduled-reminder.title") - break - case DocumentHookType.ContainerImageWatcher: - hook = t("editor.hooks.container-image-watcher.title") - break - } - - if (notification.code === NotificationCode.DocumentHookNeedsAttention) { - return t( - "notification.messages.document-hook-needs-attention-description", - { hook: hook }, - ) - } - - return t("notification.messages.document-hook-triggered-description", { - hook: hook, - }) - } - case NotificationCode.DocumentNewComment: { - const metadata = - notification.metadata as NotificationMetadataDocumentNewComment - - return t("notification.messages.document-new-comment-description", { - user: findUserName(metadata.userId), - }) - } - case NotificationCode.DocumentNewCommentReply: { - const metadata = - notification.metadata as NotificationMetadataDocumentNewCommentReply - - return t("notification.messages.document-new-comment-reply-description", { - user: findUserName(metadata.userId), - }) - } - default: - return t("notification.messages.default-description") - } -} - async function handleNotificationClick(notification: Notification) { - const href = await buildNotificationHref(notification) - if (href) { - void handleMarkRead(notification, true) // non blocking - await navigateTo(href) - } -} - -async function handleMarkRead( - notification: Notification, - noErrorToast = false, -) { - if (notification.read) { - return - } - - try { + if (!notification.read) { await markNotificationsRead.mutateAsync({ ids: [notification.id] }) - } catch { - if (!noErrorToast) { - showToastMessage("error", t("notification.errors.mark-read-failed")) - } + void fetchNotifications.refetch() + void fetchNotificationCount.refetch() + } + const href = await buildNotificationHref(notification) + if (!href) { + showToastMessage({ + type: "error", + title: t("notifications.toast.document-not-found.title"), + description: t("notifications.toast.document-not-found.description"), + }) return } + + await navigateTo(href) + emit("close-notification-box") } async function handleMarkAllRead() { - if (!hasUnreadNotifications.value) { - return - } - - try { - // send an empty array to mark all as read - await markNotificationsRead.mutateAsync({ ids: [] }) - } catch { - showToastMessage("error", t("notification.errors.mark-all-read-failed")) - return - } + await markNotificationsRead.mutateAsync({ ids: [] }) + void fetchNotifications.refetch() + void fetchNotificationCount.refetch() } +