// Login screen — Google Sign-In + Microsoft Sign-In function LoginScreen({ onLogin }) { const [error, setError] = useState(null); const [loading, setLoading] = useState(false); const [gsiReady, setGsiReady] = useState(false); const buttonRef = useRef(null); const callbackRef = useRef(null); async function handleAuthResponse(data) { localStorage.setItem("ats_token", data.access_token); localStorage.setItem("ats_user", JSON.stringify(data.user)); onLogin(data.user, data.access_token); } callbackRef.current = async function handleGoogleResponse(response) { setLoading(true); setError(null); try { const res = await fetch(`${API_BASE_URL}/auth/google`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ credential: response.credential }), }); if (!res.ok) { const data = await res.json().catch(() => ({})); throw new Error(data.detail || `Login failed (${res.status})`); } await handleAuthResponse(await res.json()); } catch (err) { setError(err.message); } finally { setLoading(false); } }; async function handleMicrosoftLogin() { setLoading(true); setError(null); try { const msalConfig = { auth: { clientId: window.__MICROSOFT_CLIENT_ID, authority: `https://login.microsoftonline.com/${window.__MICROSOFT_TENANT_ID || "common"}`, redirectUri: window.location.origin, }, }; const msalInstance = new msal.PublicClientApplication(msalConfig); await msalInstance.initialize(); const loginResp = await msalInstance.loginPopup({ scopes: ["User.Read"], prompt: "select_account", }); const res = await fetch(`${API_BASE_URL}/auth/microsoft`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ access_token: loginResp.accessToken }), }); if (!res.ok) { const data = await res.json().catch(() => ({})); throw new Error(data.detail || `Login failed (${res.status})`); } await handleAuthResponse(await res.json()); } catch (err) { if (err.errorCode === "user_cancelled") { setError(null); } else { setError(err.message || "Microsoft login failed"); } } finally { setLoading(false); } } useEffect(() => { let cancelled = false; let attempts = 0; function tryInit() { if (cancelled) return; attempts++; const gsi = window.google && window.google.accounts; const clientId = window.__GOOGLE_CLIENT_ID; if (!gsi || !clientId) { if (attempts < 50) setTimeout(tryInit, 200); return; } gsi.id.initialize({ client_id: clientId, callback: (resp) => callbackRef.current(resp), }); if (buttonRef.current) { gsi.id.renderButton(buttonRef.current, { theme: "outline", size: "large", shape: "rectangular", text: "signin_with", width: 300, }); } setGsiReady(true); } tryInit(); return () => { cancelled = true; }; }, []); const hasMicrosoft = !!window.__MICROSOFT_CLIENT_ID; const [emailMode, setEmailMode] = useState(false); const [emailInput, setEmailInput] = useState(""); const [emailSent, setEmailSent] = useState(false); async function handleEmailLogin() { if (!emailInput.trim() || !emailInput.includes("@")) { setError("Enter a valid email"); return; } setLoading(true); setError(null); try { const res = await fetch(`${API_BASE_URL}/auth/email/send-link`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ email: emailInput.trim() }), }); if (!res.ok) throw new Error("Failed to send login link"); setEmailSent(true); } catch (err) { setError(err.message); } finally { setLoading(false); } } return (
Nuance ATS
{!emailMode && !gsiReady && (
Loading sign-in...
)} {!emailMode &&
} {!emailMode && hasMicrosoft && gsiReady && ( )} {!emailMode && gsiReady && ( <>
or
)} {emailMode && !emailSent && (
Enter your email and we'll send a login link.
setEmailInput(e.target.value)} onKeyDown={(e) => e.key === "Enter" && handleEmailLogin()} placeholder="you@company.com" autoFocus style={{ width: "100%", height: 42, border: "1px solid var(--border-1)", borderRadius: 4, padding: "0 12px", fontSize: 14, outline: "none", }} />
)} {emailSent && (
✉️
Check your email
We sent a login link to {emailInput}. Click the link to sign in. It expires in 15 minutes.
)} {loading && !emailMode && (
Signing in...
)} {error && (
{error}
)}
); } Object.assign(window, { LoginScreen });