feat: add reminders for tasks and calendar events (closes #13)

- DB migration #8: reminders table (entity_type, entity_id, remind_at, dismissed, created_by)
- REST API: GET /pending, GET /?entity, POST /, PATCH /:id/dismiss, DELETE
- Client polling module (reminders.js): 60s interval, toast + Browser Notification API
- Tasks: enable reminder with custom date/time in edit modal
- Calendar: reminder offset selector (at time / 15min / 1h / 1d before)
- Bell badge shows pending count; reminders auto-dismiss after 30s or on user action
- SW shell cache updated to include reminders.js + reminders.css
- 11 new DB tests covering CRUD, pending query, dismiss, upsert, cascade delete, constraints
This commit is contained in:
Ulas
2026-04-15 11:40:24 +02:00
parent 45008a4af6
commit e384ae1037
16 changed files with 1061 additions and 20 deletions
+4
View File
@@ -6,6 +6,7 @@
import { auth } from '/api.js';
import { initI18n, getLocale, t } from '/i18n.js';
import { init as initReminders, stop as stopReminders } from '/reminders.js';
// --------------------------------------------------------
// Routen-Definitionen
@@ -144,6 +145,7 @@ async function navigate(path, userOrPushState = true, pushState = true) {
// Überlastung: navigate(path, user) nach Login vs navigate(path, false) beim Init
if (typeof userOrPushState === 'object' && userOrPushState !== null) {
currentUser = userOrPushState;
initReminders();
} else {
pushState = userOrPushState;
}
@@ -159,6 +161,7 @@ async function navigate(path, userOrPushState = true, pushState = true) {
try {
const result = await auth.me();
currentUser = result.user;
initReminders();
} catch {
currentPath = null; // Reset damit navigate('/login') nicht geblockt wird
isNavigating = false;
@@ -507,6 +510,7 @@ window.addEventListener('popstate', (e) => {
// Session abgelaufen
window.addEventListener('auth:expired', () => {
currentUser = null;
stopReminders();
navigate('/login');
});