Add simple authentication logic

This commit is contained in:
Leonardo Murça 2022-05-31 14:31:49 -03:00
parent ba06dce15b
commit 5b3465844c
7 changed files with 128 additions and 2 deletions

View file

@ -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() {
return <h1>Hello World!</h1>;
const user = useUser();
return <div>{user ? <AuthenticatedApp /> : <UnauthenticatedApp />}</div>;
}
export default App;

15
src/AuthenticatedApp.js Normal file
View 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
View 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
View 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
View 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
View 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 };

View file

@ -3,11 +3,14 @@ import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import AppProviders from './context';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<App />
<AppProviders>
<App />
</AppProviders>
</React.StrictMode>
);