// Auth screen — sign in / sign up / forgot password (() => { function AuthScreen({ onAuth }) { useLucide(); // If the page was opened from a reset email (…/?reset=TOKEN&email=…), // start in reset mode with the token/email already captured. const resetParams = (() => { try { const p = new URLSearchParams(window.location.search); const token = p.get('reset'); return token ? { token, email: p.get('email') || '' } : null; } catch { return null; } })(); // Invite link (…/?invite=TOKEN): fetch who/where it invites and pre-fill. const inviteToken = (() => { try { return new URLSearchParams(window.location.search).get('invite') || ''; } catch { return ''; } })(); const [mode, setMode] = React.useState(resetParams ? 'reset' : inviteToken ? 'signup' : 'signin'); const [resetToken] = React.useState(resetParams ? resetParams.token : ''); const [invite, setInvite] = React.useState(null); // {email, role, workspace_name} const [name, setName] = React.useState(''); const [email, setEmail] = React.useState(resetParams ? resetParams.email : ''); const [password, setPassword] = React.useState(''); const [confirm, setConfirm] = React.useState(''); const [loading, setLoading] = React.useState(false); const [error, setError] = React.useState(''); const [success, setSuccess] = React.useState(''); const [showPass, setShowPass] = React.useState(false); // Load invite details once, and pre-fill the email it was sent to. React.useEffect(() => { if (!inviteToken || !window.API?.getInviteInfo) return; let alive = true; (async () => { const { data } = await window.API.getInviteInfo(inviteToken); if (!alive) return; if (data) { setInvite(data); if (data.email) setEmail(data.email); } else setError('This invite link is invalid or has expired. Ask for a new one.'); })(); return () => { alive = false; }; }, []); // After auth (signup or signin) via an invite, join the workspace. const acceptInviteThen = async (user) => { if (inviteToken && window.API?.acceptInvite) { try { await window.API.acceptInvite(inviteToken); } catch {} try { window.history.replaceState({}, '', window.location.pathname); } catch {} } onAuth(user); }; const switchMode = (m) => { setMode(m); setError(''); setSuccess(''); }; const handleSubmit = async (e) => { e.preventDefault(); setError(''); setSuccess(''); if (mode === 'reset') { if (password !== confirm) return setError('Passwords do not match'); if (password.length < 8) return setError('Password must be at least 8 characters'); setLoading(true); try { const { error: err } = await window.db.auth.resetPassword({ token: resetToken, email, password }); if (err) { setError(err.message || 'Reset link is invalid or has expired. Request a new one.'); return; } setSuccess('Password updated! You can sign in now.'); // Drop the reset params from the URL and switch to sign-in. try { window.history.replaceState({}, '', window.location.pathname); } catch {} setPassword(''); setConfirm(''); switchMode('signin'); } catch { setError('Something went wrong. Please try again.'); } finally { setLoading(false); } return; } if (mode === 'signup') { if (!name.trim()) return setError('Full name is required'); if (password !== confirm) return setError('Passwords do not match'); if (password.length < 6) return setError('Password must be at least 6 characters'); } setLoading(true); try { if (mode === 'signin') { const { data, error: err } = await window.db.auth.signInWithPassword({ email, password }); if (err) return setError(err.message); await acceptInviteThen(data.user); } else { const { data, error: err } = await window.db.auth.signUp({ email, password, options: { data: { full_name: name } }, }); if (err) return setError(err.message); if (data.user && !data.session) { setSuccess('Check your email to confirm your account, then sign in.'); switchMode('signin'); } else if (data.user) { await acceptInviteThen(data.user); } } } catch (ex) { setError(ex.message || 'Something went wrong'); } finally { setLoading(false); } }; const handleForgot = async () => { if (!email) return setError('Enter your email address first'); setLoading(true); setError(''); try { const { error: err } = await window.db.auth.resetPasswordForEmail(email); if (err) setError(err.message); else setSuccess('Password reset link sent — check your inbox.'); } catch { setError('Failed to send reset email'); } finally { setLoading(false); } }; const inp = (extra = {}) => ({ style: { width: '100%', padding: '10px 14px', borderRadius: 10, border: '1.5px solid var(--border-default)', fontSize: 14, fontFamily: 'var(--font-sans)', outline: 'none', boxSizing: 'border-box', background: 'white', color: 'var(--text-strong)', transition: 'border-color 0.15s', ...extra, }, onFocus: e => { e.target.style.borderColor = '#3b82f6'; e.target.style.boxShadow = '0 0 0 3px rgba(59,130,246,0.12)'; }, onBlur: e => { e.target.style.borderColor = 'var(--border-default)'; e.target.style.boxShadow = 'none'; }, }); return (
{/* ── Left branding ── */}
{/* Logo mark */}

TechyFuel OS

Your complete agency operating system.
Built for modern digital teams.

{[ ['layout-dashboard', 'Executive dashboard & live analytics'], ['contact', 'CRM, pipeline & client portal'], ['message-square', 'Team chat, calls & collaboration'], ['zap', 'Automations, AI assistant & more'], ].map(([icon, text]) => (
{text}
))}
{/* ── Right form ── */}
{/* Mode tabs */}
{mode !== 'reset' && [['signin','Sign in'],['signup','Create account']].map(([m,label]) => ( ))}

{mode === 'reset' ? 'Set a new password' : mode === 'signin' ? 'Welcome back' : 'Get started free'}

{mode === 'reset' ? 'Choose a new password for your account' : mode === 'signin' ? 'Sign in to your TechyFuel OS account' : 'Create your account — no credit card needed'}

{/* Invite banner */} {invite && (
You've been invited to join {invite.workspace_name}{invite.role ? <> as {invite.role} : null}. {mode === 'signin' ? 'Sign in to accept.' : 'Create your account to accept.'} {' '}
)} {/* Alerts */} {error && (
{error}
)} {success && (
{success}
)}
{mode === 'signup' && (
setName(e.target.value)} placeholder="Alex Johnson" required {...inp()} />
)}
setEmail(e.target.value)} placeholder="you@agency.com" required readOnly={mode==='reset' || (!!invite && !!invite.email)} {...inp((mode==='reset' || (!!invite && !!invite.email)) ? { background:'var(--slate-50)', color:'var(--text-muted)' } : {})} />
setPassword(e.target.value)} placeholder="••••••••" required minLength={6} {...inp({ paddingRight:42 })} />
{(mode === 'signup' || mode === 'reset') && (
setConfirm(e.target.value)} placeholder="••••••••" required {...inp()} />
)} {mode === 'signin' && (
)}

{mode === 'reset' ? : <> {mode === 'signin' ? "Don't have an account? " : 'Already have an account? '} }

By signing in you agree to our Terms of Service & Privacy Policy.

); } Object.assign(window, { AuthScreen }); })();