- Company DELETE: cascade non-accounting deps (deals, projects, tickets, persons, leads, instances), block only on accounting (invoices, licenses, expenses, contracts) per GoBD rule. Transaction-wrapped. - User management: GET /api/aos/users + PATCH role + DELETE (guards: no self-delete, no last owner delete, no env-admin delete). - User management UI: table with inline role select, 2FA status, delete button. - Settings focus fix: moved Field component outside render (was causing unmount/remount on each keystroke → focus loss). - Bulk delete: useBulkSelect hook + BulkDeleteDialog + BulkActionBar. - Cleaned all demo/mock data; re-bootstrapped admin account.
50 lines
1.3 KiB
TypeScript
50 lines
1.3 KiB
TypeScript
'use client'
|
|
|
|
import { Trash2, X, CheckSquare } from 'lucide-react'
|
|
import { Button } from '@/components/ui/button'
|
|
import { cn } from '@/lib/utils'
|
|
|
|
export function BulkActionBar({
|
|
count,
|
|
entityLabel,
|
|
onDelete,
|
|
onClear,
|
|
className,
|
|
}: {
|
|
count: number
|
|
entityLabel: string
|
|
onDelete: () => void
|
|
onClear: () => void
|
|
className?: string
|
|
}) {
|
|
if (count === 0) return null
|
|
|
|
return (
|
|
<div
|
|
className={cn(
|
|
'fixed bottom-4 left-1/2 z-50 flex -translate-x-1/2 items-center gap-3 rounded-lg border border-border bg-background px-4 py-2.5 shadow-lg',
|
|
className
|
|
)}
|
|
>
|
|
<span className="flex items-center gap-1.5 text-sm font-medium">
|
|
<CheckSquare className="size-4 text-muted-foreground" />
|
|
{count} {count === 1 ? entityLabel : `${entityLabel}e`} ausgewählt
|
|
</span>
|
|
<div className="h-4 w-px bg-border" />
|
|
<Button
|
|
size="sm"
|
|
variant="default"
|
|
className="gap-1.5 bg-foreground text-background hover:bg-foreground/90"
|
|
onClick={onDelete}
|
|
>
|
|
<Trash2 className="size-3.5" />
|
|
Ausgewählte löschen
|
|
</Button>
|
|
<Button size="sm" variant="ghost" className="gap-1" onClick={onClear}>
|
|
<X className="size-3.5" />
|
|
Auswahl aufheben
|
|
</Button>
|
|
</div>
|
|
)
|
|
}
|