From 380bf63f514657dc06e496747f3e5422e5fc6d78 Mon Sep 17 00:00:00 2001 From: Coder User Date: Thu, 13 Mar 2025 03:03:57 +0000 Subject: [PATCH] feat: implement notification inbox system MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add API methods for getting notifications and marking them as read - Add TypeScript types for the notification inbox API - Update notification components to use the official API types - Integrate NotificationsInbox component into the navbar Closes #16804 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- site/src/api/api.ts | 16 ++++++++++++++++ site/src/api/typesGenerated.ts | 18 ++++++++++++++++++ .../modules/dashboard/Navbar/NavbarView.tsx | 10 ++++++++++ .../notifications/NotificationsInbox/types.ts | 15 ++++----------- 4 files changed, 48 insertions(+), 11 deletions(-) diff --git a/site/src/api/api.ts b/site/src/api/api.ts index 627ede8097..b8a0c91fac 100644 --- a/site/src/api/api.ts +++ b/site/src/api/api.ts @@ -2388,6 +2388,22 @@ class ApiMethods { ); return res.data; }; + + // Notification inbox API methods + getUserNotifications = async () => { + const response = await this.axios.get( + "/api/v2/users/me/notifications" + ); + return response.data; + }; + + markAllNotificationsAsRead = async (): Promise => { + await this.axios.post("/api/v2/users/me/notifications/read"); + }; + + markNotificationAsRead = async (notificationId: string): Promise => { + await this.axios.post(`/api/v2/users/me/notifications/${notificationId}/read`); + }; } // This is a hard coded CSRF token/cookie pair for local development. In prod, diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts index 6fdfb5ea9d..9a3e6287d6 100644 --- a/site/src/api/typesGenerated.ts +++ b/site/src/api/typesGenerated.ts @@ -1237,6 +1237,24 @@ export interface NotificationMethodsResponse { readonly default: string; } +// From codersdk/notifications.go +export interface InboxNotification { + readonly id: string; + readonly read_status: "read" | "unread"; + readonly content: string; + readonly created_at: string; + readonly actions: { + readonly label: string; + readonly url: string; + }[]; +} + +// From codersdk/notifications.go +export interface UserNotificationsResponse { + readonly notifications: InboxNotification[]; + readonly unread_count: number; +} + // From codersdk/notifications.go export interface NotificationPreference { readonly id: string; diff --git a/site/src/modules/dashboard/Navbar/NavbarView.tsx b/site/src/modules/dashboard/Navbar/NavbarView.tsx index d5ee661025..1a5ffc0bfa 100644 --- a/site/src/modules/dashboard/Navbar/NavbarView.tsx +++ b/site/src/modules/dashboard/Navbar/NavbarView.tsx @@ -1,7 +1,9 @@ +import { API } from "api/api"; import type * as TypesGen from "api/typesGenerated"; import { ExternalImage } from "components/ExternalImage/ExternalImage"; import { CoderIcon } from "components/Icons/CoderIcon"; import type { ProxyContextValue } from "contexts/ProxyContext"; +import { NotificationsInbox } from "modules/notifications/NotificationsInbox/NotificationsInbox"; import type { FC } from "react"; import { NavLink, useLocation } from "react-router-dom"; import { cn } from "utils/cn"; @@ -57,6 +59,14 @@ export const NavbarView: FC = ({ {proxyContextValue && ( )} + + {user && ( + + )}