6879c756f2
- E-Mail-Planer: Anspruch vor dem Senden (genau eine Mail je Faelligkeit, hoechstens 3 Versuche), Systemlesen nur fuer die Kandidatenabfrage - MailService.sendReminderEmail (Berliner Zeit, nur Text), GET /reminders/email-status, Haken im Formular mit Erklaerung - Zugriffsklassifikation und Erlaubnisliste fuer forSystem nachgezogen, Aenderungsliste und Anwenderanleitung Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
94 lines
3.1 KiB
TypeScript
94 lines
3.1 KiB
TypeScript
/**
|
|
* Erinnerungen — API-Klient (quick-260929-if2). Spiegelt den
|
|
* `RemindersController` der API. Alle Aufrufe mit `credentials: 'include'`
|
|
* (Cookie-Anmeldung), Muster `favorites-api.ts`.
|
|
*/
|
|
|
|
const API_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:3001';
|
|
|
|
/** Ereignis nach jeder erfolgreichen Aenderung — der globale Melder laedt daraufhin neu. */
|
|
export const REMINDERS_CHANGED_EVENT = 'tessera:reminders-changed';
|
|
|
|
/** Eine Erinnerung; Zeitangaben als ISO-Zeichenketten (so liefert sie die API). */
|
|
export interface Reminder {
|
|
id: string;
|
|
title: string;
|
|
description: string;
|
|
dueAt: string;
|
|
emailEnabled: boolean;
|
|
createdAt: string;
|
|
updatedAt: string;
|
|
}
|
|
|
|
/** Ein abgewiesener Aufruf; `status` ist der HTTP-Status (401, 404, 409 ...). */
|
|
export class ReminderRequestError extends Error {
|
|
public readonly status: number;
|
|
|
|
constructor(status: number) {
|
|
super(`Reminder request failed (${status})`);
|
|
this.name = 'ReminderRequestError';
|
|
this.status = status;
|
|
}
|
|
}
|
|
|
|
async function request<T>(path: string, init?: RequestInit): Promise<T> {
|
|
const res = await fetch(`${API_URL}${path}`, { credentials: 'include', ...init });
|
|
if (!res.ok) throw new ReminderRequestError(res.status);
|
|
return res.json() as Promise<T>;
|
|
}
|
|
|
|
function jsonInit(method: string, body: unknown): RequestInit {
|
|
return {
|
|
method,
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify(body),
|
|
};
|
|
}
|
|
|
|
/** Die eigenen Erinnerungen, die naechste Faelligkeit zuerst. */
|
|
export function listReminders(): Promise<Reminder[]> {
|
|
return request<Reminder[]>('/reminders');
|
|
}
|
|
|
|
export interface ReminderInput {
|
|
title: string;
|
|
description?: string;
|
|
/** ISO-8601-Zeitpunkt. */
|
|
dueAt: string;
|
|
/** Zusaetzlich per E-Mail erinnern; nur senden, wenn es sich aendert oder `true` ist. */
|
|
emailEnabled?: boolean;
|
|
}
|
|
|
|
export function createReminder(input: ReminderInput): Promise<Reminder> {
|
|
return request<Reminder>('/reminders', jsonInit('POST', input));
|
|
}
|
|
|
|
export type ReminderPatch = Partial<ReminderInput>;
|
|
|
|
export function updateReminder(id: string, patch: ReminderPatch): Promise<Reminder> {
|
|
return request<Reminder>(`/reminders/${encodeURIComponent(id)}`, jsonInit('PATCH', patch));
|
|
}
|
|
|
|
/** „Spaeter erinnern“: neue Faelligkeit (ISO), nur bei einer faelligen Erinnerung. */
|
|
export function snoozeReminder(id: string, dueAt: string): Promise<Reminder> {
|
|
return request<Reminder>(
|
|
`/reminders/${encodeURIComponent(id)}/snooze`,
|
|
jsonInit('POST', { dueAt }),
|
|
);
|
|
}
|
|
|
|
/** Loescht die Erinnerung — bedient „Loeschen“ (vorher) und „Erledigt“ (nachher). */
|
|
export function deleteReminder(id: string): Promise<{ deleted: true }> {
|
|
return request<{ deleted: true }>(`/reminders/${encodeURIComponent(id)}`, { method: 'DELETE' });
|
|
}
|
|
|
|
/** Ob die E-Mail-Erinnerung fuer diesen Benutzer moeglich ist (Versand eingerichtet, Adresse vorhanden). */
|
|
export interface ReminderEmailStatus {
|
|
smtpConfigured: boolean;
|
|
hasEmail: boolean;
|
|
}
|
|
|
|
export function getReminderEmailStatus(): Promise<ReminderEmailStatus> {
|
|
return request<ReminderEmailStatus>('/reminders/email-status');
|
|
}
|