ATProto forum built with ESAV
at main 4.4 kB view raw
1import React, { useState, useRef, useEffect } from 'react'; 2import { useAuth } from '@/providers/OAuthProvider'; 3interface AuthButtonProps { 4 compact?: boolean; 5} 6 7export default function Login({ compact = false }: AuthButtonProps) { 8 // 1. Get state and functions from the new OAuth context 9 const { status, startLogin, logout } = useAuth(); 10 11 // State for the handle input and the dropdown visibility 12 const [handle, setHandle] = useState(''); 13 const [showLoginForm, setShowLoginForm] = useState(false); 14 const formRef = useRef<HTMLDivElement>(null); 15 16 useEffect(() => { 17 // This logic for closing the dropdown on outside click is still useful 18 function handleClickOutside(event: MouseEvent) { 19 if (formRef.current && !formRef.current.contains(event.target as Node)) { 20 setShowLoginForm(false); 21 } 22 } 23 if (showLoginForm) { 24 document.addEventListener('mousedown', handleClickOutside); 25 } 26 return () => { 27 document.removeEventListener('mousedown', handleClickOutside); 28 }; 29 }, [showLoginForm]); 30 31 // Handle the form submission 32 const handleLogin = async (e: React.FormEvent) => { 33 e.preventDefault(); 34 if (!handle.trim()) { 35 alert('Please enter your handle (e.g., name.example.com)'); 36 return; 37 } 38 // This will redirect the user, so no need to manage loading states here 39 await startLogin(handle); 40 }; 41 42 // Render loading state if the provider is initializing 43 if (status === 'loading') { 44 return ( 45 <div className="flex items-center justify-center p-6 text-gray-500 dark:text-gray-400"> 46 Loading... 47 </div> 48 ); 49 } 50 51 // If logged in, show a logout button 52 if (status === 'signedIn') { 53 const buttonClass = compact 54 ? "text-sm bg-gray-600 hover:bg-gray-700 text-white rounded px-3 py-1 font-medium transition-colors" 55 : "bg-gray-600 hover:bg-gray-700 text-white rounded px-6 py-2 font-semibold text-base transition-colors"; 56 57 const loggedInContent = ( 58 <button onClick={logout} className={buttonClass}> 59 Log out 60 </button> 61 ); 62 63 if (compact) { 64 return loggedInContent; 65 } 66 67 return ( 68 <div className="p-6 bg-gray-100 dark:bg-gray-900 rounded-xl shadow border border-gray-200 dark:border-gray-800 mt-6 mx-4"> 69 <div className="flex flex-col items-center justify-center text-center"> 70 <p className="text-lg font-semibold mb-6 text-gray-800 dark:text-gray-100">You are logged in!</p> 71 {loggedInContent} 72 </div> 73 </div> 74 ); 75 } 76 77 // If logged out, show a login button/form 78 const loginButtonClass = compact 79 ? "text-sm bg-gray-600 hover:bg-gray-700 text-white rounded px-3 py-1 font-medium transition-colors" 80 : "bg-gray-600 hover:bg-gray-700 text-white rounded px-6 py-2 font-semibold text-base transition-colors mt-2"; 81 82 const loginForm = ( 83 <form onSubmit={handleLogin} className={`flex flex-col gap-${compact ? '3' : '4'}`}> 84 <p className="text-sm text-gray-500 dark:text-gray-400 mb-2"> 85 Login with your AT Protocol (Bluesky) handle 86 </p> 87 <input 88 type="text" 89 placeholder="name.example.com" 90 value={handle} 91 onChange={e => setHandle(e.target.value)} 92 className="px-3 py-2 rounded border border-gray-300 dark:border-gray-700 bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 text-base focus:outline-none focus:ring-2 focus:ring-blue-500" 93 autoComplete="webauthn" // Hint for password managers 94 /> 95 <button type="submit" className={loginButtonClass}> 96 Sign In 97 </button> 98 </form> 99 ); 100 101 if (compact) { 102 return ( 103 <div className="relative" ref={formRef}> 104 <button 105 onClick={() => setShowLoginForm(!showLoginForm)} 106 className={loginButtonClass} 107 > 108 Log in 109 </button> 110 {showLoginForm && ( 111 <div className="absolute top-full right-0 mt-2 w-80 bg-white dark:bg-gray-900 rounded-lg shadow-lg border border-gray-200 dark:border-gray-700 p-4 z-50"> 112 {loginForm} 113 </div> 114 )} 115 </div> 116 ); 117 } 118 119 return ( 120 <div className="p-6 bg-gray-100 dark:bg-gray-900 rounded-xl shadow border border-gray-200 dark:border-gray-800 mt-6 mx-4"> 121 {loginForm} 122 </div> 123 ); 124}