| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131 |
- 'use client'
- import { useState, useEffect, useCallback } from 'react'
- import { api } from '@/lib/api'
- import { useAuth } from '@/hooks/useAuth'
- import type { User } from '@/types'
- const roleLabels: Record<string, string> = {
- superadmin: 'Суперадмин',
- moderator: 'Модератор',
- landlord: 'Арендодатель',
- executor: 'Исполнитель',
- customer: 'Заказчик',
- }
- const statusLabels: Record<string, string> = {
- active: 'Активен',
- banned: 'Заблокирован',
- pending_verification: 'Ожидает проверки',
- }
- /**
- * Страница управления пользователями. Позволяет фильтровать
- * пользователей по роли, изменять роль, блокировать/разблокировать.
- * Загружает до 100 пользователей через API /admin/users.
- */
- export default function AdminUsersPage() {
- const { user: currentUser } = useAuth()
- const [users, setUsers] = useState<User[]>([])
- const [loading, setLoading] = useState(true)
- const [roleFilter, setRoleFilter] = useState('')
- const [msg, setMsg] = useState('')
- const fetchUsers = useCallback(async () => {
- const params = new URLSearchParams()
- if (roleFilter) params.set('role', roleFilter)
- params.set('limit', '100')
- try {
- const res = await api.get<{ data: User[] }>(`/admin/users?${params}`)
- setUsers(res.data)
- } catch {
- setMsg('Ошибка загрузки')
- } finally {
- setLoading(false)
- }
- }, [roleFilter])
- useEffect(() => { fetchUsers() }, [fetchUsers])
- const updateUser = async (id: string, data: Record<string, string>) => {
- try {
- await api.patch(`/admin/users/${id}`, data)
- setMsg('Обновлено')
- fetchUsers()
- } catch (err: any) {
- setMsg(err.message || 'Ошибка')
- }
- }
- if (loading) return <p className="text-white/60">Загрузка...</p>
- return (
- <div>
- <h1 className="mb-6 text-2xl font-bold text-white">Управление пользователями</h1>
- {msg && <p className="mb-4 rounded-lg bg-blue-500/10 px-4 py-2 text-sm text-blue-400">{msg}</p>}
- <div className="mb-4 flex flex-wrap gap-2">
- {['', 'customer', 'landlord', 'executor', 'moderator'].map((r) => (
- <button key={r} onClick={() => setRoleFilter(r)}
- className={`rounded-lg px-3 py-1.5 text-sm transition ${
- roleFilter === r ? 'bg-green-600 text-white' : 'bg-white/10 text-white/60 hover:bg-white/20'
- }`}
- >
- {r ? roleLabels[r] : 'Все'}
- </button>
- ))}
- </div>
- {(() => {
- return (
- <div className="space-y-2">
- {users.map((user) => {
- const isSelf = user.id === currentUser?.id
- return (
- <div key={user.id} className="flex items-center justify-between rounded-lg border border-white/10 bg-white/5 p-4">
- <div className="flex-1">
- <div className="flex items-center gap-2">
- <span className="font-medium text-white">{user.name || user.email}</span>
- {isSelf && <span className="rounded bg-green-600/30 px-1.5 py-0.5 text-xs text-green-300">это вы</span>}
- <span className={`rounded-full px-2 py-0.5 text-xs ${
- user.status === 'active' ? 'bg-green-500/20 text-green-400' :
- user.status === 'banned' ? 'bg-red-500/20 text-red-400' :
- 'bg-yellow-500/20 text-yellow-400'
- }`}>
- {statusLabels[user.status]}
- </span>
- </div>
- <p className="text-sm text-white/40">{user.email}</p>
- </div>
- {!isSelf && (
- <div className="flex items-center gap-2">
- <select value={user.role}
- onChange={(e) => updateUser(user.id, { role: e.target.value })}
- className="rounded-lg border border-white/10 bg-white/5 px-2 py-1.5 text-sm text-white outline-none"
- >
- {Object.entries(roleLabels).map(([k, v]) => (
- <option key={k} value={k} className="bg-[#1e293b]">{v}</option>
- ))}
- </select>
- <button onClick={() => updateUser(user.id, {
- status: user.status === 'banned' ? 'active' : 'banned'
- })}
- className={`rounded-lg px-3 py-1.5 text-sm transition ${
- user.status === 'banned' ? 'bg-green-600/80 text-white hover:bg-green-500' :
- 'bg-red-600/80 text-white hover:bg-red-500'
- }`}
- >
- {user.status === 'banned' ? 'Разблокировать' : 'Заблокировать'}
- </button>
- </div>
- )}
- </div>
- )
- })}
- </div>
- )
- })()}
- </div>
- )
- }
|