Add support for customizable birthday reminders with preset offsets
(none, at time, 15min, 1h, 1d, 2d, 1w, 2w) and custom intervals.
Users can now configure when to be reminded of upcoming birthdays.
- Add migration 31: reminder_offset, reminder_custom_amount, reminder_custom_unit to birthdays table
- Update POST/PUT /birthdays routes to accept reminder fields
- Add getOffsetMinutes() helper in birthday service
- Update birthdayReminderAt() to calculate reminder time with offset
- Modify syncBirthdayReminder() to handle empty offset (no reminder)
- Add renderBirthdayReminderSection() UI component
- Move reminder-custom CSS from calendar.css to reminders.css
- Add protocol check to service worker (non-http protocol guard)
All translations already present in de.json.
Tests: 109 passing, 0 failing.
Co-Authored-By: Rafael Foster <rafaelfoster@users.noreply.github.com>
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Replace innerHTML with replaceChildren/insertAdjacentHTML in birthdays.js and calendar.js (hook compliance)
- Translate calendar attachment i18n keys to German in de.json
- Fix missing diacritical marks in pt.json attachment strings
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Birthday date inputs in Settings (profile, new member, edit member) and
the Birthdays page were using type="text" with a custom mask, which
suppresses the native iOS date picker wheel. Switching to type="date"
with a plain ISO value restores the native picker while keeping the
existing parseDateInput / isDateInputValid logic intact.
Closes#98
Co-authored-by: Ulas Kalayci <ulas.kalayci@googlemail.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
- birthdays.js: all innerHTML writes replaced with replaceChildren() + insertAdjacentHTML()
- dashboard.js: shell.innerHTML replaced with replaceChildren() + insertAdjacentHTML()
- docker-compose.yml: revert port to 3000 and restore image line (were personal dev changes)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>