Todos already support a due_date field but nothing notifies the user
when a deadline is approaching — you'd only remember if you happened
to look at the Lists tab. This wires a reminder into the existing
notification pipeline so due-date todos behave like trip-start
reminders.
Details:
- New `todo_due` event type alongside trip_reminder; all four channels
(in-app, email, webhook, ntfy) supported and toggleable per user in
Settings > Notifications.
- New daily scheduler task (9 AM local TZ) queries unchecked todos
whose due_date is within the next 3 days. Each todo gets at most
one reminder per 24 hours, tracked via a new todo_items.reminded_at
column (migration 116).
- If the todo has an assigned user, only that user is reminded; if
not, every member of the trip gets the notification.
- Strings added in all 15 UI languages and for all notification
carriers.
- Gated by app_settings.notify_todo_due (default on) so admins can
disable it globally.
trip_invite: p=>({title:`Einladung zu "${p.trip}"`,body:`${p.actor} hat ${p.invitee||'ein Mitglied'} zur Reise "${p.trip}" eingeladen.`}),
booking_change: p=>({title:`Neue Buchung: ${p.booking}`,body:`${p.actor} hat eine neue Buchung "${p.booking}" (${p.type}) zu "${p.trip}" hinzugefügt.`}),
trip_reminder: p=>({title:`Reiseerinnerung: ${p.trip}`,body:`Deine Reise "${p.trip}" steht bald an!`}),
todo_due: p=>({title:`Aufgabe fällig: ${p.todo}`,body:`"${p.todo}" in "${p.trip}" ist am ${p.due} fällig.`}),
vacay_invite: p=>({title:'Vacay Fusion-Einladung',body:`${p.actor} hat dich eingeladen, Urlaubspläne zu fusionieren. Öffne TREK um anzunehmen oder abzulehnen.`}),
photos_shared: p=>({title:`${p.count} Fotos geteilt`,body:`${p.actor} hat ${p.count} Foto(s) in "${p.trip}" geteilt.`}),
collab_message: p=>({title:`Neue Nachricht in "${p.trip}"`,body:`${p.actor}: ${p.preview}`}),
trip_invite: p=>({title:`Invitation à "${p.trip}"`,body:`${p.actor} a invité ${p.invitee||'un membre'} au voyage "${p.trip}".`}),
booking_change: p=>({title:`Nouvelle réservation : ${p.booking}`,body:`${p.actor} a ajouté une réservation "${p.booking}" (${p.type}) à "${p.trip}".`}),
trip_reminder: p=>({title:`Rappel de voyage : ${p.trip}`,body:`Votre voyage "${p.trip}" approche !`}),
todo_due: p=>({title:`Tâche à échéance : ${p.todo}`,body:`"${p.todo}" dans "${p.trip}" est due le ${p.due}.`}),
vacay_invite: p=>({title:'Invitation Vacay Fusion',body:`${p.actor} vous invite à fusionner les plans de vacances. Ouvrez TREK pour accepter ou refuser.`}),
photos_shared: p=>({title:`${p.count} photos partagées`,body:`${p.actor} a partagé ${p.count} photo(s) dans "${p.trip}".`}),
collab_message: p=>({title:`Nouveau message dans "${p.trip}"`,body:`${p.actor} : ${p.preview}`}),
trip_invite: p=>({title:`Uitnodiging voor "${p.trip}"`,body:`${p.actor} heeft ${p.invitee||'een lid'} uitgenodigd voor de reis "${p.trip}".`}),
booking_change: p=>({title:`Nieuwe boeking: ${p.booking}`,body:`${p.actor} heeft een boeking "${p.booking}" (${p.type}) toegevoegd aan "${p.trip}".`}),
trip_reminder: p=>({title:`Reisherinnering: ${p.trip}`,body:`Je reis "${p.trip}" komt eraan!`}),
todo_due: p=>({title:`Taak verloopt: ${p.todo}`,body:`"${p.todo}" in "${p.trip}" verloopt op ${p.due}.`}),
vacay_invite: p=>({title:'Vacay Fusion uitnodiging',body:`${p.actor} nodigt je uit om vakantieplannen te fuseren. Open TREK om te accepteren of af te wijzen.`}),
photos_shared: p=>({title:`${p.count} foto's gedeeld`,body:`${p.actor} heeft ${p.count} foto('s) gedeeld in "${p.trip}".`}),
collab_message: p=>({title:`Nieuw bericht in "${p.trip}"`,body:`${p.actor}: ${p.preview}`}),
trip_invite: p=>({title:`Pozvánka do "${p.trip}"`,body:`${p.actor} pozval ${p.invitee||'člena'} na výlet "${p.trip}".`}),
booking_change: p=>({title:`Nová rezervace: ${p.booking}`,body:`${p.actor} přidal rezervaci "${p.booking}" (${p.type}) k "${p.trip}".`}),
trip_reminder: p=>({title:`Připomínka výletu: ${p.trip}`,body:`Váš výlet "${p.trip}" se blíží!`}),
todo_due: p=>({title:`Úkol se blíží: ${p.todo}`,body:`"${p.todo}" ve výletě "${p.trip}" má termín ${p.due}.`}),
vacay_invite: p=>({title:'Pozvánka Vacay Fusion',body:`${p.actor} vás pozval ke spojení dovolenkových plánů. Otevřete TREK pro přijetí nebo odmítnutí.`}),
photos_shared: p=>({title:`${p.count} sdílených fotek`,body:`${p.actor} sdílel ${p.count} foto v "${p.trip}".`}),
collab_message: p=>({title:`Nová zpráva v "${p.trip}"`,body:`${p.actor}: ${p.preview}`}),
vacay_invite: p=>({title:'Vacay Fusion meghívó',body:`${p.actor} meghívott a nyaralási tervek összevonásához. Nyissa meg a TREK-et az elfogadáshoz vagy elutasításhoz.`}),
photos_shared: p=>({title:`${p.count} fotó megosztva`,body:`${p.actor}${p.count} fotót osztott meg a(z) "${p.trip}" utazásban.`}),
trip_invite: p=>({title:`Invito a "${p.trip}"`,body:`${p.actor} ha invitato ${p.invitee||'un membro'} al viaggio "${p.trip}".`}),
booking_change: p=>({title:`Nuova prenotazione: ${p.booking}`,body:`${p.actor} ha aggiunto una prenotazione "${p.booking}" (${p.type}) a "${p.trip}".`}),
trip_reminder: p=>({title:`Promemoria viaggio: ${p.trip}`,body:`Il tuo viaggio "${p.trip}" si avvicina!`}),
todo_due: p=>({title:`Attività in scadenza: ${p.todo}`,body:`"${p.todo}" in "${p.trip}" scade il ${p.due}.`}),
vacay_invite: p=>({title:'Invito Vacay Fusion',body:`${p.actor} ti ha invitato a fondere i piani vacanza. Apri TREK per accettare o rifiutare.`}),
photos_shared: p=>({title:`${p.count} foto condivise`,body:`${p.actor} ha condiviso ${p.count} foto in "${p.trip}".`}),
collab_message: p=>({title:`Nuovo messaggio in "${p.trip}"`,body:`${p.actor}: ${p.preview}`}),
trip_invite: p=>({title:`Zaproszenie do "${p.trip}"`,body:`${p.actor} zaprosił ${p.invitee||'członka'} do podróży "${p.trip}".`}),
booking_change: p=>({title:`Nowa rezerwacja: ${p.booking}`,body:`${p.actor} dodał rezerwację "${p.booking}" (${p.type}) do "${p.trip}".`}),
trip_reminder: p=>({title:`Przypomnienie o podróży: ${p.trip}`,body:`Twoja podróż "${p.trip}" zbliża się!`}),
todo_due: p=>({title:`Zadanie z terminem: ${p.todo}`,body:`"${p.todo}" w "${p.trip}" — termin ${p.due}.`}),
vacay_invite: p=>({title:'Zaproszenie Vacay Fusion',body:`${p.actor} zaprosił Cię do połączenia planów urlopowych. Otwórz TREK, aby zaakceptować lub odrzucić.`}),
photos_shared: p=>({title:`${p.count} zdjęć udostępnionych`,body:`${p.actor} udostępnił ${p.count} zdjęcie/zdjęcia w "${p.trip}".`}),
collab_message: p=>({title:`Nowa wiadomość w "${p.trip}"`,body:`${p.actor}: ${p.preview}`}),
trip_invite: p=>({title:`Undangan perjalanan: "${p.trip}"`,body:`${p.actor} mengundang ${p.invitee||'seorang anggota'} ke perjalanan "${p.trip}".`}),
booking_change: p=>({title:`Pemesanan baru: ${p.booking}`,body:`${p.actor} menambahkan "${p.booking}" (${p.type}) baru ke "${p.trip}".`}),
trip_reminder: p=>({title:`Pengingat perjalanan: ${p.trip}`,body:`Perjalanan Anda "${p.trip}" akan segera tiba!`}),
todo_due: p=>({title:`Tugas jatuh tempo: ${p.todo}`,body:`"${p.todo}" di "${p.trip}" jatuh tempo pada ${p.due}.`}),
vacay_invite: p=>({title:'Undangan Penggabungan Vacay',body:`${p.actor} mengundang Anda untuk menggabungkan rencana liburan. Buka TREK untuk menerima atau menolak.`}),
photos_shared: p=>({title:`${p.count} foto dibagikan`,body:`${p.actor} membagikan ${p.count} foto di "${p.trip}".`}),
collab_message: p=>({title:`Pesan baru di "${p.trip}"`,body:`${p.actor}: ${p.preview}`}),
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.