Add simple authentication logic
This commit is contained in:
parent
ba06dce15b
commit
5b3465844c
7 changed files with 128 additions and 2 deletions
10
src/App.js
10
src/App.js
|
@ -1,5 +1,13 @@
|
||||||
|
import { lazy } from 'react';
|
||||||
|
import { useUser } from './context/user';
|
||||||
|
|
||||||
|
const AuthenticatedApp = lazy(() => import('./AuthenticatedApp'));
|
||||||
|
const UnauthenticatedApp = lazy(() => import('./UnauthenticatedApp'));
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
return <h1>Hello World!</h1>;
|
const user = useUser();
|
||||||
|
|
||||||
|
return <div>{user ? <AuthenticatedApp /> : <UnauthenticatedApp />}</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default App;
|
export default App;
|
||||||
|
|
15
src/AuthenticatedApp.js
Normal file
15
src/AuthenticatedApp.js
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
import { useAuthState } from './context/auth';
|
||||||
|
|
||||||
|
function AuthenticatedApp() {
|
||||||
|
const { logout, isPending } = useAuthState();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h2>You're logged in!</h2>
|
||||||
|
<button onClick={logout}>Logout</button>
|
||||||
|
{isPending && <h1>Loading...</h1>}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default AuthenticatedApp;
|
15
src/UnauthenticatedApp.js
Normal file
15
src/UnauthenticatedApp.js
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
import { useAuthState } from './context/auth';
|
||||||
|
|
||||||
|
function UnauthenticatedApp() {
|
||||||
|
const { login, isPending } = useAuthState();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h2>Please, log in!</h2>
|
||||||
|
<button onClick={login}>Log in</button>
|
||||||
|
{isPending && <h1>Loading...</h1>}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default UnauthenticatedApp;
|
59
src/context/auth.js
Normal file
59
src/context/auth.js
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
import { createContext, useContext, useState } from 'react';
|
||||||
|
|
||||||
|
const sleep = time => new Promise(resolve => setTimeout(resolve, time));
|
||||||
|
const getUser = () => sleep(1000).then(() => ({ username: 'Leonardo' }));
|
||||||
|
|
||||||
|
const AuthContext = createContext();
|
||||||
|
|
||||||
|
function AuthProvider(props) {
|
||||||
|
const [state, setState] = useState({
|
||||||
|
status: 'idle',
|
||||||
|
user: null,
|
||||||
|
error: null,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (state.status === 'error' && state.error) {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h1>Something went wrong!</h1>
|
||||||
|
<pre>{state.error.message ?? 'Unhandled error!'}</pre>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const login = () => {
|
||||||
|
setState({ ...state, status: 'pending' });
|
||||||
|
return getUser().then(user =>
|
||||||
|
setState({ status: 'success', user: user, error: null })
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const logout = () => {
|
||||||
|
setState({ ...state, status: 'pending' });
|
||||||
|
return getUser().then(() =>
|
||||||
|
setState({ status: 'success', user: null, error: null })
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
return <AuthContext.Provider value={{ state, login, logout }} {...props} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
function useAuthState() {
|
||||||
|
const { state, login, logout } = useContext(AuthContext);
|
||||||
|
const isPending = state.status === 'pending';
|
||||||
|
const isError = state.status === 'error';
|
||||||
|
const isSuccess = state.status === 'success';
|
||||||
|
const isAuthenticated = state.user && isSuccess;
|
||||||
|
|
||||||
|
return {
|
||||||
|
user: state.user,
|
||||||
|
isPending,
|
||||||
|
isError,
|
||||||
|
isSuccess,
|
||||||
|
isAuthenticated,
|
||||||
|
login,
|
||||||
|
logout,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export { AuthProvider, useAuthState };
|
12
src/context/index.js
Normal file
12
src/context/index.js
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
import { AuthProvider } from './auth';
|
||||||
|
import { UserProvider } from './user';
|
||||||
|
|
||||||
|
function AppProviders({ children }) {
|
||||||
|
return (
|
||||||
|
<AuthProvider>
|
||||||
|
<UserProvider>{children}</UserProvider>
|
||||||
|
</AuthProvider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default AppProviders;
|
14
src/context/user.js
Normal file
14
src/context/user.js
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
import { createContext, useContext } from 'react';
|
||||||
|
import { useAuthState } from './auth';
|
||||||
|
|
||||||
|
const UserContext = createContext();
|
||||||
|
|
||||||
|
function UserProvider(props) {
|
||||||
|
return <UserContext.Provider value={useAuthState().user} {...props} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
function useUser() {
|
||||||
|
return useContext(UserContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
export { UserProvider, useUser };
|
|
@ -3,11 +3,14 @@ import ReactDOM from 'react-dom/client';
|
||||||
import './index.css';
|
import './index.css';
|
||||||
import App from './App';
|
import App from './App';
|
||||||
import reportWebVitals from './reportWebVitals';
|
import reportWebVitals from './reportWebVitals';
|
||||||
|
import AppProviders from './context';
|
||||||
|
|
||||||
const root = ReactDOM.createRoot(document.getElementById('root'));
|
const root = ReactDOM.createRoot(document.getElementById('root'));
|
||||||
root.render(
|
root.render(
|
||||||
<React.StrictMode>
|
<React.StrictMode>
|
||||||
<App />
|
<AppProviders>
|
||||||
|
<App />
|
||||||
|
</AppProviders>
|
||||||
</React.StrictMode>
|
</React.StrictMode>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue