Sign In page won't render in my React.js app - reactjs

For some reason, I can't get my SignIn page to render when I click it on the Navbar. The route effectively changes to http://localhost:3000/signin, and that route is set up correctly to render my SignIn component, but the Home page stays the same and the SignIn button changes to "loading...". I'm using google authentication for the SignIn component, and I'm using an AuthCheck fallback and Suspense fallback in my Navbar.
NAVBAR CODE:
import React, { Suspense } from "react";
import { makeStyles } from "#material-ui/core/styles";
import AppBar from "#material-ui/core/AppBar";
import Toolbar from "#material-ui/core/Toolbar";
import Typography from "#material-ui/core/Typography";
import Button from "#material-ui/core/Button";
import Logo from '../assets/images/basketball.png';
import { Link } from 'react-router-dom';
import {AuthCheck} from 'reactfire'
const useStyles = makeStyles((theme) => ({
root: {
flexGrow: 1,
},
menuButton: {
marginRight: theme.spacing(2),
},
title: {
flexGrow: 1,
},
logo: {
height: "50px",
},
link: {
color: "black",
textDecoration: "none",
},
}));
export const Navbar = () => {
const classes = useStyles();
return (
<div className={classes.root}>
<AppBar position="static">
<Toolbar style={{ alignItems: "center", justifyContent: "center", backgroundColor: "rgb(0, 255, 225)" }}>
<Link to="/">
<img src={Logo} alt="Logo" className={classes.logo} />
</Link>
<Typography style={{flexDirection: 'column', display: 'flex', alignItems: 'center', justifyContent: 'center', color: 'black' }} variant="h2" className={classes.title}>
NBA Stat Reference
</Typography>
<Suspense fallback={'loading...'}>
<AuthCheck fallback={
<Button style={{color: "black"}}>
<Link className={classes.link} to="/signin">Sign In</Link>
</Button>
}>
<Button color="black">
<Link className={classes.link} to="/">Home</Link>
</Button>
<Button color="black">
<Link className={classes.link} to="/dashboard">Dashboard</Link>
</Button>
<Button color="black">
<Link className={classes.link} to="/about">About</Link>
</Button>
</AuthCheck>
</Suspense>
</Toolbar>
</AppBar>
</div>
);
}
SIGN IN CODE:
import React, { useState } from 'react'
import firebase from 'firebase/app';
import { AuthCheck, useAuth } from 'reactfire';
import 'firebase/auth';
import { Input } from './Input';
import { Container, Button, makeStyles, Typography, Snackbar, } from '#material-ui/core';
import { withRouter } from "react-router-dom";
import MuiAlert from '#material-ui/lab/Alert';
import { Navbar } from './Navbar'
const Alert = (props) => {
return <MuiAlert elevation={6} variant="filled" {...props} />
}
const useStyles = makeStyles({
googleButton:{
backgroundColor: 'rgb(66,133,244)',
marginTop: '2em',
padding: '0',
color: 'white',
height: '50px',
width: '240px',
border: 'none',
textAlign: 'center',
boxShadow: 'rgb(0 0 0 / 25%) 0px 2px 4px 0px',
fontSize: '16px',
lineHeight: '48px',
display: 'block',
borderRadius: '1px',
fontFamily: 'Roboto, arial, sans-serif',
cursor: 'pointer'
},
googleLogo:{
width: '48px',
height: '48px',
display: 'block'
},
typographyStyle: {
fontFamily: 'Roboto, arial, sans-serif;',
textAlign: 'center',
fontSize: '2em'
},
containerStyle: {
marginTop: '2em'
},
snackBar: {
color: 'white',
backgroundColor: '#4caf50'
}
});
export const SignIn = withRouter((props) => {
const auth = useAuth();
const classes = useStyles();
const { history } = props;
const [open, setOpen] = useState(false);
const handleSnackOpen = () => {
setOpen(true)
};
const handleSnackClose = (event, reason) => {
if (reason === "clickaway") {
return;
}
setOpen(false);
history.push("/");
};
const sign_in = async () => {
const response = await auth.signInWithPopup( new firebase.auth.GoogleAuthProvider());
if(response.user){
handleSnackOpen();
}
};
const sign_out = async () => {
await auth.signOut();
}
return (
<div>
<Navbar />
<Container maxWidth = 'sm' className={classes.containerStyle}>
<Typography className={classes.typographyStyle}>Sign In Below</Typography>
<form>
<div>
<label htmlFor="email">Email</label>
<Input name="email" placeholder="Place Email Here" />
</div>
<div>
<label htmlFor="password">Password</label>
<Input name="password" placeholder="Place Password Here" />
</div>
<Button type="submit" variant='contained' color='primary'>Submit</Button>
</form>
<AuthCheck fallback={
<Button className={classes.googleButton} onClick={sign_in}>Sign In With Google</Button>
}>
<Button variant='contained' color='secondary' onClick={sign_out}>Sign Out</Button>
</AuthCheck>
<Snackbar message={'Success'} open={open} autoHideDuration={6000} onClose={handleSnackClose}>
<Alert onClose={handleSnackClose} severity="success">
Successful Sign In - Redirect in 6 seconds
</Alert>
</Snackbar>
</Container>
</div>
)
});
INDEX.JS (ROUTES)
import React from 'react';
import ReactDOM from 'react-dom';
import {Home} from './client/components/Home';
import {About} from './client/components/About';
import {Dashboard} from './client/components/Dashboard';
import {SignIn} from './client/components/SignIn'
import './index.css'
import {
BrowserRouter as Router,
Route,
Switch
} from "react-router-dom";
import {firebaseConfig} from './firebaseConfig';
import {FirebaseAppProvider, AuthCheck} from 'reactfire';
import 'firebase/auth';
import {Provider} from 'react-redux';
import {store} from './client/Redux/store';
import * as ReactDOMClient from 'react-dom/client';
const root = ReactDOMClient.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<FirebaseAppProvider firebaseConfig={firebaseConfig} suspense={true}>
<Provider store={store}>
<Router>
<Switch>
<Route exact path="/">
<Home />
</Route>
<Route path="/about">
<About />
</Route>
<Route path="/dashboard">
<Dashboard />
</Route>
<Route path="/signin">
<SignIn />
</Route>
</Switch>
</Router>
</Provider>
</FirebaseAppProvider>
</React.StrictMode>
);

