v1.33: Eintraege in allen Listen loeschbar

This commit is contained in:
2026-10-04 19:13:36 +02:00
parent 20b5dab556
commit 2f873737c2
8 changed files with 325 additions and 10 deletions
+56 -4
View File
@@ -1,7 +1,7 @@
import { Fragment, useMemo, useState } from 'react'
import {
Building2, Home, MapPin, CalendarDays, ArrowUpDown, LayoutGrid, Ruler, Pencil,
Plus, Users, DoorOpen, Search, List, ChevronDown, ChevronRight, Flame,
Plus, Users, DoorOpen, Search, List, ChevronDown, ChevronRight, Flame, Trash2,
} from 'lucide-react'
import { Button } from '@/components/ui/button'
import { Badge } from '@/components/ui/badge'
@@ -321,6 +321,12 @@ function sortiereWohnungen(liste: Unit[]): Unit[] {
/** Wohnungszeile, in Karten- und Listenansicht gleich. */
function WohnungsZeile({ u, gebaeude, festesHaus }: { u: Unit; gebaeude: string[]; festesHaus: string }) {
const { deleteWohnung, role } = useStore()
const loesche = async () => {
if (!window.confirm(`Wohnung ${u.building}, Whg. ${u.number} wirklich löschen?`)) return
const fehler = await deleteWohnung(u.id)
if (fehler) window.alert(fehler)
}
return (
<li className="rounded-xl border bg-slate-50/60 px-3 py-2 dark:border-slate-700 dark:bg-slate-800/60">
<div className="flex items-center justify-between gap-2">
@@ -344,6 +350,17 @@ function WohnungsZeile({ u, gebaeude, festesHaus }: { u: Unit; gebaeude: string[
<span className="flex shrink-0 items-center gap-2">
<span className="font-medium text-slate-700 dark:text-slate-200">{fmtEUR.format(u.warmRent)}</span>
<WohnungDialog wohnung={u} gebaeude={gebaeude} festesHaus={festesHaus} />
{role === 'admin' && (
<button
type="button"
className="text-slate-400 transition-colors hover:text-red-600 dark:text-slate-500 dark:hover:text-red-400"
onClick={loesche}
aria-label={`Wohnung ${u.number} löschen`}
title="Wohnung löschen"
>
<Trash2 className="h-3.5 w-3.5" />
</button>
)}
</span>
</div>
</li>
@@ -378,11 +395,18 @@ function BelegungsFortschritt({ angelegt, soll }: { angelegt: number; soll: numb
}
export default function Bestand() {
const { buildings, units } = useStore()
const { buildings, units, deleteHaus, role } = useStore()
const [suche, setSuche] = useState('')
const [ansicht, setAnsicht] = useState<'karten' | 'liste'>('liste')
const [offen, setOffen] = useState<string | null>(null)
const loescheHaus = async (name: string) => {
if (!window.confirm(`Haus „${name}" wirklich löschen?`)) return
const fehler = await deleteHaus(name)
if (fehler) window.alert(fehler)
if (offen === name) setOffen(null)
}
const gebaeudeNamen = useMemo(
() => buildings.map((b) => b.name).sort(),
[buildings],
@@ -509,7 +533,21 @@ export default function Bestand() {
</div>
</div>
</div>
<HausDialog haus={h} />
<span className="flex shrink-0 items-center gap-1">
<HausDialog haus={h} />
{role === 'admin' && (
<Button
variant="ghost"
size="icon"
className="h-8 w-8 text-slate-400 hover:text-red-600 dark:text-slate-500 dark:hover:text-red-400"
onClick={() => loescheHaus(h.name)}
aria-label={`Haus ${h.adresse} löschen`}
title="Haus löschen"
>
<Trash2 className="h-4 w-4" />
</Button>
)}
</span>
</div>
<dl className="mt-4 grid grid-cols-2 gap-x-4 gap-y-2 text-xs">
<div className="flex items-center gap-1.5 text-slate-500 dark:text-slate-400">
@@ -618,7 +656,21 @@ export default function Bestand() {
</span>
</td>
<td className="px-3 py-2.5 text-right" onClick={(e) => e.stopPropagation()}>
<HausDialog haus={h} />
<span className="inline-flex items-center gap-1">
<HausDialog haus={h} />
{role === 'admin' && (
<Button
variant="ghost"
size="icon"
className="h-8 w-8 text-slate-400 hover:text-red-600 dark:text-slate-500 dark:hover:text-red-400"
onClick={() => loescheHaus(h.name)}
aria-label={`Haus ${h.adresse} löschen`}
title="Haus löschen"
>
<Trash2 className="h-4 w-4" />
</Button>
)}
</span>
</td>
</tr>
{aufgeklappt && (