feat: birthday tracking, dashboard KPIs, and app name customization (#88)

- Add Birthdays module: CRUD with calendar/reminder auto-sync, photo upload, age notes
- Add DB migration 18 (birthdays table with calendar_event_id, trigger, indexes)
- Add dashboard widgets: birthdays, family participants, budget overview
- Add Settings > General: admins can set a custom app name (reflected in title/sidebar/login)
- Improve service worker: network-first caching for mutable JS/CSS assets
- Add translations for 16 locales (birthday keys)

Fixes applied during integration:
- innerHTML replaced with insertAdjacentHTML/replaceChildren throughout birthdays.js and dashboard.js
- docker-compose.yml personal dev changes reverted

Co-authored-by: Rafael Foster <rafaelgfoster@gmail.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Ulas Kalayci
2026-04-27 07:37:09 +02:00
39 changed files with 4026 additions and 156 deletions
+53
View File
@@ -38,6 +38,7 @@
"shopping": "التسوق",
"notes": "الملاحظات",
"contacts": "جهات الاتصال",
"birthdays": "أعياد الميلاد",
"budget": "الميزانية",
"settings": "الإعدادات",
"main": "القائمة الرئيسية",
@@ -82,6 +83,19 @@
"allDay": "طوال اليوم",
"shoppingMore": "+{{count}} أخرى",
"weather": "الطقس",
"familyMembers": "أفراد العائلة",
"participantsAdded": "مشاركون مضافون",
"upcomingBirthdays": "أعياد الميلاد القادمة",
"noBirthdays": "لا توجد أعياد ميلاد بعد",
"daysLeft": "{{count}} أيام",
"budgetOverview": "نظرة عامة على الميزانية",
"monthlyIncome": "الدخل",
"monthlyExpenses": "المصروفات",
"monthlyBalance": "الرصيد",
"savingsRate": "معدل الادخار",
"topExpense": "أكبر مصروف",
"budgetEntries": "القيود",
"noBudgetData": "لا توجد بيانات ميزانية لهذا الشهر.",
"customize": "تخصيص",
"customizeTitle": "تخصيص الأدوات",
"customizeReset": "الافتراضي",
@@ -537,6 +551,7 @@
"tabAccount": "الحساب",
"tabsAriaLabel": "أقسام الإعدادات",
"sectionDesign": "التصميم",
"sectionAppName": "اسم التطبيق",
"sectionShopping": "التسوق",
"shoppingCategoriesLabel": "فئات التسوق",
"shoppingCategoriesHint": "إضافة الفئات أو إعادة تسميتها أو حذفها أو ترتيبها.",
@@ -554,6 +569,16 @@
"sectionCalendarSync": "مزامنة التقويم",
"sectionFamily": "أفراد العائلة",
"cardAppearance": "المظهر",
"appNameTitle": "اسم التطبيق",
"appNameLabel": "اسم التطبيق",
"appNameHint": "يظهر هذا الاسم في الشريط الجانبي وعنوان المتصفح وشاشة تسجيل الدخول.",
"appNamePlaceholder": "Oikos",
"appNameSavedToast": "تم حفظ اسم التطبيق.",
"sectionDate": "التاريخ",
"dateFormatTitle": "تنسيق التاريخ",
"dateFormatLabel": "تنسيق التاريخ المفضل",
"dateFormatHint": "اختر كيف تظهر التواريخ في التطبيق.",
"dateFormatSavedToast": "تم حفظ تنسيق التاريخ.",
"themeSystem": "النظام",
"themeSysLabel": "استخدام إعداد النظام",
"themeLight": "فاتح",
@@ -760,6 +785,34 @@
"placeholder": "بحث…",
"noResults": "لم يتم العثور على نتائج."
},
"birthdays": {
"title": "أعياد الميلاد",
"addButton": "إضافة عيد ميلاد",
"searchPlaceholder": "ابحث عن أعياد الميلاد…",
"upcomingTitle": "أعياد الميلاد القادمة",
"upcomingHint": "الاحتفالات القادمة، وهي متزامنة بالفعل مع التقويم.",
"peopleTitle": "الأشخاص",
"peopleHint": "ابحث وراجع وعدّل جميع أعياد الميلاد المحفوظة.",
"emptyTitle": "لا توجد أعياد ميلاد بعد",
"emptyDescription": "أضف عيد ميلاد ليبقى ظاهرًا في التقويم والتذكيرات.",
"newTitle": "عيد ميلاد جديد",
"editTitle": "تعديل عيد الميلاد",
"nameLabel": "الاسم",
"birthDateLabel": "تاريخ الميلاد",
"photoLabel": "الصورة الشخصية",
"removePhoto": "إزالة الصورة",
"notesLabel": "ملاحظات",
"notesPlaceholder": "أفكار هدايا، الكعكة المفضلة، ملاحظات عائلية…",
"calendarHint": "يتم إضافة كل عيد ميلاد تلقائيًا إلى التقويم ونظام التذكيرات.",
"requiredFields": "الاسم وتاريخ الميلاد مطلوبان.",
"createdToast": "تم حفظ عيد الميلاد.",
"updatedToast": "تم تحديث عيد الميلاد.",
"deletedToast": "تم حذف عيد الميلاد.",
"deleteConfirm": "هل تريد حذف عيد ميلاد \"{{name}}\"؟",
"ageNoteToday": "سيكمل {{age}} عامًا اليوم.",
"ageNoteTomorrow": "سيكمل {{age}} عامًا غدًا.",
"ageNoteDays": "سيكمل {{age}} عامًا بعد {{days}} يومًا."
},
"reminders": {
"sectionTitle": "تذكير",
"enableLabel": "تعيين تذكير",