Related

I'm getting an "Uncaught TypeError: Cannot read properties of undefined (reading 'push')" with react-router-dom v6

I'm getting that error Uncaught TypeError: Cannot read properties of undefined (reading 'push'). I've seen some other posts about it but I'm still stuck. I'm using react-router-dom v6. I think it has something to do with passing the props or something like that. The immediate place it's happening is in the "Home" page, if the Login button is clicked, the error will happen and the browser will not redirect to the Login page. Here's my file hierarchy
src
components
Dashboard
Dashboard.js
Home
Home.js
Login
Login.js
Panel
Panel.js
App.js
index.js
The home page has a button to go to the login page. The login page has a button to go to Dashboard. Dashboard has a button to go to Panel.
Here's the code
index.js
import App from "./components/App";
App.js
import React, { Component } from "react";
import { render } from 'react-dom';
import Login from "./Login/Login";
import Home from "./Home/Home";
import Dashboard from "./Dashboard/Dashboard";
import Panel from "./Panel/Panel";
import {
BrowserRouter as Router,
Routes,
Route,
} from "react-router-dom";
export default class App extends Component {
constructor(props){
super(props)
}
render(){
return(
<Router>
<Routes>
<Route path="/frontend/" element={<Home />}></Route>
<Route path="/frontend/panel" element={<Panel />} />
<Route path="/frontend/login" element={<Login />}/>
<Route path="/frontend/dashboard" element={<Dashboard />}/>
</Routes>
</Router>
);
}
}
const appDiv = document.getElementById("app");
render(<App />, appDiv);`
Home
import React from 'react';
import { Container, Button } from '#material-ui/core';
import { makeStyles } from '#material-ui/core/styles';
const useStyles = makeStyles({
root: {
marginLeft: "auto",
marginRight: "auto",
width: "54%",
textAlign: "center"
},
});
const Home = (props) => {
const handleLoginClick = () => {
props.history.push('/frontend/login');
}
const classes = useStyles();
return (
<Container className={classes.root}>
<h1>Home Page</h1>
<Button variant="contained" onClick={handleLoginClick}>Login</Button>
</Container>
)
}
export default Home;
Login
import React, { useState } from 'react';
import { makeStyles } from '#material-ui/core/styles';
import {
Card,
CardMedia,
CardContent,
CardActions,
TextField,
Button
} from '#material-ui/core';
import './Login.css';
const useStyles = makeStyles({
root: {
marginLeft: "auto",
marginRight: "auto",
width: "40%",
},
media: {
height: 100,
width: 250,
marginLeft: "auto",
marginRight: "auto",
},
signInButton: {
marginLeft: "auto",
marginRight: "auto"
}
});
const Login = (props) => {
const [username, setUsername] = useState('');
const [password, setPassword] = useState('');
const classes = useStyles();
const handleLogin = () => {
props.history.push('/frontend/dashboard');
}
return (
<div>
<Card className={classes.root}>
<CardMedia className={classes.media} image="../../../static/images/some_image.jpg" title="Some Image"/>
<CardContent>
<TextField type="text" placeholder="Username" variant="filled" fullWidth></TextField>
<TextField type="password" placeholder="Password" variant="filled" fullWidth></TextField>
</CardContent>
<CardActions>
<Button variant="contained" className={classes.signInButton} onClick={handleLogin}>Sign In</Button>
</CardActions>
</Card>
</div>
);
}
export default Login;
Dashboard.js
import React from 'react';
import { makeStyles } from '#material-ui/core/styles';
//import { getUser, removeUserSession } from './Utils/Common';
import Drawer from '#material-ui/core/Drawer';
import CssBaseline from '#material-ui/core/CssBaseline';
import AppBar from '#material-ui/core/AppBar';
import Toolbar from '#material-ui/core/Toolbar';
import List from '#material-ui/core/List';
import Typography from '#material-ui/core/Typography';
import Divider from '#material-ui/core/Divider';
import ListItem from '#material-ui/core/ListItem';
import ListItemText from '#material-ui/core/ListItemText';
import { Button } from '#material-ui/core';
const drawerWidth = 240;
const useStyles = makeStyles((theme) => ({
root: {
display: 'flex',
},
appBar: {
width: `calc(100% - ${drawerWidth}px)`,
marginLeft: drawerWidth,
},
drawer: {
width: drawerWidth,
flexShrink: 0,
},
drawerPaper: {
width: drawerWidth,
},
// necessary for content to be below app bar
toolbar: theme.mixins.toolbar,
content: {
flexGrow: 1,
backgroundColor: theme.palette.background.default,
padding: theme.spacing(3),
},
}));
const Dashboard = (props) => {
const classes = useStyles();
//const user = getUser();
const handleLogout = () => {
//removeUserSession();
props.history.push('/frontend');
}
const handleClickCreateGraphs = () => {
props.history.push('/frontend/panel');
}
return(
<div>
<CssBaseline />
<AppBar position="fixed" className={classes.appBar}>
<Toolbar>
<Typography variant="h6" noWrap>
Welcome
</Typography>
</Toolbar>
</AppBar>
<Drawer
className={classes.drawer}
variant="permanent"
classes={{
paper: classes.drawerPaper,
}}
anchor="left"
>
<div className={classes.toolbar} />
<Divider />
<List>
<ListItem button key="View Graphs">
<ListItemText primary="View Graphs" />
</ListItem>
<ListItem button key="Create Graphs" onClick={handleClickCreateGraphs}>
<ListItemText primary="Create Graphs" />
</ListItem>
</List>
<Divider />
<Divider />
<Button variant="contained" onClick={handleLogout}>Logout</Button>
</Drawer>
</div>
)
}
export default Dashboard;
Panel
The panel page is way too long to post here and irrelevant to the issue. Right now, it has no onclick events to take you to another page
In react-router-dom V6 you can use useNavigate hook for programmatic navigation, like this:
Home
...
import { useNavigate } from "react-router-dom";
...
const Home = (props) => {
const navigate = useNavigate();
const handleLoginClick = () => {
navigate('/frontend/login');
}
...
}

Material UI persistent drawer - content body not resizing

I have an application with a persistent drawer. The drawer contains linked routes to various other components.
In general the drawer itself works fine, but the loaded components are not resizing, when the drawer opens or closes.
In the samples on the mui doc pages this functionality in implemented in the styled main component. Means the content is in the same component as the drawer. This is different in my app, where i have an index file with the routes, a navigationbar file with the drawer and the other components with their respective files.
So, how do i implement this resizing with loaded components?
index.tsx
import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter as Router, Route, Switch } from "react-router-dom";
import "bootstrap/dist/css/bootstrap.min.css";
import NavigationBar from "./ADBPM-Components/NavigationBar";
import Login from "./login";
import PrivateRoute from "./login/PrivateRoute";
import Authenticator from "./login/auth";
import NotFound from "./notFound";
import WelcomeScreen from "./welcomeScreen";
import Test from "./test";
//Check if already authenticated
Authenticator.refreshState(() => {
refreshPage();
});
export const refreshPage = () => {
ReactDOM.render(
<Router>
<div>
<PrivateRoute noRedirect path="/" component={NavigationBar} />
<Switch>
<PrivateRoute exact path="/" component={WelcomeScreen} />
<PrivateRoute path="/test" component={Test} />
<PrivateRoute path="/changepass" component={ChangePassword} />
<PrivateRoute path="/createuser" component={CreateUser} />
<Route path="/login" component={Login} />
<Route path="/signup" component={CreateUser} />
<PrivateRoute path="/" component={NotFound} />
</Switch>
</div>
</Router>,
document.getElementById("app")
);
};
NavigationBar.tsx
import * as React from "react";
import { withRouter } from "react-router";
import { Link } from "react-router-dom";
import { Divider } from "#material-ui/core";
import Box from '#mui/material/Box';
import Toolbar from '#mui/material/Toolbar';
import Typography from '#mui/material/Typography';
import IconButton from '#mui/material/IconButton';
import MenuIcon from '#mui/icons-material/Menu';
import Drawer from '#mui/material/Drawer';
import MuiAppBar, { AppBarProps as MuiAppBarProps } from '#mui/material/AppBar';
import { styled, useTheme } from '#mui/material/styles';
import List from '#mui/material/List';
import ListItem from '#mui/material/ListItem';
import ListItemIcon from '#mui/material/ListItemIcon';
import ChevronLeftIcon from '#mui/icons-material/ChevronLeft';
import ChevronRightIcon from '#mui/icons-material/ChevronRight';
import ListItemText from '#mui/material/ListItemText';
import CssBaseline from '#mui/material/CssBaseline';
import PeopleIcon from '#mui/icons-material/People';
import QueryStatsIcon from '#mui/icons-material/QueryStats';
import BuildIcon from '#mui/icons-material/Build';
import RequestPageIcon from '#mui/icons-material/RequestPage';
import LogoutOutlinedIcon from '#mui/icons-material/LogoutOutlined';
import PasswordIcon from '#mui/icons-material/Password';
import SupervisedUserCircleIcon from '#mui/icons-material/SupervisedUserCircle';
import TableViewIcon from '#mui/icons-material/TableView';
import Authenticator from "../login/auth";
import * as pack from "../../package.json";
import { Fragment } from "react";
const drawerWidth = 240;
interface AppBarProps extends MuiAppBarProps {
open?: boolean;
}
const AppBar = styled(MuiAppBar, {
shouldForwardProp: (prop) => prop !== 'open',
})<AppBarProps>(({ theme, open }) => ({
transition: theme.transitions.create(['margin', 'width'], {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.leavingScreen,
}),
...(open && {
width: `calc(100% - ${drawerWidth}px)`,
marginLeft: `${drawerWidth}px`,
transition: theme.transitions.create(['margin', 'width'], {
easing: theme.transitions.easing.easeOut,
duration: theme.transitions.duration.enteringScreen,
}),
}),
}));
const DrawerHeader = styled('div')(({ theme }) => ({
display: 'flex',
alignItems: 'center',
padding: theme.spacing(0, 1),
// necessary for content to be below app bar
...theme.mixins.toolbar,
justifyContent: 'flex-end',
}));
function NavigationBar() {
const theme = useTheme();
const [open, setOpen] = React.useState(false);
const handleDrawerOpen = () => {
setOpen(true);
};
const handleDrawerClose = () => {
setOpen(false);
};
return (
<Fragment>
<Box sx={{ display: 'flex' }}>
<CssBaseline />
<AppBar position="fixed" open={open}>
<Toolbar>
<IconButton
color="inherit"
aria-label="open drawer"
onClick={handleDrawerOpen}
edge="start"
sx={{ mr: 2, ...(open && { display: 'none' }) }}
>
<MenuIcon />
</IconButton>
<Typography variant="h6" component="div" sx={{ flexGrow: 1 }}>
ADBPM ({pack.version})
</Typography>
<Typography variant="h6" component="div" sx={{ flexGrow: 1 }} align="right">
{` Logged in as ${Authenticator.user}`}
</Typography>
</Toolbar>
</AppBar>
<Drawer
sx={{
width: drawerWidth,
flexShrink: 0,
'& .MuiDrawer-paper': {
width: drawerWidth,
boxSizing: 'border-box',
},
}}
variant="persistent"
anchor="left"
open={open}
>
<DrawerHeader>
<IconButton onClick={handleDrawerClose}>
{theme.direction === 'ltr' ? <ChevronLeftIcon /> : <ChevronRightIcon />}
</IconButton>
</DrawerHeader>
<Divider />
<List>
<ListItem button key='Test' component={Link} to="/test">
<ListItemIcon>
<QueryStatsIcon />
</ListItemIcon>
<ListItemText primary='Test' />
</ListItem>
</List>
<Divider />
<List>
<ListItem button key='Change My Password' component={Link} to="/changepass">
<ListItemIcon>
<PasswordIcon />
</ListItemIcon>
<ListItemText primary='Change My Password' />
</ListItem>
<ListItem button key='LogOut' onClick={() => {Authenticator.logout();}}>
<ListItemIcon>
<LogoutOutlinedIcon />
</ListItemIcon>
<ListItemText primary='LogOut' />
</ListItem>
</List>
</Drawer>
</Box>
<Toolbar />
</Fragment>
);
}
export default withRouter(NavigationBar);
test.tsx
import React from "react";
import { RouteComponentProps } from "react-router";
class Test extends React.Component{
constructor(props: RouteComponentProps){
super(props);
}
render(): JSX.Element {
return (
<div>
<h4>
It is only a Test.
</h4>
</div>
);
}
}
export default Test;
I had a similar problem.
I ended up wrapping the router in a Box element with the styling in the Persistent Drawer demo.
https://codesandbox.io/s/2g979p?file=/demo.js:966-1552
const Main = styled(Box, { shouldForwardProp: (prop) => prop !== 'open' })(
({ theme, open }) => ({
flexGrow: 1,
padding: theme.spacing(3),
transition: theme.transitions.create('margin', {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.leavingScreen,
}),
marginLeft: `-${drawerWidth}px`,
...(open && {
transition: theme.transitions.create('margin', {
easing: theme.transitions.easing.easeOut,
duration: theme.transitions.duration.enteringScreen,
}),
marginLeft: 0,
}),
}),
);

How to use React context on search input and share the input with other components?

I am trying to avoid using Redux and want to share search results to components outside the header. My header appears on every page and the data is inside Lessons component. I want to search in the header and transfer the result to Lessons component and also to Students component. Any leads, please?
Below is my code.
app.js
import "./App.css";
import Lessons from "./components/Lessons";
import LoadingHOC from "./components/LoadingHOC";
import React, { useEffect, useState } from "react";
import { Route, BrowserRouter as Router, Switch, matchPath } from "react-router-dom";
import { ThemeProvider } from "#material-ui/core/styles";
import Header from "./components/Header";
import Footer from "./components/Footer";
import UpdateForm from "./components/UpdateForm";
import Register from "./components/Register";
import CreateLesson from "./components/CreateLesson";
import DeleteLesson from "./components/DeleteLesson";
import Students from "./components/Students";
import UpdateStudent from "./components/UpdateStudent"
import Login from "./components/Login";
import AddStudent from "./components/AddStudent";
import DeleteStudent from "./components/DeleteStudent";
import theme from "./theme";
function App() {
// const LessonsLoading = LoadingHOC(Lessons);
// // const StudentsLoading = LoadingHOC(Students);
/
// };
const [appState, setAppState] = useState({ loading: false, lessons: [] });
useEffect(() => {
console.log("debug app state");
setAppState({ loading: true });
// const apiUrl = "http://127.0.0.1:8000/api/";
// fetch(apiUrl)
// .then((data) => data.json())
// .then((lessons) => {
// debugger;
// setAppState({ loading: false, lessons: lessons });
// // console.log(lessons);
// });
}, []);
// console.log('debug loading', appState.loading)
// console.log('debug loading', appState.lessons)
return (
// console.log('debug lessons', appState.lessons),
// <div className="app">
// <LessonsLoading isLoading={appState.loading} lessons={appState.lessons}/>
// {/* <StudentsLoading isLoading={appState.loading} students={appState.students}/> */}
// </div>
<ThemeProvider theme={theme}>
{/* <Router> */}
<React.StrictMode>
<Header />
{/* <LoadingHOC /> */}
<Switch>
{console.log("debug lessons", appState.lessons)}
<Route
exact
path="/"
component={Lessons}
// lessons={appState.lessons}
/>
<Route exact path="/account/register" component={Register} />
<Route exact path="/account/login" component={Login} />
<Route path="/create/" component={CreateLesson} />
<Route path="/delete/" component={DeleteLesson} />
<Route path="/students" component={Students} />
<Route path="/student/:id" component={UpdateStudent}/>
<Route path="/lessons/:id" component={UpdateForm} />
<Route path="/add_student" component={AddStudent} />
{/* <Route exact path="/" component={App} /> */}
</Switch>
{/* if (!appState.loading) return <Lessons lessons={appState.lessons} />; */}
{/* <Footer /> */}
</React.StrictMode>
{/* </Router> */}
</ThemeProvider>
);
}
export default App;
header.js
import React, { useState, useEffect } from "react";
import {
fade,
makeStyles,
ThemeProvider,
createMuiTheme,
} from "#material-ui/core/styles";
import AppBar from "#material-ui/core/AppBar";
import Toolbar from "#material-ui/core/Toolbar";
import Typography from "#material-ui/core/Typography";
import IconButton from "#material-ui/core/IconButton";
import MenuIcon from "#material-ui/icons/Menu";
import AccountCircle from "#material-ui/icons/AccountCircle";
import Switch from "#material-ui/core/Switch";
import FormControlLabel from "#material-ui/core/FormControlLabel";
import FormGroup from "#material-ui/core/FormGroup";
import MenuItem from "#material-ui/core/MenuItem";
import Menu from "#material-ui/core/Menu";
import InputBase from "#material-ui/core/InputBase";
import SearchIcon from "#material-ui/icons/Search";
import { Link } from "react-router-dom";
import { useHistory } from "react-router-dom";
import { HistoryTwoTone } from "#material-ui/icons";
import axiosInstance from "./../axios";
import Students from './Students';
const useStyles = makeStyles((theme) => ({
root: {
flexGrow: 1,
},
mainTitle: {
textAlign: "center",
fontWeight: "700",
},
menuButton: {
marginRight: theme.spacing(2),
},
title: {
flexGrow: 1,
},
tableTitle: {
textAlign: "center",
},
search: {
position: "relative",
borderRadius: theme.shape.borderRadius,
backgroundColor: fade(theme.palette.common.white, 0.15),
"&:hover": {
backgroundColor: fade(theme.palette.common.white, 0.25),
},
marginLeft: 0,
width: "100%",
[theme.breakpoints.up("sm")]: {
marginLeft: theme.spacing(1),
width: "auto",
},
},
searchIcon: {
padding: theme.spacing(0, 2),
height: "100%",
position: "absolute",
pointerEvents: "none",
display: "flex",
alignItems: "center",
justifyContent: "center",
},
inputRoot: {
color: "inherit",
},
inputInput: {
padding: theme.spacing(1, 1, 1, 0),
// vertical padding + font size from searchIcon
paddingLeft: `calc(1em + ${theme.spacing(4)}px)`,
transition: theme.transitions.create("width"),
width: "100%",
[theme.breakpoints.up("sm")]: {
width: "12ch",
"&:focus": {
width: "20ch",
},
},
},
}));
// Components lib - material, bootstrap, fabric, antd
// css-in-js: styled-components, theme-ui
export default function MenuAppBar() {
const classes = useStyles();
const [auth, setAuth] = React.useState(true);
const [anchorEl, setAnchorEl] = React.useState(null);
const open = Boolean(anchorEl);
// const [studentsData, setStudentsData] = useState("");
// useEffect(() => {
// axiosInstance.get("/students").then((res) => {
// setStudentsData({ ...studentsData, students: res.data });
// });
// }, []);
const handleChange = (event) => {
setAuth(event.target.checked);
};
const handleMenu = (event) => {
setAnchorEl(event.currentTarget);
};
const handleClose = () => {
setAnchorEl(null);
};
return (
<div className={classes.root}>
<FormGroup>
<FormControlLabel
control={
<Switch
checked={auth}
onChange={handleChange}
aria-label="login switch"
/>
}
label={auth ? "Logout" : "Login"}
/>
</FormGroup>
<AppBar position="static" color="primary">
<Toolbar>
<IconButton
edge="start"
className={classes.menuButton}
color="inherit"
aria-label="menu"
onClick={handleMenu}
>
<MenuIcon />
</IconButton>
<Typography variant="h6" className={classes.title}>
Anat
</Typography>
{auth && (
<div>
<IconButton
aria-label="account of current user"
aria-controls="menu-appbar"
aria-haspopup="true"
// onClick={handleMenu}
color="inherit"
>
<AccountCircle />
</IconButton>
<Menu
id="menu-appbar"
anchorEl={anchorEl}
anchorOrigin={{
vertical: "top",
horizontal: "right",
}}
keepMounted
transformOrigin={{
vertical: "top",
horizontal: "right",
}}
open={open}
onClose={handleClose}
>
<MenuItem onClick={handleClose}>Profile</MenuItem>
{/* <Link href={"/students"} studentsList={studentsData.students}> */}
{/* <Link
to={{
pathname: "/students",
state: { studentsList: studentsData.students },
}}
> */}
<MenuItem component={Link} to={'/students'} onClick={handleClose}> Manage Students</MenuItem>
{/* </Link> */}
</Menu>
</div>
)}
<div className={classes.search}>
<div className={classes.searchIcon}>
<SearchIcon />
</div>
<InputBase
placeholder="Search…"
classes={{
root: classes.inputRoot,
input: classes.inputInput,
}}
inputProps={{ "aria-label": "search" }}
/>
</div>
</Toolbar>
</AppBar>
{/* <div><Typography variant="h6" className="mainTitle">Student Lessons
</Typography>
</div> */}
{/* <div>
<h1 className={classes.tableTitle}>Student Lessons</h1>
</div> */}
</div>
);
}
lessons.js
import React, { useEffect, useState } from "react";
import { makeStyles,fade } from "#material-ui/core/styles";
import Table from "#material-ui/core/Table";
import TableBody from "#material-ui/core/TableBody";
import TableCell from "#material-ui/core/TableCell";
import TableContainer from "#material-ui/core/TableContainer";
import TableHead from "#material-ui/core/TableHead";
import TableRow from "#material-ui/core/TableRow";
import Paper from "#material-ui/core/Paper";
import UpdateLesson from "./UpdateLesson";
import DeleteLesson from "./DeleteLesson";
import Container from "#material-ui/core/Container";
import Typography from "#material-ui/core/Typography";
import IconButton from "#material-ui/core/IconButton";
import EditIcon from "#material-ui/icons/Edit";
import Link from "#material-ui/core/Link";
import AddIcon from "#material-ui/icons/Add";
import Fab from '#material-ui/core/Fab';
import Grid from '#material-ui/core/Grid';
const useStyles = makeStyles((theme)=>({
table: {
minWidth: "450",
},
tableTitle: {
textAlign: "center",
},
title: {
textAlign: "center",
},
tablerow: {
fontWeight: "bold",
},
root: {
marginTop: theme.spacing(8),
paddingTop: theme.spacing(3),
paddingBottom: theme.spacing(3),
},
fab: {
backgroundColor: fade(theme.palette.primary.light),
// paddingHorizontal: auto,
}
}));
const Lessons = (props) => {
const [lessons, setLessons] = useState([]);
const apiUrl = "http://127.0.0.1:8000/api/";
useEffect(() => {
fetch(apiUrl)
.then((data) => data.json())
.then((lessons) => {
// debugger;
setLessons(lessons || []);
// console.log(lessons);
});
// setAppState({ loading: true });
}, []);
// const { lessons } = props;
console.log({ lessons });
const classes = useStyles();
// if (lessons === null) {
// return <div>No data</div>;
// }
return (
<React.Fragment>
<Container>
<div>
<h1 className={classes.tableTitle}>Student Lessons</h1>
</div>
<Paper>
<TableContainer component={Paper}>
<Table className={classes?.table} aria-label="simple table">
<TableHead>
<TableRow>
<TableCell className={classes.tablerow}>Id</TableCell>
<TableCell align="right" className={classes.tablerow}>
Student
</TableCell>
<TableCell align="right" className={classes.tablerow}>
Title
</TableCell>
<TableCell align="right" className={classes.tablerow}>
lesson date
</TableCell>
<TableCell align="right" className={classes.tablerow}>
payment
</TableCell>
<TableCell
align="right"
className={classes.tablerow}
></TableCell>
<TableCell
align="right"
className={classes.tablerow}
></TableCell>
</TableRow>
</TableHead>
<TableBody>
{lessons ? (
lessons.map((lesson) => (
<TableRow key={lesson.id}>
<TableCell component="th">{lesson.id}</TableCell>
<TableCell align="right">{lesson.student}</TableCell>
<TableCell align="right">{lesson.title}</TableCell>
<TableCell align="right">{lesson.lesson_date}</TableCell>
<TableCell align="right">{lesson.paid}</TableCell>
<TableCell align="center">
{/* <UpdateLesson lesson={lesson.id} /> */}
<Link href={"/lessons/" + lesson.id}>
<IconButton className={classes.icon}>
<EditIcon />
</IconButton>
</Link>
</TableCell>
<TableCell align="right">
<DeleteLesson lessonId={lesson.id} />
</TableCell>
</TableRow>
))
) : (
<div>No data</div>
)}
</TableBody>
</Table>
</TableContainer>
</Paper>
</Container>
<Container maxWidth="md" className={classes.root}>
<Grid container spacing={2}>
<Link href={'/create'}>
<Fab className={classes.fab} >
<AddIcon />
</Fab>
</Link>
<Link href={'/students'}>
<Fab className={classes.fab} >
<AddIcon />
</Fab>
</Link>
</Grid>
</Container>
</React.Fragment>
);
};
export default Lessons;
you can store value inside variable...
app.js
import {useRef, useState, useEffect} from 'react'
import Header from './Header';
const app = () => {
const searchRef = useRef(null);
const [searchValue, setSearchValue] = useState(null);
useEffect(() => {
setSearchValue(searchRef.current.value);
})
return (
<Header ref={searchRef} />
)
}
header.js
import {forwardRef} from 'react'
const Header = ({other props like children etc.}, ref) => {
return (
<header>
<input ref={ref} type="text" placeholder="search" />
</header>
)}
const ForwardHeader = forwardRef(Header);
export default ForwardHeader;
From that point you can do what ever you want to do with searchValue variable inside app.js or forward it to some of the components. But better idia will be to use simple context to manage state of search input

How can i set Routing while creating admin panel

I want to show only one component inside a white container that clicked but it is showing all components . how can I create an admin panel with fine routing ???
Like other admin panel, i just want to show proper routing But in my case, both components are displaying
App.js, main file
import { BrowserRouter, Route, Switch } from "react-router-dom"
import Home from "./Components/Home/Home"
import CreateAccount from "./Components/Create-Account/CreateAccount"
import PostRequest from "./Components/Post-request/PostRequest"
import New from "./new"
const App = () => {
return (
<BrowserRouter>
<Home />
<Route exact path="/" component={New} />
<Switch >
<Route exact path="/createAccount" component={CreateAccount} />
<Route exact path="/postRequests" component={PostRequest} />
</Switch>
</BrowserRouter>
)
}
export default App
And the Home page Component
import React from 'react';
import clsx from 'clsx';
import "./home.css"
import PostRequest from "../Post-request/PostRequest"
import CreateAccount from "../Create-Account/CreateAccount"
import { SidebarData } from "./sideBarData"
import { Link } from "react-router-dom"
import { makeStyles, useTheme } from '#material-ui/core/styles';
import Drawer from '#material-ui/core/Drawer';
import CssBaseline from '#material-ui/core/CssBaseline';
import AppBar from '#material-ui/core/AppBar';
import Toolbar from '#material-ui/core/Toolbar';
import List from '#material-ui/core/List';
import Typography from '#material-ui/core/Typography';
import Divider from '#material-ui/core/Divider';
import IconButton from '#material-ui/core/IconButton';
import MenuIcon from '#material-ui/icons/Menu';
import ChevronLeftIcon from '#material-ui/icons/ChevronLeft';
import ChevronRightIcon from '#material-ui/icons/ChevronRight';
const drawerWidth = 240;
const useStyles = makeStyles((theme) => ({
root: {
display: 'flex',
},
appBar: {
transition: theme.transitions.create(['margin', 'width'], {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.leavingScreen,
}),
},
appBarShift: {
width: `calc(100% - ${drawerWidth}px)`,
marginLeft: drawerWidth,
transition: theme.transitions.create(['margin', 'width'], {
easing: theme.transitions.easing.easeOut,
duration: theme.transitions.duration.enteringScreen,
}),
},
menuButton: {
marginRight: theme.spacing(2),
},
hide: {
display: 'none',
},
drawer: {
width: drawerWidth,
flexShrink: 0,
},
drawerPaper: {
width: drawerWidth,
},
drawerHeader: {
display: 'flex',
alignItems: 'center',
padding: theme.spacing(0, 1),
// necessary for content to be below app bar
...theme.mixins.toolbar,
justifyContent: 'flex-end',
},
content: {
flexGrow: 1,
padding: theme.spacing(3),
transition: theme.transitions.create('margin', {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.leavingScreen,
}),
marginLeft: -drawerWidth,
},
contentShift: {
transition: theme.transitions.create('margin', {
easing: theme.transitions.easing.easeOut,
duration: theme.transitions.duration.enteringScreen,
}),
marginLeft: 0,
},
}));
export default function PersistentDrawerLeft() {
const classes = useStyles();
const theme = useTheme();
const [open, setOpen] = React.useState(false);
const handleDrawerOpen = () => {
setOpen(true);
};
const handleDrawerClose = () => {
setOpen(false);
};
return (
<div className={classes.root}>
<CssBaseline />
<AppBar
position="fixed"
className={clsx(classes.appBar, {
[classes.appBarShift]: open,
})}
>
<Toolbar>
<IconButton
color="inherit"
aria-label="open drawer"
onClick={handleDrawerOpen}
edge="start"
className={clsx(classes.menuButton, open && classes.hide)}
>
<MenuIcon />
</IconButton>
<Typography variant="h6" noWrap>
Master Panel
</Typography>
</Toolbar>
</AppBar>
<Drawer
className={classes.drawer}
variant="persistent"
anchor="left"
open={open}
classes={{
paper: classes.drawerPaper,
}}
>
<div className={classes.drawerHeader}>
<IconButton onClick={handleDrawerClose}>
{theme.direction === 'ltr' ? <ChevronLeftIcon /> : <ChevronRightIcon />}
</IconButton>
</div>
<Divider />
<List>
<ul>
<h2>Admin</h2>
{SidebarData.map((item, index) => {
return (
<div>
<li key={index} className={item.cName}>
<Link className="textClass" to={item.path}>
<div className="listItem_Alignment container">
<span>{item.icon}</span>
<span className="titleLeftMargin">{item.title}</span>
</div>
</Link>
</li>
</div>
)
})}
</ul>
</List>
<Divider />
</Drawer>
<main
className={clsx(classes.content, {
[classes.contentShift]: open,
})}
>
<div className={classes.drawerHeader} />
<CreateAccount />
<PostRequest />
</main>
</div>
);
}
You can use nested routing for your admin panel. You take reference of below link.
Nested routing example

How to display a common component for all routes in react

I am new to react js and i'm trying to create a dashboard layout where i want to render a sidebar(which will be common in all the routes) and based upon the click event of sidebar items i want to render different component. Although i have achieved this, but in first instance the sidebar is present with the loaded component but once i refresh the page, only the newly loaded component remains on the page and sidebar is vanished.
//This is my main page code;
import React, { Component } from 'react';
import './Dashboard.css'
import Header from "../Header/Header";
import Footer from "../Footer/Footer";
import Sidebar from "../SideBar/Sidebar";
import Charts from "../Charts/Charts";
import About from "../About/About"
import { BrowserRouter as Router, Route, Link, Switch } from 'react-router-dom';
class Dashboard extends Component {
constructor(props) {
super(props)
}
render() {
// this.state.aboutComponent = this.props.aboutComponent;
return (
<Router>
<div>
<Sidebar></Sidebar>
<Switch>
<Route exact path={"/"} component={Charts} />
<Route exact path={"/about"} component={About} />
</Switch>
<Footer></Footer>
</div>
</Router>
)
}
}
export default Dashboard
import React from 'react';
import clsx from 'clsx';
import './Sidebar.css';
import { makeStyles, useTheme } from '#material-ui/core/styles';
import Drawer from '#material-ui/core/Drawer';
import AppBar from '#material-ui/core/AppBar';
import Toolbar from '#material-ui/core/Toolbar';
import List from '#material-ui/core/List';
import Divider from '#material-ui/core/Divider';
import IconButton from '#material-ui/core/IconButton';
import MenuIcon from '#material-ui/icons/Menu';
import DeleteIcon from '#material-ui/icons/Delete';
import ChevronLeftIcon from '#material-ui/icons/ChevronLeft';
import ChevronRightIcon from '#material-ui/icons/ChevronRight';
import ListItem from '#material-ui/core/ListItem';
import ListItemIcon from '#material-ui/core/ListItemIcon';
import ListItemText from '#material-ui/core/ListItemText';
import InboxIcon from '#material-ui/icons/MoveToInbox';
import MailIcon from '#material-ui/icons/Mail';
import Button from '#material-ui/core/Button';
import Menu from '#material-ui/core/Menu';
import MenuItem from '#material-ui/core/MenuItem';
import InfoIcon from '#material-ui/icons/Info';
import About from '../About/About';
// import { Link } from "react-router-dom";
import { useHistory } from "react-router-dom";
import { BrowserRouter as Router, Route, Link, Switch } from 'react-router-dom';
const drawerWidth = 240;
const useStyles = makeStyles((theme) => ({
root: {
display: 'flex',
},
link: {
textDecoration: 'none',
color: theme.palette.text.primary
},
appBar: {
zIndex: theme.zIndex.drawer + 1,
transition: theme.transitions.create(['width', 'margin'], {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.leavingScreen,
}),
},
appBarShift: {
marginLeft: drawerWidth,
width: `calc(100% - ${drawerWidth}px)`,
transition: theme.transitions.create(['width', 'margin'], {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.enteringScreen,
}),
},
menuButton: {
marginRight: 36,
},
hide: {
display: 'none',
},
drawer: {
width: drawerWidth,
flexShrink: 0,
whiteSpace: 'nowrap',
},
drawerOpen: {
width: drawerWidth,
transition: theme.transitions.create('width', {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.enteringScreen,
}),
},
drawerClose: {
transition: theme.transitions.create('width', {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.leavingScreen,
}),
overflowX: 'hidden',
width: theme.spacing(7) + 1,
[theme.breakpoints.up('sm')]: {
width: theme.spacing(9) + 1,
},
},
toolbar: {
display: 'flex',
alignItems: 'center',
justifyContent: 'flex-end',
padding: theme.spacing(0, 1),
// necessary for content to be below app bar
...theme.mixins.toolbar,
},
content: {
flexGrow: 1,
padding: theme.spacing(3),
},
}));
export default function Sidebar() {
const classes = useStyles();
const theme = useTheme();
const [open, setOpen] = React.useState(false);
const [component, setComponent] = React.useState('user')
const [anchorEl, setAnchorEl] = React.useState(null);
const history = useHistory();
const handleDrawerOpen = () => {
setOpen(true);
};
const handleDrawerClose = () => {
setOpen(false);
};
const handleClick = (event) => {
setAnchorEl(event.currentTarget);
};
const handleClose = () => {
setAnchorEl(null);
};
return (
// <Router>
<div className={classes.root}>
<AppBar
position="fixed"
className={clsx(classes.appBar, {
[classes.appBarShift]: open,
})}
>
<Toolbar>
<h1>SGGB</h1>
<div className="alignment">
<Button aria-controls="simple-menu" aria-haspopup="true" onClick={handleClick}>
<h4>Menu</h4>
</Button>
<Menu
id="simple-menu"
anchorEl={anchorEl}
keepMounted
open={Boolean(anchorEl)}
onClose={handleClose}
>
<MenuItem onClick={handleClose}>Profile</MenuItem>
<MenuItem onClick={handleClose}>My account</MenuItem>
<MenuItem onClick={handleClose}>Logout</MenuItem>
</Menu>
</div>
</Toolbar>
</AppBar>
<Drawer
variant="permanent"
className={clsx(classes.drawer, {
[classes.drawerOpen]: open,
[classes.drawerClose]: !open,
})}
classes={{
paper: clsx({
[classes.drawerOpen]: open,
[classes.drawerClose]: !open,
}),
}}
>
<List>
<ListItem>
<IconButton
className={clsx(classes.menuButton, {
[classes.hide]: !open,
})}
onClick={handleDrawerClose}>
{theme.direction === 'rtl' ? <ChevronRightIcon /> : <ChevronLeftIcon />}
</IconButton>
</ListItem>
<ListItem>
<IconButton
color="inherit"
aria-label="open drawer"
onClick={handleDrawerOpen}
edge="start"
className={clsx(classes.menuButton, {
[classes.hide]: open,
})}
>
<MenuIcon />
</IconButton>
</ListItem>
<Link to="/about" className={classes.link}>
<ListItem button key="about" >
<ListItemIcon>{<InfoIcon />}</ListItemIcon>
<ListItemText primary="About" />
</ListItem>
</Link>
</List>
</Drawer>
</div >
// </Router>
);
}
I have also referred to this post;
React Router display one component for all routes ( a header)
You have to put the Route component inside a Switch component like this :
<Router>
<div>
<Sidebar></Sidebar>
<Switch>
<Route exact path={"/"} component={Charts} />
<Route exact path={"/about"} component={About} />
</Switch>
<Footer></Footer>
</div>
</Router>

Resources