'use client'
import { useState, useEffect, useCallback } from 'react'
import { api, ApiRequestError } from '@/lib/api'
import type { Place } from '@/types'
type FilterTab = 'pending_moderation' | 'published' | 'rejected' | 'revision' | 'deleted'
const FILTERS: { key: FilterTab; label: string }[] = [
{ key: 'pending_moderation', label: 'Новые' },
{ key: 'published', label: 'Одобренные недавно' },
{ key: 'rejected', label: 'Отклонённые' },
{ key: 'revision', label: 'На доработке' },
{ key: 'deleted', label: 'Удалённые' },
]
function ReworkModal({ place, onClose, onConfirm }: { place: Place; onClose: () => void; onConfirm: (id: string, comment: string) => void }) {
const [comment, setComment] = useState('')
return (
e.stopPropagation()}>
Отправить на доработку
{place.title}
)
}
export default function AdminModerationPage() {
const [filter, setFilter] = useState('pending_moderation')
const [places, setPlaces] = useState([])
const [loading, setLoading] = useState(true)
const [actionMsg, setActionMsg] = useState('')
const [reworkPlace, setReworkPlace] = useState(null)
const [hardDeletePlace, setHardDeletePlace] = useState(null)
const fetchPlaces = useCallback(async () => {
setLoading(true)
try {
const res = await api.get<{ data: Place[] }>(`/places?status=${filter}&limit=50`)
setPlaces(res.data)
} catch (err) {
if (err instanceof ApiRequestError && err.status === 403) {
setActionMsg('Нет прав доступа')
}
} finally {
setLoading(false)
}
}, [filter])
useEffect(() => { fetchPlaces() }, [fetchPlaces])
const moderate = async (id: string, action: 'approve' | 'reject' | 'rework' | 'revoke', comment?: string) => {
try {
await api.post(`/places/${id}/moderate`, { action, comment: comment || '' })
setPlaces((prev) => prev.filter((p) => p.id !== id))
setActionMsg(
action === 'approve' ? 'Одобрено' :
action === 'reject' ? 'Отклонено' :
action === 'revoke' ? 'Отозвано' : 'Отправлено на доработку'
)
setReworkPlace(null)
} catch (err: any) {
setActionMsg(err.message || 'Ошибка')
}
}
const hardDelete = async (id: string) => {
try {
await api.delete(`/admin/places/${id}`)
setPlaces((prev) => prev.filter((p) => p.id !== id))
setActionMsg('Место полностью удалено')
} catch (err: any) {
setActionMsg(err.message || 'Ошибка при удалении')
}
}
const restore = async (id: string) => {
try {
await api.post(`/places/${id}/restore`, {})
setPlaces((prev) => prev.filter((p) => p.id !== id))
setActionMsg('Место восстановлено')
} catch (err: any) {
setActionMsg(err.message || 'Ошибка при восстановлении')
}
}
return (
Модерация
{actionMsg && (
{actionMsg}
)}
{FILTERS.map((f) => (
))}
{loading ? (
Загрузка...
) : places.length === 0 ? (
Нет мест
) : (
{places.map((place) => (
{place.type === 'studio' ? 'Студия' : 'Место'}
ID: {place.id.slice(0, 8)}
{place.title}
{place.address &&
{place.address}
}
{place.description &&
{place.description}
}
{place.moderation_comment && (
Комментарий модератора: {place.moderation_comment}
)}
{filter === 'pending_moderation' && (
<>
>
)}
{filter === 'published' && (
<>
>
)}
{filter === 'deleted' && (
<>
>
)}
))}
)}
{reworkPlace && (
setReworkPlace(null)}
onConfirm={(id, comment) => moderate(id, 'rework', comment)}
/>
)}
{hardDeletePlace && (
setHardDeletePlace(null)}>
e.stopPropagation()}>
Полное удаление
{hardDeletePlace.title}
Место и все его файлы будут безвозвратно удалены.
)}
)
}