Personalnummer im gedruckten Organigramm, wahlweise
Von Max gewuenscht, ausdruecklich mit Auswahl oben. Ein Haekchen in "Was soll aufs Papier?" stellt die Nummer hinter den Namen -- nicht in eine eigene Zeile: auf einem Blatt mit zweihundert Kaesten kostet jede zusaetzliche Zeile Massstab, und der entscheidet darueber, ob das Blatt noch lesbar ist. Angeboten auf jeder Tiefe, nicht nur bei "mit Personen". Die Leitung einer Einheit steht auch auf den Blaettern, die sonst keine Namen fuehren; ein Haekchen, das dort fehlte, saehe aus, als gaebe es dort keine Namen. Als Kontext statt als Eigenschaft durch den Baum: die Angabe betrifft eine einzige Zeile ganz unten, muesste aber sonst durch vier Signaturen der Seitenerzeugung durchgereicht werden. Und die Kennung der Messung traegt den Schalter mit -- die Zeilen werden breiter, also muss der Massstab neu gemessen werden, sonst liefe das Blatt ueber den Rand.
This commit is contained in:
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
import { ChevronRight, Printer } from "lucide-react";
|
import { ChevronRight, Printer } from "lucide-react";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
|
import { createContext, useCallback, useContext, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
|
||||||
import { Button } from "@/components/ui/Button";
|
import { Button } from "@/components/ui/Button";
|
||||||
import { fmtDate } from "@/lib/format";
|
import { fmtDate } from "@/lib/format";
|
||||||
import type { PrintModel, PrintPerson, PrintUnit } from "@/lib/orgchart-print";
|
import type { PrintModel, PrintPerson, PrintUnit } from "@/lib/orgchart-print";
|
||||||
@@ -40,6 +40,16 @@ const TIEFEN: { wert: Tiefe; label: string; hinweis: string }[] = [
|
|||||||
{ wert: "personen", label: "mit Personen", hinweis: "je Abteilung ein Blatt, mit allen Namen" },
|
{ wert: "personen", label: "mit Personen", hinweis: "je Abteilung ein Blatt, mit allen Namen" },
|
||||||
];
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ob die Personalnummer mitgedruckt wird.
|
||||||
|
*
|
||||||
|
* Als Kontext und nicht als Eigenschaft durch den Baum: die Angabe betrifft
|
||||||
|
* eine einzige Zeile ganz unten (PersonZeile), müsste aber sonst durch jede
|
||||||
|
* Ebene der Seitenerzeugung durchgereicht werden — vier Signaturen für ein
|
||||||
|
* Häkchen. Gewünscht von Max am 30.09., ausdrücklich mit Wahlmöglichkeit.
|
||||||
|
*/
|
||||||
|
const NummerImDruck = createContext(false);
|
||||||
|
|
||||||
type Format = "a4" | "a3";
|
type Format = "a4" | "a3";
|
||||||
// Die Satzfläche ist die Blattgrösse abzüglich der Ränder aus @page, ein
|
// Die Satzfläche ist die Blattgrösse abzüglich der Ränder aus @page, ein
|
||||||
// wenig knapper gerechnet. Die Vorschau bekommt genau diese Masse fest
|
// wenig knapper gerechnet. Die Vorschau bekommt genau diese Masse fest
|
||||||
@@ -160,6 +170,7 @@ function seitenBauen(model: PrintModel, bereiche: PrintUnit[], tiefe: Tiefe, asO
|
|||||||
export function PrintChart({ model, asOf, today }: { model: PrintModel; asOf: string; today: string }) {
|
export function PrintChart({ model, asOf, today }: { model: PrintModel; asOf: string; today: string }) {
|
||||||
const [format, setFormat] = useState<Format>("a4");
|
const [format, setFormat] = useState<Format>("a4");
|
||||||
const [tiefe, setTiefe] = useState<Tiefe>("team");
|
const [tiefe, setTiefe] = useState<Tiefe>("team");
|
||||||
|
const [mitNummer, setMitNummer] = useState(false);
|
||||||
const [gewaehlt, setGewaehlt] = useState<Set<string>>(() => new Set(model.divisions.map((d) => d.id)));
|
const [gewaehlt, setGewaehlt] = useState<Set<string>>(() => new Set(model.divisions.map((d) => d.id)));
|
||||||
const [schritt, setSchritt] = useState<"auswahl" | "vorschau">("auswahl");
|
const [schritt, setSchritt] = useState<"auswahl" | "vorschau">("auswahl");
|
||||||
|
|
||||||
@@ -203,6 +214,7 @@ export function PrintChart({ model, asOf, today }: { model: PrintModel; asOf: st
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<NummerImDruck.Provider value={mitNummer}>
|
||||||
<div className="flex flex-col gap-6">
|
<div className="flex flex-col gap-6">
|
||||||
<style>{`
|
<style>{`
|
||||||
@page { size: ${FORMATE[format].css}; margin: 12mm 14mm 14mm; }
|
@page { size: ${FORMATE[format].css}; margin: 12mm 14mm 14mm; }
|
||||||
@@ -290,6 +302,15 @@ export function PrintChart({ model, asOf, today }: { model: PrintModel; asOf: st
|
|||||||
</button>
|
</button>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Auf jeder Tiefe angeboten, nicht nur bei „mit Personen": die
|
||||||
|
Leitung einer Einheit steht auch auf den Blättern, die sonst
|
||||||
|
keine Namen führen. Ein Häkchen, das dort fehlte, sähe aus, als
|
||||||
|
gäbe es dort keine Namen. */}
|
||||||
|
<label className="mt-3 flex items-center gap-2 text-sm text-ink-body">
|
||||||
|
<input type="checkbox" checked={mitNummer} onChange={(e) => setMitNummer(e.target.checked)} />
|
||||||
|
Personalnummer hinter den Namen drucken
|
||||||
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="mt-5">
|
<div className="mt-5">
|
||||||
@@ -412,7 +433,14 @@ export function PrintChart({ model, asOf, today }: { model: PrintModel; asOf: st
|
|||||||
unterzeile={seite.unterzeile}
|
unterzeile={seite.unterzeile}
|
||||||
seite={i === 0 ? "Übersicht" : `Seite ${i + 1} von ${seiten.length}`}
|
seite={i === 0 ? "Übersicht" : `Seite ${i + 1} von ${seiten.length}`}
|
||||||
/>
|
/>
|
||||||
<Skaliert kennung={`${seite.key}|${format}|${tiefe}`} onFaktor={(f) => meldeMassstab(seite.key, f)}>
|
{/* Die Kennung trägt `mitNummer` mit: die Zeilen werden
|
||||||
|
breiter, also muss der Massstab neu gemessen werden. Ohne
|
||||||
|
das bliebe der Wert des vorigen Laufs stehen, und das Blatt
|
||||||
|
liefe über den Rand. */}
|
||||||
|
<Skaliert
|
||||||
|
kennung={`${seite.key}|${format}|${tiefe}|${mitNummer}`}
|
||||||
|
onFaktor={(f) => meldeMassstab(seite.key, f)}
|
||||||
|
>
|
||||||
<Chart seite={seite} />
|
<Chart seite={seite} />
|
||||||
</Skaliert>
|
</Skaliert>
|
||||||
</Blatt>
|
</Blatt>
|
||||||
@@ -421,6 +449,7 @@ export function PrintChart({ model, asOf, today }: { model: PrintModel; asOf: st
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
</NummerImDruck.Provider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -635,9 +664,15 @@ function Kasten({ unit, mitPersonen }: { unit: PrintUnit; mitPersonen: boolean }
|
|||||||
}
|
}
|
||||||
|
|
||||||
function PersonZeile({ p, leitung }: { p: PrintPerson; leitung?: boolean }) {
|
function PersonZeile({ p, leitung }: { p: PrintPerson; leitung?: boolean }) {
|
||||||
|
const mitNummer = useContext(NummerImDruck);
|
||||||
return (
|
return (
|
||||||
<p className="text-[10px] leading-tight">
|
<p className="text-[10px] leading-tight">
|
||||||
<span className={leitung ? "font-bold text-ink" : "text-ink"}>{p.name}</span>
|
<span className={leitung ? "font-bold text-ink" : "text-ink"}>{p.name}</span>
|
||||||
|
{/* Die Personalnummer hinter den Namen und nicht in eine eigene Zeile:
|
||||||
|
auf einem Blatt mit zweihundert Kästen kostet jede zusätzliche Zeile
|
||||||
|
Massstab, und der entscheidet darüber, ob das Blatt noch lesbar ist.
|
||||||
|
Tabellenziffern, damit die Nummern untereinander stehen. */}
|
||||||
|
{mitNummer && <span className="text-ink-muted tabular-nums"> · {p.personnelNumber}</span>}
|
||||||
{p.absent && <span className="text-ink-muted"> · abwesend</span>}
|
{p.absent && <span className="text-ink-muted"> · abwesend</span>}
|
||||||
<br />
|
<br />
|
||||||
<span className="text-ink-muted">{p.jobTitle}</span>
|
<span className="text-ink-muted">{p.jobTitle}</span>
|
||||||
|
|||||||
@@ -103,6 +103,34 @@ describe("PrintChart — Messung", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Von Max gewünscht (30.09.), ausdrücklich zum An- und Abwählen. Die Nummer
|
||||||
|
// steht hinter dem Namen und nicht in einer eigenen Zeile: auf einem Blatt mit
|
||||||
|
// zweihundert Kästen kostet jede Zeile Massstab.
|
||||||
|
describe("PrintChart — Personalnummer", () => {
|
||||||
|
/** Die Zeile, in der eine Person steht — nicht die Kopfzeile ihrer Einheit. */
|
||||||
|
function personZeile(nachname: string): string {
|
||||||
|
return screen.getAllByText(new RegExp(nachname))[0].closest("p")!.textContent ?? "";
|
||||||
|
}
|
||||||
|
|
||||||
|
it("druckt sie erst, wenn sie angehakt ist", async () => {
|
||||||
|
const user = userEvent.setup();
|
||||||
|
renderChart();
|
||||||
|
await zurVorschau(user);
|
||||||
|
// Wiesinger führt die Gesellschaft und steht damit auf jedem Blatt.
|
||||||
|
expect(personZeile("Wiesinger")).not.toContain("· 1");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("stellt sie hinter den Namen, sobald sie angehakt ist", async () => {
|
||||||
|
const user = userEvent.setup();
|
||||||
|
renderChart();
|
||||||
|
await user.click(screen.getByLabelText(/Personalnummer/));
|
||||||
|
await zurVorschau(user);
|
||||||
|
// Die Leitung steht auch auf Blättern ohne Namensliste — deshalb ist das
|
||||||
|
// Häkchen auf jeder Tiefe zu haben.
|
||||||
|
expect(personZeile("Wiesinger")).toContain("· 1");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe("PrintChart", () => {
|
describe("PrintChart", () => {
|
||||||
it("fragt zuerst, was gedruckt wird, und zeigt vorher kein Blatt", () => {
|
it("fragt zuerst, was gedruckt wird, und zeigt vorher kein Blatt", () => {
|
||||||
renderChart();
|
renderChart();
|
||||||
|
|||||||
Reference in New Issue
Block a user