diff --git a/public/grocerease-light.png b/public/grocerease-light.png new file mode 100644 index 0000000..3311940 Binary files /dev/null and b/public/grocerease-light.png differ diff --git a/public/grocerease.png b/public/grocerease.png new file mode 100644 index 0000000..49783f8 Binary files /dev/null and b/public/grocerease.png differ diff --git a/src/App.jsx b/src/App.jsx index 2851fcc..dbcdfe9 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -6,6 +6,10 @@ import { useAuth, useShoppingListData, useShoppingLists } from './api'; import { useStateWithStorage } from './utils'; +import ProtectedRoutes from './utils/ProtectedRoutes'; + +import Login from './views/Login'; + export function App() { /** * This custom hook takes the path of a shopping list @@ -45,24 +49,29 @@ export function App() { return ( - }> - - } - /> - - } - /> - } - /> + }> + }> + + } + /> + + } + /> + + } + /> + + } path="/login" /> ); diff --git a/src/api/useAuth.jsx b/src/api/useAuth.jsx index c8927c0..22dca1b 100644 --- a/src/api/useAuth.jsx +++ b/src/api/useAuth.jsx @@ -33,16 +33,33 @@ export const SignOutButton = () => ( * @see https://firebase.google.com/docs/auth/web/start#set_an_authentication_state_observer_and_get_user_data */ export const useAuth = () => { - const [user, setUser] = useState(null); + const [user, setUser] = useState(() => { + const storedUser = localStorage.getItem('user'); + return storedUser ? JSON.parse(storedUser) : null; + }); useEffect(() => { - auth.onAuthStateChanged((user) => { - setUser(user); + const unsubscribe = auth.onAuthStateChanged((user) => { if (user) { + setUser(user); + localStorage.setItem('user', JSON.stringify(user)); addUserToDatabase(user); + } else { + setUser(null); + localStorage.removeItem('user'); } }); + return () => unsubscribe(); }, []); - return { user }; + const signIn = async () => { + await signInWithPopup(auth, new GoogleAuthProvider()); + }; + + const signOut = async () => { + await auth.signOut(); + localStorage.removeItem('user'); + }; + + return { user, signIn, signOut }; }; diff --git a/src/utils/ProtectedRoutes.jsx b/src/utils/ProtectedRoutes.jsx new file mode 100644 index 0000000..c78e76d --- /dev/null +++ b/src/utils/ProtectedRoutes.jsx @@ -0,0 +1,9 @@ +import { Outlet, Navigate } from 'react-router-dom'; +import { useAuth } from '../api/useAuth'; + +const ProtectedRoutes = ({}) => { + const { user } = useAuth(); + const isAuthenticated = user || localStorage.getItem('user'); + return isAuthenticated ? : ; // Redirect to login if not authenticated +}; +export default ProtectedRoutes; diff --git a/src/views/Login.jsx b/src/views/Login.jsx new file mode 100644 index 0000000..f0fb585 --- /dev/null +++ b/src/views/Login.jsx @@ -0,0 +1,33 @@ +import { useAuth } from '../api/useAuth'; +import { useEffect } from 'react'; +import { useNavigate } from 'react-router-dom'; + +function Login() { + const { user, signIn } = useAuth(); + const navigate = useNavigate(); + + useEffect(() => { + if (user) { + navigate('/'); + } + }, [user]); + + return ( +
+
+
+ Shopping app logo +
+
+
+ +
+
+
+
+ ); +} + +export default Login;