161 lines
5.8 KiB
JavaScript
Executable File
161 lines
5.8 KiB
JavaScript
Executable File
// File: frontend/app/(protected)/admin/users/page.jsx
|
|
'use client';
|
|
|
|
import { useState, useEffect } from 'react';
|
|
import { PlusCircle, MoreHorizontal } from 'lucide-react';
|
|
import { api } from '@/lib/api';
|
|
import { Button } from '@/components/ui/button';
|
|
import { Card, CardContent, CardHeader, CardTitle, CardDescription } from '@/components/ui/card';
|
|
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table';
|
|
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuTrigger } from '@/components/ui/dropdown-menu';
|
|
import { Badge } from '@/components/ui/badge';
|
|
|
|
// Import components ที่เราเพิ่งสร้าง
|
|
import { UserFormDialog } from '../_components/user-form-dialog';
|
|
import { ConfirmDeleteDialog } from '../_components/confirm-delete-dialog';
|
|
|
|
|
|
export default function UsersPage() {
|
|
const [users, setUsers] = useState([]);
|
|
const [loading, setLoading] = useState(true);
|
|
|
|
// State สำหรับควบคุม Dialog ทั้งหมด
|
|
const [isFormOpen, setIsFormOpen] = useState(false);
|
|
const [isDeleteOpen, setIsDeleteOpen] = useState(false);
|
|
const [selectedUser, setSelectedUser] = useState(null);
|
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
|
|
|
// Function สำหรับดึงข้อมูลใหม่
|
|
const fetchUsers = async () => {
|
|
try {
|
|
setLoading(true);
|
|
const res = await api.get('/users');
|
|
setUsers(res.data);
|
|
} catch (error) {
|
|
console.error("Failed to fetch users", error);
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
};
|
|
|
|
useEffect(() => {
|
|
fetchUsers();
|
|
}, []);
|
|
|
|
// Handlers สำหรับเปิด Dialog
|
|
const handleCreate = () => {
|
|
setSelectedUser(null);
|
|
setIsFormOpen(true);
|
|
};
|
|
|
|
const handleEdit = (user) => {
|
|
setSelectedUser(user);
|
|
setIsFormOpen(true);
|
|
};
|
|
|
|
const handleDelete = (user) => {
|
|
setSelectedUser(user);
|
|
setIsDeleteOpen(true);
|
|
};
|
|
|
|
// Function ที่จะทำงานเมื่อยืนยันการลบ
|
|
const confirmDeactivate = async () => {
|
|
if (!selectedUser) return;
|
|
setIsSubmitting(true);
|
|
try {
|
|
await api.delete(`/users/${selectedUser.id}`);
|
|
fetchUsers(); // Refresh ข้อมูล
|
|
setIsDeleteOpen(false);
|
|
} catch (error) {
|
|
console.error("Failed to deactivate user", error);
|
|
// ควรมี Alert แจ้งเตือน
|
|
} finally {
|
|
setIsSubmitting(false);
|
|
}
|
|
};
|
|
|
|
|
|
return (
|
|
<>
|
|
<Card>
|
|
<CardHeader>
|
|
<div className="flex items-center justify-between">
|
|
<div>
|
|
<CardTitle>User Accounts</CardTitle>
|
|
<CardDescription>Manage all user accounts and their roles.</CardDescription>
|
|
</div>
|
|
<Button onClick={handleCreate}>
|
|
<PlusCircle className="w-4 h-4 mr-2" /> Add User
|
|
</Button>
|
|
</div>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<Table>
|
|
<TableHeader>
|
|
<TableRow>
|
|
<TableHead>Username</TableHead>
|
|
<TableHead>Email</TableHead>
|
|
<TableHead>Roles</TableHead>
|
|
<TableHead>Status</TableHead>
|
|
<TableHead><span className="sr-only">Actions</span></TableHead>
|
|
</TableRow>
|
|
</TableHeader>
|
|
<TableBody>
|
|
{loading ? (
|
|
<TableRow><TableCell colSpan={5} className="text-center">Loading...</TableCell></TableRow>
|
|
) : (
|
|
users.map((user) => (
|
|
<TableRow key={user.id}>
|
|
<TableCell className="font-medium">{user.username}</TableCell>
|
|
<TableCell>{user.email}</TableCell>
|
|
<TableCell>
|
|
<div className="flex flex-wrap gap-1">
|
|
{user.Roles?.map(role => <Badge key={role.id} variant="secondary">{role.name}</Badge>)}
|
|
</div>
|
|
</TableCell>
|
|
<TableCell>
|
|
<Badge variant={user.is_active ? 'default' : 'destructive'}>
|
|
{user.is_active ? 'Active' : 'Inactive'}
|
|
</Badge>
|
|
</TableCell>
|
|
<TableCell>
|
|
<DropdownMenu>
|
|
<DropdownMenuTrigger asChild>
|
|
<Button variant="ghost" className="w-8 h-8 p-0"><MoreHorizontal className="w-4 h-4" /></Button>
|
|
</DropdownMenuTrigger>
|
|
<DropdownMenuContent align="end">
|
|
<DropdownMenuLabel>Actions</DropdownMenuLabel>
|
|
<DropdownMenuItem onClick={() => handleEdit(user)}>Edit</DropdownMenuItem>
|
|
<DropdownMenuItem onClick={() => handleDelete(user)} className="text-red-500">
|
|
Deactivate
|
|
</DropdownMenuItem>
|
|
</DropdownMenuContent>
|
|
</DropdownMenu>
|
|
</TableCell>
|
|
</TableRow>
|
|
))
|
|
)}
|
|
</TableBody>
|
|
</Table>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
{/* Render Dialogs ที่นี่ (มันจะไม่แสดงผลจนกว่า state จะเป็น true) */}
|
|
<UserFormDialog
|
|
user={selectedUser}
|
|
isOpen={isFormOpen}
|
|
setIsOpen={setIsFormOpen}
|
|
onSuccess={fetchUsers}
|
|
/>
|
|
|
|
<ConfirmDeleteDialog
|
|
isOpen={isDeleteOpen}
|
|
setIsOpen={setIsDeleteOpen}
|
|
isLoading={isSubmitting}
|
|
title="Are you sure?"
|
|
description={`This will deactivate the user "${selectedUser?.username}". They will no longer be able to log in.`}
|
|
onConfirm={confirmDeactivate}
|
|
/>
|
|
</>
|
|
);
|
|
} |