Files
Vorrania/web/src/dashboard/KartenConfig.jsx
Scarriffle 9b0771ae0e Kategorien-Anteile: einstellbare Kategorie-Tiefe (Unterkategorien zusammenfassen)
/dashboard/by-category bekommt depth: rollt jede Artikel-Kategorie auf ihren
Vorfahren der gewuenschten Stufe hoch (1 = oberste Ebene), ohne depth zaehlt
jede zugeordnete Kategorie einzeln (feinste). Neue Karten-Konfig select
Kategorie-Tiefe (Feinste / oberste / bis 2. / bis 3. Stufe). KartenConfig zeigt
jetzt auch bei select den Hinweis.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-30 17:39:30 +02:00

94 lines
3.4 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import Icon from "../components/Icon";
import { ZEITRAEUME } from "./cards";
import { locationOptions } from "../locationPath";
/**
* Konfig-Dialog einer Karte wie in HomeAssistant: ein eigener Dialog mit den
* Optionen der Karte, statt Dropdowns im Kartenkopf. Welche Felder erscheinen,
* bestimmt `karte.config`. Die Werte landen in den Karten-Props (bzw. `tage`
* beim Zeitraum) und werden mit dem Layout gespeichert.
*/
export default function KartenConfig({
karte, props: karteProps = {}, tage,
produkte = [], locations = [], onProps, onTage, onClose,
}) {
const felder = karte?.config || [];
function feld(f) {
if (f.type === "product") {
return (
<label key={f.key}>
{f.label}
<select value={karteProps[f.key] ?? ""}
onChange={(e) => onProps({ [f.key]: e.target.value ? Number(e.target.value) : undefined })}>
<option value=""> Artikel wählen </option>
{produkte.map((p) => <option key={p.id} value={p.id}>{p.name}</option>)}
</select>
</label>
);
}
if (f.type === "location") {
return (
<label key={f.key}>
{f.label}{f.hint ? <span className="muted small"> ({f.hint})</span> : null}
<select value={karteProps[f.key] ?? ""}
onChange={(e) => onProps({ [f.key]: e.target.value || undefined })}>
<option value=""> alle Orte </option>
{locationOptions(locations).map((o) => <option key={o.id} value={o.id}>{o.label}</option>)}
</select>
</label>
);
}
if (f.type === "zeitraum") {
return (
<label key="zeitraum">
{f.label}
<select value={tage ?? karte.zeitraum} onChange={(e) => onTage(Number(e.target.value))}>
{ZEITRAEUME.map((z) => <option key={z.tage} value={z.tage}>{z.label}</option>)}
</select>
</label>
);
}
if (f.type === "select") {
return (
<label key={f.key}>
{f.label}{f.hint ? <span className="muted small"> ({f.hint})</span> : null}
<select value={karteProps[f.key] ?? f.default ?? ""}
onChange={(e) => onProps({ [f.key]: e.target.value })}>
{(f.optionen || []).map((o) => <option key={o.value} value={o.value}>{o.label}</option>)}
</select>
</label>
);
}
if (f.type === "boolean") {
return (
<label key={f.key} className="check-inline">
<input type="checkbox" checked={karteProps[f.key] ?? f.default ?? false}
onChange={(e) => onProps({ [f.key]: e.target.checked })} />
<span>{f.label}</span>
</label>
);
}
return null;
}
return (
<div className="modal-backdrop" onClick={(e) => e.target === e.currentTarget && onClose()}>
<div className="modal" role="dialog" aria-modal="true">
<div className="modal-head">
<Icon name="settings" size={18} />
<h2>{karte?.titel} einstellen</h2>
</div>
<div className="modal-body" style={{ display: "grid", gap: "var(--sp-3)" }}>
{felder.length === 0
? <p className="muted">Diese Karte hat keine Einstellungen.</p>
: felder.map(feld)}
</div>
<div className="btn-pair">
<button type="button" className="btn primary" onClick={onClose}>Fertig</button>
</div>
</div>
</div>
);
}