Merge pull request 'feat(auth): gate Google sign-in on CRM profile' (#11) from feat/login-methods into goutamnextflow

This commit was merged in pull request #11.
This commit is contained in:
2026-07-12 21:52:11 +00:00
+24 -10
View File
@@ -24,8 +24,8 @@ const EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
export function LoginFlow() {
const router = useRouter();
const { login, loginWithOAuth, completeOAuthLogin } = useAuth();
const { ready } = useAppShell();
const { login, loginWithOAuth, completeOAuthLogin, logout } = useAuth();
const { ready, sdk } = useAppShell();
const [step, setStep] = useState<Step>("identify");
const [email, setEmail] = useState("");
const [account, setAccount] = useState<Account | null>(null);
@@ -76,20 +76,29 @@ export function LoginFlow() {
if (!ready) { setStep("connecting"); return; }
setStep("connecting");
completeOAuthLogin(code)
.then((ace) => {
if (ace) {
// Clear the ?code=… from the URL, then enter the app.
window.history.replaceState({}, "", "/portal/login");
router.replace("/dashboard");
} else {
.then(async (ace) => {
if (!ace) { replace("identify"); return; }
// Google is sign-IN only: require an existing CRM profile. If the account
// has none, sign back out and show an error rather than silently admitting it.
let registered = false;
try {
const st = await sdk.query<{ registered: boolean }>("crm.account.registrationStatus");
registered = !!st?.registered;
} catch { registered = false; }
window.history.replaceState({}, "", "/portal/login");
if (!registered) {
try { await logout(); } catch { /* ignore */ }
setFlash("No account is registered for this Google email. Please register first.");
replace("identify");
return;
}
router.replace("/dashboard");
})
.catch(() => {
setFlash("Google sign-in didn't complete. Please try again.");
replace("identify");
});
}, [ready, completeOAuthLogin, router]);
}, [ready, completeOAuthLogin, router, sdk, logout]);
/* ---- auth resolution ---- */
function afterAuth(factor: "password" | "passkey" | "otp" | "totp" | "push" | "social") {
@@ -144,7 +153,12 @@ export function LoginFlow() {
/* =================================================================== */
return (
<div className="card anim-fade-up" key={step}>
{step === "identify" && <Identify email={email} setEmail={setEmail} onSocial={onSocial} onEmail={identifyEmail} onPhone={startPhoneLogin} toRegister={() => router.push("/portal/register")} />}
{step === "identify" && (
<>
{flash && <div style={{ marginBottom: 16 }}><FlashNote tone="error">{flash}</FlashNote></div>}
<Identify email={email} setEmail={setEmail} onSocial={onSocial} onEmail={identifyEmail} onPhone={startPhoneLogin} toRegister={() => router.push("/portal/register")} />
</>
)}
{step === "connecting" && (
<div className="interstitial">