fix(reminders): keine Dauermeldung ohne localStorage, Mail nach Zeitaenderung, null-Pruefung
- Merkliste zusaetzlich im Arbeitsspeicher (sonst alle 10 s dieselbe Meldung) - Aendern der Faelligkeit atomar gegen gleichzeitiges Faelligwerden, setzt Mail-Spur zurueck - UpdateReminderDto lehnt null ab (400 statt 500) - keine Mails an deaktivierte Benutzer - Spaeter erinnern beschriftet heute/morgen nach dem berechneten Zeitpunkt - Bearbeiten schickt dueAt nur bei geaenderter Zeit Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -30,12 +30,7 @@ export const CATCH_UP_WINDOW_MS = 24 * 60 * 60 * 1000;
|
||||
/** Eintraege der lokalen Merkliste, die aelter sind, werden entfernt. */
|
||||
const NOTIFIED_TTL_MS = 7 * 24 * 60 * 60 * 1000;
|
||||
|
||||
export type BrowserPermissionState =
|
||||
| 'desktop'
|
||||
| 'granted'
|
||||
| 'default'
|
||||
| 'denied'
|
||||
| 'unsupported';
|
||||
export type BrowserPermissionState = 'desktop' | 'granted' | 'default' | 'denied' | 'unsupported';
|
||||
|
||||
type TauriInvoke = (command: string, args?: Record<string, unknown>) => Promise<unknown>;
|
||||
|
||||
@@ -135,6 +130,19 @@ function readNotified(): Record<string, number> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Merkliste im Arbeitsspeicher dieses Tabs. Sie greift IMMER, auch wenn der
|
||||
* localStorage gesperrt, voll oder im privaten Modus nicht nutzbar ist — sonst
|
||||
* meldete der Melder dieselbe faellige Erinnerung 24 Stunden lang bei jeder
|
||||
* Pruefung erneut. Der localStorage bleibt fuer die Abstimmung zwischen Tabs.
|
||||
*/
|
||||
const notifiedInMemory = new Map<string, number>();
|
||||
|
||||
/** Nur fuer Tests: leert die Merkliste im Arbeitsspeicher. */
|
||||
export function resetNotifiedMemoryForTests(): void {
|
||||
notifiedInMemory.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Merkt sich `key` (`${id}|${dueAt}`) lokal. `true` nur beim ERSTEN Mal — so
|
||||
* meldet jeder Client jede Faelligkeit hoechstens einmal, auch ueber mehrere
|
||||
@@ -143,16 +151,22 @@ function readNotified(): Record<string, number> {
|
||||
* aelter als 7 Tage werden dabei entfernt.
|
||||
*/
|
||||
export function claimNotification(key: string, nowMs: number): boolean {
|
||||
for (const [k, at] of notifiedInMemory) {
|
||||
if (nowMs - at > NOTIFIED_TTL_MS) notifiedInMemory.delete(k);
|
||||
}
|
||||
const record = readNotified();
|
||||
for (const [k, at] of Object.entries(record)) {
|
||||
if (nowMs - at > NOTIFIED_TTL_MS) delete record[k];
|
||||
}
|
||||
const first = !(key in record);
|
||||
if (first) record[key] = nowMs;
|
||||
const first = !(key in record) && !notifiedInMemory.has(key);
|
||||
if (first) {
|
||||
record[key] = nowMs;
|
||||
notifiedInMemory.set(key, nowMs);
|
||||
}
|
||||
try {
|
||||
window.localStorage.setItem(NOTIFIED_KEY, JSON.stringify(record));
|
||||
} catch {
|
||||
/* Speicher voll oder gesperrt: dann eben ohne Merkliste */
|
||||
/* Speicher voll oder gesperrt: dann greift nur die Merkliste im Arbeitsspeicher */
|
||||
}
|
||||
return first;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user