| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309 |
- "use client"
- import React, { useState, useEffect } from 'react'
- import { Button } from '@/components/ui/button'
- import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
- import { Input } from '@/components/ui/input'
- import { Label } from '@/components/ui/label'
- import { Alert, AlertDescription } from '@/components/ui/alert'
- import { Badge } from '@/components/ui/badge'
- import { authApi } from '@/lib/api'
- import { useAuth } from '@/lib/auth-context'
- interface User {
- id: string
- username: string
- email?: string
- role: 'admin' | 'user'
- active: boolean
- created_at: string
- last_login?: string
- }
- export function UserManagement() {
- const { user: currentUser } = useAuth()
- const [users, setUsers] = useState<User[]>([])
- const [loading, setLoading] = useState(true)
- const [error, setError] = useState<string | null>(null)
- const [showCreateForm, setShowCreateForm] = useState(false)
- const [editingUser, setEditingUser] = useState<User | null>(null)
- const [formData, setFormData] = useState({
- username: '',
- email: '',
- password: '',
- role: 'user' as 'admin' | 'user',
- active: true
- })
- useEffect(() => {
- loadUsers()
- }, [])
- const loadUsers = async () => {
- try {
- setLoading(true)
- const data = await authApi.getUsers()
- setUsers(data.users || [])
- setError(null)
- } catch (err) {
- setError(err instanceof Error ? err.message : 'Failed to load users')
- } finally {
- setLoading(false)
- }
- }
- const handleCreateUser = async (e: React.FormEvent) => {
- e.preventDefault()
- if (!formData.username.trim() || !formData.password.trim()) {
- setError('Username and password are required')
- return
- }
- try {
- await authApi.createUser({
- username: formData.username.trim(),
- email: formData.email.trim() || undefined,
- password: formData.password,
- role: formData.role
- })
- await loadUsers()
- setFormData({
- username: '',
- email: '',
- password: '',
- role: 'user',
- active: true
- })
- setShowCreateForm(false)
- setError(null)
- } catch (err) {
- setError(err instanceof Error ? err.message : 'Failed to create user')
- }
- }
- const handleUpdateUser = async (e: React.FormEvent) => {
- e.preventDefault()
- if (!editingUser) return
- try {
- await authApi.updateUser(editingUser.id, {
- email: formData.email.trim() || undefined,
- role: formData.role,
- active: formData.active
- })
- await loadUsers()
- setEditingUser(null)
- setFormData({
- username: '',
- email: '',
- password: '',
- role: 'user',
- active: true
- })
- setError(null)
- } catch (err) {
- setError(err instanceof Error ? err.message : 'Failed to update user')
- }
- }
- const handleDeleteUser = async (userId: string, username: string) => {
- if (!confirm(`Are you sure you want to delete user "${username}"? This action cannot be undone.`)) {
- return
- }
- try {
- await authApi.deleteUser(userId)
- setUsers(prev => prev.filter(user => user.id !== userId))
- setError(null)
- } catch (err) {
- setError(err instanceof Error ? err.message : 'Failed to delete user')
- }
- }
- const startEditUser = (user: User) => {
- setEditingUser(user)
- setFormData({
- username: user.username,
- email: user.email || '',
- password: '',
- role: user.role,
- active: user.active
- })
- }
- const cancelEdit = () => {
- setEditingUser(null)
- setFormData({
- username: '',
- email: '',
- password: '',
- role: 'user',
- active: true
- })
- }
- const formatDate = (dateString: string) => {
- return new Date(dateString).toLocaleDateString() + ' ' + new Date(dateString).toLocaleTimeString()
- }
- if (loading) {
- return <div className="p-4">Loading users...</div>
- }
- return (
- <div className="space-y-6">
- {error && (
- <Alert variant="destructive">
- <AlertDescription>{error}</AlertDescription>
- </Alert>
- )}
- <Card>
- <CardHeader>
- <div className="flex justify-between items-center">
- <div>
- <CardTitle>User Management</CardTitle>
- <CardDescription>
- Manage user accounts and permissions
- </CardDescription>
- </div>
- <Button onClick={() => setShowCreateForm(!showCreateForm)}>
- {showCreateForm ? 'Cancel' : 'Create User'}
- </Button>
- </div>
- </CardHeader>
- <CardContent>
- {(showCreateForm || editingUser) && (
- <form onSubmit={editingUser ? handleUpdateUser : handleCreateUser} className="space-y-4 mb-6 p-4 border rounded-lg">
- <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
- <div>
- <Label htmlFor="username">Username</Label>
- <Input
- id="username"
- value={formData.username}
- onChange={(e) => setFormData(prev => ({ ...prev, username: e.target.value }))}
- placeholder="Username"
- required
- disabled={!!editingUser}
- />
- </div>
- <div>
- <Label htmlFor="email">Email</Label>
- <Input
- id="email"
- type="email"
- value={formData.email}
- onChange={(e) => setFormData(prev => ({ ...prev, email: e.target.value }))}
- placeholder="Email (optional)"
- />
- </div>
- {!editingUser && (
- <div>
- <Label htmlFor="password">Password</Label>
- <Input
- id="password"
- type="password"
- value={formData.password}
- onChange={(e) => setFormData(prev => ({ ...prev, password: e.target.value }))}
- placeholder="Password"
- required
- />
- </div>
- )}
- <div>
- <Label htmlFor="role">Role</Label>
- <select
- id="role"
- value={formData.role}
- onChange={(e) => setFormData(prev => ({ ...prev, role: e.target.value as 'admin' | 'user' }))}
- className="w-full p-2 border rounded-md"
- >
- <option value="user">User</option>
- <option value="admin">Admin</option>
- </select>
- </div>
- </div>
- {editingUser && (
- <div className="flex items-center space-x-2">
- <input
- type="checkbox"
- id="active"
- checked={formData.active}
- onChange={(e) => setFormData(prev => ({ ...prev, active: e.target.checked }))}
- />
- <Label htmlFor="active">Active</Label>
- </div>
- )}
- <div className="flex space-x-2">
- <Button type="submit">
- {editingUser ? 'Update User' : 'Create User'}
- </Button>
- <Button type="button" variant="outline" onClick={editingUser ? cancelEdit : () => setShowCreateForm(false)}>
- Cancel
- </Button>
- </div>
- </form>
- )}
- {users.length === 0 ? (
- <div className="text-center py-8 text-muted-foreground">
- No users found. Create your first user to get started.
- </div>
- ) : (
- <div className="space-y-4">
- {users.map((user) => (
- <div key={user.id} className="border rounded-lg p-4">
- <div className="flex justify-between items-start">
- <div className="space-y-2">
- <div className="flex items-center space-x-2">
- <h3 className="font-medium">{user.username}</h3>
- <Badge variant={user.role === 'admin' ? "default" : "secondary"}>
- {user.role}
- </Badge>
- <Badge variant={user.active ? "default" : "destructive"}>
- {user.active ? 'Active' : 'Inactive'}
- </Badge>
- {user.id === currentUser?.id && (
- <Badge variant="outline">You</Badge>
- )}
- </div>
- <div className="text-sm text-muted-foreground">
- {user.email && <p>Email: {user.email}</p>}
- <p>Created: {formatDate(user.created_at)}</p>
- {user.last_login && (
- <p>Last login: {formatDate(user.last_login)}</p>
- )}
- </div>
- </div>
- <div className="flex space-x-2">
- <Button
- size="sm"
- variant="outline"
- onClick={() => startEditUser(user)}
- >
- Edit
- </Button>
- {user.id !== currentUser?.id && (
- <Button
- size="sm"
- variant="destructive"
- onClick={() => handleDeleteUser(user.id, user.username)}
- >
- Delete
- </Button>
- )}
- </div>
- </div>
- </div>
- ))}
- </div>
- )}
- </CardContent>
- </Card>
- </div>
- )
- }
|