import React, { useState, useEffect, useRef } from 'react'; import { Table, Button, Tag, Space, Modal, Form, Select, Spin, Input, Tooltip } from 'antd'; import { InfoCircleOutlined, EditOutlined, LockOutlined, UnlockOutlined, DeleteOutlined } from '@ant-design/icons'; import { useNavigate } from 'react-router-dom'; import { useUsers, useUpdateUser, useDeleteUser, useUser } from '../../hooks/useUsers'; import { User, UserListParams } from '../../types/api'; import type { ColumnsType, SorterResult } from 'antd/es/table/interface'; const UserListPage: React.FC = () => { const navigate = useNavigate(); const [params, setParams] = useState({ limit: 20, offset: 0, sort: 'id', order: 'asc' }); const { data, isLoading } = useUsers(params); const updateUser = useUpdateUser(); const deleteUser = useDeleteUser(); // Редактирование const [editModal, setEditModal] = useState<{ open: boolean; userId: string | null }>({ open: false, userId: null, }); const { data: editingUser, isLoading: loadingUser } = useUser(editModal.userId || ''); const [editForm] = Form.useForm(); const [editHasErrors, setEditHasErrors] = useState(true); const originalUserRef = useRef(null); // Изменение статуса const [statusModal, setStatusModal] = useState<{ open: boolean; userId: string | null; newStatus: string; currentReason: string; }>({ open: false, userId: null, newStatus: 'active', currentReason: '', }); const [statusForm] = Form.useForm(); // ==================== Редактирование ==================== const handleEdit = (id: string) => { setEditModal({ open: true, userId: id }); }; const handleSaveEdit = () => { editForm.validateFields().then((values) => { if (!editModal.userId || !originalUserRef.current) return; const original = originalUserRef.current; const cleanedValues: Record = {}; const allKeys = new Set([...Object.keys(values), ...Object.keys(original)]); allKeys.forEach((key) => { const newVal = values[key]; if (newVal === '' || newVal === undefined || newVal === null) { const origVal = (original as any)[key]; if (origVal && origVal !== '-' && origVal !== '' && origVal !== undefined && origVal !== null) { cleanedValues[key] = null; } return; } if (newVal === '-') return; cleanedValues[key] = newVal; }); const payload = Object.fromEntries( Object.entries(cleanedValues).filter(([key, v]) => { const origVal = (original as any)[key]; return JSON.stringify(v) !== JSON.stringify(origVal === '-' ? undefined : origVal); }) ); updateUser.mutate( { id: editModal.userId, data: payload }, { onSuccess: () => setEditModal({ open: false, userId: null }) } ); }); }; useEffect(() => { if (editingUser && editModal.open) { originalUserRef.current = editingUser; const clean = (val: any) => (val === '-' || val === 'undefined' ? undefined : val); setTimeout(() => { editForm.setFieldsValue({ email: clean(editingUser.email), nickname: clean(editingUser.nickname), role: clean(editingUser.role), status: clean(editingUser.status), reason: clean(editingUser.reason), }); validateEditForm(); }, 0); } }, [editingUser, editModal.open, editForm]); const validateEditForm = () => { const role = editForm.getFieldValue('role'); const status = editForm.getFieldValue('status'); const hasErrors = !role || !status; setEditHasErrors(hasErrors); }; // ==================== Изменение статуса ==================== const handleStatusChange = (user: User) => { if (user.status === 'deleted') return; const newStatus = user.status === 'active' ? 'frozen' : 'active'; const currentReason = user.reason && user.reason !== '-' ? user.reason : ''; setStatusModal({ open: true, userId: user.id, newStatus, currentReason, }); }; useEffect(() => { if (statusModal.open) { setTimeout(() => { statusForm.setFieldsValue({ reason: statusModal.currentReason }); }, 0); } }, [statusModal.open, statusModal.currentReason, statusForm]); const handleStatusSave = () => { statusForm.validateFields().then((values) => { if (!statusModal.userId) return; const payload: any = { status: statusModal.newStatus }; if (values.reason && values.reason.trim() !== '') { payload.reason = values.reason; } updateUser.mutate( { id: statusModal.userId, data: payload }, { onSuccess: () => setStatusModal({ open: false, userId: null, newStatus: 'active', currentReason: '' }) } ); }); }; // ==================== Удаление ==================== const handleDelete = (id: string) => { Modal.confirm({ title: 'Удалить пользователя?', content: 'Это действие нельзя отменить. При необходимости предварительно укажите причину через редактирование.', okText: 'Удалить', okType: 'danger', cancelText: 'Отмена', onOk: () => deleteUser.mutate(id), }); }; // ==================== Таблица ==================== const handleTableChange = ( pagination: any, _filters: any, sorter: SorterResult | SorterResult[] ) => { const s = Array.isArray(sorter) ? sorter[0] : sorter; setParams(prev => ({ ...prev, sort: s.field as string, order: s.order === 'ascend' ? 'asc' : s.order === 'descend' ? 'desc' : undefined, offset: ((pagination.current - 1) * pagination.pageSize) || 0, limit: pagination.pageSize || prev.limit, })); }; const columns: ColumnsType = [ { title: , key: 'detail', width: 48, align: 'center', render: (_, record) => (