Files
cinny/src/app/hooks/useTauriToastActions.ts
T
Lotus CIandClaude Opus 5.5 343de27cad feat(desktop): toast "Mark as read" marks the room read (cinny-desktop #9)
Handles the native `lotus-notification-mark-read` event through the
same `markAsRead` path as the room menu's "Mark as Read", honouring the
private-receipt settings. Verified: 3 unread → 0 on the server.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PPmy3tPq869XDW4njjVaKA
2026-09-23 19:48:23 -04:00

74 lines
2.9 KiB
TypeScript

import { useNavigate } from 'react-router-dom';
import { MsgType } from 'matrix-js-sdk';
import { useSetAtom } from 'jotai';
import { Icons } from 'folds';
import { useMatrixClient } from './useMatrixClient';
import { useTauriEvent } from './useTauri';
import { createErrorToast, toastQueueAtom } from '../state/toast';
import { useSetting } from '../state/hooks/settings';
import { settingsAtom } from '../state/settings';
import { markAsRead } from '../utils/notifications';
/** Payload of the `lotus-notification-activate` event (a plain body click). */
interface ActivateDetail {
path?: string;
}
/** Payload of the `lotus-notification-reply` event (the inline reply box). */
interface ReplyDetail {
roomId?: string;
/** Set for a thread notification: the reply goes into that thread. */
threadId?: string;
text?: string;
}
/** Payload of the `lotus-notification-mark-read` event (the Mark as read button). */
interface MarkReadDetail {
roomId?: string;
}
/**
* P5-41 / P5-35 — wire the native WinRT toast's click + quick-reply back into the
* client. The Rust side (`show_rich_toast`) dispatches DOM CustomEvents via
* `emit_to_web`:
* - `lotus-notification-activate` → route to the room the toast was for, reusing
* the same `useNavigate(path)` mechanism the web `notificationclick` path uses
* (see ClientNonUIFeatures).
* - `lotus-notification-reply` → send the typed reply straight to the room.
* - `lotus-notification-mark-read` → mark the room read, the same path as the
* room menu's "Mark as Read" (cinny-desktop #9).
* No-op outside Tauri (the events never fire).
*/
export function useTauriToastActions(): void {
const navigate = useNavigate();
const mx = useMatrixClient();
const setToast = useSetAtom(toastQueueAtom);
const [hideActivity] = useSetting(settingsAtom, 'hideActivity');
useTauriEvent<ActivateDetail>('lotus-notification-activate', ({ path }) => {
if (path) navigate(path);
});
useTauriEvent<ReplyDetail>('lotus-notification-reply', ({ roomId, threadId, text }) => {
// `roomId` is the real room id carried in the notification data, never the
// coalescing tag (`room:thread`, `lotus-invites`) — cinny-desktop #17.
if (!roomId || !text) return;
// #79 — a quick-reply failure (offline, no send permission, etc.) used to
// be swallowed with no feedback, leaving the user believing it was sent.
// Surface it via the in-app error toast instead.
mx.sendMessage(roomId, threadId ?? null, { msgtype: MsgType.Text, body: text }).catch(() => {
setToast(
createErrorToast(
'Your quick reply could not be sent. Please try again.',
Icons.Warning,
'Reply failed',
),
);
});
});
useTauriEvent<MarkReadDetail>('lotus-notification-mark-read', ({ roomId }) => {
if (roomId) markAsRead(mx, roomId, hideActivity).catch(() => undefined);
});
}