Compare commits
3
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ddf9da1a55 | ||
|
|
022e5e6987 | ||
|
|
5c765925d2 |
@@ -783,15 +783,20 @@ function ReminderMonitor() {
|
||||
const { reminders, removeReminder } = useReminders();
|
||||
const setToast = useSetAtom(toastQueueAtom);
|
||||
const mDirects = useAtomValue(mDirectAtom);
|
||||
const [showNotifications] = useSetting(settingsAtom, 'showNotifications');
|
||||
const quietActive = useNotificationsQuiet();
|
||||
const firedRef = useRef<Set<string>>(new Set());
|
||||
const removingRef = useRef<Set<string>>(new Set());
|
||||
// Read the latest reminders / DM map via refs so the poll interval below is
|
||||
// created once — not torn down and restarted (which resets its 30s countdown
|
||||
// and can indefinitely defer a near-due reminder) on every reminder sync (N115).
|
||||
// Read the latest reminders / DM map / notification prefs via refs so the poll
|
||||
// interval below is created once — not torn down and restarted (which resets
|
||||
// its 30s countdown and can indefinitely defer a near-due reminder) on every
|
||||
// reminder sync (N115).
|
||||
const remindersRef = useRef(reminders);
|
||||
remindersRef.current = reminders;
|
||||
const mDirectsRef = useRef(mDirects);
|
||||
mDirectsRef.current = mDirects;
|
||||
const osNotifyRef = useRef(false);
|
||||
osNotifyRef.current = showNotifications && !quietActive;
|
||||
|
||||
useEffect(() => {
|
||||
const check = () => {
|
||||
@@ -815,6 +820,23 @@ function ReminderMonitor() {
|
||||
const hashPath = mDirectsRef.current.has(r.roomId)
|
||||
? getDirectRoomPath(r.roomId, r.eventId)
|
||||
: getHomeRoomPath(r.roomId, r.eventId);
|
||||
// [Gitea #338] A reminder is only done once the user has SEEN it: the
|
||||
// toast stays until clicked or dismissed (it used to vanish after 4 s
|
||||
// and the reminder was deleted at once, so one due while the user was
|
||||
// away was lost). The removal is persisted on that click/dismiss; an
|
||||
// unseen reminder comes back on the next start.
|
||||
const done = () => {
|
||||
if (removingRef.current.has(key)) return;
|
||||
removingRef.current.add(key);
|
||||
removeReminder(r.eventId, r.timestamp).catch(() => {
|
||||
removingRef.current.delete(key);
|
||||
});
|
||||
};
|
||||
const open = () => {
|
||||
done();
|
||||
// window.location.hash setter auto-prepends '#' (as the toast does)
|
||||
window.location.hash = hashPath;
|
||||
};
|
||||
setToast({
|
||||
id: `reminder-${key}`,
|
||||
displayName: 'Reminder',
|
||||
@@ -822,16 +844,30 @@ function ReminderMonitor() {
|
||||
roomName,
|
||||
roomId: r.roomId,
|
||||
hashPath,
|
||||
sticky: true,
|
||||
onClick: open,
|
||||
onDismiss: done,
|
||||
});
|
||||
}
|
||||
// Persist the removal, retrying on a later tick if it fails — without
|
||||
// re-showing the toast (N114). The server echo drops it from
|
||||
// `reminders` once the write lands.
|
||||
if (!removingRef.current.has(key)) {
|
||||
removingRef.current.add(key);
|
||||
removeReminder(r.eventId, r.timestamp).catch(() => {
|
||||
removingRef.current.delete(key);
|
||||
});
|
||||
// Away from the window: also raise an OS notification (the reminder is
|
||||
// an explicit request, but quiet hours / notifications-off win). Never
|
||||
// put decrypted E2EE text in it (N106).
|
||||
if (osNotifyRef.current && notificationPermission('granted') && !document.hasFocus()) {
|
||||
const encrypted = !!room?.hasEncryptionStateEvent();
|
||||
showOsNotification(
|
||||
'Reminder',
|
||||
{
|
||||
icon: LogoSVG,
|
||||
badge: LogoSVG,
|
||||
body: encrypted ? `A message in ${roomName}` : body,
|
||||
tag: `reminder-${key}`,
|
||||
data: { path: hashPath, roomId: r.roomId },
|
||||
},
|
||||
() => {
|
||||
window.focus();
|
||||
open();
|
||||
},
|
||||
).catch(() => undefined);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user