"use client"; import { useEffect } from "react"; import { useSiteInspectionStore } from "@/stores/useSiteInspectionStore"; import { useSiteInspectionSSE } from "@/hooks/useSiteInspectionSSE"; import { useSiteInspectionResult } from "@/lib/queries"; import { Progress } from "@/components/ui/progress"; import { Card, CardContent } from "@/components/ui/card"; import { ErrorState } from "@/components/common/ErrorState"; import { Globe, Search, Check, X, Circle, Loader2, ExternalLink, } from "lucide-react"; import { cn } from "@/lib/utils"; import { getScoreTailwindColor } from "@/lib/constants"; import type { DiscoveredPage } from "@/types/site-inspection"; interface SiteCrawlProgressProps { siteInspectionId: string; } /** * 사이트 크롤링 검사 진행 상태 표시 컴포넌트. * 크롤링 단계와 검사 단계를 시각적으로 표현한다. */ export function SiteCrawlProgress({ siteInspectionId, }: SiteCrawlProgressProps) { const { status, rootUrl, crawlProgress, discoveredPages, aggregateScores, errorMessage, initFromApi, } = useSiteInspectionStore(); // API에서 현재 상태 조회 (리로드 시 스토어 복원용) const { data: apiResult } = useSiteInspectionResult(siteInspectionId); useEffect(() => { if (apiResult && status === "idle") { initFromApi(apiResult); } }, [apiResult, status, initFromApi]); // SSE 연결 useSiteInspectionSSE(siteInspectionId); const handleRetry = () => { window.location.reload(); }; // 전체 진행률 계산 const completedPages = discoveredPages.filter( (p) => p.status === "completed" ).length; const totalPages = discoveredPages.length; const overallProgress = totalPages > 0 ? Math.round((completedPages / totalPages) * 100) : 0; return (
{/* URL 표시 */} {rootUrl && (
{rootUrl}
)} {/* 크롤링 단계 */} {status === "crawling" && ( )} {/* 검사 단계 */} {(status === "inspecting" || status === "completed") && ( )} {/* 에러 상태 */} {status === "error" && (
)} {/* 초기 연결 중 상태 */} {status === "idle" && (

서버에 연결하는 중...

)}
); } /** 크롤링 단계 UI */ function CrawlPhase({ pagesFound, currentUrl, }: { pagesFound: number; currentUrl: string; }) { return (

사이트 링크 수집 중...

{pagesFound}개 페이지 발견

{/* 크롤링 진행 바 (무한 애니메이션) */}
{/* 현재 크롤링 중인 URL */} {currentUrl && (

{currentUrl}

)} ); } /** 검사 단계 UI */ function InspectionPhase({ pages, completedPages, totalPages, overallProgress, aggregateScores, }: { pages: DiscoveredPage[]; completedPages: number; totalPages: number; overallProgress: number; aggregateScores: { overall_score: number; grade: string } | null; }) { return (
{/* 전체 진행률 */}

페이지 검사 진행

{completedPages}/{totalPages}
{overallProgress}% 완료 {aggregateScores && ( 현재 평균: {aggregateScores.overall_score}점{" "} {aggregateScores.grade} )}
{/* 개별 페이지 목록 */}
{pages.map((page) => ( ))}
); } /** 개별 페이지 진행 항목 */ function PageProgressItem({ page }: { page: DiscoveredPage }) { let displayPath: string; try { const parsed = new URL(page.url); displayPath = parsed.pathname + parsed.search || "/"; } catch { displayPath = page.url; } return (
{/* 상태 아이콘 */} {/* URL 경로 */} {displayPath} {/* 점수 (완료 시) */} {page.status === "completed" && page.overall_score !== null && ( {page.overall_score}점 )} {/* 검사 중 표시 */} {page.status === "inspecting" && ( 검사 중 )}
); } /** 페이지 상태 아이콘 */ function PageStatusIcon({ status }: { status: DiscoveredPage["status"] }) { switch (status) { case "pending": return ; case "inspecting": return ( ); case "completed": return ; case "error": return ; default: return ; } }