import { Component, createEffect, createSignal, For } from 'solid-js' import type { AdminUserInfo } from '../graphql/generated/schema' import formStyles from '../styles/Form.module.css' import Button from '../ui/Button' import Modal from '../ui/Modal' export interface UserEditModalProps { user: AdminUserInfo isOpen: boolean onClose: () => void onSave: (userData: { id: number email?: string name?: string slug?: string roles: string[] }) => Promise } // Доступные роли в системе (без роли Администратор - она определяется автоматически) const AVAILABLE_ROLES = [ { id: 'Редактор', name: 'Редактор', description: 'Редактирование публикаций и управление сообществом', emoji: '✒️' }, { id: 'Эксперт', name: 'Эксперт', description: 'Добавление доказательств и опровержений, управление темами', emoji: '🔬' }, { id: 'Автор', name: 'Автор', description: 'Создание и редактирование своих публикаций', emoji: '📝' }, { id: 'Читатель', name: 'Читатель', description: 'Чтение и комментирование', emoji: '📖' } ] const UserEditModal: Component = (props) => { const [formData, setFormData] = createSignal({ id: props.user.id, email: props.user.email || '', name: props.user.name || '', slug: props.user.slug || '', roles: props.user.roles?.filter((role) => role !== 'Администратор') || [] // Исключаем админскую роль из ручного управления }) const [errors, setErrors] = createSignal>({}) const [loading, setLoading] = createSignal(false) // Проверяем, является ли пользователь администратором по ролям, которые приходят с сервера const isAdmin = () => { return (props.user.roles || []).includes('Администратор') } // Получаем информацию о роли по ID const getRoleInfo = (roleId: string) => { return AVAILABLE_ROLES.find((role) => role.id === roleId) || { name: roleId, emoji: '🎭' } } // Формируем строку с ролями и эмоджи const getRolesDisplay = () => { const roles = formData().roles if (roles.length === 0) { return isAdmin() ? '🪄 Администратор' : 'Роли не назначены' } const roleTexts = roles.map((roleId) => { const role = getRoleInfo(roleId) return `${role.emoji} ${role.name}` }) if (isAdmin()) { return `🪄 Администратор, ${roleTexts.join(', ')}` } return roleTexts.join(', ') } // Обновляем форму при изменении пользователя createEffect(() => { if (props.user) { setFormData({ id: props.user.id, email: props.user.email || '', name: props.user.name || '', slug: props.user.slug || '', roles: props.user.roles?.filter((role) => role !== 'Администратор') || [] // Исключаем админскую роль }) setErrors({}) } }) const updateField = (field: string, value: string) => { setFormData((prev) => ({ ...prev, [field]: value })) // Очищаем ошибку при изменении поля if (errors()[field]) { setErrors((prev) => ({ ...prev, [field]: '' })) } } const handleRoleToggle = (roleId: string) => { setFormData((prev) => { const currentRoles = prev.roles const newRoles = currentRoles.includes(roleId) ? currentRoles.filter((r) => r !== roleId) : [...currentRoles, roleId] return { ...prev, roles: newRoles } }) // Очищаем ошибку ролей при изменении if (errors().roles) { setErrors((prev) => ({ ...prev, roles: '' })) } } const validateForm = (): boolean => { const newErrors: Record = {} const data = formData() // Email if (!data.email.trim()) { newErrors.email = 'Email обязателен' } else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(data.email.trim())) { newErrors.email = 'Неверный формат email' } // Имя if (!data.name.trim()) { newErrors.name = 'Имя обязательно' } else if (data.name.trim().length < 2) { newErrors.name = 'Имя должно содержать минимум 2 символа' } // Slug if (!data.slug.trim()) { newErrors.slug = 'Slug обязателен' } else if (!/^[a-z0-9_-]+$/.test(data.slug.trim())) { newErrors.slug = 'Slug может содержать только латинские буквы, цифры, дефисы и подчеркивания' } // Роли (админы освобождаются от этого требования) if (!isAdmin() && data.roles.length === 0) { newErrors.roles = 'Выберите хотя бы одну роль (или назначьте админский email)' } setErrors(newErrors) return Object.keys(newErrors).length === 0 } const handleSave = async () => { if (!validateForm()) { return } setLoading(true) try { // Отправляем только обычные роли, админская роль определяется на сервере по email await props.onSave(formData()) props.onClose() } catch (error) { console.error('Ошибка при сохранении пользователя:', error) setErrors({ general: 'Ошибка при сохранении пользователя' }) } finally { setLoading(false) } } return (
{/* Компактная системная информация */}
ID: {props.user.id}
Регистрация:{' '} {props.user.created_at ? new Date(props.user.created_at * 1000).toLocaleDateString('ru-RU') : '—'}
Активность:{' '} {props.user.last_seen ? new Date(props.user.last_seen * 1000).toLocaleDateString('ru-RU') : '—'}
{/* Текущие роли в строку */}
{getRolesDisplay()}
{/* Основные данные в компактной сетке */}
updateField('email', e.currentTarget.value)} disabled={loading()} placeholder="user@example.com" /> {errors().email && (
⚠️ {errors().email}
)}
💡 Администраторы определяются автоматически по настройкам сервера
updateField('name', e.currentTarget.value)} disabled={loading()} placeholder="Иван Иванов" /> {errors().name && (
⚠️ {errors().name}
)}
updateField('slug', e.currentTarget.value.toLowerCase())} disabled={loading()} placeholder="ivan-ivanov" />
💡 Только латинские буквы, цифры, дефисы и подчеркивания
{errors().slug && (
⚠️ {errors().slug}
)}
{/* Роли */}
{(role) => ( )}
{!isAdmin() && errors().roles && (
⚠️ {errors().roles}
)}
💡 {isAdmin() ? 'Администраторы имеют все права автоматически. Дополнительные роли опциональны.' : 'Выберите роли для пользователя. Минимум одна роль обязательна.'}
{/* Общая ошибка */} {errors().general && (
⚠️ {errors().general}
)} {/* Компактные кнопки действий */}
) } export default UserEditModal