import { useState, useEffect, useCallback, useRef } from 'react' import { motion } from 'framer-motion' import { Shield } from 'lucide-react' import { useAccessibility } from '../contexts/AccessibilityContext' interface LoginScreenProps { onComplete: () => void } export function LoginScreen({ onComplete }: LoginScreenProps) { const [username, setUsername] = useState('') const [passwordDots, setPasswordDots] = useState(0) const [showCursor, setShowCursor] = useState(true) const [activeField, setActiveField] = useState<'username' | 'password' | 'done' | null>('username') const [buttonPressed, setButtonPressed] = useState(false) const [isExiting, setIsExiting] = useState(false) const [isLoading, setIsLoading] = useState(false) const [typingComplete, setTypingComplete] = useState(false) const [buttonHovered, setButtonHovered] = useState(false) const [connectionState, setConnectionState] = useState<'connecting' | 'connected'>('connecting') const { requestFocusAfterLogin } = useAccessibility() const fullUsername = 'a.recruiter' const passwordLength = 8 const prefersReducedMotion = typeof window !== 'undefined' ? window.matchMedia('(prefers-reduced-motion: reduce)').matches : false // Refs for interval/timeout cleanup const usernameIntervalRef = useRef | null>(null) const passwordIntervalRef = useRef | null>(null) const cursorIntervalRef = useRef | null>(null) const timeoutRefs = useRef[]>([]) const loginButtonRef = useRef(null) const addTimeout = useCallback((fn: () => void, delay: number) => { const id = setTimeout(fn, delay) timeoutRefs.current.push(id) return id }, []) const canLogin = typingComplete && connectionState === 'connected' const handleLogin = useCallback(() => { if (!canLogin || isExiting || isLoading) return setButtonPressed(true) addTimeout(() => { setIsLoading(true) addTimeout(() => { setIsExiting(true) addTimeout(() => { requestFocusAfterLogin() onComplete() }, prefersReducedMotion ? 0 : 200) }, prefersReducedMotion ? 0 : 600) }, 100) }, [canLogin, isExiting, isLoading, onComplete, requestFocusAfterLogin, prefersReducedMotion, addTimeout]) const startLoginSequence = useCallback(() => { if (prefersReducedMotion) { setUsername(fullUsername) setPasswordDots(passwordLength) setActiveField('done') setTypingComplete(true) // Button is immediately available for user to click return } // Username typing: 80ms per character let usernameIndex = 0 usernameIntervalRef.current = setInterval(() => { if (usernameIndex <= fullUsername.length) { setUsername(fullUsername.slice(0, usernameIndex)) usernameIndex++ } else { if (usernameIntervalRef.current) { clearInterval(usernameIntervalRef.current) } setActiveField('password') // Password dots: 60ms per dot, after 300ms pause addTimeout(() => { let dotCount = 0 passwordIntervalRef.current = setInterval(() => { if (dotCount <= passwordLength) { setPasswordDots(dotCount) dotCount++ } else { if (passwordIntervalRef.current) { clearInterval(passwordIntervalRef.current) } setActiveField('done') setTypingComplete(true) // Button becomes interactive — user clicks to proceed } }, 60) }, 300) } }, 80) }, [prefersReducedMotion, addTimeout]) // Focus the login button when login becomes available for keyboard accessibility useEffect(() => { if (canLogin && loginButtonRef.current) { loginButtonRef.current.focus() } }, [canLogin]) useEffect(() => { // Cursor blink: 530ms interval cursorIntervalRef.current = setInterval(() => { setShowCursor(prev => !prev) }, 530) // Connection status: transitions to connected after ~2000ms const connectionTimeout = addTimeout(() => { setConnectionState('connected') }, 2000) // Delay start slightly for card entrance animation const startTimeout = addTimeout(() => { startLoginSequence() }, 400) // Capture ref value for cleanup const pendingTimeouts = timeoutRefs.current return () => { if (cursorIntervalRef.current) clearInterval(cursorIntervalRef.current) if (usernameIntervalRef.current) clearInterval(usernameIntervalRef.current) if (passwordIntervalRef.current) clearInterval(passwordIntervalRef.current) clearTimeout(startTimeout) clearTimeout(connectionTimeout) pendingTimeouts.forEach(id => clearTimeout(id)) } }, [startLoginSequence, addTimeout]) const buttonBg = buttonPressed ? '#085858' : buttonHovered && canLogin ? '#0A8080' : '#0D6E6E' return (
{isLoading ? (
Loading clinical records...
) : ( <> {/* Branding Header */}
CareerRecord PMR Clinical Information System
{/* Login Form */}
{/* Username Field */}
{username} {activeField === 'username' && ( )}
{/* Password Field */}
{'\u2022'.repeat(passwordDots)} {activeField === 'password' && ( )}
{/* Log In Button — user clicks to proceed */} {/* Connection Status Indicator */}
{connectionState === 'connected' ? 'Secure connection established' : 'Awaiting secure connection...'}
{/* Footer */}

Secure clinical system login

)}
) }