// Auth screen — login + register + Google sign-in. Approval gate on the backend. function AuthScreen({ onSignIn }) { const [mode, setMode] = React.useState('login'); const [email, setEmail] = React.useState(''); const [username, setUsername] = React.useState(''); const [password, setPassword] = React.useState(''); const [name, setName] = React.useState(''); const [loading, setLoading] = React.useState(false); const [error, setError] = React.useState(null); const [info, setInfo] = React.useState(null); const [googleClientId, setGoogleClientId] = React.useState(''); // Probe whether Google sign-in is configured on this deployment. React.useEffect(() => { api.get('/api/auth/google/config') .then(c => setGoogleClientId(c.client_id || '')) .catch(() => {}); }, []); // Initialize Google Identity Services once the client id arrives. React.useEffect(() => { if (!googleClientId) return; const onGoogleResponse = async (resp) => { setError(null); setInfo(null); setLoading(true); try { const r = await api.post('/api/auth/google', { credential: resp.credential }); if (r.access_token) { api.setToken(r.access_token); const me = await api.get('/api/auth/me'); onSignIn(me); } else if (r.status === 'pending') { setInfo(r.message || "Signed up with Google. Waiting for admin approval."); setMode('login'); } } catch (e) { setError(e.detail || e.message || 'Google sign-in failed'); } setLoading(false); }; // Inject the GIS script once. if (!document.getElementById('gis-script')) { const s = document.createElement('script'); s.id = 'gis-script'; s.src = 'https://accounts.google.com/gsi/client'; s.async = true; s.defer = true; s.onload = () => initGis(onGoogleResponse); document.head.appendChild(s); } else if (window.google?.accounts?.id) { initGis(onGoogleResponse); } function initGis(callback) { try { window.google.accounts.id.initialize({ client_id: googleClientId, callback }); const el = document.getElementById('gsi-btn'); if (el) window.google.accounts.id.renderButton(el, { theme: 'outline', size: 'large', width: 360, text: 'continue_with' }); } catch (e) { /* render is best-effort */ } } }, [googleClientId]); const submit = async (e) => { e?.preventDefault(); setLoading(true); setError(null); setInfo(null); try { if (mode === 'login') { const res = await api.post('/api/auth/login', { username: username || email, password }); api.setToken(res.access_token); const user = await api.get('/api/auth/me'); onSignIn(user); } else { const res = await api.post('/api/auth/register', { username, email, password, full_name: name || null, }); api.setToken(res.access_token); const user = await api.get('/api/auth/me'); onSignIn(user); } } catch (e) { setError(e.detail || e.message || 'Sign-in failed'); setLoading(false); return; } setLoading(false); }; return (
Invest in algo-driven crypto strategies through a unit-priced fund. Buy units, sell units, watch the NAV move — we handle the keys.
{mode === 'login' ? 'Use your username/email or sign in with Google.' : 'Sign up immediately and submit your KYC details for review.'}