import { Component, createEffect, createSignal, For, Show } 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' // Список администраторских email const ADMIN_EMAILS = ['welcome@discours.io'] 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: 'admin', name: 'Системный администратор', description: 'Администраторы определяются автоматически по настройкам сервера', emoji: '🪄' }, { id: 'editor', name: 'Редактор', description: 'Редактирование публикаций и управление сообществом', emoji: '✒️' }, { id: 'expert', name: 'Эксперт', description: 'Добавление доказательств и опровержений, управление темами', emoji: '🔬' }, { id: 'author', name: 'Автор', description: 'Создание и редактирование своих публикаций', emoji: '📝' }, { id: 'reader', name: 'Читатель', description: 'Чтение и комментирование', emoji: '📖' } ] // Создаем маппинги для конвертации между ID и названиями const ROLE_ID_TO_NAME = Object.fromEntries(AVAILABLE_ROLES.map((role) => [role.id, role.name])) const ROLE_NAME_TO_ID = Object.fromEntries(AVAILABLE_ROLES.map((role) => [role.name, role.id])) const UserEditModal: Component = (props) => { // Инициализируем форму с использованием ID ролей const [formData, setFormData] = createSignal({ id: props.user.id, email: props.user.email || '', name: props.user.name || '', slug: props.user.slug || '', roles: (props.user.roles || []).map((roleName) => ROLE_NAME_TO_ID[roleName] || roleName) }) const [errors, setErrors] = createSignal>({}) const [loading, setLoading] = createSignal(false) // Проверяем, является ли пользователь администратором по ролям, которые приходят с сервера const isAdmin = () => { const roles = formData().roles return roles.includes('admin') || (props.user.email ? ADMIN_EMAILS.includes(props.user.email) : false) } // Обновляем поле формы const updateField = (field: keyof ReturnType, value: string) => { setFormData((prev) => ({ ...prev, [field]: value })) if (errors()[field]) { setErrors((prev) => { const newErrors = { ...prev } delete newErrors[field] return newErrors }) } } // Обновляем эффект для инициализации формы 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 || []).map((roleName) => ROLE_NAME_TO_ID[roleName] || roleName) }) setErrors({}) } }) // Обновим логику проверки выбранности роли const isRoleSelected = (roleId: string) => { const roles = formData().roles || [] const isSelected = roles.includes(roleId) console.log(`Checking role ${roleId}:`, isSelected) return isSelected } const handleRoleToggle = (roleId: string) => { console.log('Attempting to toggle role:', roleId) console.log('Current roles:', formData().roles) console.log('Is admin:', isAdmin()) console.log('Role is admin:', roleId === 'admin') if (roleId === 'admin') { console.log('Admin role cannot be changed') return // Системная роль не может быть изменена } // Создаем новый массив ролей с учетом текущего состояния setFormData((prev) => { const currentRoles = prev.roles || [] const isCurrentlySelected = currentRoles.includes(roleId) const newRoles = isCurrentlySelected ? currentRoles.filter((r) => r !== roleId) // Убираем роль : [...currentRoles, roleId] // Добавляем роль console.log('Current roles before:', currentRoles) console.log('Is currently selected:', isCurrentlySelected) console.log('New roles:', newRoles) return { ...prev, roles: newRoles } }) // Очищаем ошибки, связанные с ролями if (errors().roles) { setErrors((prev) => { const newErrors = { ...prev } delete newErrors.roles return newErrors }) } } const validateForm = (): boolean => { const newErrors: Record = {} const data = formData() if (!data.email.trim() || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(data.email.trim())) { newErrors.email = 'Неверный формат email' } if (!data.name.trim() || data.name.trim().length < 2) { newErrors.name = 'Имя должно содержать минимум 2 символа' } if (!data.slug.trim() || !/^[a-z0-9_-]+$/.test(data.slug.trim())) { newErrors.slug = 'Slug может содержать только латинские буквы, цифры, дефисы и подчеркивания' } if (!isAdmin() && (data.roles || []).filter((role: string) => role !== 'admin').length === 0) { newErrors.roles = 'Выберите хотя бы одну роль' } setErrors(newErrors) return Object.keys(newErrors).length === 0 } const handleSave = async () => { if (!validateForm()) { return } setLoading(true) try { await props.onSave({ ...formData(), // Конвертируем ID ролей обратно в названия для сервера roles: (formData().roles || []).map((roleId) => ROLE_ID_TO_NAME[roleId]).join(',') }) props.onClose() } catch (error) { console.error('Ошибка при сохранении пользователя:', error) setErrors({ general: 'Ошибка при сохранении пользователя' }) } finally { setLoading(false) } } // Обновляем компонент выбора роли const RoleSelector = (props: { role: (typeof AVAILABLE_ROLES)[0] isSelected: boolean onToggle: () => void isDisabled?: boolean }) => { return ( ) } // В основном компоненте модального окна обновляем рендеринг ролей return (
{/* Основные данные */}
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) => ( handleRoleToggle(role.id)} isDisabled={role.id === 'admin'} /> )}
{!isAdmin() && errors().roles && (
⚠️ {errors().roles}
)}
💡 Системные роли (администратор) назначаются автоматически и не могут быть изменены вручную. {!isAdmin() && ' Выберите дополнительные роли для пользователя - минимум одна роль обязательна.'}
{/* Общая ошибка */} {errors().general && (
⚠️ {errors().general}
)} {/* Компактные кнопки действий */}
) } export default UserEditModal