Auth rework

This commit is contained in:
seb
2026-06-23 11:08:40 +02:00
parent 24f68c94f3
commit 09f53b5ac2
8 changed files with 27 additions and 34 deletions

View File

@@ -42,5 +42,6 @@ requirement without needing HTTPS on the frontend dev server.
- `src/api/index.js` — all backend communication (`credentials: 'include'`).
- `src/auth/googleSignIn.js` — Google Identity Services helper.
- `src/auth/AuthContext.jsx` — session state + login/logout.
- `src/auth/AuthProvider.jsx` — session state + login/logout.
- `src/auth/useAuth.js` — auth context hook.
- `src/components/*` — small function components with local state.

View File

@@ -1,6 +1,6 @@
import Box from '@mui/material/Box';
import CircularProgress from '@mui/material/CircularProgress';
import { useAuth } from './auth/AuthContext';
import { useAuth } from './auth/useAuth';
import LoginPage from './components/LoginPage';
import AppShell from './components/AppShell';

View File

@@ -1,17 +1,9 @@
import {
createContext,
useCallback,
useContext,
useEffect,
useMemo,
useState,
} from 'react';
import { useCallback, useEffect, useMemo, useState } from 'react';
import { useSnackbar } from 'notistack';
import { auth } from '../api';
import { AuthContext } from './context';
const AuthContext = createContext(null);
export function AuthProvider({ children }) {
export default function AuthProvider({ children }) {
const { enqueueSnackbar } = useSnackbar();
const [user, setUser] = useState(null);
const [googleClientId, setGoogleClientId] = useState(null);
@@ -42,22 +34,17 @@ export function AuthProvider({ children }) {
};
}, [enqueueSnackbar]);
const loginWithGoogle = useCallback(
async (credential) => {
const { user: me } = await auth.loginWithGoogle(credential);
setUser(me);
setStatus('authed');
enqueueSnackbar(`Welcome, ${me.email}`, { variant: 'success' });
},
[enqueueSnackbar],
);
const loginWithGoogle = useCallback(async (credential) => {
const { user: me } = await auth.loginWithGoogle(credential);
setUser(me);
setStatus('authed');
}, []);
const logout = useCallback(async () => {
await auth.logout();
setUser(null);
setStatus('anon');
enqueueSnackbar('Signed out', { variant: 'info' });
}, [enqueueSnackbar]);
}, []);
const value = useMemo(
() => ({ user, googleClientId, status, loginWithGoogle, logout }),
@@ -66,9 +53,3 @@ export function AuthProvider({ children }) {
return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
}
export function useAuth() {
const ctx = useContext(AuthContext);
if (!ctx) throw new Error('useAuth must be used within an AuthProvider');
return ctx;
}

3
src/auth/context.js Normal file
View File

@@ -0,0 +1,3 @@
import { createContext } from 'react';
export const AuthContext = createContext(null);

8
src/auth/useAuth.js Normal file
View File

@@ -0,0 +1,8 @@
import { useContext } from 'react';
import { AuthContext } from './context';
export function useAuth() {
const ctx = useContext(AuthContext);
if (!ctx) throw new Error('useAuth must be used within an AuthProvider');
return ctx;
}

View File

@@ -7,7 +7,7 @@ import Stack from '@mui/material/Stack';
import Typography from '@mui/material/Typography';
import GoogleIcon from '@mui/icons-material/Google';
import { useSnackbar } from 'notistack';
import { useAuth } from '../auth/AuthContext';
import { useAuth } from '../auth/useAuth';
import { requestGoogleIdToken } from '../auth/googleSignIn';
export default function LoginPage() {

View File

@@ -7,7 +7,7 @@ import MenuItem from '@mui/material/MenuItem';
import ListItemIcon from '@mui/material/ListItemIcon';
import ListItemText from '@mui/material/ListItemText';
import LogoutIcon from '@mui/icons-material/Logout';
import { useAuth } from '../auth/AuthContext';
import { useAuth } from '../auth/useAuth';
// Menu open/close state is local; toggling it only re-renders this component.
export default function UserMenu() {
@@ -22,7 +22,7 @@ export default function UserMenu() {
onClick={(e) => setAnchorEl(e.currentTarget)}
sx={{ p: 0, width: 32, height: 32, borderRadius: '50%' }}
>
<Avatar alt={user?.email} sx={{ width: 32, height: 32 }}>
<Avatar src={user?.picture} alt={user?.email} sx={{ width: 32, height: 32 }}>
{user?.email?.[0]?.toUpperCase()}
</Avatar>
</IconButton>

View File

@@ -2,7 +2,7 @@ import { createRoot } from 'react-dom/client';
import CssBaseline from '@mui/material/CssBaseline';
import { ThemeProvider, createTheme } from '@mui/material/styles';
import { SnackbarProvider } from 'notistack';
import { AuthProvider } from './auth/AuthContext';
import AuthProvider from './auth/AuthProvider';
import App from './App';
const theme = createTheme({