import { sql } from "kysely"; import { zeitstempel } from "./db/json"; import { istHinzugewaehlt } from "./kollegen"; import type { OrgEb } from "./org"; // Die angefangenen Neueinstellungen auf der Übersicht. // // Bis September 2026 sah jede Person nur die eigenen. Seit die Auswahl in der // Glocke auch hierfür gilt (lib/kollegen.ts), kommen die Entwürfe der // hinzugewählten Kolleg:innen dazu — damit eine angefangene Einstellung nicht // liegen bleibt, weil die eine Person im Urlaub ist und die andere nicht weiss, // dass es sie gibt. // // **Nur ansehen.** Fortsetzen und Löschen bleiben bei der Person, von der der // Entwurf stammt; die Regeln hire_drafts_update und hire_drafts_delete lassen // nichts anderes zu. Ein Entwurf ist unfertige Arbeit ohne Sperre und ohne // Historie — zwei Personen, die abwechselnd hineinschreiben, überschreiben // einander lautlos. export type EntwurfZeile = { id: string; step: number; payload: Record; updated_at: string; created_by: string | null; author_name: string | null; author_email: string | null; }; export type Entwurf = { id: string; step: number; payload: Record; updated_at: string; /** Ob der Entwurf von der angemeldeten Person stammt — nur dann darf sie ihn anfassen. */ vonMir: boolean; /** Wer ihn angefangen hat. Leer bei den eigenen: der Name sagte dort nichts. */ autor: string | null; }; /** * Die Entwürfe als *Teilabfrage* — zum Einhängen in die eine Abfrage, die die * Übersicht ohnehin stellt (lib/db/json.ts). * * Die Bedingung wiederholt, was `hire_drafts_select` ohnehin durchlässt. Das * ist Absicht: die Regel in der Datenbank ist die Grenze, aber sie steht in * einer Migration und lässt sich von hier aus nicht lesen. Steht sie auch in * der Abfrage, sagt der Quelltext, was die Liste zeigt — und ein Test kann es * festhalten. Fällt eine der beiden aus, bleibt die andere. * * `created_by` kann leer sein (die Person wurde gelöscht). Solche Zeilen zeigt * niemand: anders als bei einer Notiz steht in einem Entwurf nichts, was ohne * die Person, die ihn angefangen hat, noch weiterginge. */ export function entwuerfeAbfrage(eb: OrgEb, userId: string) { return eb .selectFrom("hire_drafts as d") .leftJoin("profiles as p", "p.id", "d.created_by") .select(["d.id", "d.step", "d.payload", "d.created_by"]) .select(["p.full_name as author_name", "p.email as author_email"]) .select((x) => zeitstempel(x.ref("d.updated_at")).as("updated_at")) .where((e) => e.or([e("d.created_by", "=", userId), istHinzugewaehlt(userId, "d.created_by")])) // Die eigenen zuerst. Vor der Freigabe standen dort nur sie; wer seinen // halbfertigen Entwurf sucht, soll ihn nicht zwischen fremden suchen. .orderBy(sql`case when "d"."created_by" = ${userId} then 0 else 1 end`) .orderBy("d.updated_at", "desc"); } /** Der reine Teil: aus den Zeilen die Entwürfe mit lesbarem Verfasser. */ export function baueEntwuerfe(rows: EntwurfZeile[], userId: string | null): Entwurf[] { return rows.map((row) => { const vonMir = userId !== null && row.created_by === userId; return { id: row.id, step: row.step, payload: row.payload, updated_at: row.updated_at, vonMir, // Ohne Namen die E-Mail — sonst stünde an einem fremden Entwurf nichts // ausser dem Hinweis, dass er fremd ist. autor: vonMir ? null : row.author_name?.trim() || row.author_email || "Unbekannt", }; }); }