feat: 3-click SSO registration - unified /auth page, Google/Apple/GitHub OAuth, email fallback, provider model
This commit is contained in:
+32
-1
@@ -40,6 +40,7 @@ interface AuthContextType {
|
||||
loading: boolean;
|
||||
login: (email: string, password: string) => Promise<void>;
|
||||
register: (email: string, name: string, password: string) => Promise<void>;
|
||||
oauthLogin: (provider: string) => Promise<void>;
|
||||
logout: () => void;
|
||||
refreshUser: () => Promise<void>;
|
||||
streak: StreakData | null;
|
||||
@@ -65,6 +66,16 @@ export function AuthProvider({ children }: { children: ReactNode }) {
|
||||
} else {
|
||||
setLoading(false);
|
||||
}
|
||||
|
||||
// Listen for token changes (e.g., from OAuth popup)
|
||||
const handleStorage = (e: StorageEvent) => {
|
||||
if (e.key === "flh_token" && e.newValue) {
|
||||
setToken(e.newValue);
|
||||
fetchUser(e.newValue);
|
||||
}
|
||||
};
|
||||
window.addEventListener("storage", handleStorage);
|
||||
return () => window.removeEventListener("storage", handleStorage);
|
||||
}, []);
|
||||
|
||||
const fetchUser = async (t: string) => {
|
||||
@@ -118,6 +129,26 @@ export function AuthProvider({ children }: { children: ReactNode }) {
|
||||
setUser(data.user);
|
||||
}, []);
|
||||
|
||||
const oauthLogin = useCallback(async (provider: string) => {
|
||||
// Open a popup window for OAuth
|
||||
const width = 600;
|
||||
const height = 700;
|
||||
const left = window.screenX + (window.innerWidth - width) / 2;
|
||||
const top = window.screenY + (window.innerHeight - height) / 2;
|
||||
|
||||
const popup = window.open(
|
||||
`/mobile/api/auth/${provider}`,
|
||||
`oauth-${provider}`,
|
||||
`width=${width},height=${height},left=${left},top=${top},popup=1`
|
||||
);
|
||||
|
||||
if (!popup) {
|
||||
// Popup blocked — fall back to direct navigation
|
||||
window.location.href = `/mobile/api/auth/${provider}`;
|
||||
}
|
||||
// The popup will close itself after successful auth via the callback page
|
||||
}, []);
|
||||
|
||||
const logout = useCallback(() => {
|
||||
localStorage.removeItem("flh_token");
|
||||
setToken(null);
|
||||
@@ -170,7 +201,7 @@ export function AuthProvider({ children }: { children: ReactNode }) {
|
||||
}, [token, user, refreshStreak, refreshXp]);
|
||||
|
||||
return (
|
||||
<AuthContext.Provider value={{ user, token, loading, login, register, logout, refreshUser, streak, xp, refreshStreak, refreshXp }}>
|
||||
<AuthContext.Provider value={{ user, token, loading, login, register, oauthLogin, logout, refreshUser, streak, xp, refreshStreak, refreshXp }}>
|
||||
{children}
|
||||
</AuthContext.Provider>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user