import type { Tx } from "./db"; import { jsonArrayFrom, zeitstempel } from "./db/json"; import { fmtName } from "./format"; import type { OrgEb } from "./org"; import type { Database } from "./types"; export type OpenNote = Database["public"]["Tables"]["employee_notes"]["Row"] & { employeeName: string; }; /** Was die Teilabfrage liefert: die Notiz plus den Namen aus dem Join. */ export type NotizZeile = Omit & { created_at: string; done_at: string | null; first_name: string | null; last_name: string | null; }; // „Meine Notizen" (Topbar-Glocke): das geteilte, mitarbeiterübergreifende // Postfach aller noch nicht erledigten HR-Notizen — unabhängig davon, wer sie // verfasst hat oder zu wem sie gehören (mit Nutzer abgestimmt). // // Früher zwei Abfragen, in JavaScript zusammengeführt, weil die API-Schicht // für eine einzelne verschachtelte Abfrage keine Verknüpfung anbot. Am // direkten Zugang ist es schlicht ein Join. /** * Die offenen Notizen als *Teilabfrage* — zum Einhängen in die eine Abfrage, * die eine Seite ohnehin stellt (lib/db/json.ts). * * Die beiden Zeitstempel gehen durch zeitstempel(): innerhalb von JSON * formatiert Postgres sie anders als der Treiber es sonst täte, und der * Unterschied fällt erst beim Vergleichen auf. */ export function offeneNotizenAbfrage(eb: OrgEb) { return eb .selectFrom("employee_notes as n") .leftJoin("employees as e", "e.id", "n.employee_id") .select([ "n.id", "n.employee_id", "n.author_user_id", "n.author_name", "n.category", "n.note_text", "n.due_date", "n.done", "n.done_by", "e.first_name", "e.last_name", ]) .select((x) => [zeitstempel(x.ref("n.created_at")).as("created_at"), zeitstempel(x.ref("n.done_at")).as("done_at")]) .where("n.done", "=", false) .orderBy("n.created_at", "desc"); } /** Der reine Teil: aus den Zeilen die Notizen mit lesbarem Namen. */ export function baueOffeneNotizen(rows: NotizZeile[]): OpenNote[] { return rows.map((row) => { const { first_name, last_name, ...note } = row; return { ...(note as Database["public"]["Tables"]["employee_notes"]["Row"]), employeeName: first_name && last_name ? fmtName(first_name, last_name) : "Unbekannt", }; }); } export async function loadOpenNotes(tx: Tx): Promise { const { notes } = await tx .selectNoFrom((eb) => [jsonArrayFrom(offeneNotizenAbfrage(eb)).as("notes")]) .executeTakeFirstOrThrow(); return baueOffeneNotizen(notes as NotizZeile[]); }