Geburtstagskalender + Geburtstagsgruß-Modal im Kundenportal

Admin (Vertrags-Cockpit):
- Neue Section "Geburtstage" zeigt Kunden mit Geburtstag
- Fenster: -7 bis +30 Tage um heute
- Farbcodierung: heute (pink), vergangen (amber), bevorstehend (grau)
- Anzeige: Name, Kundennummer, Geburtsdatum, Alter, "Heute!" / "In X Tagen" / "Vor X Tagen"

Portal (Kundenportal):
- Modal mit Geburtstagsgruß wenn Geburtstag heute oder in den letzten 7 Tagen war
- Unterscheidet zwischen aktuellem Geburtstag und nachträglichen Glückwünschen
- Schönes Gradient-Design mit Konfetti-Emojis
- Wird pro Jahr nur einmal angezeigt (Customer.lastBirthdayGreetingYear)
- Bestätigung speichert das aktuelle Jahr

Backend:
- Neues Feld Customer.lastBirthdayGreetingYear (Int?)
- Service birthday.service.ts mit Fenster-Logik + Alter-Berechnung
- Endpoints /api/birthdays/upcoming (Admin),
  /api/birthdays/my-birthday (Portal GET + POST /acknowledge)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-23 11:51:20 +02:00
parent 2775e9d4dc
commit 018784cca6
9 changed files with 467 additions and 1 deletions
+40
View File
@@ -1579,4 +1579,44 @@ export const publicApi = {
getConsentPdfUrl: (hash: string) => `/api/public/consent/${hash}/pdf`,
};
// ============ BIRTHDAY API ============
export interface BirthdayEntry {
customerId: number;
customerNumber: string;
name: string;
birthDate: string;
age: number;
daysUntil: number;
isToday: boolean;
isPast: boolean;
portalEnabled: boolean;
email?: string | null;
phone?: string | null;
}
export interface MyBirthdayCheck {
show: boolean;
isToday: boolean;
daysAgo: number;
firstName: string;
age: number;
}
export const birthdayApi = {
getUpcoming: async (past: number = 7, future: number = 30) => {
const res = await api.get<ApiResponse<BirthdayEntry[]>>('/birthdays/upcoming', {
params: { past, future },
});
return res.data;
},
getMyBirthday: async () => {
const res = await api.get<ApiResponse<MyBirthdayCheck | null>>('/birthdays/my-birthday');
return res.data;
},
acknowledgeMyBirthday: async () => {
const res = await api.post<ApiResponse<void>>('/birthdays/my-birthday/acknowledge');
return res.data;
},
};
export default api;