"use client";
import { useState, useCallback } from "react";
import {
Box,
Button,
Typography,
Alert,
CircularProgress,
Paper,
List,
ListItem,
ListItemIcon,
ListItemText,
Chip,
Stack,
Divider,
} from "@mui/material";
import { useDropzone } from "react-dropzone";
import CloudUploadIcon from "@mui/icons-material/CloudUpload";
import CheckCircleIcon from "@mui/icons-material/CheckCircle";
import CancelIcon from "@mui/icons-material/Cancel";
import InfoIcon from "@mui/icons-material/Info";
import { proofModeWorker, VerificationResult } from "@/lib/proofmode-worker";
export default function VerifyTab() {
const [isVerifying, setIsVerifying] = useState(false);
const [error, setError] = useState<string | null>(null);
const [result, setResult] = useState<VerificationResult | null>(null);
const [fileName, setFileName] = useState<string | null>(null);
const onDrop = useCallback(async (acceptedFiles: File[]) => {
if (acceptedFiles.length === 0) return;
const file = acceptedFiles[0];
setFileName(file.name);
setError(null);
setResult(null);
setIsVerifying(true);
try {
const verificationResult = await proofModeWorker.checkFile(file);
setResult(verificationResult);
} catch (err) {
setError(err instanceof Error ? err.message : "Verification failed");
} finally {
setIsVerifying(false);
}
}, []);
const { getRootProps, getInputProps, isDragActive } = useDropzone({
onDrop,
accept: {
"image/*": [".jpg", ".jpeg", ".png", ".gif", ".webp"],
"video/*": [".mp4", ".mov", ".avi"],
"application/zip": [".zip"],
},
maxFiles: 1,
});
const renderVerificationCheck = (label: string, passed?: boolean) => {
if (passed === undefined) return null;
return (
<ListItem>
<ListItemIcon>
{passed ? (
<CheckCircleIcon color="success" />
) : (
<CancelIcon color="error" />
)}
</ListItemIcon>
<ListItemText
primary={label}
secondary={passed ? "Verified" : "Not verified"}
/>
</ListItem>
);
};
return (
<Box>
<Paper
{...getRootProps()}
sx={{
p: 4,
textAlign: "center",
backgroundColor: isDragActive ? "action.hover" : "background.paper",
border: "2px dashed",
borderColor: isDragActive ? "primary.main" : "divider",
cursor: "pointer",
transition: "all 0.2s ease",
"&:hover": {
borderColor: "primary.main",
backgroundColor: "action.hover",
},
}}
>
<input {...getInputProps()} />
<CloudUploadIcon
sx={{ fontSize: 48, color: "text.secondary", mb: 2 }}
/>
<Typography variant="h6" gutterBottom>
{isDragActive
? "Drop the file here"
: "Drop a file here or click to select"}
</Typography>
<Typography variant="body2" color="text.secondary">
Supports images, videos, and ProofMode bundles (.zip)
</Typography>
</Paper>
{isVerifying && (
<Box sx={{ display: "flex", justifyContent: "center", mt: 4 }}>
<CircularProgress />
</Box>
)}
{error && (
<Alert severity="error" sx={{ mt: 2 }}>
{error}
</Alert>
)}
{result && (
<Box sx={{ mt: 4 }}>
<Stack direction="row" spacing={2} alignItems="center" sx={{ mb: 2 }}>
<Typography variant="h6">Verification Result</Typography>
<Chip
label={result.valid ? "Valid" : "Invalid"}
color={result.valid ? "success" : "error"}
size="small"
/>
</Stack>
{fileName && (
<Typography variant="body2" color="text.secondary" sx={{ mb: 2 }}>
File: {fileName}
</Typography>
)}
<Paper variant="outlined" sx={{ p: 2 }}>
<Typography variant="subtitle2" sx={{ mb: 1 }}>
Verification Checks
</Typography>
<List dense>
{renderVerificationCheck("C2PA Manifest", result.checks.c2pa)}
{renderVerificationCheck("PGP Signature", result.checks.pgp)}
{renderVerificationCheck("OpenTimestamps", result.checks.ots)}
{renderVerificationCheck("EXIF Metadata", result.checks.exif)}
</List>
</Paper>
{result.errors && result.errors.length > 0 && (
<Alert severity="warning" sx={{ mt: 2 }}>
<Typography variant="subtitle2" gutterBottom>
Warnings:
</Typography>
<ul>
{result.errors.map((error, index) => (
<li key={index}>{error}</li>
))}
</ul>
</Alert>
)}
{result.details && (
<Paper variant="outlined" sx={{ mt: 2, p: 2 }}>
<Typography variant="subtitle2" gutterBottom>
<InfoIcon
sx={{ fontSize: 16, verticalAlign: "text-bottom", mr: 0.5 }}
/>
Detailed Information
</Typography>
<Box
component="pre"
sx={{
mt: 1,
p: 1,
backgroundColor: "rgba(139, 195, 74, 0.08)",
borderRadius: 1,
overflow: "auto",
fontSize: "0.875rem",
}}
>
{JSON.stringify(result.details, null, 2)}
</Box>
</Paper>
)}
</Box>
)}
</Box>
);
}