diff --git a/frontend/src/app/providers/layout/navigation/navigation.tsx b/frontend/src/app/providers/layout/navigation/navigation.tsx index d89fe05..8e380fa 100644 --- a/frontend/src/app/providers/layout/navigation/navigation.tsx +++ b/frontend/src/app/providers/layout/navigation/navigation.tsx @@ -120,6 +120,26 @@ export const Navigation = () => { {isDark ? : } + {/* Админка */} + + + + + + {/* Permissions */} +
+ {permissions.map(({ key, label }) => ( + + ))} +
+ + ); +}; diff --git a/frontend/src/modules/admin/index.ts b/frontend/src/modules/admin/index.ts new file mode 100644 index 0000000..b997e10 --- /dev/null +++ b/frontend/src/modules/admin/index.ts @@ -0,0 +1,3 @@ +export { AdminPanel } from "./AdminPanel"; +export { useAdminStore } from "./store/useAdminStore"; +export type { AdminUser } from "./types"; diff --git a/frontend/src/modules/admin/store/useAdminStore.ts b/frontend/src/modules/admin/store/useAdminStore.ts new file mode 100644 index 0000000..cda4279 --- /dev/null +++ b/frontend/src/modules/admin/store/useAdminStore.ts @@ -0,0 +1,69 @@ +import { create } from "zustand"; +import type { AdminUser, PermissionKey } from "../types"; + +const mockUsers: AdminUser[] = [ + { + id: "1", + login: "admin", + name: "Иван", + last_name: "Петров", + is_active: true, + permission_admin: true, + permission_manage_agent: true, + permission_view: true, + }, + { + id: "2", + login: "operator", + name: "Анна", + last_name: "Сидорова", + is_active: true, + permission_admin: false, + permission_manage_agent: true, + permission_view: true, + }, + { + id: "3", + login: "viewer", + name: "Сергей", + last_name: "Козлов", + is_active: true, + permission_admin: false, + permission_manage_agent: false, + permission_view: true, + }, + { + id: "4", + login: "dev_user", + name: "Мария", + last_name: "Новикова", + is_active: false, + permission_admin: false, + permission_manage_agent: true, + permission_view: true, + }, +]; + +interface AdminState { + users: AdminUser[]; + toggleActive: (id: string) => void; + togglePermission: (id: string, permission: PermissionKey) => void; +} + +export const useAdminStore = create((set) => ({ + users: mockUsers, + + toggleActive: (id: string) => + set((state) => ({ + users: state.users.map((u) => + u.id === id ? { ...u, is_active: !u.is_active } : u, + ), + })), + + togglePermission: (id: string, permission: PermissionKey) => + set((state) => ({ + users: state.users.map((u) => + u.id === id ? { ...u, [permission]: !u[permission] } : u, + ), + })), +})); diff --git a/frontend/src/modules/admin/types.ts b/frontend/src/modules/admin/types.ts new file mode 100644 index 0000000..28686a5 --- /dev/null +++ b/frontend/src/modules/admin/types.ts @@ -0,0 +1,15 @@ +export interface AdminUser { + id: string; + login: string; + name: string; + last_name: string; + is_active: boolean; + permission_admin: boolean; + permission_manage_agent: boolean; + permission_view: boolean; +} + +export type PermissionKey = + | "permission_admin" + | "permission_manage_agent" + | "permission_view"; diff --git a/frontend/src/pages/admin.page.tsx b/frontend/src/pages/admin.page.tsx index 1db30d9..600ce98 100644 --- a/frontend/src/pages/admin.page.tsx +++ b/frontend/src/pages/admin.page.tsx @@ -1,730 +1,5 @@ -import React, { useState, useEffect, useCallback } from "react"; -import { agentApiService } from "@/modules/agent"; -import type { TokenUser, TokenCreate, TokenUpdatePermissions, TokenPasswordReset } from "@/modules/agent"; -import { FiUsers, FiUserPlus, FiEdit2, FiTrash2, FiUnlock, FiLock, FiKey, FiX, FiCheck, FiSearch } from "react-icons/fi"; +import { AdminPanel } from "@/modules/admin"; -export const AdminPage: React.FC = () => { - const [users, setUsers] = useState([]); - const [inactiveUsers, setInactiveUsers] = useState([]); - const [isLoading, setIsLoading] = useState(false); - const [error, setError] = useState(null); - const [successMessage, setSuccessMessage] = useState(null); - const [activeTab, setActiveTab] = useState<"active" | "inactive">("active"); - const [searchQuery, setSearchQuery] = useState(""); - - // Modal states - const [showCreateModal, setShowCreateModal] = useState(false); - const [showEditModal, setShowEditModal] = useState(false); - const [showPasswordModal, setShowPasswordModal] = useState(false); - const [selectedUser, setSelectedUser] = useState(null); - - // Form states - const [createData, setCreateData] = useState({ - login: "", - name: "", - last_name: "", - password: "", - permission_admin: false, - permission_manage_agent: false, - permission_view: false, - is_active: false, - }); - - const [editData, setEditData] = useState({ - is_active: false, - permission_admin: false, - permission_manage_agent: false, - permission_view: false, - }); - - const [passwordData, setPasswordData] = useState({ - new_password: "", - }); - - const fetchUsers = useCallback(async () => { - setIsLoading(true); - setError(null); - try { - const [active, inactive] = await Promise.all([ - agentApiService.getUsers(), - agentApiService.getInactiveUsers(), - ]); - setUsers(active); - setInactiveUsers(inactive); - } catch (err) { - setError(err instanceof Error ? err.message : "Ошибка при загрузке пользователей"); - } finally { - setIsLoading(false); - } - }, []); - - useEffect(() => { - fetchUsers(); - }, [fetchUsers]); - - const handleCreateUser = async (e: React.FormEvent) => { - e.preventDefault(); - setError(null); - try { - await agentApiService.createUser(createData); - setSuccessMessage("Пользователь успешно создан"); - setShowCreateModal(false); - setCreateData({ - login: "", - name: "", - last_name: "", - password: "", - permission_admin: false, - permission_manage_agent: false, - permission_view: false, - is_active: false, - }); - await fetchUsers(); - } catch (err) { - setError(err instanceof Error ? err.message : "Ошибка при создании пользователя"); - } - }; - - const handleUpdatePermissions = async (e: React.FormEvent) => { - e.preventDefault(); - if (!selectedUser) return; - - setError(null); - try { - await agentApiService.updateUserPermissions(selectedUser.login, editData); - setSuccessMessage("Права пользователя обновлены"); - setShowEditModal(false); - await fetchUsers(); - } catch (err) { - setError(err instanceof Error ? err.message : "Ошибка при обновлении прав"); - } - }; - - const handleResetPassword = async (e: React.FormEvent) => { - e.preventDefault(); - if (!selectedUser) return; - - setError(null); - try { - await agentApiService.resetUserPassword(selectedUser.login, passwordData); - setSuccessMessage("Пароль изменен"); - setShowPasswordModal(false); - setPasswordData({ new_password: "" }); - } catch (err) { - setError(err instanceof Error ? err.message : "Ошибка при сбросе пароля"); - } - }; - - const handleActivateUser = async (login: string) => { - setError(null); - try { - await agentApiService.activateUser(login); - setSuccessMessage("Пользователь активирован"); - await fetchUsers(); - } catch (err) { - setError(err instanceof Error ? err.message : "Ошибка при активации пользователя"); - } - }; - - const handleDeactivateUser = async (login: string) => { - setError(null); - try { - await agentApiService.deactivateUser(login); - setSuccessMessage("Пользователь деактивирован"); - await fetchUsers(); - } catch (err) { - setError(err instanceof Error ? err.message : "Ошибка при деактивации пользователя"); - } - }; - - const handleDeleteUser = async (login: string) => { - if (!confirm(`Вы уверены, что хотите удалить пользователя ${login}?`)) return; - - setError(null); - try { - await agentApiService.deleteUser(login); - setSuccessMessage("Пользователь удален"); - await fetchUsers(); - } catch (err) { - setError(err instanceof Error ? err.message : "Ошибка при удалении пользователя"); - } - }; - - const openEditModal = (user: TokenUser) => { - setSelectedUser(user); - setEditData({ - is_active: user.is_active, - permission_admin: user.permission_admin, - permission_manage_agent: user.permission_manage_agent, - permission_view: user.permission_view, - }); - setShowEditModal(true); - }; - - const openPasswordModal = (user: TokenUser) => { - setSelectedUser(user); - setPasswordData({ new_password: "" }); - setShowPasswordModal(true); - }; - - const filteredUsers = (activeTab === "active" ? users : inactiveUsers).filter( - (user) => - user.login.toLowerCase().includes(searchQuery.toLowerCase()) || - user.name.toLowerCase().includes(searchQuery.toLowerCase()) || - user.last_name.toLowerCase().includes(searchQuery.toLowerCase()) - ); - - const inputStyle: React.CSSProperties = { - width: "100%", - padding: "10px 12px", - border: "1px solid var(--border)", - borderRadius: "8px", - backgroundColor: "var(--input-bg)", - color: "var(--text-primary)", - fontSize: "14px", - }; - - const labelStyle: React.CSSProperties = { - display: "block", - marginBottom: "8px", - color: "var(--text-secondary)", - fontSize: "14px", - fontWeight: 500, - }; - - const buttonBaseStyle: React.CSSProperties = { - padding: "8px 16px", - borderRadius: "8px", - border: "none", - fontSize: "14px", - fontWeight: 500, - cursor: "pointer", - display: "inline-flex", - alignItems: "center", - gap: "6px", - }; - - return ( -
-
- {/* Header */} -
-
-
- -
-
-

- Управление пользователями -

-

- Администрирование учетных записей -

-
-
-
- - {/* Messages */} - {successMessage && ( -
-
- {successMessage} - -
-
- )} - - {error && ( -
-
- {error} - -
-
- )} - - {/* Tabs and Actions */} -
-
- {/* Tabs */} -
- - -
- - {/* Create Button */} - -
- - {/* Search */} -
- - setSearchQuery(e.target.value)} - placeholder="Поиск по логину, имени или фамилии..." - className="w-full pl-10 pr-4 py-2.5 rounded-lg border" - style={{ - backgroundColor: "var(--input-bg)", - borderColor: "var(--border)", - color: "var(--text-primary)", - }} - /> -
-
- - {/* Users Table */} - {isLoading ? ( -
- Загрузка... -
- ) : filteredUsers.length === 0 ? ( -
- Пользователи не найдены -
- ) : ( -
- - - - - - - - - - - - - - {filteredUsers.map((user, index) => ( - - - - - - - - - - ))} - -
ЛогинИмяФамилияАдминУправлениеПросмотрДействия
{user.login}{user.name}{user.last_name} - {user.permission_admin ? ( - - ) : ( - - )} - - {user.permission_manage_agent ? ( - - ) : ( - - )} - - {user.permission_view ? ( - - ) : ( - - )} - -
- - - {activeTab === "active" ? ( - - ) : ( - - )} - -
-
-
- )} -
- - {/* Create User Modal */} - {showCreateModal && ( -
-
-
-

Создать пользователя

- -
-
-
- - setCreateData({ ...createData, login: e.target.value })} - required - style={inputStyle} - /> -
-
- - setCreateData({ ...createData, name: e.target.value })} - required - style={inputStyle} - /> -
-
- - setCreateData({ ...createData, last_name: e.target.value })} - required - style={inputStyle} - /> -
-
- - setCreateData({ ...createData, password: e.target.value })} - required - style={inputStyle} - /> -
-
- - - - -
-
- - -
-
-
-
- )} - - {/* Edit Permissions Modal */} - {showEditModal && selectedUser && ( -
-
-
-

- Редактировать: {selectedUser.login} -

- -
-
-
- - - - -
-
- - -
-
-
-
- )} - - {/* Reset Password Modal */} - {showPasswordModal && selectedUser && ( -
-
-
-

- Сброс пароля: {selectedUser.login} -

- -
-
-
- - setPasswordData({ new_password: e.target.value })} - required - style={inputStyle} - /> -
-
- - -
-
-
-
- )} -
- ); +export const AdminPage = () => { + return ; };