feat(auth): first-time Google onboarding (option 3)

After a Google sign-in with no CRM profile, route to /portal/onboarding — the
registration flow in mode='onboard': email skipped (Google-verified, prefilled
via getUserEmail), sets a password (updateUser) so email+password login also
works, skips the OTP-verify step, and persists the profile via crm.account.register.
Existing-profile users go straight to the dashboard. Bumps SDK ^0.2.3.
This commit is contained in:
tanweer919
2026-07-13 03:35:55 +05:30
parent 34cb44cfa8
commit 948abf75fd
4 changed files with 80 additions and 27 deletions
+5 -11
View File
@@ -24,7 +24,7 @@ const EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
export function LoginFlow() {
const router = useRouter();
const { login, loginWithOAuth, completeOAuthLogin, logout } = useAuth();
const { login, loginWithOAuth, completeOAuthLogin } = useAuth();
const { ready, sdk } = useAppShell();
const [step, setStep] = useState<Step>("identify");
const [email, setEmail] = useState("");
@@ -78,27 +78,21 @@ export function LoginFlow() {
completeOAuthLogin(code)
.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.
// First-time Google user (no CRM profile yet) → complete onboarding; an
// existing profile → straight to the dashboard.
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");
router.replace(registered ? "/dashboard" : "/portal/onboarding");
})
.catch(() => {
setFlash("Google sign-in didn't complete. Please try again.");
replace("identify");
});
}, [ready, completeOAuthLogin, router, sdk, logout]);
}, [ready, completeOAuthLogin, router, sdk]);
/* ---- auth resolution ---- */
function afterAuth(factor: "password" | "passkey" | "otp" | "totp" | "push" | "social") {