import { useParams, useNavigate } from 'react-router-dom'; import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import { useEffect } from 'react'; import { getReview, retryReview } from '../api/client'; import { wsClient } from '../api/websocket'; import ReviewProgress from '../components/ReviewProgress'; import CommentsList from '../components/CommentsList'; import { formatDistance } from 'date-fns'; import { ru } from 'date-fns/locale'; export default function ReviewDetail() { const { id } = useParams<{ id: string }>(); const navigate = useNavigate(); const queryClient = useQueryClient(); const { data: review, isLoading } = useQuery({ queryKey: ['review', id], queryFn: () => getReview(Number(id)), refetchInterval: (data) => { // Refetch if review is in progress return data?.status && ['pending', 'fetching', 'analyzing', 'commenting'].includes(data.status) ? 5000 : false; }, }); const retryMutation = useMutation({ mutationFn: () => retryReview(Number(id)), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['review', id] }); }, }); // Listen to WebSocket updates useEffect(() => { const unsubscribe = wsClient.on('review_progress', (data: any) => { if (data.review_id === Number(id)) { queryClient.invalidateQueries({ queryKey: ['review', id] }); } }); return () => { unsubscribe(); }; }, [id, queryClient]); if (isLoading) { return (
Загрузка...
); } if (!review) { return (
Ревью не найдено
); } return (

Ревью #{review.id}

PR #{review.pull_request.pr_number}: {review.pull_request.title}

{/* PR Info */}

Информация о Pull Request

Автор: {review.pull_request.author}
Ветки: {review.pull_request.source_branch} → {review.pull_request.target_branch}
URL: {review.pull_request.url}
Начато: {formatDistance(new Date(review.started_at), new Date(), { addSuffix: true, locale: ru })}
{review.completed_at && (
Завершено: {formatDistance(new Date(review.completed_at), new Date(), { addSuffix: true, locale: ru })}
)}
{/* Progress */}

Прогресс

{review.status === 'failed' && (
Ошибка: {review.error_message}
)}
{/* Comments */}

Комментарии ({review.comments?.length || 0})

); }