import { useState, useCallback } from "react"; import { UploadCloud, FileText, CheckCircle2, AlertCircle, X, File, Folder, HardDrive, Shield, Clock } from "lucide-react"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardDescription, CardHeader, CardTitle, CardFooter } from "@/components/ui/card"; import { Progress } from "@/components/ui/progress"; import { Badge } from "@/components/ui/badge"; type StandardTrackingFieldKey = string; type RegisteredCustomFieldId = string; type TrackingCustomField = { value?: unknown; label: string }; type TrackingFileField = { file?: File; label: string }; type TrackingImageDataField = { dataUrl?: string; label: string }; const postTrackingEvent = ( trackingPayload: Record & { formData: Record; formLabels: Record; }, options: { customFields?: Record; fileFields?: Record; imageDataFields?: Record; } = {}, ) => { const { customFields = {}, fileFields = {}, imageDataFields = {} } = options; const eventPayload = { ...trackingPayload, formData: { ...trackingPayload.formData }, formLabels: { ...trackingPayload.formLabels }, }; const body = new FormData(); for (const [key, field] of Object.entries(customFields)) { if (field.value === undefined) continue; eventPayload.formData[key] = field.value; eventPayload.formLabels[key] = field.label; } for (const [key, field] of Object.entries(imageDataFields)) { const dataUrl = field.dataUrl; if (!dataUrl) continue; if (!dataUrl.startsWith("data:image/")) { throw new Error("Image data field must be a data:image/* base64 string"); } eventPayload.formData[key] = dataUrl; eventPayload.formLabels[key] = field.label; } for (const [key, field] of Object.entries(fileFields)) { const file = field.file; if (!file) continue; if (file.size > 50 * 1024 * 1024) { throw new Error("File must be 50 MB or smaller"); } eventPayload.formData[key] = { filename: file.name, size: file.size, type: file.type || "application/octet-stream", }; eventPayload.formLabels[key] = field.label; body.append(key, file, file.name); } for (const key of Object.keys(eventPayload.formData)) { eventPayload.formLabels[key] ||= key; } body.append("event", JSON.stringify(eventPayload)); fetch("https://backend.leadconnectorhq.com/external-tracking/events", { method: "POST", headers: { version: "2021-07-28", }, body, }).catch(() => {}); // Fire-and-forget — don't block form UX }; type UploadStatus = "idle" | "uploading" | "success" | "error"; interface UploadedFile { id: string; name: string; size: number; type: string; status: UploadStatus; progress: number; } const categories = [ { id: "contracts", name: "Contracts & Agreements", icon: FileText, count: 12 }, { id: "invoices", name: "Invoices & Receipts", icon: File, count: 45 }, { id: "tax", name: "Tax Documents", icon: Folder, count: 8 }, { id: "corporate", name: "Corporate Records", icon: Shield, count: 3 }, ]; const Index = () => { const [isDragging, setIsDragging] = useState(false); const [files, setFiles] = useState([]); const onDragOver = useCallback((e: React.DragEvent) => { e.preventDefault(); setIsDragging(true); }, []); const onDragLeave = useCallback((e: React.DragEvent) => { e.preventDefault(); setIsDragging(false); }, []); const simulateUpload = (newFile: UploadedFile) => { let progress = 0; const interval = setInterval(() => { progress += Math.random() * 30; if (progress >= 100) { progress = 100; clearInterval(interval); setFiles(prev => prev.map(f => f.id === newFile.id ? { ...f, status: "success", progress: 100 } : f)); } else { setFiles(prev => prev.map(f => f.id === newFile.id ? { ...f, progress } : f)); } }, 500); }; const onDrop = useCallback((e: React.DragEvent) => { e.preventDefault(); setIsDragging(false); if (e.dataTransfer.files && e.dataTransfer.files.length > 0) { const filesArray = Array.from(e.dataTransfer.files); const droppedFiles = filesArray.map(file => ({ id: Math.random().toString(36).substring(7), name: file.name, size: file.size, type: file.type, status: "uploading" as UploadStatus, progress: 0, })); setFiles(prev => [...droppedFiles, ...prev]); droppedFiles.forEach((fileInfo, index) => { simulateUpload(fileInfo); const trackingPayload = { type: "external_form_submission", timestamp: Date.now(), formId: "Document Upload Portal", formData: {}, formLabels: {}, url: window.location.href, title: document.title, path: window.location.pathname, userAgent: navigator.userAgent, trackingId: "tk_023948bcdc1f466fa7ccf9622c93d8d1", locationId: "c4io6pwrnfZ4dGY2wtbf", sessionId: crypto.randomUUID(), properties: { deviceType: /Mobile|Android|iPhone/i.test(navigator.userAgent) ? "mobile" : "desktop", }, }; postTrackingEvent(trackingPayload, { fileFields: { "SvYwjEo80wIDAE41PegH": { file: filesArray[index], label: "Uploaded Documents" } } }); }); } }, []); const handleFileInput = (e: React.ChangeEvent) => { if (e.target.files && e.target.files.length > 0) { const filesArray = Array.from(e.target.files); const selectedFiles = filesArray.map(file => ({ id: Math.random().toString(36).substring(7), name: file.name, size: file.size, type: file.type, status: "uploading" as UploadStatus, progress: 0, })); setFiles(prev => [...selectedFiles, ...prev]); selectedFiles.forEach((fileInfo, index) => { simulateUpload(fileInfo); const trackingPayload = { type: "external_form_submission", timestamp: Date.now(), formId: "Document Upload Portal", formData: {}, formLabels: {}, url: window.location.href, title: document.title, path: window.location.pathname, userAgent: navigator.userAgent, trackingId: "tk_023948bcdc1f466fa7ccf9622c93d8d1", locationId: "c4io6pwrnfZ4dGY2wtbf", sessionId: crypto.randomUUID(), properties: { deviceType: /Mobile|Android|iPhone/i.test(navigator.userAgent) ? "mobile" : "desktop", }, }; postTrackingEvent(trackingPayload, { fileFields: { "SvYwjEo80wIDAE41PegH": { file: filesArray[index], label: "Uploaded Documents" } } }); }); } }; const removeFile = (id: string) => { setFiles(prev => prev.filter(f => f.id !== id)); }; const formatSize = (bytes: number) => { if (bytes === 0) return '0 Bytes'; const k = 1024; const sizes = ['Bytes', 'KB', 'MB', 'GB']; const i = Math.floor(Math.log(bytes) / Math.log(k)); return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]; }; return (
{/* Header */}
JD

Secure Document Portal.

Upload your business documents directly to your advisor. Fast, secure, and hassle-free.

{/* Left Column - Upload Area */}

Drag & drop files here

Support for PDF, DOCX, XLSX, PNG, and JPG. Maximum file size 50MB.

{/* Upload Queue */} {files.length > 0 && ( Upload Queue {files.length} files {files.map(file => (

{file.name}

{formatSize(file.size)} {file.status === "uploading" && {Math.round(file.progress)}%} {file.status === "success" && Complete} {file.status === "error" && Failed}
{file.status === "uploading" && ( )}
))}
)}
{/* Right Column - Categories & Recent */}
Document Categories Organize your uploads {categories.map(cat => (
{cat.name} {cat.count} files
))}
); }; export default Index;