Gerichte: Live-Suche
Filtert die Liste bereits während des Tippens (Name, ohne Groß-/ Kleinschreibung). "Alle auswählen" bezieht sich auf die gefilterte Liste, Treffer-Hinweis bei leerem Ergebnis.
This commit is contained in:
@@ -21,6 +21,13 @@ export default function DishManager() {
|
|||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
const [selected, setSelected] = useState<Set<string>>(new Set());
|
const [selected, setSelected] = useState<Set<string>>(new Set());
|
||||||
const [bulkBusy, setBulkBusy] = useState(false);
|
const [bulkBusy, setBulkBusy] = useState(false);
|
||||||
|
const [search, setSearch] = useState("");
|
||||||
|
|
||||||
|
// Live-Suche: filtert die Liste bereits während des Tippens
|
||||||
|
const visible = useMemo(() => {
|
||||||
|
const q = search.trim().toLowerCase();
|
||||||
|
return q ? dishes.filter((d) => d.name.toLowerCase().includes(q)) : dishes;
|
||||||
|
}, [dishes, search]);
|
||||||
|
|
||||||
const load = useCallback(async () => {
|
const load = useCallback(async () => {
|
||||||
const { data, error } = await supabase
|
const { data, error } = await supabase
|
||||||
@@ -83,10 +90,16 @@ export default function DishManager() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// "Alle auswählen" bezieht sich auf die aktuell gefilterte Liste
|
||||||
function toggleAll() {
|
function toggleAll() {
|
||||||
setSelected((prev) =>
|
setSelected((prev) => {
|
||||||
prev.size === dishes.length ? new Set() : new Set(dishes.map((d) => d.id))
|
const next = new Set(prev);
|
||||||
);
|
const everyVisibleSelected = visible.every((d) => next.has(d.id));
|
||||||
|
visible.forEach((d) =>
|
||||||
|
everyVisibleSelected ? next.delete(d.id) : next.add(d.id)
|
||||||
|
);
|
||||||
|
return next;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function removeSelected() {
|
async function removeSelected() {
|
||||||
@@ -109,7 +122,8 @@ export default function DishManager() {
|
|||||||
await load();
|
await load();
|
||||||
}
|
}
|
||||||
|
|
||||||
const allSelected = dishes.length > 0 && selected.size === dishes.length;
|
const allSelected =
|
||||||
|
visible.length > 0 && visible.every((d) => selected.has(d.id));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="max-w-3xl">
|
<div className="max-w-3xl">
|
||||||
@@ -182,6 +196,16 @@ export default function DishManager() {
|
|||||||
<p className="text-gray-500">Lade Gerichte…</p>
|
<p className="text-gray-500">Lade Gerichte…</p>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
|
{dishes.length > 0 && (
|
||||||
|
<input
|
||||||
|
type="search"
|
||||||
|
className="input mb-3"
|
||||||
|
placeholder="Gericht suchen…"
|
||||||
|
value={search}
|
||||||
|
onChange={(e) => setSearch(e.target.value)}
|
||||||
|
aria-label="Gerichte durchsuchen"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
{dishes.length > 0 && (
|
{dishes.length > 0 && (
|
||||||
<div className="flex items-center gap-3 mb-2 text-sm">
|
<div className="flex items-center gap-3 mb-2 text-sm">
|
||||||
<label className="flex items-center gap-2 cursor-pointer">
|
<label className="flex items-center gap-2 cursor-pointer">
|
||||||
@@ -206,7 +230,7 @@ export default function DishManager() {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<ul className="divide-y divide-gray-200 border border-gray-200 rounded-md bg-white">
|
<ul className="divide-y divide-gray-200 border border-gray-200 rounded-md bg-white">
|
||||||
{dishes.map((dish) => (
|
{visible.map((dish) => (
|
||||||
<li key={dish.id} className="flex items-center gap-3 px-4 py-2">
|
<li key={dish.id} className="flex items-center gap-3 px-4 py-2">
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
@@ -245,6 +269,11 @@ export default function DishManager() {
|
|||||||
Noch keine Gerichte angelegt.
|
Noch keine Gerichte angelegt.
|
||||||
</li>
|
</li>
|
||||||
)}
|
)}
|
||||||
|
{dishes.length > 0 && visible.length === 0 && (
|
||||||
|
<li className="px-4 py-3 text-gray-500">
|
||||||
|
Keine Treffer für „{search}“.
|
||||||
|
</li>
|
||||||
|
)}
|
||||||
</ul>
|
</ul>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|||||||
Reference in New Issue
Block a user