diff --git a/src/App.js b/src/App.js index e02f818..e037c55 100644 --- a/src/App.js +++ b/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() { - return

Hello World!

; + const user = useUser(); + + return
{user ? : }
; } export default App; diff --git a/src/AuthenticatedApp.js b/src/AuthenticatedApp.js new file mode 100644 index 0000000..7e2a874 --- /dev/null +++ b/src/AuthenticatedApp.js @@ -0,0 +1,15 @@ +import { useAuthState } from './context/auth'; + +function AuthenticatedApp() { + const { logout, isPending } = useAuthState(); + + return ( +
+

You're logged in!

+ + {isPending &&

Loading...

} +
+ ); +} + +export default AuthenticatedApp; diff --git a/src/UnauthenticatedApp.js b/src/UnauthenticatedApp.js new file mode 100644 index 0000000..2bfab1c --- /dev/null +++ b/src/UnauthenticatedApp.js @@ -0,0 +1,15 @@ +import { useAuthState } from './context/auth'; + +function UnauthenticatedApp() { + const { login, isPending } = useAuthState(); + + return ( +
+

Please, log in!

+ + {isPending &&

Loading...

} +
+ ); +} + +export default UnauthenticatedApp; diff --git a/src/context/auth.js b/src/context/auth.js new file mode 100644 index 0000000..61f1287 --- /dev/null +++ b/src/context/auth.js @@ -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 ( +
+

Something went wrong!

+
{state.error.message ?? 'Unhandled error!'}
+
+ ); + } + + 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 ; +} + +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 }; diff --git a/src/context/index.js b/src/context/index.js new file mode 100644 index 0000000..f5ad165 --- /dev/null +++ b/src/context/index.js @@ -0,0 +1,12 @@ +import { AuthProvider } from './auth'; +import { UserProvider } from './user'; + +function AppProviders({ children }) { + return ( + + {children} + + ); +} + +export default AppProviders; diff --git a/src/context/user.js b/src/context/user.js new file mode 100644 index 0000000..a4139dc --- /dev/null +++ b/src/context/user.js @@ -0,0 +1,14 @@ +import { createContext, useContext } from 'react'; +import { useAuthState } from './auth'; + +const UserContext = createContext(); + +function UserProvider(props) { + return ; +} + +function useUser() { + return useContext(UserContext); +} + +export { UserProvider, useUser }; diff --git a/src/index.js b/src/index.js index d563c0f..fa6639d 100644 --- a/src/index.js +++ b/src/index.js @@ -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( - + + + );