tahamajs/IE / Projects /front /src /components /profile /IdentityVerificationPanel.tsx
tahamajs's picture
download
raw
5.16 kB
import { useIdentityVerification } from "@/hooks/useIdentityVerification";
import { useProfile } from "@/hooks/useProfile";
import { Mail, Building, Upload, CheckCircle2, XCircle, Loader2 } from "lucide-react";
import { useRef, useState } from "react";
import { toast } from "react-toastify";
interface IdentityVerificationPanelProps {
username: string;
}
export function IdentityVerificationPanel({ username }: IdentityVerificationPanelProps) {
const { profile, isLoading: profileLoading, error: profileError } = useProfile(username);
const { verifying, verifyEmail, uploadCVForVetting } = useIdentityVerification(username);
const fileRef = useRef<HTMLInputElement>(null);
const [uploading, setUploading] = useState(false);
if (profileLoading) {
return (
<div className="space-y-4">
<h2 className="text-xl font-bold gradient-text">Identity Verification</h2>
<div className="glass rounded-xl p-8 flex justify-center">
<Loader2 className="w-6 h-6 animate-spin text-primary" />
</div>
</div>
);
}
if (profileError || !profile) {
return (
<div className="space-y-4">
<h2 className="text-xl font-bold gradient-text">Identity Verification</h2>
<div className="glass rounded-xl p-4 text-red-500 text-center">
<XCircle className="w-8 h-8 mx-auto mb-2" />
<p>Failed to load profile data. Please try again later.</p>
</div>
</div>
);
}
const handleFileUpload = async (e: React.ChangeEvent<HTMLInputElement>) => {
const file = e.target.files?.[0];
if (!file) return;
const allowedTypes = ["application/pdf", "application/msword", "application/vnd.openxmlformats-officedocument.wordprocessingml.document"];
if (!allowedTypes.includes(file.type)) {
toast.error("Please upload a PDF or Word document (.pdf, .doc, .docx)");
return;
}
if (file.size > 5 * 1024 * 1024) {
toast.error("File size must be less than 5MB");
return;
}
setUploading(true);
try {
await uploadCVForVetting(file);
toast.success("CV uploaded successfully. Our team will review it shortly.");
} catch {
toast.error("Failed to upload CV. Please try again.");
} finally {
setUploading(false);
if (fileRef.current) fileRef.current.value = "";
}
};
return (
<div className="space-y-4">
<h2 className="text-xl font-bold gradient-text">Identity Verification</h2>
<div className="glass rounded-xl p-4 flex items-center justify-between">
<div className="flex items-center gap-3">
<Mail className="w-5 h-5 text-primary" />
<div>
<p className="font-semibold text-sm">Email</p>
<p className="text-xs text-gray-500">{profile.email || "No email provided"}</p>
</div>
</div>
{profile.isEmailVerified ? (
<span className="flex items-center gap-1 text-green-600 text-sm">
<CheckCircle2 className="w-4 h-4" /> Verified
</span>
) : (
<button onClick={verifyEmail} disabled={verifying} className="btn btn-secondary btn-sm">
{verifying ? <Loader2 className="w-4 h-4 animate-spin" /> : "Verify"}
</button>
)}
</div>
<div className="glass rounded-xl p-4 flex items-center justify-between">
<div className="flex items-center gap-3">
<img src="https://orcid.org/sites/default/files/images/orcid_16x16.png" className="w-5 h-5" alt="ORCID" />
<div>
<p className="font-semibold text-sm">ORCID</p>
<p className="text-xs text-gray-500">{profile.orcid || "Not connected"}</p>
</div>
</div>
{profile.orcid ? (
<span className="flex items-center gap-1 text-green-600 text-sm">
<CheckCircle2 className="w-4 h-4" /> Connected
</span>
) : (
<a href="/oauth2/authorization/orcid" className="btn btn-secondary btn-sm">
Connect ORCID
</a>
)}
</div>
<div className="glass rounded-xl p-4">
<div className="flex items-center gap-3 mb-3">
<Upload className="w-5 h-5 text-primary" />
<div>
<p className="font-semibold text-sm">Institutional Vetting</p>
<p className="text-xs text-gray-500">Upload your CV for manual verification</p>
</div>
</div>
<input
ref={fileRef}
type="file"
accept=".pdf,.doc,.docx"
className="hidden"
onChange={handleFileUpload}
disabled={uploading}
/>
<button onClick={() => fileRef.current?.click()} disabled={verifying || uploading} className="btn btn-secondary btn-sm">
{(verifying || uploading) ? <Loader2 className="w-4 h-4 animate-spin" /> : "Upload CV"}
</button>
{(profile as any).isVetted && (
<div className="mt-3 text-xs text-green-600 flex items-center gap-1">
<CheckCircle2 className="w-3 h-3" /> Your institution has verified your identity
</div>
)}
</div>
</div>
);
}

Xet Storage Details

Size:
5.16 kB
·
Xet hash:
75aa1320005f0b3b03fb80a746648c31ee7c7e35fb09ce713ba71b282dcd3be4

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.