diff --git a/package-lock.json b/package-lock.json index e8f1bd5..e2cb8e2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,6 +19,7 @@ "@testing-library/user-event": "^13.5.0", "react": "^17.0.2", "react-dom": "^17.0.2", + "react-router-dom": "^6.2.1", "react-scripts": "5.0.0", "web-vitals": "^2.1.3" } @@ -8523,6 +8524,14 @@ "he": "bin/he" } }, + "node_modules/history": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/history/-/history-5.2.0.tgz", + "integrity": "sha512-uPSF6lAJb3nSePJ43hN3eKj1dTWpN9gMod0ZssbFTIsen+WehTmEadgL+kg78xLJFdRfrrC//SavDzmRVdE+Ig==", + "dependencies": { + "@babel/runtime": "^7.7.6" + } + }, "node_modules/hoist-non-react-statics": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", @@ -13726,6 +13735,30 @@ "node": ">=0.10.0" } }, + "node_modules/react-router": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.2.1.tgz", + "integrity": "sha512-2fG0udBtxou9lXtK97eJeET2ki5//UWfQSl1rlJ7quwe6jrktK9FCCc8dQb5QY6jAv3jua8bBQRhhDOM/kVRsg==", + "dependencies": { + "history": "^5.2.0" + }, + "peerDependencies": { + "react": ">=16.8" + } + }, + "node_modules/react-router-dom": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.2.1.tgz", + "integrity": "sha512-I6Zax+/TH/cZMDpj3/4Fl2eaNdcvoxxHoH1tYOREsQ22OKDYofGebrNm6CTPUcvLvZm63NL/vzCYdjf9CUhqmA==", + "dependencies": { + "history": "^5.2.0", + "react-router": "6.2.1" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } + }, "node_modules/react-scripts": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.0.tgz", @@ -22735,6 +22768,14 @@ "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==" }, + "history": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/history/-/history-5.2.0.tgz", + "integrity": "sha512-uPSF6lAJb3nSePJ43hN3eKj1dTWpN9gMod0ZssbFTIsen+WehTmEadgL+kg78xLJFdRfrrC//SavDzmRVdE+Ig==", + "requires": { + "@babel/runtime": "^7.7.6" + } + }, "hoist-non-react-statics": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", @@ -26381,6 +26422,23 @@ "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz", "integrity": "sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A==" }, + "react-router": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.2.1.tgz", + "integrity": "sha512-2fG0udBtxou9lXtK97eJeET2ki5//UWfQSl1rlJ7quwe6jrktK9FCCc8dQb5QY6jAv3jua8bBQRhhDOM/kVRsg==", + "requires": { + "history": "^5.2.0" + } + }, + "react-router-dom": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.2.1.tgz", + "integrity": "sha512-I6Zax+/TH/cZMDpj3/4Fl2eaNdcvoxxHoH1tYOREsQ22OKDYofGebrNm6CTPUcvLvZm63NL/vzCYdjf9CUhqmA==", + "requires": { + "history": "^5.2.0", + "react-router": "6.2.1" + } + }, "react-scripts": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.0.tgz", diff --git a/package.json b/package.json index be1f78b..a8185c6 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "@testing-library/user-event": "^13.5.0", "react": "^17.0.2", "react-dom": "^17.0.2", + "react-router-dom": "^6.2.1", "react-scripts": "5.0.0", "web-vitals": "^2.1.3" }, diff --git a/src/App.js b/src/App.js index 390272c..680c01e 100644 --- a/src/App.js +++ b/src/App.js @@ -1,22 +1,24 @@ -import { Container, Button } from '@mui/material'; +import { Container } from '@mui/material'; import { AuthForm } from './Components/AuthForm'; -import { useAuth } from './Contexts/AuthContext'; -function App() { - const { user, signOut } = useAuth(); - console.log(user); - const handleSignOut = (e) => { - e.preventDefault(); - signOut(); - }; +import { Appbar } from './Components/Appbar'; +import { Routes, Route } from 'react-router-dom'; +import { PrivateRoute } from './Components/PrivateRoute'; +function App() { return ( <> - - {!user ? ( - - ) : ( - - )} + + + + + + } + /> + } /> + ); diff --git a/src/Components/Appbar.js b/src/Components/Appbar.js new file mode 100644 index 0000000..db476de --- /dev/null +++ b/src/Components/Appbar.js @@ -0,0 +1,44 @@ +import { useState } from 'react'; +import { Box, AppBar, Typography, Toolbar, IconButton } from '@mui/material'; +import AccountCircle from '@mui/icons-material/AccountCircle'; +import { UserProfile } from './UserProfile'; + +export const Appbar = () => { + const [showDrawer, setShowDrawer] = useState(false); + + const toggleDrawer = () => (event) => { + if ( + event.type === 'keydown' && + (event.key === 'Tab' || event.key === 'Shift') + ) { + return; + } + + setShowDrawer((showDrawer) => !showDrawer); + }; + + return ( + + + + + supachat + +
+ + + + +
+
+
+
+ ); +}; diff --git a/src/Components/AuthForm.js b/src/Components/AuthForm.js index 1b45178..16f8317 100644 --- a/src/Components/AuthForm.js +++ b/src/Components/AuthForm.js @@ -1,4 +1,4 @@ -import { useState } from 'react'; +import { useState, useEffect } from 'react'; import { Box, Tabs, @@ -12,6 +12,7 @@ import { import LoadingButton from '@mui/lab/LoadingButton'; import { useSnackbar } from '../Contexts/SnackbarContext'; import { useAuth } from '../Contexts/AuthContext'; +import { useNavigate } from 'react-router-dom'; export function AuthForm({ setSession }) { const [tabindex, setTabIndex] = useState(0); @@ -78,46 +79,69 @@ export function AuthForm({ setSession }) { - + ); } -const AuthInputs = ({ tabIndex }) => { +const AuthInputs = ({ tabIndex, setTabIndex }) => { const initial = { email: '', password: '', confirmPassword: '' }; const [credentials, setCredentials] = useState(initial); + const [loading, setLoading] = useState(false); const { showSnackBar } = useSnackbar(); - const { signIn, signUp } = useAuth(); + const { signIn, signUp, user } = useAuth(); + const navigate = useNavigate(); const handleValueChanged = ({ target: { name, value } }) => { setCredentials({ ...credentials, [name]: value }); }; - const handleSubmit = async (e) => { - e.preventDefault(); - - if (credentials.email === '' || credentials.password === '') - return showSnackBar('error', 'missing inputs'); - - if (tabIndex === 1 && credentials.password !== credentials.confirmPassword) - return showSnackBar('error', `passwords don't match`); + useEffect(() => { + if (user) navigate('/'); + }, [user, navigate]); - const { user, error } = - tabIndex === 0 - ? await signIn(credentials.email, credentials.password) - : await signUp(credentials.email, credentials.password); - - if (error) return showSnackBar('error', error.message); - - if (user) { - tabIndex === 0 - ? showSnackBar('success', `logged in!`) - : showSnackBar( - 'info', - `verification email has been sent to ${credentials.email} pls check this before signing in` - ); + const handleSubmit = async (e) => { + try { + e.preventDefault(); + setLoading(true); + + if (credentials.email === '' || credentials.password === '') { + setLoading(false); + return showSnackBar('error', 'missing inputs'); + } + + if ( + tabIndex === 1 && + credentials.password !== credentials.confirmPassword + ) { + setLoading(false); + return showSnackBar('error', `passwords don't match`); + } + + const { user, error } = + tabIndex === 0 + ? await signIn(credentials.email, credentials.password) + : await signUp(credentials.email, credentials.password); + + if (error) { + setLoading(false); + return showSnackBar('error', error.message); + } + + if (user) { + tabIndex === 0 + ? showSnackBar('success', `logged in!`) + : showSnackBar( + 'info', + `verification email sent to ${credentials.email}` + ); + } + tabIndex === 1 && setTabIndex(0); + navigate('/'); + } catch (error) { + console.log(error); } }; @@ -165,7 +189,7 @@ const AuthInputs = ({ tabIndex }) => { handleSubmit(e)} type="submit" > diff --git a/src/Components/Home.js b/src/Components/Home.js new file mode 100644 index 0000000..e69de29 diff --git a/src/Components/PrivateRoute.js b/src/Components/PrivateRoute.js new file mode 100644 index 0000000..adc8267 --- /dev/null +++ b/src/Components/PrivateRoute.js @@ -0,0 +1,7 @@ +import { Navigate } from 'react-router-dom'; +import { useAuth } from '../Contexts/AuthContext'; + +export const PrivateRoute = ({ children }) => { + const { user } = useAuth(); + return user ? children : ; +}; diff --git a/src/Components/UserProfile.js b/src/Components/UserProfile.js new file mode 100644 index 0000000..b1a656e --- /dev/null +++ b/src/Components/UserProfile.js @@ -0,0 +1,53 @@ +import { + Drawer, + Button, + IconButton, + Toolbar, + Box, + TextField, + Divider, + Stack, +} from '@mui/material'; +import { useAuth } from '../Contexts/AuthContext'; +import { useSnackbar } from '../Contexts/SnackbarContext'; +import CloseIcon from '@mui/icons-material/Close'; + +export const UserProfile = ({ showDrawer, toggleDrawer }) => { + const { user, signOut } = useAuth(); + const { showSnackBar } = useSnackbar(); + + const handleSignOut = (e) => { + e.preventDefault(); + signOut(); + showSnackBar('info', 'user logged out'); + }; + + return ( + + + user profile + + + + + + + + + + + + ); +}; diff --git a/src/Contexts/AuthContext.js b/src/Contexts/AuthContext.js index 30af977..e8dcd84 100644 --- a/src/Contexts/AuthContext.js +++ b/src/Contexts/AuthContext.js @@ -5,16 +5,18 @@ const AuthContext = createContext(); const AuthProvider = ({ children }) => { const [user, setUser] = useState(); + const [authLoading, setAuthLoading] = useState(true); useEffect(() => { const session = supabase.auth.session(); setUser(session?.user ?? null); const { data: listener } = supabase.auth.onAuthStateChange( - async (event, session) => { + (event, session) => { setUser(session?.user ?? null); } ); + setAuthLoading(false); return () => { listener?.unsubscribe(); @@ -52,7 +54,11 @@ const AuthProvider = ({ children }) => { const value = { signUp, signIn, signOut, user }; - return {children}; + return ( + + {!authLoading && children} + + ); }; const useAuth = () => { diff --git a/src/Contexts/SnackbarContext.js b/src/Contexts/SnackbarContext.js index 4801aa9..d949202 100644 --- a/src/Contexts/SnackbarContext.js +++ b/src/Contexts/SnackbarContext.js @@ -18,7 +18,10 @@ const SnackbarProvider = ({ children }) => { const handleSnackClose = (event, reason) => { if (reason === 'clickaway') return; - setSnack(initialSnack); + setSnack({ + ...snack, + show: false, + }); }; return ( diff --git a/src/index.js b/src/index.js index b625121..0bfac46 100644 --- a/src/index.js +++ b/src/index.js @@ -5,6 +5,7 @@ import { createTheme, ThemeProvider } from '@mui/material/styles'; import { CssBaseline } from '@mui/material'; import { SnackbarProvider } from './Contexts/SnackbarContext'; import { AuthProvider } from './Contexts/AuthContext'; +import { BrowserRouter } from 'react-router-dom'; const theme = createTheme({ palette: { @@ -14,14 +15,16 @@ const theme = createTheme({ ReactDOM.render( - - - - - - - - + + + + + + + + + + , document.getElementById('root') );