feat: 3-click SSO registration - unified /auth page, Google/Apple/GitHub OAuth, email fallback, provider model

This commit is contained in:
root
2026-06-15 12:42:03 +02:00
parent 64ae34e9c9
commit d194e295ad
12 changed files with 1150 additions and 294 deletions
+32 -1
View File
@@ -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>
);