"use client" import { useCallback, useEffect, useMemo, useState } from "react" import { KeyRoundIcon, RefreshCwIcon, RouteIcon, SearchIcon } from "lucide-react" import { toast } from "sonner" import { DashboardPage, DashboardTableShell, DashboardTableStateRow, DashboardToolbar, } from "@/components/dashboard-page" import { ListPagination } from "@/components/list-pagination" import { OptionCombobox } from "@/components/option-combobox" import { Badge } from "@/components/ui/badge" import { Button } from "@/components/ui/button" import { Input } from "@/components/ui/input" import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@/components/ui/table" import { fetchPermissions, type AdminPermission, type PageResult, } from "@/lib/api/admin" import { Status } from "@/lib/generated/enums" import { useAppLocale, useI18n } from "@/i18n/provider" import { getPermissionDisplayName, getPermissionGroupName } from "@/lib/permission-i18n" export default function DashboardPermissionsPage() { const t = useI18n() const { locale } = useAppLocale() const [keywordInput, setKeywordInput] = useState("") const [groupNameInput, setGroupNameInput] = useState("") const [statusFilterInput, setStatusFilterInput] = useState("all") const [keyword, setKeyword] = useState("") const [groupName, setGroupName] = useState("") const [statusFilter, setStatusFilter] = useState("all") const [page, setPage] = useState(1) const [limit, setLimit] = useState(20) const [loading, setLoading] = useState(true) const [result, setResult] = useState>({ results: [], page: { page: 1, limit: 20, total: 0 }, }) const listStatusOptions = useMemo( () => [ { value: "all", label: t("status.all") }, { value: String(Status.Ok), label: t("status.ok") }, { value: String(Status.Disabled), label: t("status.disabled") }, { value: String(Status.Deleted), label: t("status.deleted") }, ], [t] ) const loadData = useCallback(async () => { setLoading(true) try { const data = await fetchPermissions({ keyword: keyword.trim() || undefined, groupName: groupName.trim() || undefined, status: statusFilter === "all" ? undefined : statusFilter, page, limit, }) setResult(data) } catch (error) { toast.error(error instanceof Error ? error.message : t("permission.loadFailed")) } finally { setLoading(false) } }, [groupName, keyword, limit, page, statusFilter, t]) useEffect(() => { void loadData() }, [loadData]) function applyFilters() { setKeyword(keywordInput) setGroupName(groupNameInput) setStatusFilter(statusFilterInput) setPage(1) } function handleFilterKeyDown(event: React.KeyboardEvent) { if (event.key !== "Enter") { return } event.preventDefault() applyFilters() } function handlePageChange(nextPage: number) { if (nextPage < 1 || nextPage === page) { return } setPage(nextPage) } return ( void loadData()} disabled={loading}> {t("permission.refresh")} } >
setKeywordInput(event.target.value)} onKeyDown={handleFilterKeyDown} placeholder={t("permission.filterKeyword")} className="pl-9" />
setGroupNameInput(event.target.value)} onKeyDown={handleFilterKeyDown} placeholder={t("permission.filterGroup")} className="w-full sm:w-44" />
{ setLimit(nextLimit) setPage(1) }} /> } > {t("permission.columnPermission")} {t("permission.columnCode")} {t("permission.columnGroup")} {t("permission.columnApi")} {t("permission.columnStatus")} {result.results.map((item) => (
{getPermissionDisplayName(item.code, item.name, locale)}
{item.type}
{item.code} {getPermissionGroupName(item.groupName, locale)}
{item.method || "ANY"}
{item.apiPath || "-"}
{getStatusLabel(item.status, t)}
))} {loading || result.results.length === 0 ? ( ) : null}
) } function getStatusLabel( status: number, t: (key: string, values?: Record) => string ) { if (status === Status.Ok) { return t("status.ok") } if (status === Status.Disabled) { return t("status.disabled") } if (status === Status.Deleted) { return t("status.deleted") } return String(status) }