fix: make Google login and session recovery resilient

This commit is contained in:
2026-09-06 13:50:58 +03:00
parent 53903cbe61
commit 52fdb5fe17
4 changed files with 162 additions and 68 deletions
+43 -41
View File
@@ -16,46 +16,46 @@ export const LoginPage = ({ onLogin }) => {
const [ready, setReady] = useState(false);
const [noConfig, setNoConfig] = useState(false);
const [attempt,setAttempt]=useState(0),[signingIn,setSigningIn]=useState(false);
const loginCallback=useRef(onLogin);loginCallback.current=onLogin;
useEffect(() => {
let cancelled = false;
(async () => {
const { clientId } = await getGoogleConfig();
if (cancelled) return;
if (!clientId) { setNoConfig(true); return; }
const init = () => {
if (!window.google?.accounts?.id || !btnRef.current) return;
window.google.accounts.id.initialize({
client_id: clientId,
callback: async (resp) => {
try {
const user = await loginWithGoogle(resp.credential);
onLogin(user);
} catch (e) {
setErr(e.message || 'Giriş başarısız');
}
},
});
window.google.accounts.id.renderButton(btnRef.current, {
theme: 'outline', size: 'large', text: 'continue_with', locale: 'tr', width: 320,
});
setReady(true);
};
if (window.google?.accounts?.id) { init(); return; }
let s = document.getElementById('gsi-script');
if (!s) {
s = document.createElement('script');
s.id = 'gsi-script';
s.src = 'https://accounts.google.com/gsi/client';
s.async = true;
s.defer = true;
document.head.appendChild(s);
}
s.addEventListener('load', init);
let cancelled=false,script=null,scriptTimer=null,loginPending=false;
const controller=new AbortController();
setErr(null);setReady(false);setNoConfig(false);setSigningIn(false);
const failed=()=>{clearTimeout(scriptTimer);if(!cancelled){setErr('Google giriş ekranı yüklenemedi. Bağlantınızı kontrol edip yeniden deneyin.');setReady(false);}script?.remove();};
const init=()=>{
if(cancelled)return;
if(!window.google?.accounts?.id||!btnRef.current){failed();return;}
clearTimeout(scriptTimer);
try {
window.google.accounts.id.initialize({client_id:clientId,callback:async response=>{
if(cancelled||loginPending)return;
loginPending=true;setSigningIn(true);setErr(null);
try{const user=await loginWithGoogle(response.credential,{signal:controller.signal});if(!cancelled)loginCallback.current(user);}
catch(error){if(!cancelled)setErr(error.message || 'Giriş başarısız');}
finally{loginPending=false;if(!cancelled)setSigningIn(false);}
}});
btnRef.current.replaceChildren();
window.google.accounts.id.renderButton(btnRef.current,{theme:'outline',size:'large',text:'continue_with',locale:'tr',width:Math.min(320,btnRef.current.parentElement.clientWidth)});
setReady(true);
} catch { failed(); }
};
let clientId;
void (async()=>{
try{
const config=await getGoogleConfig({signal:controller.signal});
if(cancelled)return;clientId=config.clientId;
if(!clientId){setNoConfig(true);return;}
if(window.google?.accounts?.id){init();return;}
script=document.getElementById('gsi-script');
if(!script){script=document.createElement('script');script.id='gsi-script';script.src='https://accounts.google.com/gsi/client';script.async=true;script.defer=true;}
script.addEventListener('load',init);script.addEventListener('error',failed);
scriptTimer=setTimeout(failed,15000);
if(!script.isConnected)document.head.appendChild(script);
}catch(error){if(!cancelled)setErr(error.message || 'Giriş hizmetine ulaşılamadı.');}
})();
return () => { cancelled = true; };
}, [onLogin]);
return()=>{cancelled=true;controller.abort();clearTimeout(scriptTimer);script?.removeEventListener('load',init);script?.removeEventListener('error',failed);};
},[attempt]);
return (
<div className="min-h-screen bg-[#0f172a] text-white flex flex-col lg:flex-row">
@@ -89,16 +89,18 @@ export const LoginPage = ({ onLogin }) => {
{noConfig ? (
<div className="text-sm text-amber-700 bg-amber-50 border border-amber-200 rounded-xl p-4">
Google girişi henüz yapılandırılmadı (sunucuda GOOGLE_CLIENT_ID eksik).
Google girişi henüz etkinleştirilmedi. Lütfen yöneticinizle görüşün.
</div>
) : (
<div className="flex flex-col items-center gap-4">
<div ref={btnRef} className="min-h-[44px]" />
{!ready && <p className="text-xs text-slate-400">Google giriş yükleniyor…</p>}
{!ready && !err && <p role="status" className="text-xs text-slate-400">Google giriş yükleniyor…</p>}
</div>
)}
{err && <p className="mt-4 text-sm text-red-600">{err}</p>}
{signingIn&&<p role="status" className="mt-4 text-sm">Giriş doğrulanıyor…</p>}
{err && <p role="alert" className="mt-4 text-sm text-red-600">{err}</p>}
{(err||noConfig)&&<button disabled={signingIn} onClick={()=>setAttempt(n=>n+1)} className="border rounded px-4 py-2 mt-3 text-sm">Girişi yeniden dene</button>}
<p className="mt-8 text-[11px] text-slate-400 flex items-center justify-center gap-1">
<ShieldCheck className="w-3.5 h-3.5" /> Girişin Google tarafından güvenle doğrulanır.