feat: Remind Me Later, mobile bookmarks, bug fixes, and doc cleanup
Features: - Remind Me Later: message context menu item opens a preset time picker (20 min / 1 hr / 3 hr / tomorrow 9am); reminders persist to Matrix account data (io.lotus.reminders); ReminderMonitor fires a Lotus Toast when due, checks every 30s and on tab focus - Mobile Bookmarks: BookmarksPanel now renders on all screen sizes; passes isMobile prop for full-screen absolute overlay on mobile Bug fixes: - usePan.ts: memory leak from stale closure in document listener cleanup - EventReaders.tsx: replace hardcoded hex colors with TDS CSS variables - CallControls.tsx: replace hardcoded hex colors with TDS CSS variables - CustomHtml.css.ts: replace hardcoded yellow/black highlight with theme tokens Docs: - LOTUS_TODO.md: restore deleted content (Confirmed facts table, Pending Audits, P5-30 completed status, full feature descriptions), keep new additions (P4-7/8/9, P5-41–57, Implementation Reference), eliminate duplicate sections - LOTUS_BUGS.md: merge RESILIENCE_AUDIT.md findings into Architectural & Resilience Audit table; delete RESILIENCE_AUDIT.md - Remove stale LOTUS_DENOISE_ENGINEERING_REVIEW.md and LOTUS_TODO_REFERENCE.md Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -36,6 +36,7 @@ import { useMediaAuthentication } from '../../hooks/useMediaAuthentication';
|
||||
import { usePresenceUpdater } from '../../hooks/usePresenceUpdater';
|
||||
import { useDeepLinkNavigate } from '../../hooks/useDeepLinkNavigate';
|
||||
import { toastQueueAtom } from '../../state/toast';
|
||||
import { useReminders } from '../../hooks/useReminders';
|
||||
|
||||
function isInQuietHours(start: string, end: string): boolean {
|
||||
const now = new Date();
|
||||
@@ -382,6 +383,50 @@ function DeepLinkNavigator() {
|
||||
return null;
|
||||
}
|
||||
|
||||
function ReminderMonitor() {
|
||||
const mx = useMatrixClient();
|
||||
const { reminders, removeReminder } = useReminders();
|
||||
const setToast = useSetAtom(toastQueueAtom);
|
||||
const mDirects = useAtomValue(mDirectAtom);
|
||||
const firedRef = useRef<Set<string>>(new Set());
|
||||
|
||||
useEffect(() => {
|
||||
const check = () => {
|
||||
const now = Date.now();
|
||||
reminders.forEach((r) => {
|
||||
const key = `${r.eventId}-${r.timestamp}`;
|
||||
if (r.timestamp <= now && !firedRef.current.has(key)) {
|
||||
firedRef.current.add(key);
|
||||
const room = mx.getRoom(r.roomId);
|
||||
const hashPath = mDirects.has(r.roomId)
|
||||
? getDirectRoomPath(r.roomId)
|
||||
: getHomeRoomPath(r.roomId);
|
||||
setToast({
|
||||
id: `reminder-${key}`,
|
||||
displayName: 'Reminder',
|
||||
body: r.message,
|
||||
roomName: room?.name ?? 'Unknown Room',
|
||||
roomId: r.roomId,
|
||||
hashPath,
|
||||
});
|
||||
removeReminder(r.eventId, r.timestamp);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
check();
|
||||
const interval = setInterval(check, 30_000);
|
||||
const onVisible = () => { if (document.visibilityState === 'visible') check(); };
|
||||
document.addEventListener('visibilitychange', onVisible);
|
||||
return () => {
|
||||
clearInterval(interval);
|
||||
document.removeEventListener('visibilitychange', onVisible);
|
||||
};
|
||||
}, [mx, reminders, setToast, removeReminder, mDirects]);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function LotusDenoiseFeature() {
|
||||
const setToast = useSetAtom(toastQueueAtom);
|
||||
|
||||
@@ -417,6 +462,7 @@ export function ClientNonUIFeatures({ children }: ClientNonUIFeaturesProps) {
|
||||
<PresenceUpdater />
|
||||
<InviteNotifications />
|
||||
<MessageNotifications />
|
||||
<ReminderMonitor />
|
||||
<LotusDenoiseFeature />
|
||||
<DeepLinkNavigator />
|
||||
{children}
|
||||
|
||||
Reference in New Issue
Block a user