diff --git a/web/src/components/Einzelstuecke.jsx b/web/src/components/Einzelstuecke.jsx index 400a823..0180749 100644 --- a/web/src/components/Einzelstuecke.jsx +++ b/web/src/components/Einzelstuecke.jsx @@ -48,6 +48,9 @@ export default function Einzelstuecke({ product, locations, shops, isAdmin, onCh const [addForm, setAddForm] = useState(EMPTY_ADD); const [remove, setRemove] = useState(null); // { item, reason, note } | null const [lend, setLend] = useState(null); // Stück, das gerade verliehen wird + // Aufgeklappte Stücke. Die Zeile zeigt nur, was man im Alltag braucht + // (wo liegt es, ist es verliehen) – Kaufdaten und Belege auf Wunsch. + const [offen, setOffen] = useState(() => new Set()); const [showAdd, setShowAdd] = useState(false); // Anlege-Maske ein-/ausklappen const [suggestion, setSuggestion] = useState(null); // { itemId, date } aus PDF-Analyse const [docFile, setDocFile] = useState(null); // Beleg, der beim Anlegen mitkommt @@ -254,6 +257,14 @@ export default function Einzelstuecke({ product, locations, shops, isAdmin, onCh const ortName = (id) => locationPathById(id, locations); + function klappe(id) { + setOffen((alt) => { + const neu = new Set(alt); + if (neu.has(id)) neu.delete(id); else neu.add(id); + return neu; + }); + } + return (
@@ -271,9 +282,7 @@ export default function Einzelstuecke({ product, locations, shops, isAdmin, onCh - - - + @@ -292,36 +301,10 @@ export default function Einzelstuecke({ product, locations, shops, isAdmin, onCh ) : {ortName(it.location_id) || "–"}} - - - - + {/* cell-row statt field-inline: letzteres bricht in Tabellen um + (styles.css) und stellte die Symbole uebereinander. */} + {offen.has(it.id) && ( - + )} ))} - {items.length === 0 && } + {items.length === 0 && }
QRUIDLagerortVerliehen anGekauft amGarantie bisGekauft beiNotizQRUIDLagerortVerliehen an
- {isAdmin ? ( - { if ((e.target.value || "") !== (it.acquired_on || "")) patchItem(it, { acquired_on: e.target.value || null }); }} /> - ) : {it.acquired_on || "–"}} - - {isAdmin ? ( - { if ((e.target.value || "") !== (it.warranty_until || "")) patchItem(it, { warranty_until: e.target.value || null }); }} /> - ) : {it.warranty_until || "–"}} - - {isAdmin ? ( - - ) : {it.shop_name || "–"}} - - {isAdmin ? ( - { if ((e.target.value || "") !== (it.note || "")) patchItem(it, { note: e.target.value || null }); }} /> - ) : {it.note || "–"}} - -
+
{/* Verleihen und Zurücknehmen ist eine Buchung – das darf jeder. */} @@ -337,13 +320,42 @@ export default function Einzelstuecke({ product, locations, shops, isAdmin, onCh )} +
+
+
+ + +
+ +
Verleih
@@ -428,9 +440,10 @@ export default function Einzelstuecke({ product, locations, shops, isAdmin, onCh
Noch keine Einzelstücke.
Noch keine Einzelstücke.
diff --git a/web/src/components/Icon.jsx b/web/src/components/Icon.jsx index 7634c48..090ab51 100644 --- a/web/src/components/Icon.jsx +++ b/web/src/components/Icon.jsx @@ -119,6 +119,8 @@ const PATHS = { ), plus: , + // Aufklappen. Zeigt nach unten; zugeklappt dreht die Zelle es nach rechts. + chevron: , trash: ( <> diff --git a/web/src/components/Verleih.jsx b/web/src/components/Verleih.jsx index 273b7c8..01adc97 100644 --- a/web/src/components/Verleih.jsx +++ b/web/src/components/Verleih.jsx @@ -18,8 +18,10 @@ export function FristBadge({ loan, warnTage = 7 }) { if (!loan || !loan.due_on) return null; const tage = daysUntil(loan.due_on); const art = loan.days_overdue ? "danger" : (tage != null && tage <= warnTage ? "warn" : null); + // Bei Ueberfaelligkeit die Tage ausschreiben: „vor 1 Woche" (relativeExpiry) + // liest sich als Zeitpunkt, gemeint ist aber eine Dauer. const text = loan.days_overdue - ? `überfällig (${relativeExpiry(-loan.days_overdue)})` + ? `${loan.days_overdue} ${loan.days_overdue === 1 ? "Tag" : "Tage"} überfällig` : `zurück ${relativeExpiry(tage)}`; return art ? {text} diff --git a/web/src/styles.css b/web/src/styles.css index 2fe92d3..b122308 100644 --- a/web/src/styles.css +++ b/web/src/styles.css @@ -410,6 +410,10 @@ td select { width: auto; min-width: 0; max-width: 100%; } /* Zelle mit Eingabe plus Kennzeichen (z.B. "niedrig"): eine Zeile, damit das Kennzeichen immer an derselben Stelle sitzt statt mal darunter zu rutschen. */ .cell-row { display: flex; align-items: center; gap: 6px; } +/* Zugeklappt zeigt der Pfeil nach rechts, aufgeklappt nach unten. Eine Drehung + statt zweier Symbole – so bleibt die Bewegung sichtbar. */ +.rot-90 { transform: rotate(-90deg); transition: transform 120ms ease; } +.icon { transition: transform 120ms ease; } /* Zwei Zeilen in einer Zelle: Steuerelement oben, Erläuterung darunter. */ .cell-col { display: flex; flex-direction: column; gap: 2px; align-items: stretch; } /* Beschriftung mit Erklaerung im Tooltip: die gepunktete Linie zeigt an, dass