Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 12 additions & 5 deletions frontend/src/components/auth/SocialAuth.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,20 @@ const GITHUB_ICON = (
);

export default function SocialAuth() {
const { loginWithProvider, error: authError } = useAuth();
const { loginWithProvider } = useAuth();
const [loadingProvider, setLoadingProvider] = useState(null);
const [error, setError] = useState(null);

async function handleProviderLogin(providerName) {
setError(null);
setLoadingProvider(providerName);
await loginWithProvider(providerName);
// Page navigates away on redirect — loading state clears on return
try {
await loginWithProvider(providerName);
} catch (err) {
setError(err.message);
} finally {
setLoadingProvider(null);
}
}

return (
Expand All @@ -34,8 +41,8 @@ export default function SocialAuth() {
<div className="flex-1 border-t border-surface-border" />
</div>

{authError && (
<p className="text-sm text-red-500 mb-3 text-center">{authError}</p>
{error && (
<p className="text-sm text-red-500 mb-3 text-center">{error}</p>
)}

<div className="space-y-3">
Expand Down
45 changes: 16 additions & 29 deletions frontend/src/context/AuthContext.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { createContext, useContext, useReducer, useCallback, useEffect } from 'react';
import { signInWithRedirect, getRedirectResult, signOut as firebaseSignOut } from 'firebase/auth';
import { signInWithPopup, signOut as firebaseSignOut } from 'firebase/auth';
import { auth, providers } from '../config/firebase.js';
import { authApi } from '../lib/api';

Expand Down Expand Up @@ -34,32 +34,10 @@ export function AuthProvider({ children }) {

useEffect(() => {
const controller = new AbortController();

async function init() {
try {
const result = await getRedirectResult(auth);
if (result) {
const idToken = await result.user.getIdToken();
const data = await authApi.oauthLogin(idToken);
dispatch({ type: 'AUTH_SUCCESS', payload: data.user });
return;
}
} catch (err) {
let message = err.message;
if (err.code === 'auth/account-exists-with-different-credential') {
message = 'An account with this email already exists. Try signing in with a different provider.';
}
dispatch({ type: 'AUTH_ERROR', payload: message });
return;
}

authApi
.me(controller.signal)
.then((data) => dispatch({ type: 'AUTH_SUCCESS', payload: data.user }))
.catch(() => dispatch({ type: 'LOGOUT' }));
}

init();
authApi
.me(controller.signal)
.then((data) => dispatch({ type: 'AUTH_SUCCESS', payload: data.user }))
.catch(() => dispatch({ type: 'LOGOUT' }));
return () => controller.abort();
}, []);

Expand All @@ -86,9 +64,18 @@ export function AuthProvider({ children }) {
const loginWithProvider = useCallback(async (providerName) => {
dispatch({ type: 'LOADING' });
try {
await signInWithRedirect(auth, providers[providerName]);
const result = await signInWithPopup(auth, providers[providerName]);
const idToken = await result.user.getIdToken();
const data = await authApi.oauthLogin(idToken);
dispatch({ type: 'AUTH_SUCCESS', payload: data.user });
} catch (err) {
dispatch({ type: 'AUTH_ERROR', payload: err.message });
await firebaseSignOut(auth).catch(() => {});
let message = err.message;
if (err.code === 'auth/account-exists-with-different-credential') {
const other = providerName === 'google' ? 'GitHub' : 'Google';
message = `An account with this email already exists. Try signing in with ${other} instead.`;
}
dispatch({ type: 'AUTH_ERROR', payload: message });
throw err;
}
}, []);
Expand Down
Loading