diff --git a/.changeset/25921-collab-mention-notifications.md b/.changeset/25921-collab-mention-notifications.md new file mode 100644 index 00000000000..b13da3a4de6 --- /dev/null +++ b/.changeset/25921-collab-mention-notifications.md @@ -0,0 +1,18 @@ +--- +'@object-ui/collaboration': patch +'@object-ui/types': patch +--- + +refactor(collaboration, types)!: retire the zero-consumer `useMentionNotifications` hook and the `MentionNotification` interface + +Clause-②: no (narrowing) +Metadata-protocol: none + + + +**BREAKING** for a host that imports `useMentionNotifications`, `MentionNotificationsConfig` or `MentionNotificationsResult` from `@object-ui/collaboration`, or the type `MentionNotification` from `@object-ui/types`. The hook held a client-side list of mention notifications with read flags; no console surface used it, because mention notifications are server records (`sys_notification`, topic `collab.mention`) that the console bell reads from the inbox feed. `CommentEntry` and `ActivityEntry` stay exported unchanged. The `CommentSearchResult` entry of this release said `MentionNotification` stays exported; it leaves here. + +- FROM `useMentionNotifications` TO a local hook in your own code, or read the server inbox (`GET /api/v1/notifications`) as the console bell does. +- FROM `MentionNotificationsConfig` TO a local interface in your own code: `{ currentUserId: string; initialNotifications?: MentionNotification[]; onDeliver?: (notification: MentionNotification) => void | Promise }`. +- FROM `MentionNotificationsResult` TO a local interface in your own code, typed by what your own hook returns. +- FROM `MentionNotification` TO a local interface in your own code: `{ id: string; type: 'mention'; recipientId: string; commentId: string | number; mentionedBy: string; commentText: string; objectName?: string; recordId?: string; createdAt: string; read?: boolean; channels?: Array<'in_app' | 'email' | 'push'> }`. diff --git a/ui/packages/collaboration/src/index.ts b/ui/packages/collaboration/src/index.ts index 1703d015649..16be36f9eba 100644 --- a/ui/packages/collaboration/src/index.ts +++ b/ui/packages/collaboration/src/index.ts @@ -62,12 +62,6 @@ export { type CollaborationTranslate, } from './useCollaborationTranslation.js'; -export { - useMentionNotifications, - type MentionNotificationsConfig, - type MentionNotificationsResult, -} from './useMentionNotifications.js'; - export { PresenceAvatars, type PresenceAvatarsProps, diff --git a/ui/packages/collaboration/src/useMentionNotifications.ts b/ui/packages/collaboration/src/useMentionNotifications.ts deleted file mode 100644 index 4a0c5413afd..00000000000 --- a/ui/packages/collaboration/src/useMentionNotifications.ts +++ /dev/null @@ -1,97 +0,0 @@ -/** - * ObjectUI - * Copyright (c) 2024-present ObjectStack Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -import { useState, useCallback, useMemo } from 'react'; -import type { MentionNotification } from '@object-ui/types'; - -export interface MentionNotificationsConfig { - /** Current user ID to filter notifications for */ - currentUserId: string; - /** Initial notifications */ - initialNotifications?: MentionNotification[]; - /** Callback when a notification should be delivered (email/push) */ - onDeliver?: (notification: MentionNotification) => void | Promise; -} - -export interface MentionNotificationsResult { - /** All notifications for the current user */ - notifications: MentionNotification[]; - /** Unread notifications count */ - unreadCount: number; - /** Add a new mention notification (triggered when @mention is detected) */ - addNotification: (notification: MentionNotification) => void; - /** Mark a notification as read */ - markAsRead: (notificationId: string) => void; - /** Mark all notifications as read */ - markAllAsRead: () => void; - /** Dismiss/remove a notification */ - dismiss: (notificationId: string) => void; - /** Clear all notifications */ - clearAll: () => void; -} - -/** - * Hook for managing @mention notifications with delivery support. - * - * Tracks mention notifications for the current user and provides - * callbacks for delivery via email/push channels. - */ -export function useMentionNotifications({ - currentUserId, - initialNotifications = [], - onDeliver, -}: MentionNotificationsConfig): MentionNotificationsResult { - const [notifications, setNotifications] = useState( - initialNotifications.filter(n => n.recipientId === currentUserId), - ); - - const unreadCount = useMemo( - () => notifications.filter(n => !n.read).length, - [notifications], - ); - - const addNotification = useCallback( - (notification: MentionNotification) => { - if (notification.recipientId !== currentUserId) return; - setNotifications(prev => { - if (prev.some(n => n.id === notification.id)) return prev; - return [notification, ...prev]; - }); - onDeliver?.(notification); - }, - [currentUserId, onDeliver], - ); - - const markAsRead = useCallback((notificationId: string) => { - setNotifications(prev => - prev.map(n => (n.id === notificationId ? { ...n, read: true } : n)), - ); - }, []); - - const markAllAsRead = useCallback(() => { - setNotifications(prev => prev.map(n => ({ ...n, read: true }))); - }, []); - - const dismiss = useCallback((notificationId: string) => { - setNotifications(prev => prev.filter(n => n.id !== notificationId)); - }, []); - - const clearAll = useCallback(() => { - setNotifications([]); - }, []); - - return { - notifications, - unreadCount, - addNotification, - markAsRead, - markAllAsRead, - dismiss, - clearAll, - }; -} diff --git a/ui/packages/types/src/__tests__/record-id-string-survivors-10078.test.ts b/ui/packages/types/src/__tests__/record-id-string-survivors-10078.test.ts index ea2b8d70d56..a0650d934af 100644 --- a/ui/packages/types/src/__tests__/record-id-string-survivors-10078.test.ts +++ b/ui/packages/types/src/__tests__/record-id-string-survivors-10078.test.ts @@ -14,7 +14,8 @@ * * Director batch #195 item 1, letter A (objectui#9511) made a record id a * `string` wherever METADATA names one, and extended it as "the same - * principle" to `CommentEntry.recordId` / `MentionNotification.recordId`. The + * principle" to `CommentEntry.recordId` and to the `recordId` of a mention + * notification interface that has since been retired with its only reader. The * two below are runtime / API shapes that ruling did not name; carrying the * rule to them is the `domain:spec` seat's inheritance decision in the claim on * objectui#10078. Each carried the same id with the old `string | number` diff --git a/ui/packages/types/src/index.ts b/ui/packages/types/src/index.ts index abd31697534..e745cddbac1 100644 --- a/ui/packages/types/src/index.ts +++ b/ui/packages/types/src/index.ts @@ -1070,7 +1070,6 @@ export type { DetailSectionNodeSchema, ViewComponentSchema, CommentEntry, - MentionNotification, ActivityEntry, // Feed / Chatter Protocol Types FeedItemType, diff --git a/ui/packages/types/src/views.ts b/ui/packages/types/src/views.ts index 226369246b0..bdcdac3ecb6 100644 --- a/ui/packages/types/src/views.ts +++ b/ui/packages/types/src/views.ts @@ -479,34 +479,6 @@ export interface CommentEntry { recordId?: string; } -/** - * Mention notification - delivered when a user is @mentioned in a comment - */ -export interface MentionNotification { - /** Unique notification ID */ - id: string; - /** Type of notification */ - type: 'mention'; - /** ID of the user being notified */ - recipientId: string; - /** The comment that contains the mention */ - commentId: string | number; - /** Author who mentioned the recipient */ - mentionedBy: string; - /** The comment text (or excerpt) */ - commentText: string; - /** Object name the comment belongs to */ - objectName?: string; - /** Record ID the comment belongs to. A string, per the one record-id rule (objectui#9511). */ - recordId?: string; - /** When the mention was created */ - createdAt: string; - /** Whether the notification has been read */ - read?: boolean; - /** Delivery channels */ - channels?: Array<'in_app' | 'email' | 'push'>; -} - /** * Activity Entry - represents a single activity/field change on a record */