import { useState, useCallback } from 'react'; import AuthenticatedLayout from '@/Layouts/AuthenticatedLayout'; import { Head, Link, router } from '@inertiajs/react'; import { Users, Plus, Pencil, Trash2, Mail, Shield, ArrowUpDown, ArrowUp, ArrowDown, Search, X } from 'lucide-react'; import { Input } from "@/Components/ui/input"; import { debounce } from "lodash"; import { Button } from '@/Components/ui/button'; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@/Components/ui/table"; import { format } from 'date-fns'; import { Can } from '@/Components/Permission/Can'; import { cn } from "@/lib/utils"; import Pagination from "@/Components/shared/Pagination"; import { SearchableSelect } from "@/Components/ui/searchable-select"; import { Switch } from "@/Components/ui/switch"; import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, } from "@/Components/ui/alert-dialog"; interface Role { id: number; name: string; display_name: string; } interface User { id: number; name: string; email: string; username: string | null; created_at: string; roles: Role[]; is_active: boolean; } interface PaginationLinks { url: string | null; label: string; active: boolean; } interface Props { users: { data: User[]; from: number; links: PaginationLinks[]; }; filters: { per_page?: string; sort_by?: string; sort_order?: 'asc' | 'desc'; search?: string; role?: string; is_active?: string; }; roles: Role[]; } export default function UserIndex({ users, roles, filters }: Props) { const [perPage, setPerPage] = useState(filters.per_page || "10"); const [searchTerm, setSearchTerm] = useState(filters.search || ""); const [roleFilter, setRoleFilter] = useState(filters.role || "all"); const [isActiveFilter, setIsActiveFilter] = useState(filters.is_active || "all"); const [deleteId, setDeleteId] = useState(null); const [deleteName, setDeleteName] = useState(''); const [modelOpen, setModelOpen] = useState(false); const confirmDelete = (id: number, name: string) => { setDeleteId(id); setDeleteName(name); setModelOpen(true); }; const handleDelete = () => { if (deleteId) { router.delete(route('users.destroy', deleteId), { onSuccess: () => { setModelOpen(false); }, onFinish: () => setModelOpen(false), }); } }; const handlePerPageChange = (value: string) => { setPerPage(value); router.get( route('users.index'), { ...filters, per_page: value, search: searchTerm, role: roleFilter, is_active: isActiveFilter }, { preserveState: false, replace: true, preserveScroll: true } ); }; // Debounced Search Handler const debouncedSearch = useCallback( debounce((term: string, role: string, isActive: string) => { router.get( route('users.index'), { ...filters, search: term, role: role, is_active: isActive }, { preserveState: true, replace: true, preserveScroll: true } ); }, 500), [] ); const handleSearchChange = (term: string) => { setSearchTerm(term); debouncedSearch(term, roleFilter, isActiveFilter); }; const handleRoleChange = (value: string) => { setRoleFilter(value); router.get( route('users.index'), { ...filters, search: searchTerm, role: value, is_active: isActiveFilter }, { preserveState: false, replace: true, preserveScroll: true } ); }; const handleIsActiveChange = (value: string) => { setIsActiveFilter(value); router.get( route('users.index'), { ...filters, search: searchTerm, role: roleFilter, is_active: value }, { preserveState: false, replace: true, preserveScroll: true } ); }; const handleClearSearch = () => { setSearchTerm(""); router.get( route('users.index'), { ...filters, search: "", role: roleFilter, is_active: isActiveFilter }, { preserveState: true, replace: true, preserveScroll: true } ); }; const handleSort = (field: string) => { let newSortBy: string | undefined = field; let newSortOrder: 'asc' | 'desc' | undefined = 'asc'; if (filters.sort_by === field) { if (filters.sort_order === 'asc') { newSortOrder = 'desc'; } else { newSortBy = undefined; newSortOrder = undefined; } } router.get( route('users.index'), { ...filters, sort_by: newSortBy, sort_order: newSortOrder }, { preserveState: true, replace: true } ); }; const SortIcon = ({ field }: { field: string }) => { if (filters.sort_by !== field) { return ; } if (filters.sort_order === "asc") { return ; } return ; }; return (

使用者管理

管理系統使用者帳號與角色分配

{/* Toolbar */}
{/* Search */}
handleSearchChange(e.target.value)} className="pl-10 pr-10" /> {searchTerm && ( )}
{/* Role Filter */} ({ label: role.display_name, value: role.id.toString() })) ]} placeholder="角色篩選" className="w-full md:w-[180px]" /> {/* Status Filter */} {/* Action Buttons */}
# 角色 狀態 操作 {users.data.map((user, index) => ( {users.from + index}

{user.name}

{user.email}
{user.roles.length > 0 ? ( user.roles.map(role => (
{role.name === 'super-admin' && } {role.display_name}
)) ) : ( 未分配角色 )}
{user.is_active ? '啟用' : '停用'}
router.patch(route('users.toggle-active', user.id), {}, { preserveScroll: true })} className="data-[state=checked]:bg-green-500" />
{format(new Date(user.created_at), 'yyyy/MM/dd')}
))}
{/* 分頁元件 - 統一樣式 */}
每頁顯示
確定要刪除此使用者嗎? 您即將刪除使用者「{deleteName}」。此操作無法復原,請確認是否繼續。 取消 確認刪除
); }