import { useCallback, useEffect, useState } from "react"; import { Check, Copy, FolderOpen, KeyRound, MessageSquare, RotateCcw, Trash2, UserPlus, Users } from "lucide-react"; import { Button } from "@/components/ui/button"; import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, } from "@/components/ui/alert-dialog"; import { Badge } from "@/components/ui/badge"; import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from "@/components/ui/dialog"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@/components/ui/table"; import { createUser, deleteUser, listUsers, resetPassword, roleLabel, statusLabel, type StoredUser, } from "@/lib/auth-service"; import { countProjectsByOwner, formatStamp, listProjects, removeProjectsOfOwner, type StoredProject, } from "@/lib/studio-storage"; import { listFeedback, markFeedbackRead, removeFeedback, type FeedbackItem } from "@/lib/feedback-service"; type Props = { open: boolean; onOpenChange: (v: boolean) => void; }; export default function AdminPanel({ open, onOpenChange }: Props) { const [users, setUsers] = useState([]); const [counts, setCounts] = useState>({}); const [createOpen, setCreateOpen] = useState(false); const [newLogin, setNewLogin] = useState(""); const [createError, setCreateError] = useState(null); const [credentials, setCredentials] = useState<{ username: string; password: string } | null>(null); const [toDelete, setToDelete] = useState(null); const [viewing, setViewing] = useState<{ user: StoredUser; items: StoredProject[] } | null>(null); const [feedback, setFeedback] = useState([]); const refresh = useCallback(() => { setUsers(listUsers()); setCounts(countProjectsByOwner()); setFeedback(listFeedback()); }, []); useEffect(() => { if (open) refresh(); }, [open, refresh]); const totalProjects = Object.values(counts).reduce((a, b) => a + b, 0); const activeUsers = users.filter((u) => u.status === "active").length; const pendingUsers = users.length - activeUsers; const copy = (value: string) => { void navigator.clipboard?.writeText(value); }; const submitCreate = () => { const result = createUser(newLogin); if (!result.ok) { setCreateError(result.error); return; } setCreateError(null); setCreateOpen(false); setNewLogin(""); setCredentials({ username: result.user.username, password: result.tempPassword }); refresh(); }; return ( <> Панель админа Управление пользователями студии и обзор сохранённых схем.
{[ { label: "Пользователей", value: users.length }, { label: "Активных", value: activeUsers }, { label: "Ожидают входа", value: pendingUsers }, { label: "Всего схем", value: totalProjects }, { label: "Новых пожеланий", value: feedback.filter((f) => !f.read).length }, ].map((s) => (

{s.label}

{s.value}

))}

Пожелания пользователей

{feedback.length === 0 ? (

Пока нет сообщений.

) : (
    {feedback.map((f) => (
  • {f.username} · {formatStamp(f.createdAt)} {!f.read && новое}

    {f.text}

    {!f.read && ( )}
  • ))}
)}
Логин Роль Создан Статус Схемы Действия {users.map((u) => ( {u.username} {roleLabel(u.role)} {formatStamp(u.createdAt)} {statusLabel(u.status)} {counts[u.id] ?? 0}
))}
{/* Создание пользователя */} Создать пользователя Укажите логин — система выдаст одноразовый временный пароль для первого входа.
{ setNewLogin(e.target.value); setCreateError(null); }} className="h-12" /> {createError &&

{createError}

}
{/* Показ временного пароля */} !v && setCredentials(null)}> Временный пароль Передайте пароль пользователю «{credentials?.username}». При первом входе он задаст постоянный пароль.
{credentials?.password}
{/* Проекты пользователя */} !v && setViewing(null)}> Проекты «{viewing?.user.username}» Схемы, сохранённые этим пользователем. {viewing && viewing.items.length === 0 ? (

У пользователя пока нет схем.

) : (
{viewing?.items.map((p) => (
{`Превью

{p.title}

{formatStamp(p.updatedAt)} · элементов: {p.elements}

))}
)}
!v && setToDelete(null)}> Удалить пользователя? Пользователь «{toDelete?.username}» и все его схемы будут удалены безвозвратно. Отмена { if (toDelete) { removeProjectsOfOwner(toDelete.id); deleteUser(toDelete.id); } setToDelete(null); refresh(); }} > Удалить ); }