import { useEffect, useState } from 'react' import Alert from '@mui/material/Alert' import Box from '@mui/material/Box' import Button from '@mui/material/Button' import Stack from '@mui/material/Stack' import TableCell from '@mui/material/TableCell' import TablePagination from '@mui/material/TablePagination' import TableRow from '@mui/material/TableRow' import TextField from '@mui/material/TextField' import Typography from '@mui/material/Typography' import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query' import { useUnit } from 'effector-react' import { Controller, useForm } from 'react-hook-form' import { Link as RouterLink } from 'react-router-dom' import { createAdminUser, deleteAdminUser, fetchAdminUsers, updateAdminUser } from '@/entities/user/api/user-api' import type { AdminUser } from '@/entities/user/model/types' import { getErrorMessage } from '@/shared/lib/get-error-message' import { invalidateQueryKeys } from '@/shared/lib/invalidate-query-keys' import { useEditDialogState } from '@/shared/lib/use-edit-dialog-state' import { $user } from '@/shared/model/auth' import { AdminDialog } from '@/shared/ui/AdminDialog/AdminDialog' import { AdminTable } from '@/shared/ui/AdminTable' import { EntityRowActions } from '@/shared/ui/EntityRowActions' import { UserAvatar } from '@/shared/ui/UserAvatar' type UserFormState = { email: string name: string } const emptyUserForm = (): UserFormState => ({ email: '', name: '' }) function formatDt(v: string) { try { const d = new Date(v) if (Number.isNaN(d.getTime())) return '—' return d.toLocaleString() } catch { return '—' } } export function AdminUsersPage() { const queryClient = useQueryClient() const { dialogOpen, editing, openCreateDialog, openEditDialog, closeDialog } = useEditDialogState() const [qInput, setQInput] = useState('') const [q, setQ] = useState('') const [page, setPage] = useState(0) const [rowsPerPage, setRowsPerPage] = useState(20) const currentUser = useUnit($user) const currentUserId = currentUser?.id const userForm = useForm({ defaultValues: emptyUserForm(), mode: 'onChange', }) useEffect(() => { const t = window.setTimeout(() => { setQ(qInput.trim()) setPage(0) }, 250) return () => window.clearTimeout(t) }, [qInput]) const usersQuery = useQuery({ queryKey: ['admin', 'users', { q, page, rowsPerPage }], queryFn: () => fetchAdminUsers({ q: q || undefined, page: page + 1, pageSize: rowsPerPage, }), }) const createMut = useMutation({ mutationFn: async () => { const v = userForm.getValues() await createAdminUser({ email: v.email.trim(), name: v.name.trim() || null, }) }, onSuccess: () => { void invalidateQueryKeys(queryClient, [['admin', 'users']]) closeDialog() }, }) const updateMut = useMutation({ mutationFn: async () => { const v = userForm.getValues() await updateAdminUser(editing!.id, { email: v.email.trim(), name: v.name.trim() || null, }) }, onSuccess: () => { void invalidateQueryKeys(queryClient, [['admin', 'users']]) closeDialog() }, }) const deleteMut = useMutation({ mutationFn: async (id: string) => deleteAdminUser(id), onSuccess: () => { void invalidateQueryKeys(queryClient, [['admin', 'users']]) }, }) const mutationError = createMut.error ?? updateMut.error ?? deleteMut.error const openCreate = () => { userForm.reset(emptyUserForm()) openCreateDialog() } const openEdit = (u: AdminUser) => { openEditDialog(u) userForm.reset({ email: u.email, name: u.name ?? '', }) } const emailValue = userForm.watch('email') const isSaveDisabled = !emailValue.trim() || createMut.isPending || updateMut.isPending const users = usersQuery.data?.items ?? [] const total = usersQuery.data?.total ?? 0 return ( Админка — пользователи Управление пользователями доступно пользователю с правами администратора. setQInput(e.target.value)} fullWidth /> {usersQuery.isError && ( Ошибка загрузки. Проверьте, что сервер запущен, и у вас есть права администратора. )} {mutationError && ( {getErrorMessage(mutationError)} )} {users.length === 0 && !usersQuery.isLoading ? ( Пользователей пока нет. ) : ( users.map((u) => ( {u.email} {u.name ?? '—'} {formatDt(u.createdAt)} {formatDt(u.updatedAt)} openEdit(u)} onDelete={u.id === currentUserId ? undefined : () => deleteMut.mutate(u.id)} deleteDisabled={deleteMut.isPending} confirmDeleteMessage={`Удалить пользователя ${u.email}?`} /> )) )} setPage(p)} rowsPerPage={rowsPerPage} onRowsPerPageChange={(e) => { setRowsPerPage(Number(e.target.value)) setPage(0) }} rowsPerPageOptions={[10, 20, 50, 100]} /> } > ( )} /> } /> ) }