"use client"; import { useState, useEffect } from "react"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter, DialogClose } from "@/components/ui/dialog"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; import { Pagination, PaginationContent, PaginationEllipsis, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious, } from "@/components/ui/pagination"; import { PlusCircle, Pencil, Trash2, Search, X, Loader2, Eye, EyeOff, KeyRound } from "lucide-react"; import { useToast } from "@/components/ui/toast-provider"; import { Badge } from "@/components/ui/badge"; // Define the User type interface UserApp { id_user: number; username: string; nip: string | null; role_user: 'admin' | 'ketuajurusan' | 'ketuaprodi'; created_at: string; updated_at: string; } export default function DataTableAkun() { const { showSuccess, showError } = useToast(); // State for data const [users, setUsers] = useState([]); const [filteredData, setFilteredData] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); // State for filtering const [searchTerm, setSearchTerm] = useState(""); const [roleFilter, setRoleFilter] = useState("all"); // State for pagination const [currentPage, setCurrentPage] = useState(1); const [pageSize, setPageSize] = useState(10); const [paginatedData, setPaginatedData] = useState([]); // State for form const [formMode, setFormMode] = useState<"add" | "edit" | "reset-password">("add"); const [formData, setFormData] = useState>({}); const [isSubmitting, setIsSubmitting] = useState(false); const [isDialogOpen, setIsDialogOpen] = useState(false); const [showPassword, setShowPassword] = useState(false); // State for delete confirmation const [deleteId, setDeleteId] = useState(null); const [isDeleting, setIsDeleting] = useState(false); const [isDeleteDialogOpen, setIsDeleteDialogOpen] = useState(false); // Fetch data on component mount useEffect(() => { fetchUsers(); }, []); // Filter data when search term or role filter changes useEffect(() => { filterData(); }, [searchTerm, roleFilter, users]); // Update paginated data when filtered data or pagination settings change useEffect(() => { paginateData(); }, [filteredData, currentPage, pageSize]); // Fetch users data from API const fetchUsers = async () => { try { setLoading(true); const response = await fetch("/api/keloladata/data-akun"); if (!response.ok) { throw new Error("Failed to fetch data"); } const data = await response.json(); setUsers(data); setFilteredData(data); setError(null); } catch (err) { setError("Error fetching data. Please try again later."); console.error("Error fetching data:", err); } finally { setLoading(false); } }; // Filter data based on search term and role const filterData = () => { let filtered = [...users]; // Filter by search term if (searchTerm) { filtered = filtered.filter( (item) => (item.username?.toLowerCase() || "").includes(searchTerm.toLowerCase()) || (item.nip?.toLowerCase() || "").includes(searchTerm.toLowerCase()) ); } // Filter by role if (roleFilter && roleFilter !== "all") { filtered = filtered.filter((item) => item.role_user === roleFilter); } setFilteredData(filtered); // Reset to first page when filters change setCurrentPage(1); }; // Paginate data const paginateData = () => { const startIndex = (currentPage - 1) * pageSize; const endIndex = startIndex + pageSize; setPaginatedData(filteredData.slice(startIndex, endIndex)); }; // Get total number of pages const getTotalPages = () => { return Math.ceil(filteredData.length / pageSize); }; // Handle page change const handlePageChange = (page: number) => { setCurrentPage(page); }; // Handle page size change const handlePageSizeChange = (size: string) => { setPageSize(Number(size)); setCurrentPage(1); }; // Reset form data const resetForm = () => { setFormData({}); setShowPassword(false); }; // Handle form input changes const handleInputChange = (e: React.ChangeEvent) => { const { name, value } = e.target; setFormData((prev) => ({ ...prev, [name]: value })); }; // Handle role select change const handleRoleChange = (value: string) => { setFormData((prev) => ({ ...prev, role_user: value as 'admin' | 'ketuajurusan' | 'ketuaprodi' })); }; // Open form dialog for adding new user const handleAdd = () => { setFormMode("add"); resetForm(); setIsDialogOpen(true); }; // Open form dialog for editing user const handleEdit = (data: UserApp) => { setFormMode("edit"); setFormData({ ...data, password: "" }); // Don't include password in edit form initially setIsDialogOpen(true); }; // Open form dialog for resetting password const handleResetPassword = (data: UserApp) => { setFormMode("reset-password"); setFormData({ id_user: data.id_user, username: data.username, nip: data.nip, role_user: data.role_user, password: "" }); setIsDialogOpen(true); }; // Open delete confirmation dialog const handleDeleteConfirm = (id: number) => { setDeleteId(id); setIsDeleteDialogOpen(true); }; // Handle form submission const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); // Validation if (formMode !== "reset-password") { if (!formData.username?.trim()) { showError("Username harus diisi"); return; } if (!formData.role_user) { showError("Role user harus dipilih"); return; } } if (formMode === "add" && !formData.password?.trim()) { showError("Password harus diisi untuk user baru"); return; } if (formMode === "reset-password" && !formData.password?.trim()) { showError("Password baru harus diisi"); return; } setIsSubmitting(true); try { let response; if (formMode === "add") { // Create new user response = await fetch("/api/keloladata/data-akun", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ username: formData.username?.trim(), nip: formData.nip?.trim() || null, password: formData.password, role_user: formData.role_user, }), }); } else { // Update existing user (edit or reset password) const updateData: any = { id_user: formData.id_user, username: formData.username?.trim(), nip: formData.nip?.trim() || null, role_user: formData.role_user, }; // Include password if it's provided if (formData.password?.trim()) { updateData.password = formData.password; } response = await fetch("/api/keloladata/data-akun", { method: "PUT", headers: { "Content-Type": "application/json", }, body: JSON.stringify(updateData), }); } if (!response.ok) { const errorData = await response.json(); throw new Error(errorData.error || "Failed to save data"); } await fetchUsers(); setIsDialogOpen(false); resetForm(); if (formMode === "add") { showSuccess("User berhasil ditambahkan"); } else if (formMode === "reset-password") { showSuccess("Password berhasil direset"); } else { showSuccess("User berhasil diperbarui"); } } catch (err) { console.error("Error saving data:", err); showError(err instanceof Error ? err.message : "Gagal menyimpan data"); } finally { setIsSubmitting(false); } }; // Handle delete const handleDelete = async () => { if (deleteId === null) return; setIsDeleting(true); try { const response = await fetch(`/api/keloladata/data-akun?id_user=${deleteId}`, { method: "DELETE", }); if (!response.ok) { const errorData = await response.json(); throw new Error(errorData.error || "Failed to delete user"); } await fetchUsers(); setIsDeleteDialogOpen(false); setDeleteId(null); showSuccess("User berhasil dihapus"); } catch (err) { console.error("Error deleting data:", err); showError(err instanceof Error ? err.message : "Gagal menghapus user"); } finally { setIsDeleting(false); } }; // Get role badge color const getRoleBadgeColor = (role: string) => { switch (role) { case 'admin': return 'bg-red-500 hover:bg-red-600'; case 'ketuajurusan': return 'bg-blue-500 hover:bg-blue-600'; case 'ketuaprodi': return 'bg-green-500 hover:bg-green-600'; default: return 'bg-gray-500 hover:bg-gray-600'; } }; // Get role label const getRoleLabel = (role: string) => { switch (role) { case 'admin': return 'Admin'; case 'ketuajurusan': return 'Ketua Jurusan'; case 'ketuaprodi': return 'Ketua Prodi'; default: return role; } }; // Calculate the range of entries being displayed function getDisplayRange() { if (filteredData.length === 0) return { start: 0, end: 0 }; const start = (currentPage - 1) * pageSize + 1; const end = Math.min(currentPage * pageSize, filteredData.length); return { start, end }; } // Generate pagination items function renderPaginationItems() { const totalPages = getTotalPages(); const items = []; // Always show first page items.push( handlePageChange(1)} className="cursor-pointer" > 1 ); // Show ellipsis if needed if (currentPage > 3) { items.push( ); } // Show pages around current page for (let i = Math.max(2, currentPage - 1); i <= Math.min(totalPages - 1, currentPage + 1); i++) { if (i === 1 || i === totalPages) continue; items.push( handlePageChange(i)} className="cursor-pointer" > {i} ); } // Show ellipsis if needed if (currentPage < totalPages - 2) { items.push( ); } // Always show last page if there's more than one page if (totalPages > 1) { items.push( handlePageChange(totalPages)} className="cursor-pointer" > {totalPages} ); } return items; } if (loading) { return (
); } if (error) { return (
{error}
); } return (
{/* Header and Actions */}

Kelola Akun

Kelola akun pengguna sistem PODIF

{/* Filters */}
setSearchTerm(e.target.value)} className="pl-8" /> {searchTerm && ( )}
{/* Table Controls */}
Show entries
{/* Table */}
No Username NIP Role Aksi {paginatedData.length === 0 ? ( Tidak ada data yang tersedia ) : ( paginatedData.map((user, index) => ( {(currentPage - 1) * pageSize + index + 1} {user.username} {user.nip || '-'} {getRoleLabel(user.role_user)}
)) )}
{/* Pagination */} {!loading && !error && filteredData.length > 0 && (
Showing {getDisplayRange().start} to {getDisplayRange().end} of {filteredData.length} entries
handlePageChange(Math.max(1, currentPage - 1))} className={currentPage === 1 ? "pointer-events-none opacity-50" : "cursor-pointer"} /> {renderPaginationItems()} handlePageChange(Math.min(getTotalPages(), currentPage + 1))} className={currentPage === getTotalPages() ? "pointer-events-none opacity-50" : "cursor-pointer"} />
)} {/* Form Dialog */} {formMode === "add" ? "Tambah Akun Baru" : formMode === "reset-password" ? "Reset Password" : "Edit Akun"}
{formMode !== "reset-password" && ( <>
)} {formMode === "reset-password" && (

Reset password untuk user: {formData.username}

)} {(formMode === "add" || formMode === "reset-password" || formMode === "edit") && (
)}
{/* Delete Confirmation Dialog */} Konfirmasi Hapus

Apakah Anda yakin ingin menghapus akun ini? Tindakan ini tidak dapat dibatalkan.

); }