Snaplocal / client /src /components /VerificationPanel.jsx
Kuruva Laxmi
Deployment preparation: Configure Vercel, API URLs, and CORS
f359e2d
Raw
History Blame Contribute Delete
8.51 kB
import { useState, useEffect } from 'react';
import { Upload, CheckCircle, AlertCircle, Loader2, FileCheck } from 'lucide-react';
import api from '../api/api';
const VerificationPanel = ({ photographerId }) => {
const [verification, setVerification] = useState(null);
const [loading, setLoading] = useState(true);
const [uploadingID, setUploadingID] = useState(false);
const [uploadingPortfolio, setUploadingPortfolio] = useState(false);
useEffect(() => {
fetchVerificationStatus();
}, []);
const fetchVerificationStatus = async () => {
try {
const res = await api.get(`/verification/status/${photographerId}`);
setVerification(res.data);
} catch (err) {
console.error('Failed to load verification status:', err);
} finally {
setLoading(false);
}
};
const handleIDUpload = async (e) => {
const file = e.target.files?.[0];
if (!file) return;
// In real app, upload to Cloudinary or similar
setUploadingID(true);
try {
// Mock upload - in production use FormData with multipart
const idUrl = URL.createObjectURL(file);
const res = await api.post('/verification/submit', {
idDocumentUrl: idUrl,
});
setVerification(res.data);
alert('ID uploaded successfully!');
} catch (err) {
alert('Failed to upload ID');
} finally {
setUploadingID(false);
}
};
const handlePortfolioUpload = async (e) => {
const files = e.target.files;
if (!files || files.length === 0) return;
setUploadingPortfolio(true);
try {
const portfolioUrls = Array.from(files).map(file => URL.createObjectURL(file));
const res = await api.post('/verification/submit', {
portfolioUrls,
});
setVerification(res.data);
alert(`${files.length} portfolio images uploaded!`);
} catch (err) {
alert('Failed to upload portfolio images');
} finally {
setUploadingPortfolio(false);
}
};
if (loading) {
return (
<div className="flex items-center justify-center py-12">
<Loader2 className="animate-spin text-blue-600" size={32} />
</div>
);
}
const statusColor = {
verified: 'green',
pending: 'amber',
rejected: 'red',
not_started: 'gray',
};
const statusIcon = {
verified: <CheckCircle className="text-green-600" size={32} />,
pending: <AlertCircle className="text-amber-600" size={32} />,
rejected: <AlertCircle className="text-red-600" size={32} />,
not_started: <AlertCircle className="text-gray-600" size={32} />,
};
const status = verification?.status || 'not_started';
const color = statusColor[status];
return (
<div>
<h2 className="text-2xl font-bold mb-6">📋 Photographer Verification</h2>
{/* Status Card */}
<div className={`bg-${color}-50 border border-${color}-200 rounded-lg p-6 mb-6`}>
<div className="flex items-center gap-4">
<div>{statusIcon[status]}</div>
<div>
<h3 className={`text-lg font-bold text-${color}-900 capitalize`}>
Status: {status.replace('_', ' ')}
</h3>
{verification?.submittedAt && (
<p className={`text-sm text-${color}-700`}>
Submitted: {new Date(verification.submittedAt).toLocaleDateString()}
</p>
)}
{verification?.verifiedAt && (
<p className={`text-sm text-${color}-700`}>
Verified: {new Date(verification.verifiedAt).toLocaleDateString()}
</p>
)}
</div>
</div>
</div>
{/* ID Verification Section */}
<div className="bg-white border border-gray-200 rounded-lg p-6 mb-6">
<h3 className="text-lg font-bold mb-4 flex items-center gap-2">
<FileCheck size={20} />
Step 1: ID Verification
</h3>
{verification?.idDocument ? (
<div className="bg-green-50 border border-green-200 rounded-lg p-4 mb-4">
<div className="flex items-center gap-2 text-green-700 font-semibold">
<CheckCircle size={20} />
ID Document Verified ✓
</div>
{verification?.idVerifiedAt && (
<p className="text-sm text-green-600 mt-1">
Verified on {new Date(verification.idVerifiedAt).toLocaleDateString()}
</p>
)}
</div>
) : (
<div>
<p className="text-gray-700 mb-4">
Upload a clear copy of your government-issued ID (Aadhar, PAN, Passport, etc.)
</p>
<label className="flex items-center justify-center border-2 border-dashed border-gray-300 rounded-lg p-8 hover:border-blue-500 cursor-pointer transition">
<div className="text-center">
<Upload className="mx-auto mb-2 text-gray-400" size={32} />
<p className="font-semibold text-gray-700">Click to upload ID</p>
<p className="text-sm text-gray-500">or drag and drop</p>
</div>
<input
type="file"
onChange={handleIDUpload}
disabled={uploadingID}
className="hidden"
accept="image/*,.pdf"
/>
</label>
{uploadingID && <p className="text-sm text-blue-600 mt-2">Uploading...</p>}
</div>
)}
</div>
{/* Portfolio Verification Section */}
<div className="bg-white border border-gray-200 rounded-lg p-6 mb-6">
<h3 className="text-lg font-bold mb-4 flex items-center gap-2">
<FileCheck size={20} />
Step 2: Portfolio Verification
</h3>
{verification?.portfolioSamples?.length > 0 ? (
<div>
<p className="text-green-700 font-semibold mb-4">
✓ {verification.portfolioSamples.length} portfolio images uploaded
</p>
<div className="grid grid-cols-2 md:grid-cols-4 gap-4 mb-4">
{verification.portfolioSamples.map((sample, idx) => (
<div key={idx} className="aspect-square bg-gray-200 rounded-lg overflow-hidden">
<img
src={sample.url}
alt={`Portfolio ${idx + 1}`}
className="w-full h-full object-cover"
/>
</div>
))}
</div>
</div>
) : (
<div>
<p className="text-gray-700 mb-4">
Upload 3-5 of your best portfolio samples to showcase your work quality.
</p>
<label className="flex items-center justify-center border-2 border-dashed border-gray-300 rounded-lg p-8 hover:border-blue-500 cursor-pointer transition">
<div className="text-center">
<Upload className="mx-auto mb-2 text-gray-400" size={32} />
<p className="font-semibold text-gray-700">Click to upload portfolio</p>
<p className="text-sm text-gray-500">Upload multiple images (PNG, JPG)</p>
</div>
<input
type="file"
onChange={handlePortfolioUpload}
disabled={uploadingPortfolio}
multiple
className="hidden"
accept="image/*"
/>
</label>
{uploadingPortfolio && <p className="text-sm text-blue-600 mt-2">Uploading...</p>}
</div>
)}
</div>
{/* Admin Notes */}
{verification?.adminNotes && (
<div className="bg-blue-50 border border-blue-200 rounded-lg p-6">
<h3 className="font-bold text-blue-900 mb-2">Admin Notes</h3>
<p className="text-blue-800">{verification.adminNotes}</p>
</div>
)}
{/* Rejection Info */}
{status === 'rejected' && verification?.rejectionReason && (
<div className="bg-red-50 border border-red-200 rounded-lg p-6 mb-6">
<h3 className="font-bold text-red-900 mb-2">Rejection Reason</h3>
<p className="text-red-800 mb-4">{verification.rejectionReason}</p>
{verification?.resubmissionAllowed && (
<button className="bg-red-600 text-white px-4 py-2 rounded-lg hover:bg-red-700 font-medium">
Resubmit Application
</button>
)}
</div>
)}
</div>
);
};
export default VerificationPanel;