Files
BanGUI/frontend/src/pages/map/MapBansTable.tsx

158 lines
5.2 KiB
TypeScript

import {
Badge,
Button,
Table,
TableBody,
TableCell,
TableCellLayout,
TableHeader,
TableHeaderCell,
TableRow,
Text,
Tooltip,
tokens,
} from "@fluentui/react-components";
import { ChevronLeftRegular, ChevronRightRegular } from "@fluentui/react-icons";
import type { MapBanItem } from "../../types/map";
interface MapBansTableProps {
pageBans: MapBanItem[];
visibleCount: number;
page: number;
pageSize: number;
totalPages: number;
hasPrev: boolean;
hasNext: boolean;
onPageChange: (nextPage: number) => void;
onPageSizeChange: (pageSize: number) => void;
}
export function MapBansTable({
pageBans,
visibleCount,
page,
pageSize,
totalPages,
hasPrev,
hasNext,
onPageChange,
onPageSizeChange,
}: MapBansTableProps): React.JSX.Element {
return (
<>
<Table size="small" aria-label="Bans list">
<TableHeader>
<TableRow>
<TableHeaderCell>IP Address</TableHeaderCell>
<TableHeaderCell>Jail</TableHeaderCell>
<TableHeaderCell>Banned At</TableHeaderCell>
<TableHeaderCell>Country</TableHeaderCell>
<TableHeaderCell>Origin</TableHeaderCell>
<TableHeaderCell>Times Banned</TableHeaderCell>
</TableRow>
</TableHeader>
<TableBody>
{visibleCount === 0 ? (
<TableRow>
<TableCell colSpan={6}>
<TableCellLayout>
<Text size={200} style={{ color: tokens.colorNeutralForeground3 }}>
No bans found.
</Text>
</TableCellLayout>
</TableCell>
</TableRow>
) : (
pageBans.map((ban) => (
<TableRow key={`${ban.ip}-${ban.banned_at}`}>
<TableCell>
<TableCellLayout>{ban.ip}</TableCellLayout>
</TableCell>
<TableCell>
<TableCellLayout>{ban.jail}</TableCellLayout>
</TableCell>
<TableCell>
<TableCellLayout>{new Date(ban.banned_at).toLocaleString()}</TableCellLayout>
</TableCell>
<TableCell>
<TableCellLayout>
{ban.country_name ?? ban.country_code ? (
ban.country_name ?? ban.country_code
) : (
<Tooltip
content="Country could not be resolved — will retry automatically."
relationship="description"
>
<Text style={{ color: tokens.colorNeutralForeground3 }}></Text>
</Tooltip>
)}
</TableCellLayout>
</TableCell>
<TableCell>
<TableCellLayout>
<Badge
appearance="tint"
color={ban.origin === "blocklist" ? "brand" : "informative"}
>
{ban.origin === "blocklist" ? "Blocklist" : "Selfblock"}
</Badge>
</TableCellLayout>
</TableCell>
<TableCell>
<TableCellLayout>{String(ban.ban_count)}</TableCellLayout>
</TableCell>
</TableRow>
))
)}
</TableBody>
</Table>
{visibleCount > 0 && (
<div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", gap: tokens.spacingHorizontalS, marginTop: tokens.spacingVerticalS }}>
<div style={{ display: "flex", alignItems: "center", gap: tokens.spacingHorizontalS }}>
<Text size={200} style={{ color: tokens.colorNeutralForeground3 }}>
Showing {pageBans.length} of {visibleCount} filtered ban{visibleCount !== 1 ? "s" : ""}
{" · "}Page {page} of {totalPages}
</Text>
<div style={{ display: "flex", alignItems: "center", gap: tokens.spacingHorizontalS }}>
<Text size={200} style={{ color: tokens.colorNeutralForeground3 }}>
Page size
</Text>
<select
aria-label="Page size"
value={pageSize}
onChange={(event): void => {
onPageSizeChange(Number(event.target.value));
}}
>
{[25, 50, 100].map((option) => (
<option key={option} value={option}>
{option}
</option>
))}
</select>
</div>
</div>
<div style={{ display: "flex", gap: tokens.spacingHorizontalXS }}>
<Button
icon={<ChevronLeftRegular />}
appearance="subtle"
disabled={!hasPrev}
onClick={(): void => onPageChange(page - 1)}
aria-label="Previous page"
/>
<Button
icon={<ChevronRightRegular />}
appearance="subtle"
disabled={!hasNext}
onClick={(): void => onPageChange(page + 1)}
aria-label="Next page"
/>
</div>
</div>
)}
</>
);
}