import React, { useState } from "react"; import { motion } from "framer-motion"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Separator } from "@/components/ui/separator"; import { Zap, Target, Upload, CheckCircle2, ArrowRight, Mail, Sparkles, Shield, Globe, AlertCircle, Loader2, } from "lucide-react"; import { useAuth } from "@/contexts/AuthContext"; export default function LoginForm() { const { firebaseLogin, requestOTP, verifyOTP } = useAuth(); const [email, setEmail] = useState(""); const [showOtp, setShowOtp] = useState(false); const [otp, setOtp] = useState(["", "", "", "", "", ""]); const [loading, setLoading] = useState(false); const [error, setError] = useState(""); // Business email validation const PERSONAL_EMAIL_DOMAINS = [ "gmail.com", "yahoo.com", "hotmail.com", "outlook.com", "aol.com", "icloud.com", "mail.com", "protonmail.com", "yandex.com", "zoho.com", "gmx.com", "live.com", "msn.com", ]; const isBusinessEmail = (email) => { if (!email || !email.includes("@")) return false; const domain = email.split("@")[1].toLowerCase(); return !PERSONAL_EMAIL_DOMAINS.includes(domain); }; const handleGoogleLogin = async () => { setLoading(true); setError(""); try { await firebaseLogin(); } catch (err) { setError(err.message || "Failed to sign in with Google"); } finally { setLoading(false); } }; const handleEmailSubmit = async (e) => { e.preventDefault(); setLoading(true); setError(""); if (!email) { setError("Please enter your email address"); setLoading(false); return; } if (!isBusinessEmail(email)) { setError("Only business email addresses are allowed. Personal email accounts (Gmail, Yahoo, etc.) are not permitted."); setLoading(false); return; } try { await requestOTP(email); setShowOtp(true); } catch (err) { setError(err.message || "Failed to send OTP"); } finally { setLoading(false); } }; const handleOtpChange = (index, value) => { if (value.length <= 1 && /^\d*$/.test(value)) { const newOtp = [...otp]; newOtp[index] = value; setOtp(newOtp); setError(""); // Auto-focus next input if (value && index < 5) { const nextInput = document.getElementById(`otp-${index + 1}`); nextInput?.focus(); } } }; const handleOtpPaste = (e, startIndex = 0) => { e.preventDefault(); const pastedData = e.clipboardData.getData("text"); // Extract only digits from pasted content const digits = pastedData.replace(/\D/g, "").slice(0, 6); if (digits.length > 0) { const newOtp = [...otp]; // Fill the OTP array with pasted digits starting from the current field for (let i = 0; i < digits.length && (startIndex + i) < 6; i++) { newOtp[startIndex + i] = digits[i]; } setOtp(newOtp); setError(""); // Focus on the next empty input or the last input if all are filled const nextEmptyIndex = Math.min(startIndex + digits.length, 5); const nextInput = document.getElementById(`otp-${nextEmptyIndex}`); nextInput?.focus(); } }; const handleOtpKeyDown = (index, e) => { if (e.key === "Backspace" && !otp[index] && index > 0) { const prevInput = document.getElementById(`otp-${index - 1}`); prevInput?.focus(); } }; const handleOtpVerify = async (e) => { e.preventDefault(); setLoading(true); setError(""); const otpString = otp.join(""); if (otpString.length !== 6) { setError("Please enter a valid 6-digit OTP"); setLoading(false); return; } try { await verifyOTP(email, otpString); // Success - user will be redirected by AuthContext } catch (err) { setError(err.message || "Invalid OTP. Please try again."); setOtp(["", "", "", "", "", ""]); } finally { setLoading(false); } }; const features = [ { icon: Zap, title: "Lightning Fast", description: "Process documents in seconds and get outputs for ERP ingestion", color: "text-amber-500", bg: "bg-amber-50", }, { icon: Target, title: "100% Accuracy", description: "Industry-leading extraction with Visual Reasoning Processor", color: "text-emerald-500", bg: "bg-emerald-50", }, { icon: Globe, title: "Any Format, Any Language", description: "PDF, images, scanned docs — multi-lingual support included", color: "text-blue-500", bg: "bg-blue-50", }, ]; const supportedFormats = [ { ext: "PDF", color: "bg-red-500" }, { ext: "PNG", color: "bg-blue-500" }, { ext: "JPG", color: "bg-green-500" }, { ext: "TIFF", color: "bg-purple-500" }, ]; return (
{/* Left Side - Product Showcase */}
{/* Background Elements */}
{/* Logo & Brand */}
EZOFIS AI Logo { // Fallback: hide image if logo not found e.target.style.display = 'none'; }} />

EZOFISOCR

VRP Intelligence

{/* Main Content */}

Pure Agentic Document Intelligence

Deterministic, layout-aware extraction (without LLM) using our proprietary{" "} Visual Reasoning Processor (VRP)

{/* Product Preview Card */}

Drop a document to extract data

Invoices, purchase orders, delivery notes, receipts, and operational documents

{supportedFormats.map((format, i) => ( {format.ext} ))}
Ready to extract
99.8% Accuracy
{/* Features */}
{features.map((feature, index) => (

{feature.title}

{feature.description}

))}
{/* Trust Badge */} Enterprise-grade security • SOC 2 Compliant • GDPR Ready
{/* Right Side - Sign In Form */}
{/* Mobile Logo */}
EZOFIS AI Logo { // Fallback: hide image if logo not found e.target.style.display = 'none'; }} />

EZOFISOCR

VRP Intelligence

{showOtp ? "Enter verification code" : "Secure Access"}

{showOtp ? `We sent a code to ${email}` : "Access your document intelligence workspace"}

{/* Error Message */} {error && (

{error}

)} {!showOtp ? ( <> {/* Google Sign In */}
or continue with email
{/* Email Input */}
{ setEmail(e.target.value); setError(""); }} className="h-12 pl-12 text-base border-slate-200 focus:border-blue-500 focus:ring-blue-500" />
) : ( /* OTP Input */
{otp.map((digit, index) => ( handleOtpChange(index, e.target.value)} onKeyDown={(e) => handleOtpKeyDown(index, e)} onPaste={(e) => handleOtpPaste(e, index)} className="w-12 h-14 text-center text-xl font-semibold border-slate-200 focus:border-blue-500 focus:ring-blue-500" /> ))}
)} {/* Notice */}
Only business email addresses are allowed

By signing in, you agree to our{" "} Terms of Service {" "} and{" "} Privacy Policy

{/* Mobile Features */}
{features.map((feature) => (
{feature.title}
))}
); }