/** * Edit Platform User Modal * Allows superusers to edit all aspects of platform staff including: * - Basic info (name, email, username) * - Password reset * - Role assignment * - Permissions (can_approve_plugins, etc.) * - Account status (active/inactive) */ import React, { useState, useEffect } from 'react'; import { useTranslation } from 'react-i18next'; import { X, User, Mail, Lock, Shield, CheckCircle, XCircle, Save, Eye, EyeOff, AlertCircle, } from 'lucide-react'; import { useMutation, useQueryClient } from '@tanstack/react-query'; import apiClient from '../../../api/client'; import { useCurrentUser } from '../../../hooks/useAuth'; interface EditPlatformUserModalProps { isOpen: boolean; onClose: () => void; user: { id: number; username: string; email: string; first_name: string; last_name: string; role: string; is_active: boolean; permissions: { can_approve_plugins?: boolean; [key: string]: any; }; }; } const EditPlatformUserModal: React.FC = ({ isOpen, onClose, user, }) => { const { t } = useTranslation(); const queryClient = useQueryClient(); const { data: currentUser } = useCurrentUser(); // Check if current user can edit this user const currentRole = currentUser?.role?.toLowerCase(); const targetRole = user.role?.toLowerCase(); const canEditRole = currentRole === 'superuser' || (currentRole === 'platform_manager' && targetRole === 'platform_support'); // Get available permissions for current user // Superusers always have all permissions, others check the permissions field const availablePermissions = { can_approve_plugins: currentRole === 'superuser' || !!currentUser?.permissions?.can_approve_plugins, can_whitelist_urls: currentRole === 'superuser' || !!currentUser?.permissions?.can_whitelist_urls, }; // Form state const [formData, setFormData] = useState({ username: user.username, email: user.email, first_name: user.first_name, last_name: user.last_name, role: user.role, is_active: user.is_active, }); const [permissions, setPermissions] = useState({ can_approve_plugins: user.permissions?.can_approve_plugins || false, can_whitelist_urls: user.permissions?.can_whitelist_urls || false, }); const [password, setPassword] = useState(''); const [confirmPassword, setConfirmPassword] = useState(''); const [showPassword, setShowPassword] = useState(false); const [passwordError, setPasswordError] = useState(''); // Update mutation const updateMutation = useMutation({ mutationFn: async (data: any) => { const response = await apiClient.patch(`/api/platform/users/${user.id}/`, data); return response.data; }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['platform', 'users'] }); onClose(); }, }); // Reset form when user changes useEffect(() => { setFormData({ username: user.username, email: user.email, first_name: user.first_name, last_name: user.last_name, role: user.role, is_active: user.is_active, }); setPermissions({ can_approve_plugins: user.permissions?.can_approve_plugins || false, can_whitelist_urls: user.permissions?.can_whitelist_urls || false, }); setPassword(''); setConfirmPassword(''); setPasswordError(''); }, [user]); const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); // Validate password if provided if (password) { if (password !== confirmPassword) { setPasswordError('Passwords do not match'); return; } if (password.length < 8) { setPasswordError('Password must be at least 8 characters'); return; } } // Prepare update data const updateData: any = { ...formData, permissions: permissions, }; // Only include password if changed if (password) { updateData.password = password; } updateMutation.mutate(updateData); }; const handlePermissionToggle = (permission: string) => { setPermissions((prev) => ({ ...prev, [permission]: !prev[permission as keyof typeof prev], })); }; if (!isOpen) return null; return (
{/* Background overlay */}
{/* Modal panel */}
{/* Header */}

Edit Platform User

{user.username} ({user.email})

{/* Form */}
{/* Basic Info */}

Basic Information

setFormData({ ...formData, first_name: e.target.value }) } className="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg focus:ring-2 focus:ring-indigo-500 dark:bg-gray-700 dark:text-white" />
setFormData({ ...formData, last_name: e.target.value }) } className="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg focus:ring-2 focus:ring-indigo-500 dark:bg-gray-700 dark:text-white" />
{/* Account Details */}

Account Details

setFormData({ ...formData, username: e.target.value }) } className="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg focus:ring-2 focus:ring-indigo-500 dark:bg-gray-700 dark:text-white font-mono" />
setFormData({ ...formData, email: e.target.value }) } className="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg focus:ring-2 focus:ring-indigo-500 dark:bg-gray-700 dark:text-white" />
{/* Role */}

Role & Access

{canEditRole ? 'Platform Managers have full administrative access. Support staff have limited access.' : 'You do not have permission to change this user\'s role.'}

{/* Permissions */}

Special Permissions

{availablePermissions.can_approve_plugins && ( )} {availablePermissions.can_whitelist_urls && ( )} {!availablePermissions.can_approve_plugins && !availablePermissions.can_whitelist_urls && (

You don't have any special permissions to grant.

)}
{/* Password Reset */}

Reset Password (Optional)

{ setPassword(e.target.value); setPasswordError(''); }} placeholder="Leave blank to keep current password" className="w-full px-3 py-2 pr-10 border border-gray-300 dark:border-gray-600 rounded-lg focus:ring-2 focus:ring-indigo-500 dark:bg-gray-700 dark:text-white" />
{password && (
{ setConfirmPassword(e.target.value); setPasswordError(''); }} className="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg focus:ring-2 focus:ring-indigo-500 dark:bg-gray-700 dark:text-white" />
)} {passwordError && (
{passwordError}
)}
{/* Account Status */}

Account Status

{/* Error Display */} {updateMutation.isError && (
Failed to update user. Please try again.
)} {/* Actions */}
); }; export default EditPlatformUserModal;