"use client"; import { Printer } from "lucide-react"; import { useEffect } from "react"; import { Button } from "@/components/ui/Button"; import { alleReichungen, fortschrittVon, istErledigt, type AufgabenGruppe, type AufgabenStand, } from "@/lib/checklist"; import { artTitel, checklistDateiname, type ChecklistArt } from "@/lib/checklist-print"; import type { ChecklistKopf } from "@/lib/checklist-print-data"; import { fmtDate, fmtName } from "@/lib/format"; // Der Ausdruck einer Checkliste — eine Seite, zum Abheften oder Mitnehmen. // // Warum überhaupt Papier, wenn die Liste in der Anwendung steht: sie wird // besprochen. Beim Eintrittsgespräch liegt sie auf dem Tisch, beim Austritt // geht sie an die Lohnverrechnung, und in einer Personalakte auf Papier fehlt // sie sonst. Gedruckt wird deshalb der **Stand**, mit Datum des Auszugs — kein // Formular zum Ausfüllen. // // Erzeugt wird kein PDF im Server: gedruckt wird über den Browser, wie beim // Organigramm. Der Grund ist derselbe — eine PDF-Bibliothek müsste Schriften, // Umbrüche und Seitenränder selbst nachbauen, und das Ergebnis wäre ein // zweites Aussehen neben dem der Anwendung. Der Dateiname im Speichern-Dialog // kommt aus dem Dokumenttitel; den setzt diese Seite auf die Konvention. const GLYPH_AN = "☒"; const GLYPH_AUS = "☐"; export function PrintChecklist({ art, kopf, gruppen, staende, today, }: { art: ChecklistArt; kopf: ChecklistKopf; gruppen: readonly AufgabenGruppe[]; staende: AufgabenStand[]; /** Vom Server: das Auszugsdatum gehört nicht an die Uhr des Browsers. */ today: string; }) { const dateiname = checklistDateiname(art, kopf, today); // Der Titel ist der Vorschlag im Druckdialog. Ohne ihn hiesse die Datei nach // der Adresse der Seite, also etwa „employees-…-checkliste". useEffect(() => { const vorher = document.title; document.title = dateiname; return () => { document.title = vorher; }; }, [dateiname]); const punkte = alleReichungen(gruppen); const karte = new Map(staende.map((s) => [s.item_key, s])); const stand = fortschrittVon(punkte, staende); return (

So kommt es aus dem Drucker. Vorgeschlagener Dateiname:{" "} {dateiname}.pdf

Im Druckdialog „Als PDF speichern“ wählen. Hintergrundgrafiken müssen dort eingeschaltet sein, sonst fehlen die Flächen hinter den Gruppentiteln — in Chrome unter „Weitere Einstellungen“.

{/* ── Kopf ───────────────────────────────────────────── */}

{artTitel(art)}

Alpenwerk Industrie GmbH

Auszug vom {fmtDate(today)}

Pers.-Nr.
{kopf.personnel_number}
Eintritt
{fmtDate(kopf.entry_date)}
Name
{fmtName(kopf.first_name, kopf.last_name)}
Position
{kopf.position_title ?? kopf.job_title} {kopf.position_number && · Planstelle {kopf.position_number}}
{/* ── Fortschritt ────────────────────────────────────── */}
{stand.erledigt} von {stand.gesamt} erledigt {stand.offen.length > 0 && ( {stand.offen.length} offen )}
{/* ── Die Punkte ─────────────────────────────────────── */}
{gruppen.map((gruppe) => (

{gruppe.label}

    {gruppe.punkte.map((punkt) => { const s = karte.get(punkt.key); const fertig = istErledigt(punkt, s); return (
  • {fertig ? GLYPH_AN : GLYPH_AUS} {punkt.label} {/* Bei Ja/Nein und Text steht der Wert daneben — ein Haken allein sagte dort nicht, was erfasst wurde. */} {punkt.art !== "haken" && ( {": "} {s?.wert ?? "—"} )} {s?.kommentar && ( {s.kommentar} )} {s?.updated_by_name && fertig && ( {s.updated_by_name} {s.updated_at ? ` · ${fmtDate(s.updated_at)}` : ""} )}
  • ); })}
))}
{/* Hier standen zwei Unterschriftenfelder — „Datum, Unterschrift Mitarbeiter:in" und „… Personalabteilung". Der Kunde hat sie gestrichen (Anforderung 3 aus dem Workshop): das Blatt ist eine Arbeitsliste für die Personalabteilung und kein Dokument, das jemand gegenzeichnet. Wer eine Aufgabe abgehakt hat, steht ohnehin an der Aufgabe selbst. */}
); }