feat: Interviews, Mail-Papierkorb, Kontaktart
Drei Aenderungen aus dem Alltagsgebrauch:
- Der Kalender heisst jetzt "Interviews" - dafuer wird er benutzt. Der Wert in
ViewState wandert mit, damit Menue und Kopfzeile nicht auseinanderlaufen.
Sichtbare Reste ("Kalenderfarbe") heissen jetzt Terminfarbe.
- Mails haben einen Papierkorb, der unter dem Menuepunkt aufklappt. Loeschen
heisst dabei ausschliesslich: im CRM. Im Postfach crm@perinco.de bleibt die
Mail unberuehrt - Schreibrechte darauf hat die Anwendung nicht. Damit der
Delta-Abgleich geloeschte Mails nicht wieder einliest, bleibt nach dem Leeren
eine leere Zeile als Merker stehen (crm_purged); runMailSync() ueberspringt
alles, was im CRM geloescht ist. Zurueckholen und Leeren darf jeder
Angemeldete, Leeren nach einer Warnung.
- Der Kontaktstatus (Neu .. Verloren) wird zur Kontaktart: Recruiter, Partner,
Endkunde. Die Spalte heisst jetzt kind, weil "Status" das Feld falsch
benannte. migrateLeadKind() stellt bestehende Datenbanken um und setzt alle
vorhandenen Kontakte auf Recruiter - welche Art jemand ist, sagt der alte
Status nicht (so mit dem Nutzer entschieden).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
025390e18a
commit
8741a9ae0c
+3
-3
@@ -85,7 +85,7 @@ export const authApi = {
|
||||
}),
|
||||
me: () => request<{ user: AppUser }>('/auth/me'),
|
||||
/**
|
||||
* Eigene Kalenderfarbe und eigenes Foto setzen - ohne Adminrechte.
|
||||
* Eigene Terminfarbe und eigenes Foto setzen - ohne Adminrechte.
|
||||
* null setzt zurueck: Farbe auf die Palettenfarbe, Foto auf die Initiale.
|
||||
*/
|
||||
updateMe: (input: { color?: string | null; avatar?: string | null }) =>
|
||||
@@ -113,7 +113,7 @@ export interface UserInput {
|
||||
export const usersApi = {
|
||||
list: () => request<AppUser[]>('/users'),
|
||||
/**
|
||||
* Aktive Benutzer - fuer jeden Angemeldeten abrufbar. Der Kalender braucht
|
||||
* Aktive Benutzer - fuer jeden Angemeldeten abrufbar. Die Terminansicht braucht
|
||||
* die Liste fuer @-Mentions, Teilnehmer und Farben, auch fuer Rolle "user".
|
||||
*/
|
||||
directory: () => request<AppUser[]>('/users/directory'),
|
||||
@@ -197,7 +197,7 @@ export const opportunitiesApi = {
|
||||
remove: (id: number) => request<{ ok: true }>(`/opportunities/${id}`, { method: 'DELETE' }),
|
||||
};
|
||||
|
||||
// ---------- Kalender ----------
|
||||
// ---------- Interviews (Termine) ----------
|
||||
|
||||
export interface EventInput {
|
||||
title: string;
|
||||
|
||||
+29
-1
@@ -23,7 +23,11 @@ export interface MailMessageSummary {
|
||||
received_at: string;
|
||||
body_preview: string | null;
|
||||
has_attachments: boolean;
|
||||
/** Im Postfach geloescht - nicht zu verwechseln mit `crm_deleted_at`. */
|
||||
is_deleted: boolean;
|
||||
/** Gesetzt = liegt im Papierkorb des CRM (UTC). */
|
||||
crm_deleted_at: string | null;
|
||||
crm_deleted_by_name: string | null;
|
||||
web_link: string | null;
|
||||
link_count: number;
|
||||
open_candidates: number;
|
||||
@@ -115,6 +119,8 @@ export interface MailStatus {
|
||||
last_candidates: number;
|
||||
counts: {
|
||||
messages: number;
|
||||
/** Mails im Papierkorb des CRM. */
|
||||
trash: number;
|
||||
open_candidates: number;
|
||||
adopted_candidates: number;
|
||||
links: number;
|
||||
@@ -133,6 +139,8 @@ export interface MailSyncResult {
|
||||
deletedMessages?: number;
|
||||
newCandidates?: number;
|
||||
adoptedContacts?: number;
|
||||
/** Im CRM geloeschte Mails, die der Abgleich deshalb nicht angefasst hat. */
|
||||
skippedTrashed?: number;
|
||||
hasMore?: boolean;
|
||||
error?: string;
|
||||
}
|
||||
@@ -171,12 +179,22 @@ export type MailListFilter = 'alle' | 'unlinked' | 'linked' | 'candidates';
|
||||
export const mailApi = {
|
||||
status: () => apiRequest<MailStatus>('/mail/status'),
|
||||
|
||||
messages: (params: { search?: string; filter?: MailListFilter; limit?: number; offset?: number } = {}) => {
|
||||
messages: (
|
||||
params: {
|
||||
search?: string;
|
||||
filter?: MailListFilter;
|
||||
limit?: number;
|
||||
offset?: number;
|
||||
/** true = nur der Papierkorb, sonst alles ausser dem Papierkorb. */
|
||||
trash?: boolean;
|
||||
} = {}
|
||||
) => {
|
||||
const query = new URLSearchParams();
|
||||
if (params.search) query.set('search', params.search);
|
||||
if (params.filter && params.filter !== 'alle') query.set('filter', params.filter);
|
||||
if (params.limit) query.set('limit', String(params.limit));
|
||||
if (params.offset) query.set('offset', String(params.offset));
|
||||
if (params.trash) query.set('trash', 'true');
|
||||
const suffix = query.toString() ? `?${query}` : '';
|
||||
return apiRequest<{ total: number; limit: number; offset: number; messages: MailMessageSummary[] }>(
|
||||
`/mail/messages${suffix}`
|
||||
@@ -193,6 +211,16 @@ export const mailApi = {
|
||||
|
||||
unlink: (linkId: number) => apiRequest<{ ok: true }>(`/mail/links/${linkId}`, { method: 'DELETE' }),
|
||||
|
||||
/**
|
||||
* Papierkorb. Geloescht wird ausschliesslich im CRM - das Postfach
|
||||
* crm@perinco.de bleibt unberuehrt, der Abgleich holt geloeschte Mails aber
|
||||
* nicht wieder herein.
|
||||
*/
|
||||
trashMessage: (id: number) => apiRequest<{ ok: true }>(`/mail/messages/${id}`, { method: 'DELETE' }),
|
||||
restoreMessage: (id: number) =>
|
||||
apiRequest<{ ok: true }>(`/mail/messages/${id}/restore`, { method: 'POST' }),
|
||||
emptyTrash: () => apiRequest<{ ok: true; purged: number }>('/mail/trash/empty', { method: 'POST' }),
|
||||
|
||||
candidates: (params: { status?: CandidateStatus | 'alle'; limit?: number } = {}) => {
|
||||
const query = new URLSearchParams();
|
||||
query.set('status', params.status ?? 'offen');
|
||||
|
||||
Reference in New Issue
Block a user