Merge pull request 'fix(onboarding): prefill verified email; SDK 0.2.4' (#13) from tanweer919/lynkeduppro-crm:feat/login-methods into goutamnextflow

This commit was merged in pull request #13.
This commit is contained in:
2026-07-12 22:26:05 +00:00
5 changed files with 798 additions and 31 deletions
+1
View File
@@ -41,3 +41,4 @@ yarn-error.log*
next-env.d.ts next-env.d.ts
.vercel .vercel
.env*.local
+780 -20
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -9,7 +9,7 @@
"lint": "eslint" "lint": "eslint"
}, },
"dependencies": { "dependencies": {
"@abe-kap/appshell-sdk": "^0.2.3", "@abe-kap/appshell-sdk": "^0.2.4",
"clsx": "^2.1.1", "clsx": "^2.1.1",
"lucide-react": "^1.21.0", "lucide-react": "^1.21.0",
"next": "16.2.9", "next": "16.2.9",
+6 -3
View File
@@ -24,7 +24,7 @@ const EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
export function LoginFlow() { export function LoginFlow() {
const router = useRouter(); const router = useRouter();
const { login, loginWithOAuth, completeOAuthLogin } = useAuth(); const { login, loginWithOAuth, completeOAuthLogin, getUserEmail } = useAuth();
const { ready, sdk } = useAppShell(); const { ready, sdk } = useAppShell();
const [step, setStep] = useState<Step>("identify"); const [step, setStep] = useState<Step>("identify");
const [email, setEmail] = useState(""); const [email, setEmail] = useState("");
@@ -86,13 +86,16 @@ export function LoginFlow() {
registered = !!st?.registered; registered = !!st?.registered;
} catch { registered = false; } } catch { registered = false; }
window.history.replaceState({}, "", "/portal/login"); window.history.replaceState({}, "", "/portal/login");
router.replace(registered ? "/dashboard" : "/portal/onboarding"); if (registered) { router.replace("/dashboard"); return; }
// Capture the verified email now (session is fresh) so onboarding prefills it.
try { const em = await getUserEmail(); if (em) sessionStorage.setItem("onboard_email", em); } catch { /* ignore */ }
router.replace("/portal/onboarding");
}) })
.catch(() => { .catch(() => {
setFlash("Google sign-in didn't complete. Please try again."); setFlash("Google sign-in didn't complete. Please try again.");
replace("identify"); replace("identify");
}); });
}, [ready, completeOAuthLogin, router, sdk]); }, [ready, completeOAuthLogin, router, sdk, getUserEmail]);
/* ---- auth resolution ---- */ /* ---- auth resolution ---- */
function afterAuth(factor: "password" | "passkey" | "otp" | "totp" | "push" | "social") { function afterAuth(factor: "password" | "passkey" | "otp" | "totp" | "push" | "social") {
+10 -7
View File
@@ -54,9 +54,11 @@ export function RegisterFlow({ mode = "register" }: { mode?: "register" | "onboa
const [emailVerified, setEmailVerified] = useState(false); const [emailVerified, setEmailVerified] = useState(false);
const [phoneVerified, setPhoneVerified] = useState(false); const [phoneVerified, setPhoneVerified] = useState(false);
// Onboarding: prefill the verified email from the Google session (the ACE omits it). // Onboarding: prefill the verified email from the session-storage hint the login
// page stashed at OAuth time, then confirmed via the live Supabase session.
useEffect(() => { useEffect(() => {
if (!onboard) return; if (!onboard) return;
try { const cached = sessionStorage.getItem("onboard_email"); if (cached) setEmail(cached); } catch { /* ignore */ }
getUserEmail().then((e) => { if (e) setEmail(e); }).catch(() => { /* ignore */ }); getUserEmail().then((e) => { if (e) setEmail(e); }).catch(() => { /* ignore */ });
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, [onboard]); }, [onboard]);
@@ -205,12 +207,13 @@ function StepAccount(p: {
<h1>Complete your profile</h1> <h1>Complete your profile</h1>
<p className="sub">Tell us a bit about you to set up your account.</p> <p className="sub">Tell us a bit about you to set up your account.</p>
<div style={{ marginTop: 16 }}> <div className="field" style={{ marginTop: 16 }}>
{p.sso ? ( <label className="label">Email address</label>
<div className="conn-banner conn-green"><Icon name="check" size={16} /> Connected with {cap(p.sso.provider)} · {p.sso.email}</div> <div className="input-wrap">
) : ( <span className="input-ico"><Icon name="mail" size={17} /></span>
<div className="conn-banner conn-blue"><Icon name="mail" size={16} /> {p.onboard ? "Signed in as" : "Creating account for"} {p.email}</div> <input className="input" type="email" value={p.email} disabled readOnly aria-label="Email address" />
)} </div>
<span className="faint" style={{ fontSize: 12 }}>{p.onboard ? "Verified with Google — this can't be changed." : "The email you're registering with."}</span>
</div> </div>
<div className="row gap-3" style={{ marginTop: 18, alignItems: "center" }}> <div className="row gap-3" style={{ marginTop: 18, alignItems: "center" }}>