|
import React, { useState, useEffect } from "react"; |
|
import { BACKEND_URL } from "../constants"; |
|
import { apiFetch } from "../utils/apiFetch"; |
|
|
|
interface UserInfo { |
|
connected: boolean; |
|
username: string | null; |
|
} |
|
|
|
const OAuthButton: React.FC = () => { |
|
const [userInfo, setUserInfo] = useState<UserInfo | null>(null); |
|
const [loading, setLoading] = useState(true); |
|
const [error, setError] = useState<string | null>(null); |
|
|
|
useEffect(() => { |
|
const fetchUserInfo = async () => { |
|
try { |
|
setLoading(true); |
|
const response = await apiFetch("/api/user"); |
|
if (!response.ok) { |
|
throw new Error(`HTTP error! status: ${response.status}`); |
|
} |
|
const data: UserInfo = await response.json(); |
|
setUserInfo(data); |
|
setError(null); |
|
} catch (err) { |
|
setError( |
|
err instanceof Error ? err.message : "Failed to fetch user info", |
|
); |
|
setUserInfo(null); |
|
} finally { |
|
setLoading(false); |
|
} |
|
}; |
|
|
|
fetchUserInfo(); |
|
}, []); |
|
|
|
const handleLogin = () => { |
|
const uri = `${BACKEND_URL}/oauth/huggingface/login`; |
|
|
|
|
|
window.parent?.postMessage({ type: "SET_SCROLLING", enabled: true }, "*"); |
|
|
|
|
|
setTimeout(() => { |
|
window.location.assign(uri + window.location.search); |
|
}, 500); |
|
}; |
|
|
|
const handleLogout = () => { |
|
const uri = `${BACKEND_URL}/oauth/huggingface/logout`; |
|
window.location.assign(uri); |
|
}; |
|
|
|
|
|
if (loading) { |
|
return ( |
|
<div className="flex items-center justify-center"> |
|
<div className="animate-spin rounded-full h-4 w-4 border-b-2 border-blue-500"></div> |
|
<span className="ml-2 text-gray-400 dark:text-gray-500 text-base"> |
|
Loading... |
|
</span> |
|
</div> |
|
); |
|
} |
|
|
|
|
|
if (error) { |
|
return ( |
|
<div className="p-3 bg-red-900/20 dark:bg-red-100/20 border border-red-700 dark:border-red-300 rounded-lg"> |
|
<p className="text-red-400 dark:text-red-600 text-base"> |
|
Error: {error} |
|
</p> |
|
</div> |
|
); |
|
} |
|
|
|
|
|
if (!userInfo?.connected) { |
|
return ( |
|
<button |
|
onClick={handleLogin} |
|
className="flex items-center justify-center space-x-3 px-4 py-2 bg-white dark:bg-[#0B0F19] hover:bg-gray-100 dark:hover:bg-[#1A1F2E] text-[#2C3236] dark:text-[#D6DAE2] rounded-full transition-colors duration-200 focus:outline-none focus:ring-2 focus:ring-blue-500/50 w-full h-12" |
|
aria-label="Sign in with Hugging Face" |
|
> |
|
<img |
|
src="https://huggingface.co/front/assets/huggingface_logo-noborder.svg" |
|
alt="Hugging Face" |
|
className="h-5 w-5" |
|
/> |
|
<span className="font-medium text-base">Sign in with Hugging Face</span> |
|
</button> |
|
); |
|
} |
|
|
|
|
|
return ( |
|
<button |
|
onClick={handleLogout} |
|
className="flex items-center justify-center space-x-3 px-4 py-2 bg-white dark:bg-[#0B0F19] hover:bg-gray-100 dark:hover:bg-[#1A1F2E] text-[#2C3236] dark:text-[#D6DAE2] rounded-full transition-colors duration-200 focus:outline-none focus:ring-2 focus:ring-blue-500/50 w-full h-12" |
|
aria-label="Logout" |
|
> |
|
<img |
|
src="https://huggingface.co/front/assets/huggingface_logo-noborder.svg" |
|
alt="Hugging Face" |
|
className="h-5 w-5" |
|
/> |
|
<span className="font-medium text-base"> |
|
Logout ({userInfo.username || "User"}) |
|
</span> |
|
</button> |
|
); |
|
}; |
|
|
|
export default OAuthButton; |
|
|