sharenet/frontend/src/app/users/page.tsx

169 lines
No EOL
5 KiB
TypeScript

/**
* This file is part of Sharenet.
*
* Sharenet is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.
*
* You may obtain a copy of the license at:
* https://creativecommons.org/licenses/by-nc-sa/4.0/
*
* Copyright (c) 2024 Continuist <continuist02@gmail.com>
*/
'use client';
import { useState, useEffect } from 'react';
import { userApi, User } from '@/lib/api';
import { Button } from '@/components/ui/button';
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from '@/components/ui/table';
import {
Dialog,
DialogContent,
DialogHeader,
DialogTitle,
DialogTrigger,
} from '@/components/ui/dialog';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
export default function UsersPage() {
const [users, setUsers] = useState<User[]>([]);
const [isDialogOpen, setIsDialogOpen] = useState(false);
const [editingUser, setEditingUser] = useState<User | null>(null);
const [formData, setFormData] = useState({
username: '',
email: '',
});
useEffect(() => {
loadUsers();
}, []);
const loadUsers = async () => {
try {
const response = await userApi.getAll();
setUsers(response.data);
} catch (error) {
console.error('Error loading users:', error);
}
};
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
try {
if (editingUser) {
await userApi.update(editingUser.id, formData);
} else {
await userApi.create(formData);
}
setIsDialogOpen(false);
setEditingUser(null);
setFormData({ username: '', email: '' });
loadUsers();
} catch (error) {
console.error('Error saving user:', error);
}
};
const handleEdit = (user: User) => {
setEditingUser(user);
setFormData({ username: user.username, email: user.email });
setIsDialogOpen(true);
};
const handleDelete = async (id: string) => {
if (confirm('Are you sure you want to delete this user?')) {
try {
await userApi.delete(id);
loadUsers();
} catch (error) {
console.error('Error deleting user:', error);
}
}
};
return (
<div className="space-y-4">
<div className="flex justify-between items-center">
<h1 className="text-2xl font-bold">Users</h1>
<Dialog open={isDialogOpen} onOpenChange={setIsDialogOpen}>
<DialogTrigger asChild>
<Button onClick={() => {
setEditingUser(null);
setFormData({ username: '', email: '' });
}}>
Add User
</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>{editingUser ? 'Edit User' : 'Add User'}</DialogTitle>
</DialogHeader>
<form onSubmit={handleSubmit} className="space-y-4">
<div className="space-y-2">
<Label htmlFor="username">Username</Label>
<Input
id="username"
value={formData.username}
onChange={(e) => setFormData({ ...formData, username: e.target.value })}
required
/>
</div>
<div className="space-y-2">
<Label htmlFor="email">Email</Label>
<Input
id="email"
type="email"
value={formData.email}
onChange={(e) => setFormData({ ...formData, email: e.target.value })}
required
/>
</div>
<Button type="submit">{editingUser ? 'Update' : 'Create'}</Button>
</form>
</DialogContent>
</Dialog>
</div>
<Table>
<TableHeader>
<TableRow>
<TableHead>ID</TableHead>
<TableHead>Username</TableHead>
<TableHead>Email</TableHead>
<TableHead>Created At</TableHead>
<TableHead>Updated At</TableHead>
<TableHead>Actions</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{users.map((user) => (
<TableRow key={user.id}>
<TableCell>{user.id}</TableCell>
<TableCell>{user.username}</TableCell>
<TableCell>{user.email}</TableCell>
<TableCell>{new Date(user.created_at).toLocaleString()}</TableCell>
<TableCell>{new Date(user.updated_at).toLocaleString()}</TableCell>
<TableCell>
<div className="space-x-2">
<Button variant="outline" size="sm" onClick={() => handleEdit(user)}>
Edit
</Button>
<Button variant="destructive" size="sm" onClick={() => handleDelete(user.id)}>
Delete
</Button>
</div>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</div>
);
}