import { useCallback, useMemo, useState } from 'react';
import { Alert, Badge, Button, Divider, Group, Loader, Stack, Text, SegmentedControl } from '@mantine/core';
import { useTranslation } from 'react-i18next';
import type { SignatureValidationReportEntry } from '../../../types/validateSignature';
import type { ValidateSignatureOperationHook } from '../../../hooks/tools/validateSignature/useValidateSignatureOperation';
import './reportView/styles.css';
import FitText from '../../shared/FitText';
import { SuggestedToolsSection } from '../shared/SuggestedToolsSection';
interface ValidateSignatureResultsProps {
operation: ValidateSignatureOperationHook;
results: SignatureValidationReportEntry[];
isLoading: boolean;
errorMessage: string | null;
reportAvailable?: boolean;
}
const useFileSummary = (results: SignatureValidationReportEntry[]) => {
return useMemo(() => {
if (results.length === 0) {
return { fileCount: 0, signatureCount: 0, fullyValidCount: 0 };
}
let signatureCount = 0;
let fullyValidCount = 0;
results.forEach((result) => {
signatureCount += result.signatures.length;
result.signatures.forEach((signature) => {
const isValid = signature.valid;
if (isValid) {
fullyValidCount += 1;
}
});
});
return {
fileCount: results.length,
signatureCount,
fullyValidCount,
};
}, [results]);
};
const findFileByExtension = (files: File[], extension: string) => {
return files.find((file) => file.name.toLowerCase().endsWith(extension));
};
const ValidateSignatureResults = ({
operation,
results,
isLoading,
errorMessage,
}: ValidateSignatureResultsProps) => {
const { t } = useTranslation();
const summary = useFileSummary(results);
const pdfFile = useMemo(() => findFileByExtension(operation.files, '.pdf'), [operation.files]);
const csvFile = useMemo(() => findFileByExtension(operation.files, '.csv'), [operation.files]);
const jsonFile = useMemo(() => findFileByExtension(operation.files, '.json'), [operation.files]);
const [selectedType, setSelectedType] = useState<'pdf' | 'csv' | 'json'>('pdf');
const selectedFile = useMemo(() => {
if (selectedType === 'pdf') return pdfFile ?? null;
if (selectedType === 'csv') return csvFile ?? null;
return jsonFile ?? null;
}, [selectedType, pdfFile, csvFile, jsonFile]);
const selectedDownloadLabel = useMemo(() => {
if (selectedType === 'pdf') return t('validateSignature.downloadPdf', 'Download PDF Report');
if (selectedType === 'csv') return t('validateSignature.downloadCsv', 'Download CSV');
return t('validateSignature.downloadJson', 'Download JSON');
}, [selectedType, t]);
const downloadTypeOptions = [
{ label: t('validateSignature.downloadType.pdf', 'PDF'), value: 'pdf' },
{ label: t('validateSignature.downloadType.csv', 'CSV'), value: 'csv' },
{ label: t('validateSignature.downloadType.json', 'JSON'), value: 'json' },
];
const handleDownload = useCallback((file: File) => {
const blobUrl = URL.createObjectURL(file);
const link = document.createElement('a');
link.href = blobUrl;
link.download = file.name;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
URL.revokeObjectURL(blobUrl);
}, []);
// Show the big loader only while we're still waiting for the first results.
if (isLoading && results.length === 0) {
return (
{t('validateSignature.processing', 'Validating signatures...')}
);
}
if (!isLoading && results.length === 0) {
return (
{t('validateSignature.noResults', 'Run the validation to generate a report.')}
);
}
return (
{/* While results are visible but background work continues (e.g. generating files),
show a light inline indicator without blocking downloads UI. */}
{isLoading && results.length > 0 && (
{t('validateSignature.finalizing', 'Preparing downloads...')}
)}
{errorMessage && (
{errorMessage}
)}
{t('validateSignature.report.filesEvaluated', '{{count}} files evaluated', {
count: summary.fileCount,
})}
{t('validateSignature.report.signaturesFound', '{{count}} signatures detected', {
count: summary.signatureCount,
})}
{summary.signatureCount > 0 && (
{t('validateSignature.report.signaturesValid', '{{count}} fully valid', {
count: summary.fullyValidCount,
})}
)}
{results.map((result) => {
const hasError = Boolean(result.error);
const hasSignatures = result.signatures.length > 0;
const allValid = hasSignatures && result.signatures.every((signature) => signature.valid);
const badgeLabel = hasError
? t('validateSignature.status.invalid', 'Invalid')
: hasSignatures
? allValid
? t('validateSignature.status.valid', 'Valid')
: t('validateSignature.status.invalid', 'Invalid')
: t('validateSignature.noSignaturesShort', 'No signatures');
const badgeClass = hasError
? 'status-badge status-badge--invalid'
: hasSignatures
? allValid
? 'status-badge status-badge--valid'
: 'status-badge status-badge--warning'
: 'status-badge status-badge--neutral';
return (
{badgeLabel}
{t('validateSignature.report.signatureCountLabel', '{{count}} signatures', {
count: result.signatures.length,
})}
{!result.error && result.signatures.length === 0 && (
{t('validateSignature.noSignatures', 'No digital signatures found in this document')}
)}
);
})}
{t('validateSignature.report.downloads', 'Downloads')}
setSelectedType(v as 'pdf' | 'csv' | 'json')}
data={downloadTypeOptions}
/>
{selectedType === 'pdf' && !pdfFile && (
{t('validateSignature.report.noPdf', 'PDF report will be available after a successful validation.')}
)}
);
};
export default ValidateSignatureResults;