fieles neues
This commit is contained in:
@@ -1,20 +1,35 @@
|
||||
import { useState, useEffect, useCallback } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { databases, DATABASE_ID } from '@/lib/appwrite';
|
||||
import { ID, Query } from 'appwrite';
|
||||
import Header from './Header';
|
||||
import { useToast } from '@/hooks/useToast';
|
||||
import FilialDetail from './FilialDetail';
|
||||
import UserCreateForm from './UserCreateForm';
|
||||
import { Card, CardHeader, CardTitle, CardContent } from '@/components/ui/card';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { Separator } from '@/components/ui/separator';
|
||||
import { ScrollArea } from '@/components/ui/scroll-area';
|
||||
|
||||
const ROLE_LABELS = {
|
||||
admin: 'Admin',
|
||||
firmenleiter: 'Firmenleiter',
|
||||
filialleiter: 'Filialleiter',
|
||||
service: 'Service',
|
||||
lager: 'Lager',
|
||||
};
|
||||
|
||||
export default function AdminPanel() {
|
||||
const { showToast } = useToast();
|
||||
const navigate = useNavigate();
|
||||
|
||||
const [stats, setStats] = useState({ users: 0, locations: 0, assets: 0, lagerstandorte: 0, locationsWithoutFilialleiter: 0 });
|
||||
const [locations, setLocations] = useState([]);
|
||||
const [users, setUsers] = useState([]);
|
||||
const [userSearchQuery, setUserSearchQuery] = useState('');
|
||||
const [showUserForm, setShowUserForm] = useState(false);
|
||||
const [newFiliale, setNewFiliale] = useState({ name: '', address: '' });
|
||||
const [addingFiliale, setAddingFiliale] = useState(false);
|
||||
const [editingId, setEditingId] = useState(null);
|
||||
@@ -24,11 +39,12 @@ export default function AdminPanel() {
|
||||
try {
|
||||
const [locsRes, usersRes, assetsRes, lsRes] = await Promise.all([
|
||||
databases.listDocuments(DATABASE_ID, 'locations', [Query.limit(100)]),
|
||||
databases.listDocuments(DATABASE_ID, 'users_meta', [Query.limit(200)]),
|
||||
databases.listDocuments(DATABASE_ID, 'users_meta', [Query.limit(500)]),
|
||||
databases.listDocuments(DATABASE_ID, 'assets', [Query.limit(1)]),
|
||||
databases.listDocuments(DATABASE_ID, 'lagerstandorte', [Query.limit(1)]),
|
||||
]);
|
||||
setLocations(locsRes.documents);
|
||||
setUsers(usersRes.documents);
|
||||
const locationsWithoutFilialleiter = locsRes.documents.filter(
|
||||
(loc) => !usersRes.documents.some((u) => u.locationId === loc.$id && u.role === 'filialleiter')
|
||||
).length;
|
||||
@@ -115,6 +131,19 @@ export default function AdminPanel() {
|
||||
}
|
||||
}
|
||||
|
||||
const filteredUsers = users.filter(
|
||||
(u) =>
|
||||
!userSearchQuery.trim() ||
|
||||
(u.userName || '').toLowerCase().includes(userSearchQuery.toLowerCase()) ||
|
||||
(u.userId || '').toLowerCase().includes(userSearchQuery.toLowerCase())
|
||||
);
|
||||
|
||||
const getLocationName = (locationId) => {
|
||||
if (!locationId) return 'Nicht zugeordnet';
|
||||
const loc = locations.find((l) => l.$id === locationId);
|
||||
return loc?.name || 'Unbekannte Filiale';
|
||||
};
|
||||
|
||||
const statItems = [
|
||||
{ label: 'Benutzer', value: stats.users },
|
||||
{ label: 'Filialen', value: stats.locations },
|
||||
@@ -226,6 +255,70 @@ export default function AdminPanel() {
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card className="mt-6">
|
||||
<CardHeader>
|
||||
<CardTitle>Benutzer verwaltung</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="mb-4 flex gap-2">
|
||||
<Input
|
||||
placeholder="Benutzer suchen..."
|
||||
value={userSearchQuery}
|
||||
onChange={(e) => setUserSearchQuery(e.target.value)}
|
||||
className="max-w-xs"
|
||||
/>
|
||||
<Button size="sm" variant="outline" onClick={() => setShowUserForm(true)}>
|
||||
Neuer Benutzer
|
||||
</Button>
|
||||
</div>
|
||||
<ScrollArea className="h-[280px] rounded-lg border">
|
||||
<div className="space-y-1 p-2">
|
||||
{users
|
||||
.filter((u) =>
|
||||
(u.userName || u.userId || '')
|
||||
.toLowerCase()
|
||||
.includes(userSearchQuery.toLowerCase())
|
||||
)
|
||||
.map((u) => (
|
||||
<button
|
||||
key={u.$id}
|
||||
type="button"
|
||||
onClick={() => navigate(`/admin/user/${u.userId}`)}
|
||||
className="flex w-full items-center justify-between rounded border px-3 py-2 text-left text-sm hover:bg-muted/50"
|
||||
>
|
||||
<span className="font-medium">{u.userName || u.userId}</span>
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-muted-foreground">
|
||||
{locations.find((l) => l.$id === u.locationId)?.name || 'Nicht zugeordnet'}
|
||||
</span>
|
||||
<Badge variant="secondary">{ROLE_LABELS[u.role] || u.role}</Badge>
|
||||
</div>
|
||||
</button>
|
||||
))}
|
||||
{users.filter((u) =>
|
||||
(u.userName || u.userId || '').toLowerCase().includes(userSearchQuery.toLowerCase())
|
||||
).length === 0 && (
|
||||
<p className="py-4 text-center text-sm text-muted-foreground">
|
||||
{userSearchQuery ? 'Keine Benutzer gefunden' : 'Keine Benutzer vorhanden'}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</ScrollArea>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{showUserForm && (
|
||||
<UserCreateForm
|
||||
locations={locations}
|
||||
onSuccess={() => {
|
||||
setShowUserForm(false);
|
||||
loadData();
|
||||
}}
|
||||
onCancel={() => setShowUserForm(false)}
|
||||
showToast={showToast}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user