feat: list end customers in companies admin and improve dark/light mode contrast across all admin components
All checks were successful
Staging Build / build (push) Successful in 2m36s

This commit is contained in:
DanielS
2026-06-25 02:11:07 +02:00
parent bf27c62f62
commit ef9422908d
11 changed files with 222 additions and 240 deletions

View File

@@ -147,10 +147,10 @@ export function UserList({ initialUsers, companies }: UserListProps) {
let lastCompanyName: string | null = null
return (
<Card className="glass-dark border-white/10 shadow-2xl overflow-visible">
<Card className="bg-white dark:bg-slate-900/50 border border-slate-200 dark:border-white/10 shadow-sm overflow-visible text-slate-900 dark:text-white">
<CardHeader>
<CardTitle>Benutzerverwaltung</CardTitle>
<CardDescription className="text-slate-400">
<CardDescription className="text-slate-500 dark:text-slate-400">
Rollen, Firmenzuweisungen, Passwörter und Benutzerkonten verwalten.
</CardDescription>
</CardHeader>
@@ -163,31 +163,31 @@ export function UserList({ initialUsers, companies }: UserListProps) {
placeholder="Benutzer suchen (E-Mail, Firma, Rolle)..."
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
className="w-full pl-9 pr-4 py-2 text-sm bg-white/5 border border-white/10 rounded-md text-slate-200 placeholder-slate-500 focus:outline-none focus:ring-2 focus:ring-primary focus:ring-offset-2 focus:ring-offset-slate-950 transition-all"
className="w-full pl-9 pr-4 py-2 text-sm bg-slate-50 dark:bg-white/5 border border-slate-200 dark:border-white/10 rounded-md text-slate-900 dark:text-slate-200 placeholder-slate-500 focus:outline-none focus:ring-2 focus:ring-primary focus:ring-offset-2 focus:ring-offset-slate-50 dark:focus:ring-offset-slate-950 transition-all"
/>
</div>
<div className="flex flex-wrap items-center gap-3">
<div className="flex items-center gap-2 bg-white/5 border border-white/10 rounded-md px-3 py-2 cursor-pointer hover:bg-white/10 transition-colors">
<div className="flex items-center gap-2 bg-slate-50 dark:bg-white/5 border border-slate-200 dark:border-white/10 rounded-md px-3 py-2 cursor-pointer hover:bg-slate-100 dark:hover:bg-white/10 transition-colors">
<input
type="checkbox"
id="hideLocked"
checked={hideLocked}
onChange={(e) => setHideLocked(e.target.checked)}
className="h-4 w-4 rounded border-white/10 bg-slate-950 text-primary focus:ring-primary focus:ring-offset-slate-950 accent-primary cursor-pointer"
className="h-4 w-4 rounded border-slate-200 dark:border-white/10 bg-white dark:bg-slate-950 text-primary focus:ring-primary focus:ring-offset-slate-50 dark:focus:ring-offset-slate-950 accent-primary cursor-pointer"
/>
<label htmlFor="hideLocked" className="text-xs text-slate-300 font-medium cursor-pointer select-none">
<label htmlFor="hideLocked" className="text-xs text-slate-700 dark:text-slate-300 font-medium cursor-pointer select-none">
Gesperrte ausblenden
</label>
</div>
<div className="flex items-center gap-2 bg-white/5 border border-white/10 rounded-md px-3 py-2 cursor-pointer hover:bg-white/10 transition-colors">
<div className="flex items-center gap-2 bg-slate-50 dark:bg-white/5 border border-slate-200 dark:border-white/10 rounded-md px-3 py-2 cursor-pointer hover:bg-slate-100 dark:hover:bg-white/10 transition-colors">
<input
type="checkbox"
id="groupByCompany"
checked={groupByCompany}
onChange={(e) => setGroupByCompany(e.target.checked)}
className="h-4 w-4 rounded border-white/10 bg-slate-950 text-primary focus:ring-primary focus:ring-offset-slate-950 accent-primary cursor-pointer"
className="h-4 w-4 rounded border-slate-200 dark:border-white/10 bg-white dark:bg-slate-950 text-primary focus:ring-primary focus:ring-offset-slate-50 dark:focus:ring-offset-slate-950 accent-primary cursor-pointer"
/>
<label htmlFor="groupByCompany" className="text-xs text-slate-300 font-medium cursor-pointer select-none">
<label htmlFor="groupByCompany" className="text-xs text-slate-700 dark:text-slate-300 font-medium cursor-pointer select-none">
Nach Firma gruppieren
</label>
</div>
@@ -195,12 +195,12 @@ export function UserList({ initialUsers, companies }: UserListProps) {
</div>
<Table containerClassName="overflow-visible">
<TableHeader>
<TableRow className="border-white/10 hover:bg-white/5">
<TableHead className="text-slate-200">E-Mail</TableHead>
<TableHead className="text-slate-200">Rolle</TableHead>
<TableHead className="text-slate-200">Firma</TableHead>
<TableHead className="text-slate-200">Zuletzt angemeldet</TableHead>
<TableHead className="text-right text-slate-200">Aktionen</TableHead>
<TableRow className="border-slate-200 dark:border-white/10 hover:bg-slate-50 dark:hover:bg-white/5">
<TableHead className="text-slate-700 dark:text-slate-200">E-Mail</TableHead>
<TableHead className="text-slate-700 dark:text-slate-200">Rolle</TableHead>
<TableHead className="text-slate-700 dark:text-slate-200">Firma</TableHead>
<TableHead className="text-slate-700 dark:text-slate-200">Zuletzt angemeldet</TableHead>
<TableHead className="text-right text-slate-700 dark:text-slate-200">Aktionen</TableHead>
</TableRow>
</TableHeader>
<TableBody>
@@ -217,14 +217,14 @@ export function UserList({ initialUsers, companies }: UserListProps) {
return (
<Fragment key={user.id}>
{showGroupHeader && (
<TableRow className="bg-white/5 border-y border-white/10 hover:bg-white/5">
<TableRow className="bg-slate-50 dark:bg-white/5 border-y border-slate-200 dark:border-white/10 hover:bg-slate-100 dark:hover:bg-white/5">
<TableCell colSpan={5} className="font-semibold text-primary py-2 px-4 text-xs tracking-wider uppercase">
Firma: {currentCompanyName}
</TableCell>
</TableRow>
)}
<TableRow className="border-white/5 hover:bg-white/5 transition-colors">
<TableCell className="font-medium text-white">
<TableRow className="border-slate-150 dark:border-white/5 hover:bg-slate-50 dark:hover:bg-white/5 transition-colors">
<TableCell className="font-medium text-slate-900 dark:text-white">
<div className="flex flex-col">
<div className="flex items-center gap-2">
<Mail className="w-4 h-4 text-slate-500" />
@@ -251,7 +251,7 @@ export function UserList({ initialUsers, companies }: UserListProps) {
(e.target as HTMLInputElement).blur()
}
}}
className="bg-transparent border-b border-transparent hover:border-white/20 focus:border-primary focus:outline-none text-xs text-slate-400 w-20 px-1 py-0.5 transition-all placeholder:text-slate-600 placeholder:italic"
className="bg-transparent border-b border-transparent hover:border-slate-300 dark:hover:border-white/20 focus:border-primary focus:outline-none text-xs text-slate-600 dark:text-slate-400 w-20 px-1 py-0.5 transition-all placeholder:text-slate-500 placeholder:italic"
/>
<input
type="text"
@@ -273,7 +273,7 @@ export function UserList({ initialUsers, companies }: UserListProps) {
(e.target as HTMLInputElement).blur()
}
}}
className="bg-transparent border-b border-transparent hover:border-white/20 focus:border-primary focus:outline-none text-xs text-slate-400 w-24 px-1 py-0.5 transition-all placeholder:text-slate-600 placeholder:italic"
className="bg-transparent border-b border-transparent hover:border-slate-300 dark:hover:border-white/20 focus:border-primary focus:outline-none text-xs text-slate-600 dark:text-slate-400 w-24 px-1 py-0.5 transition-all placeholder:text-slate-500 placeholder:italic"
/>
</div>
</div>
@@ -286,18 +286,18 @@ export function UserList({ initialUsers, companies }: UserListProps) {
<select
value={role}
onChange={(e) => handleRoleChange(user.id, e.target.value as Role)}
className={`text-xs font-semibold rounded px-3 py-1.5 cursor-pointer focus:outline-none focus:ring-2 transition-colors ${
className={`text-xs font-semibold rounded px-3 py-1.5 cursor-pointer focus:outline-none focus:ring-2 transition-colors bg-white dark:bg-slate-950/80 ${
role === 'admin'
? 'bg-purple-500/20 text-purple-300 border border-purple-500/40 focus:ring-purple-500/50'
? 'text-purple-600 dark:text-purple-300 border border-purple-500/40 focus:ring-purple-500/50'
: role === 'gesperrt'
? 'bg-red-500/20 text-red-300 border border-red-500/40 focus:ring-red-500/50'
: 'bg-blue-500/20 text-blue-300 border border-blue-500/40 focus:ring-blue-500/50'
? 'text-red-600 dark:text-red-300 border border-red-500/40 focus:ring-red-500/50'
: 'text-blue-600 dark:text-blue-300 border border-blue-500/40 focus:ring-blue-500/50'
}`}
style={{ appearance: 'auto' }}
>
<option value="admin">Admin</option>
<option value="partner">Partner</option>
<option value="gesperrt">Gesperrt</option>
<option value="admin" className="bg-white dark:bg-slate-900 text-slate-900 dark:text-slate-100">Admin</option>
<option value="partner" className="bg-white dark:bg-slate-900 text-slate-900 dark:text-slate-100">Partner</option>
<option value="gesperrt" className="bg-white dark:bg-slate-900 text-slate-900 dark:text-slate-100">Gesperrt</option>
</select>
)}
</div>
@@ -315,21 +315,21 @@ export function UserList({ initialUsers, companies }: UserListProps) {
setCompanyDropdownOpen(companyDropdownOpen === user.id ? null : user.id)
setCompanySearch('')
}}
className="text-xs bg-white/5 border border-white/10 rounded px-3 py-1.5 text-slate-300 hover:bg-white/10 cursor-pointer focus:outline-none focus:ring-1 focus:ring-primary/50 max-w-[180px] truncate text-left"
className="text-xs bg-slate-50 dark:bg-white/5 border border-slate-200 dark:border-white/10 rounded px-3 py-1.5 text-slate-700 dark:text-slate-300 hover:bg-slate-100 dark:hover:bg-white/10 cursor-pointer focus:outline-none focus:ring-1 focus:ring-primary/50 max-w-[180px] truncate text-left"
>
{user.company_name || 'Keine Firma'}
</button>
)}
</div>
{companyDropdownOpen === user.id && (
<div className="absolute z-50 mt-1 left-0 w-56 bg-slate-900 border border-white/10 rounded-lg shadow-xl overflow-hidden">
<div className="p-2 border-b border-white/10">
<div className="absolute z-50 mt-1 left-0 w-56 bg-white dark:bg-slate-900 border border-slate-200 dark:border-white/10 rounded-lg shadow-xl overflow-hidden">
<div className="p-2 border-b border-slate-200 dark:border-white/10">
<input
type="text"
placeholder="Firma suchen..."
value={companySearch}
onChange={(e) => setCompanySearch(e.target.value)}
className="w-full text-xs bg-white/5 border border-white/10 rounded px-2 py-1.5 text-slate-200 placeholder-slate-500 focus:outline-none focus:ring-1 focus:ring-primary/50"
className="w-full text-xs bg-slate-50 dark:bg-white/5 border border-slate-200 dark:border-white/10 rounded px-2 py-1.5 text-slate-900 dark:text-slate-200 placeholder-slate-500 focus:outline-none focus:ring-1 focus:ring-primary/50"
autoFocus
/>
</div>
@@ -337,8 +337,8 @@ export function UserList({ initialUsers, companies }: UserListProps) {
<button
type="button"
onClick={() => { handleCompanyChange(user.id, ''); setCompanyDropdownOpen(null); setCompanySearch(''); }}
className={`w-full text-left text-xs px-3 py-2 hover:bg-white/10 transition-colors ${
!user.company_id ? 'text-primary font-semibold' : 'text-slate-300'
className={`w-full text-left text-xs px-3 py-2 hover:bg-slate-100 dark:hover:bg-white/10 transition-colors ${
!user.company_id ? 'text-primary font-semibold' : 'text-slate-700 dark:text-slate-300'
}`}
>
Keine Firma
@@ -350,8 +350,8 @@ export function UserList({ initialUsers, companies }: UserListProps) {
key={c.id}
type="button"
onClick={() => { handleCompanyChange(user.id, c.id); setCompanyDropdownOpen(null); setCompanySearch(''); }}
className={`w-full text-left text-xs px-3 py-2 hover:bg-white/10 transition-colors ${
user.company_id === c.id ? 'text-primary font-semibold' : 'text-slate-300'
className={`w-full text-left text-xs px-3 py-2 hover:bg-slate-100 dark:hover:bg-white/10 transition-colors ${
user.company_id === c.id ? 'text-primary font-semibold' : 'text-slate-700 dark:text-slate-300'
}`}
>
{c.name}