import React from 'react'; import AdminLayout from '../../layouts/AdminLayout'; import { Box, Heading, HStack, VStack, Button, Select, Input, Table, Thead, Tbody, Tr, Th, Td, Text, Badge, IconButton, useToast, Modal, ModalOverlay, ModalContent, ModalHeader, ModalBody, ModalFooter, ModalCloseButton, useDisclosure, FormControl, FormLabel, NumberInput, NumberInputField, Switch } from '@chakra-ui/react'; import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; import { adminListComments, adminUpdateCommentStatus, adminBanUser, adminListUnbanRequests, adminResolveUnban } from '../../services/admin/comments'; import { deleteComment } from '../../services/comments'; import { FiTrash2 } from 'react-icons/fi'; const CommentsAdminPage: React.FC = () => { const [status, setStatus] = React.useState(''); const [targetType, setTargetType] = React.useState(''); const [targetId, setTargetId] = React.useState(''); const [userId, setUserId] = React.useState(''); const [page, setPage] = React.useState(1); const [reportedOnly, setReportedOnly] = React.useState(false); const toast = useToast(); const qc = useQueryClient(); const listQ = useQuery({ queryKey: ['admin-comments', { status, targetType, targetId, userId, page }], queryFn: () => adminListComments({ status: status as any, target_type: targetType, target_id: targetId, user_id: userId, page, page_size: 50 }), keepPreviousData: true, }); const unbanQ = useQuery({ queryKey: ['admin-unban-requests'], queryFn: adminListUnbanRequests, }); const updateStatusMut = useMutation({ mutationFn: (args: { id: number; s: 'visible'|'hidden' }) => adminUpdateCommentStatus(args.id, args.s), onSuccess: async () => { await qc.invalidateQueries({ queryKey: ['admin-comments'] }); }, }); const deleteMut = useMutation({ mutationFn: (id: number) => deleteComment(id), onSuccess: async () => { await qc.invalidateQueries({ queryKey: ['admin-comments'] }); toast({ status: 'success', title: 'Smazáno' }); }, }); const [banUserId, setBanUserId] = React.useState(null); const banModal = useDisclosure(); const [banReason, setBanReason] = React.useState('Porušení pravidel diskuse'); const [banHours, setBanHours] = React.useState(0); const banMut = useMutation({ mutationFn: () => adminBanUser(banUserId || 0, banReason, banHours), onSuccess: async () => { banModal.onClose(); setBanUserId(null); toast({ status: 'success', title: 'Uživatel zablokován' }); }, }); const resolveUnbanMut = useMutation({ mutationFn: (args: { id: number; action: 'approve'|'reject' }) => adminResolveUnban(args.id, args.action), onSuccess: async () => { await qc.invalidateQueries({ queryKey: ['admin-unban-requests'] }); toast({ status: 'success', title: 'Vyřízeno' }); }, }); const itemsAll = listQ.data?.items || []; const items = React.useMemo(() => { if (!reportedOnly) return itemsAll; return itemsAll.filter((c: any) => (c as any).reports && (c as any).reports > 0); }, [itemsAll, reportedOnly]); return ( Komentáře (moderace) { setTargetId(e.target.value); setPage(1); }} maxW="200px" /> { setUserId(e.target.value); setPage(1); }} maxW="200px" /> Jen nahlášené setReportedOnly(e.target.checked)} /> {items.map((c) => ( ))}
ID Uživatel Cíl Obsah Spam Hlášení Status Akce
#{c.id} #{c.user?.id} {c.user?.first_name} {c.user?.last_name} {c.target_type} {c.target_id} {c.content} {(c as any).spam_score ? 0.5 ? 'orange' : 'green'}>{(c as any).spam_score.toFixed(2)} : '-'} {(c as any).reports ? 2 ? 'red' : 'yellow'}>{(c as any).reports} : '-'} } onClick={() => deleteMut.mutate(c.id)} />
Stránka {page} • {listQ.data?.total || 0} komentářů Žádosti o odblokování {(unbanQ.data?.items || []).map((r) => ( ))}
ID Uživatel Text Status Akce
#{r.id} #{r.user_id} {r.message} {r.status}
{/* Ban modal */} Zablokovat uživatele #{banUserId} Důvod setBanReason(e.target.value)} /> Doba (hodiny) – 0 = trvale setBanHours(Number(v) || 0)}> Rychlá volba:
); }; export default CommentsAdminPage;