// ───────────────────────────────────────────────────────────── // PlagiarismDetailPage — Main Feature Component // ───────────────────────────────────────────────────────────── 'use client'; import React from 'react'; import { useTranslations } from 'next-intl'; import { PlagiarismCheck } from '../lib/types'; import { getFileExtension, formatDate, formatFileSize, formatCurrency, } from '../lib/api'; import { usePlagiarismDetail } from '../lib/useDetail'; import { FileTypeBadge, InfoRow, SectionCard, StatusBadge, SimilarityMeter, Avatar, SkeletonLoader, ErrorState, } from '..'; // ── Icons (inline SVG for zero-dep) ────────────────────────── const IconUser = () => ( ); const IconFile = () => ( ); const IconCalendar = () => ( ); const IconPayment = () => ( ); const IconShield = () => ( ); const IconCert = () => ( ); const IconDownload = () => ( ); // const IconBack = () => ( // // // // ); const IconSource = () => ( ); // ── Sub-components ──────────────────────────────────────────── interface CheckDetailViewProps { check: PlagiarismCheck; } const CheckHeader: React.FC = ({ check }) => { const t = useTranslations('DetailPage'); return (

{check.sender.name}

{check.sender.email}

{t('id')}: {check.id}

); }; const SubmissionInfoCard: React.FC = ({ check }) => { const t = useTranslations('DetailPage'); return ( } accent="blue" > } value={ {check.sender.name} } /> } value={ {check.fileName} } /> {formatFileSize(check.fileSize)} } /> } value={formatDate(check.submittedAt)} /> } value={ {formatCurrency(check.paymentAmount, check.currency)} } /> ); }; const ResultCard: React.FC = ({ check }) => { const t = useTranslations('DetailPage'); if (check.status === 'processing' || check.status === 'pending') { return ( } accent="violet" >

{t('analysisInProgress')}

{t('resultsReadyAfterProcessing')}

); } if (!check.result) { return ( } accent="violet" >

{t('noResultAvailable')}

); } const { result } = check; return ( } accent={ result.similarityLevel === 'low' ? 'green' : result.similarityLevel === 'high' ? 'red' : 'amber' } >
{/* Meter */} {/* Stats grid */}

{result.checkedWords.toLocaleString()}

{t('wordsChecked')}

{result.matchedWords.toLocaleString()}

{t('wordsMatched')}

{/* Sources */} {result.sources.length > 0 && (

{t('matchedSources')}

{result.sources.map((src, i) => (

{src.title}

{src.url}
= 30 ? 'text-red-600' : src.matchPercentage >= 15 ? 'text-amber-600' : 'text-emerald-600'}`} > {src.matchPercentage}%

{src.matchedWords.toLocaleString()} {t('words')}

))}
)} } value={formatDate(result.processedAt)} />
); }; const CertificateCard: React.FC = ({ check }) => { const t = useTranslations('DetailPage'); if (!check.certificate) { return ( } accent="violet">

{t('noCertificate')}

{check.result?.similarityLevel === 'high' && (

{t('noCertificateHighSimilarity')}

)}
); } const { certificate } = check; return ( } accent="green"> {/* Certificate visual */}

{certificate.issuerName}

{certificate.verificationCode}

{t('certificateId')}: {certificate.id}

} value={formatDate(certificate.issuedAt)} /> } value={formatDate(certificate.expiresAt)} />
); }; // ── Detail View (assembled) ─────────────────────────────────── const CheckDetailView: React.FC = ({ check }) => (
); // ── Page ────────────────────────────────────────────────────── interface PlagiarismDetailPageProps { checkId: string; onBack?: () => void; } export const PlagiarismDetailPage: React.FC = ({ checkId, }) => { const t = useTranslations('DetailPage'); const { check, loadingState, error, reload } = usePlagiarismDetail(checkId); return (
{loadingState === 'loading' && } {loadingState === 'error' && ( )} {loadingState === 'success' && check && ( )}
); };