feat: chat
This commit is contained in:
@@ -54,7 +54,7 @@ const EVENTS: {
|
||||
key: "community",
|
||||
label: "Community",
|
||||
description:
|
||||
"Rare announcements — such as a direct disciple of Śrīla Prabhupāda joining.",
|
||||
"Rare announcements — such as new feature, downtime etc.",
|
||||
// Announcements are in-app/push only; we deliberately don't email them.
|
||||
channels: ["in_app", "push"],
|
||||
},
|
||||
|
||||
@@ -44,6 +44,22 @@ type NotificationsContextValue = {
|
||||
refreshUnread: () => void;
|
||||
/** Zero the badge locally (after the page marks everything read). */
|
||||
clearUnread: () => void;
|
||||
/**
|
||||
* Last chat message seen over realtime, or null. Chat deliberately does NOT
|
||||
* flow through the notification tray — a new message highlights its row in
|
||||
* the inbox instead — so it rides the same private channel under its own
|
||||
* event name and is surfaced here rather than bumping `unread`.
|
||||
*/
|
||||
lastChatActivity: ChatActivity | null;
|
||||
};
|
||||
|
||||
/** Payload of the BFF's `chat_activity` event. */
|
||||
export type ChatActivity = {
|
||||
conversation_id: string;
|
||||
seq: number;
|
||||
sender_id: string;
|
||||
/** Client-side receipt time, so consumers can react to repeats. */
|
||||
at: number;
|
||||
};
|
||||
|
||||
const NotificationsContext = createContext<NotificationsContextValue | null>(
|
||||
@@ -93,6 +109,9 @@ export function NotificationsProvider({
|
||||
const { user } = useAuth();
|
||||
const [unread, setUnread] = useState(0);
|
||||
const [lastEventAt, setLastEventAt] = useState(0);
|
||||
const [lastChatActivity, setLastChatActivity] = useState<ChatActivity | null>(
|
||||
null,
|
||||
);
|
||||
|
||||
const refreshUnread = useCallback(() => {
|
||||
notifications
|
||||
@@ -178,6 +197,15 @@ export function NotificationsProvider({
|
||||
channel.bind("pusher:subscription_error", (status: unknown) => {
|
||||
console.warn("notifications: realtime subscription failed", status);
|
||||
});
|
||||
// Chat activity: no toast, no unread bump, nothing in the tray. The
|
||||
// inbox subscribes to this to highlight the affected row.
|
||||
channel.bind(
|
||||
"chat_activity",
|
||||
(data: Omit<ChatActivity, "at">) => {
|
||||
if (!data?.conversation_id) return;
|
||||
setLastChatActivity({ ...data, at: Date.now() });
|
||||
},
|
||||
);
|
||||
channel.bind("notification", (data: IncomingEvent) => {
|
||||
setUnread((u) => u + 1);
|
||||
setLastEventAt(Date.now());
|
||||
@@ -208,7 +236,13 @@ export function NotificationsProvider({
|
||||
|
||||
return (
|
||||
<NotificationsContext.Provider
|
||||
value={{ unread, lastEventAt, refreshUnread, clearUnread }}
|
||||
value={{
|
||||
unread,
|
||||
lastEventAt,
|
||||
refreshUnread,
|
||||
clearUnread,
|
||||
lastChatActivity,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</NotificationsContext.Provider>
|
||||
|
||||
Reference in New Issue
Block a user