import { useCallback, useEffect, useState } from "react"; import { ActionIcon, Badge, Button, Card, Group, Loader, Modal, Select, Stack, Table, Text, TextInput, Title, Tooltip, } from "@mantine/core"; import { useDisclosure } from "@mantine/hooks"; import { notifications } from "@mantine/notifications"; import { IconPlus, IconRefresh, IconUserOff } from "@tabler/icons-react"; import { api, ApiError } from "../api"; import type { UserView } from "../types"; import { fmtTime, trunc } from "../util"; function notifyErr(e: unknown) { notifications.show({ color: "red", title: "Error", message: e instanceof ApiError ? e.message : String(e) }); } export function UsersPage({ usersBackend }: { usersBackend: string }) { const [users, setUsers] = useState(null); const [err, setErr] = useState(null); const [loading, setLoading] = useState(false); const [addOpen, addCtl] = useDisclosure(false); const load = useCallback(() => { setLoading(true); api .listUsers() .then((u) => { setUsers(u); setErr(null); }) .catch((e: ApiError) => setErr(e.message)) .finally(() => setLoading(false)); }, []); useEffect(() => { load(); }, [load]); const revoke = async (u: UserView) => { if (!window.confirm(`¿Revocar a "${u.handle}"? Pierde acceso al bus en AMBOS planos de inmediato (control y datos).`)) return; try { await api.revokeUser(u.sign_pub); notifications.show({ color: "teal", title: "Revocado", message: u.handle }); load(); } catch (e) { notifyErr(e); } }; return ( Users {users && {users.length}} backend: {usersBackend} {err && {err}} {!users && !err && } {users && ( Handle Rol Estado sign_pub Creado {users.map((u) => ( {u.handle} {u.role} {u.status} {trunc(u.sign_pub, 12, 8)} {fmtTime(u.created_at)} {u.status === "active" && ( revoke(u)}> )} ))}
)}
); } function AddUserModal({ opened, onClose, onAdded }: { opened: boolean; onClose: () => void; onAdded: () => void }) { const [handle, setHandle] = useState(""); const [signPub, setSignPub] = useState(""); const [role, setRole] = useState("member"); const [busy, setBusy] = useState(false); const submit = async () => { setBusy(true); try { await api.addUser({ handle: handle.trim(), sign_pub: signPub.trim(), role }); notifications.show({ color: "teal", title: "User añadido", message: handle }); setHandle(""); setSignPub(""); setRole("member"); onClose(); onAdded(); } catch (e) { notifyErr(e); } finally { setBusy(false); } }; const ready = handle.trim().length > 0 && signPub.trim().length === 64; return ( setHandle(e.currentTarget.value)} data-autofocus /> setSignPub(e.currentTarget.value)} error={signPub.length > 0 && signPub.trim().length !== 64 ? "64 chars hex" : undefined} />