I am trying to make a react component to display a notification on use.
The thing is that it's not working correctly...
The notification is supposed to appear when a user logs-in with an email with wrong provider
what am I doing is that I check for user email after he logs in if the mail doesn't contain the right provider I log him out.
what is happening is that the notification is showing up and disappearing quickly after logging the user out though I made a long interval for it.
I tried experimenting with material UI the react UI framework.
Nothing is working so far
Navbar.js
import React, { Component } from "react";
import withFirebaseAuth from "react-with-firebase-auth";
import * as firebase from "firebase/app";
import firebaseConfig from "../../firebase.config";
import "firebase/auth";
// Material UI
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 IconButton from "#material-ui/core/IconButton";
import MenuIcon from "#material-ui/icons/Menu";
import AccountCircle from "#material-ui/icons/AccountCircle";
import Tooltip from "#material-ui/core/Tooltip";
import Notify from "../notification/notification"
const firebaseApp = firebase.initializeApp(firebaseConfig);
const useStyles = makeStyles(theme => ({
root: {
flexGrow: 1
},
menuButton: {
marginRight: theme.spacing(2)
},
title: {
flexGrow: 1
}
}));
const filler = () => {console.log(' ')}
function HomeNav(props) {
const { user, signOut, signInWithGoogle } = props;
const classes = useStyles();
const userMail = (user)?user.email.includes("#hijrah.org"):'';
let notify = false;
if(user && !userMail){
signOut();
notify = true;
}
return (
<div className={classes.root}>
<AppBar position="static">
<Toolbar>
<IconButton
edge="start"
className={classes.menuButton}
color="inherit"
aria-label="menu"
>
<MenuIcon />
</IconButton>
<Typography variant="h6" className={classes.title}>
News
</Typography>
{user? (
<Tooltip title={user.displayName}>
<IconButton
edge="end"
aria-label="account of current user"
aria-haspopup="true"
onClick={signOut}
color="inherit"
>
<AccountCircle />
</IconButton>
</Tooltip>
) : (
<Button color="inherit" onClick={signInWithGoogle}>
Login
</Button>
)}
</Toolbar>
</AppBar>
<React.Fragment>
{/*this is the part where i try to display notification on*/}
{(notify)? <Notify /> : <span></span>}
</React.Fragment>
</div>
);
}
class Nav extends Component {
render() {
return <HomeNav {...this.props} />;
}
}
const firebaseAppAuth = firebaseApp.auth();
const providers = {
googleProvider: new firebase.auth.GoogleAuthProvider()
};
providers.googleProvider.setCustomParameters({hd:"hijrah.org"});
export default withFirebaseAuth({
providers,
firebaseAppAuth
})(Nav);
my notification component notify.js
import React from "react";
import PropTypes from "prop-types";
import clsx from "clsx";
import CheckCircleIcon from "#material-ui/icons/CheckCircle";
import ErrorIcon from "#material-ui/icons/Error";
import InfoIcon from "#material-ui/icons/Info";
import CloseIcon from "#material-ui/icons/Close";
import { amber, green } from "#material-ui/core/colors";
import IconButton from "#material-ui/core/IconButton";
import Snackbar from "#material-ui/core/Snackbar";
import SnackbarContent from "#material-ui/core/SnackbarContent";
import WarningIcon from "#material-ui/icons/Warning";
import { makeStyles } from "#material-ui/core/styles";
const variantIcon = {
success: CheckCircleIcon,
warning: WarningIcon,
error: ErrorIcon,
info: InfoIcon
};
const useStyles1 = makeStyles(theme => ({
success: {
backgroundColor: green[600]
},
error: {
backgroundColor: theme.palette.error.dark
},
info: {
backgroundColor: theme.palette.primary.main
},
warning: {
backgroundColor: amber[700]
},
icon: {
fontSize: 20
},
iconVariant: {
opacity: 0.9,
marginRight: theme.spacing(1)
},
message: {
display: "flex",
alignItems: "center"
}
}));
function MySnackbarContentWrapper(props) {
const classes = useStyles1();
const { className, message, onClose, variant, ...other } = props;
const Icon = variantIcon[variant];
return (
<SnackbarContent
className={clsx(classes[variant], className)}
aria-describedby="client-snackbar"
message={
<span id="client-snackbar" className={classes.message}>
<Icon className={clsx(classes.icon, classes.iconVariant)} />
{message}
</span>
}
action={[
<IconButton
key="close"
aria-label="close"
color="inherit"
onClick={onClose}
>
<CloseIcon className={classes.icon} />
</IconButton>
]}
{...other}
/>
);
}
MySnackbarContentWrapper.propTypes = {
className: PropTypes.string,
message: PropTypes.string,
onClose: PropTypes.func,
variant: PropTypes.oneOf(["error", "info", "success", "warning"]).isRequired
};
export default function CustomizedSnackbars() {
const [open, setOpen] = React.useState(true);
const handleClose = (event, reason) => {
if (reason === "clickaway") {
return;
}
setOpen(false);
};
return (
<div>
<Snackbar
anchorOrigin={{
vertical: "bottom",
horizontal: "left"
}}
open={open}
autoHideDuration={60000}
onClose={handleClose}
>
<MySnackbarContentWrapper
onClose={handleClose}
variant="warning"
message="Please login with a #hijrah.org mail"
/>
</Snackbar>
</div>
);
}
I expect to display the error message after I log out the user and for it to stay for like 5 seconds.
I suspect what is happening in that when you log the user out, the Nav component is no longer rendered and therefore neither is the Notify Component as it is a child of Nav (Nav >> HomeNav >> Notify). Because it is no longer rendered the message disappears.
If that is the case, you should move the Notify to a higher level in your app so that it is displayed regardless of whether the user is logged in or not.
Related
I am trying to write out a website with responsive-based app bar with a drawer tagged onto it. I am using this design found at https://medium.com/#tsubasakondo_36683/create-responsive-drawer-menu-with-react-material-ui-617a42764b69 and modifying it accordingly. But unfortunately, I am getting this issue, in which the drawer covers the portion of the content trying to be displayed. Please know that I have seen similar questions on this site, but I couldn't figure out how to solve them or the answers were kind of vague. Any help would be much appreciated, please let me know if I need to clarify anything further. All of this is using Material UI components.
Here is my code:
Material UI App-Bar
//Used code: https://medium.com/#tsubasakondo_36683/create-responsive-drawer-menu-with-react-material-ui-617a42764b69
//Picture/Icon Imports
import home from "../Icons/home.png";
import about from "../Icons/about.png";
import contact from "../Icons/contact.png";
import resume from "../Icons/resume.png";
import minecraft from "../Icons/minecraft.png";
import github from "../Icons/github.png"
import React from 'react';
import PropTypes from 'prop-types';
import AppBar from '#material-ui/core/AppBar';
import CssBaseline from '#material-ui/core/CssBaseline';
import Drawer from '#material-ui/core/Drawer';
import Hidden from '#material-ui/core/Hidden';
import IconButton from '#material-ui/core/IconButton';
import List from '#material-ui/core/List';
import ListItem from '#material-ui/core/ListItem';
import ListItemText from '#material-ui/core/ListItemText';
import MenuIcon from '#material-ui/icons/Menu';
import CloseIcon from '#material-ui/icons/Close';
import Toolbar from '#material-ui/core/Toolbar';
import Typography from '#material-ui/core/Typography';
import { makeStyles, useTheme } from '#material-ui/core/styles';
import {Link} from "react-router-dom";
const drawerWidth = 240;
const useStyles = makeStyles(theme => ({
root: {
display: 'flex',
},
drawer: {
[theme.breakpoints.up('sm')]: {
width: drawerWidth,
flexShrink: 0,
},
},
appBar: {
zIndex: theme.zIndex.drawer + 1,
},
menuButton: {
marginRight: theme.spacing(2),
[theme.breakpoints.up('sm')]: {
display: 'none',
},
},
toolbar: theme.mixins.toolbar,
drawerPaper: {
width: drawerWidth
},
content: {
flexGrow: 1,
padding: theme.spacing(0),
},
closeMenuButton: {
marginRight: 'auto',
marginLeft: 0,
},
}));
function NavBar() {
const DifferentPages = [
{Text: "Home", location: "/", Image: home},
{Text: "About", location: "/about", Image: about},
{Text: "Contact", location: "/contact", Image: contact},
{Text: "Resume", location: "/resume", Image: resume},
{Text: "Minecraft", location: "/minecraft", Image: minecraft},
]
const classes = useStyles();
const theme = useTheme();
const [mobileOpen, setMobileOpen] = React.useState(false);
function handleDrawerToggle() {
setMobileOpen(!mobileOpen)
}
const drawer = (
<div>
<List>
{DifferentPages.map((Text) => (
<ListItem button component={Link} to={Text.location}>
<img src={Text.Image} width={"25"} height={"25"}/>
<ListItemText primary={Text.Text} />
</ListItem>
))}
<ListItem button href={"example.com"}>
<img src={github} width={"25"} height={"25"}/>
<ListItemText>
Github
</ListItemText>
</ListItem>
</List>
</div>
);
return (
<div className={classes.root}>
<CssBaseline />
<AppBar position="fixed" className={classes.appBar}>
<Toolbar>
<IconButton
color="inherit"
aria-label="Open drawer"
edge="start"
onClick={handleDrawerToggle}
className={classes.menuButton}
>
<MenuIcon />
</IconButton>
<Typography variant="h6" noWrap>
Responsive drawer
</Typography>
</Toolbar>
</AppBar>
<nav className={classes.drawer}>
<Hidden smUp implementation="css">
<Drawer
variant="temporary"
anchor={theme.direction === 'rtl' ? 'right' : 'left'}
open={mobileOpen}
onClose={handleDrawerToggle}
classes={{
paper: classes.drawerPaper,
}}
ModalProps={{
keepMounted: true, // Better open performance on mobile.
}}
>
<IconButton onClick={handleDrawerToggle} className={classes.closeMenuButton}>
<CloseIcon/>
</IconButton>
{drawer}
</Drawer>
</Hidden>
<Hidden xsDown implementation="css">
<Drawer
className={classes.drawer}
variant="permanent"
classes={{
paper: classes.drawerPaper,
}}
>
<div className={classes.toolbar} />
{drawer}
</Drawer>
</Hidden>
</nav>
<div className={classes.content}>
<div className={classes.toolbar} />
</div>
</div>
);
}
NavBar.propTypes = {
container: PropTypes.object,
};
export default NavBar;
App.js: NOTE** in App.js, I can add style={{paddingleft:240}} to the div before routes and it kind of remedy this issue, however, once the screen is small enough (i.e.like mobile) view and the drawer is hidden, 240px padding is still there.
(edited down for simplicity - content still the same)
import React from 'react';
import './App.css';
import { HashRouter as Router, Routes, Route} from 'react-router-dom';
//Page Routes
import NavigationAppBar from "./Navigation-Bar/NavigationAppBar";
import Home from './Page-Information/main';
function App() {
return (
<Router>
<NavigationAppBar/>
<div>
<Routes>
<Route exact path='/' exact element={<Home />} />
</Routes>
</div>
</Router>
);
}
export default App;
Home.js: (edited down for simplicity - content still the same)
import React from 'react';
const Home = () => {
return (
<div>
<h3>Example</h3>
</div>
);
};
export default Home;
I have forked the default persistent demo updated it into separate files.
You can add breakpoint for smaller device to remove margin or padding as appropriate.
const Main = styled("main", { 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
}),
[theme.breakpoints.down('sm')]: {
//add CSS here.
}
})
);
i have inertia progress bar initialized in my app.js
app.js
import React from "react";
import { render } from "react-dom";
import { createInertiaApp } from "#inertiajs/inertia-react";
import { InertiaProgress } from "#inertiajs/progress";
createInertiaApp({
resolve: (name) => require(`./Pages/${name}`),
setup({ el, App, props }) {
render(<App {...props} />, el);
},
});
InertiaProgress.init({
// The color of the progress bar.
color: "red",
// Whether the NProgress spinner will be shown.
showSpinner: true,
});
but the progressbar won't appear every time I render the appbar in the layout, its only the layout file, because if I render without it The progressbar will appear as usual
here is my Layout.tsx
import {
Button,
Container,
ListItem,
ListItemIcon,
ListItemText,
useTheme,
} from "#mui/material";
import React from "react";
import { styled, ThemeProvider } from "#mui/material/styles";
import CssBaseline from "#mui/material/CssBaseline";
import MuiDrawer from "#mui/material/Drawer";
import Box from "#mui/material/Box";
import MuiAppBar, { AppBarProps as MuiAppBarProps } from "#mui/material/AppBar";
import Toolbar from "#mui/material/Toolbar";
import List from "#mui/material/List";
import Typography from "#mui/material/Typography";
import Divider from "#mui/material/Divider";
import IconButton from "#mui/material/IconButton";
import MenuIcon from "#mui/icons-material/Menu";
import ChevronLeftIcon from "#mui/icons-material/ChevronLeft";
import { listItems } from "./ListItems";
import { usePage } from "#inertiajs/inertia-react";
import { Inertia } from "#inertiajs/inertia";
import route from "ziggy-js";
import FlashMessage from "./FlashMessage";
import { withStyles } from "#mui/styles";
const Layout = ({
children,
title,
}: {
children: React.ReactNode;
title: React.ReactNode;
}) => {
const theme = useTheme();
const authUser: any = usePage().props.user;
const drawerWidth: number = 240;
interface AppBarProps extends MuiAppBarProps {
open?: boolean;
}
const [open, setOpen] = React.useState(false);
const toggleDrawer = () => {
setOpen(!open);
};
const handleLogout = () => {
if (confirm("are you sure want to logout?")) {
Inertia.post(route("logout"));
}
};
return (
<ThemeProvider theme={theme}>
<Box sx={{ display: "flex" }}>
<CssBaseline />
<AppBar position="absolute" open={open}>
<Toolbar
sx={{
pr: "24px", // keep right padding when drawer closed
}}
>
<IconButton
edge="start"
color="inherit"
aria-label="open drawer"
onClick={toggleDrawer}
sx={{
marginRight: "36px",
...(open && { display: "none" }),
}}
>
<MenuIcon />
</IconButton>
<Typography
component="h1"
variant="h6"
color="inherit"
noWrap
sx={{ flexGrow: 1, marginLeft: 2 }}
>
{title}
</Typography>
<Button
{...(authUser ? { display: "none" } : { sx: {} })}
variant="text"
color="inherit"
onClick={handleLogout}
>
Logout
</Button>
</Toolbar>
</AppBar>
<Drawer variant="permanent" open={open}>
<Toolbar
sx={{
display: "flex",
alignItems: "center",
justifyContent: "flex-end",
px: [1],
}}
>
<IconButton onClick={toggleDrawer}>
<ChevronLeftIcon />
</IconButton>
</Toolbar>
<Divider />
<List>{listItems}</List>
</Drawer>
<Box
component="main"
}}
>
<Toolbar />
<FlashMessage />
<Container sx={{ marginTop: "50px" }}>{children}</Container>
</Box>
</Box>
</ThemeProvider>
);
};
export default Layout;
I think my progressbar appears under the appbar, is there any solution to this problem?
Just find out what the zIndex for your AppBar is (1100 by default I think)
console.log(Theme.zIndex.appBar)
Then on your CSS file, add a line to make the zIndex of the progress bar higher:
#nprogress .bar {
z-index: 1101!important;
}
I have created a Material-UI persistent drawer in which there is a list item component that aims to change the icon color whenever a user clicks on the list item. But my styling is only working with Material-UI icon, not with external SVG.
Here is codesandbox link for the same project to understand it better.
Here is my AppBarDrawer.js parent component that renders my listItem component. Working fine and can be ignored
import React from "react";
import clsx from "clsx";
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";
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 DrawerList from "./components/DrawerList";
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(true);
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>
Persistent drawer
</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>
<DrawerList />
</List>
</Drawer>
<main
className={clsx(classes.content, {
[classes.contentShift]: open
})}
>
<div className={classes.drawerHeader} />
<Typography paragraph>
Lorem Nulla posuere sollicitudin aliquam ultrices sagittis orci a
</Typography>
</main>
</div>
);
}
The Main file DrawerList.js which is not giving desired out
Here the real issue is my external icons color is not changing to white whenever I click on it however the last icon named ExitToAppOutlined is a Material-UI icon and is working fine on click.
import React, { useState } from "react";
import ListItem from "#material-ui/core/ListItem";
import Link from "#material-ui/core/Link";
import ListItemIcon from "#material-ui/core/ListItemIcon";
import { ExitToAppOutlined } from "#material-ui/icons";
import ListItemText from "#material-ui/core/ListItemText";
import { useStyles } from "./DrawerListStyle";
import Typography from "#material-ui/core/Typography";
import Box from "#material-ui/core/Box";
import { SvgIcon } from "#material-ui/core";
import { ReactComponent as Appointment } from "../../assets/Appointment.svg";
import { ReactComponent as Customers } from "../../assets/manage customers 2.svg";
const itemList = [
{
text: "Book Appointment",
icon: (
<SvgIcon>
{/* external icons as svg */}
<Appointment />
</SvgIcon>
)
},
{
text: "Manage",
icon: (
<SvgIcon>
{/* external icons as svg */}
<Customers />
</SvgIcon>
)
},
{
text: "Logout",
// Material Icons
icon: <ExitToAppOutlined />
}
];
const DrawerList = () => {
const [selectedIndex, setSelectedIndex] = useState(0);
const classes = useStyles();
const ListData = () =>
itemList.map((item, index) => {
const { text, icon } = item;
return (
<ListItem
button
key={text}
component={Link}
selected={index === selectedIndex}
onClick={(e) => handleListItemClick(e, index)}
style={selectedIndex === index ? { backgroundColor: "#6A2CD8" } : {}}
>
<ListItemIcon
className={classes.iconStyle}
style={selectedIndex === index ? { color: "#fff" } : {}}
>
{icon}
<ListItemText>
<Typography
component="div"
className={classes.iconTitle}
style={selectedIndex === index ? { color: "#fff" } : {}}
>
<Box fontWeight={500} fontSize={13.5}>
{text}
</Box>
</Typography>
</ListItemText>
</ListItemIcon>
</ListItem>
);
});
const handleListItemClick = (e, index) => {
setSelectedIndex(index);
};
return (
<div className={classes.root}>
<ListData />
</div>
);
};
export default DrawerList;
DrawerListStyle.js just an stylejs file and can be ignored
import { makeStyles } from "#material-ui/core";
const useStyles = makeStyles((theme) => ({
root: {
marginTop: theme.spacing(2)
},
iconStyle: {
margin: theme.spacing(0, 0, 1, 0),
color: "#6A2CD8"
},
iconTitle: {
margin: theme.spacing(0, 0, 0, 1),
color: "#555458"
}
}));
export { useStyles };
Material-UI sets the color of your ListItemIcon when the ListItem is selected, but because your custom svg icons already have the fill attribute set to another color, it overrides the color from MUI. The fix is simple, override the fill attribute again in your custom svg using makeStyles:
const useStyles = makeStyles((theme) => ({
{...}
listItem: {
"&.Mui-selected": {
"& path": {
fill: "white"
}
}
}
}));
<ListItem className={classes.listItem}
Live Demo
you can also use SVGR to build your own icons.
you can follow these steps:
1- install svgr using
npm install --save-dev #svgr/cli
# or use yarn
yarn add --dev #svgr/cli
2- add your icons in public/icons
3- create a file named svgr.config.js and place it in the root of project
module.exports = {
icon: true,
dimensions: false,
expandProps: false,
replaceAttrValues: {
'#000': 'currentColor',
'#292D32': 'currentColor',
'#292d32': 'currentColor',
'#55BB9D': 'currentColor',
'#FFBC50': 'currentColor',
'#A7A7A7': 'currentColor'
}
};
4- add script in package.json
"svg": "svgr --ext=jsx -d src/#share/icons public/icons"
5 - run yarn svg.
once you run above command svgr grab all icons in the public folder and gerenate React component inside src/#share/icons folder based on the config you provided.
and replace every color text of svg into current color.
in this case replace every key in replaceAttrValues to the currentColor.
then in your react component you can simply do this:
import { MyIcon } from '#share/icons';
import { SvgIcon } from '#mui/material';
function MyComponent() {
return <p><SvgIcon component={MyIcon} /> check this icon </p>
};
export default MyComponent;
in this way you can change the color the way you change the text color of p element.
I'm trying to apply styles to my React form. I'm using withStytles from Material UI.
The styles however are not taking into affect. I tried testing the code in my first <DialogContentText> in the code below, but it's not working.
EDIT: edited my code to reflect David's answer.
import React, { Component, Fragment } from 'react';
import { withStyles } from '#material-ui/core/styles';
import Button from '#material-ui/core/Button';
import Dialog from '#material-ui/core/Dialog';
import DialogActions from '#material-ui/core/DialogActions';
import DialogContent from '#material-ui/core/DialogContent';
import DialogContentText from '#material-ui/core/DialogContentText';
import DialogTitle from '#material-ui/core/DialogTitle';
import IconButton from '#material-ui/core/IconButton';
import AddCircleIcon from '#material-ui/icons/AddCircle';
import TextField from '#material-ui/core/TextField';
import FormHelperText from '#material-ui/core/FormHelperText';
import Select from '#material-ui/core/Select';
import MenuItem from '#material-ui/core/MenuItem';
import InputLabel from '#material-ui/core/InputLabel';
import FormControl from '#material-ui/core/FormControl';
const styles = theme => ({
formControl: {
width: 500
},
selectEmpty: {
marginTop: theme.spacing(2),
},});
export default class extends Component {
state = {
open: false,
bucket: {
name:'',
category: '',
about: '',
}
}
handleToggle = () => {
this.setState({
open: !this.state.open
})
}
handleChange = name => ({ target: { value } }) => {
this.setState({
bucket:{
...this.state.bucket,
[name]: value,
}
})
}
render() {
const { open, bucket: { name, category, about } } = this.state;
const { classes } = this.props;
return <Fragment>
<IconButton color="primary" size="large" onClick={this.handleToggle}>
<AddCircleIcon/>
</IconButton>
<Dialog open={open} onClose={this.handleToggle} aria-labelledby="form-dialog-title">
<DialogTitle id="form-dialog-title">Create your Bucket</DialogTitle>
<DialogContent>
<DialogContentText>
Get started! Make your bucket by telling us a little bit more.
</DialogContentText>
<form>
<TextField
id="filled-password-input"
label="Bucket Title"
value={name}
variant="filled"
onChange={this.handleChange('name')}
margin="normal"
required = "true"
className = {classes.formControl}
/>
<br/>
<br/>
<FormControl>
<InputLabel htmlFor="category"> What type of Bucket </InputLabel>
<Select
labelId="demo-simple-select-helper-label"
id="demo-simple-select-helper"
value={category}
onChange={this.handleChange('category')}
required = "true"
>
<MenuItem value={'personal'}> Personal </MenuItem>
<MenuItem value={'social'}> Social </MenuItem>
</Select>
</FormControl>
<FormHelperText>Is this your personal or social Bucket?</FormHelperText>
<TextField
id="filled-password-input"
label="About"
multiline
rows="5"
value={about}
variant="filled"
onChange={this.handleChange('about')}
margin="normal"
/>
<FormHelperText>Will this be your tech stock watchlist?</FormHelperText>
<br/>
<br/>
</form>
</DialogContent>
<DialogActions>
<Button
color="primary"
variant="raised"
onClick={this.handleSubmit}
>
Create Bucket
</Button>
</DialogActions>
</Dialog>
</Fragment>
}
}
export withStyles(styles)(YourComponent);
How would I be able to apply these styles to my code below? Thank you for assistance.
TL;DR: You are trying to use a React Hook const classes = useStyles; within a class component. Also, useStyles is a function, not an object.
NL;PR: Hooks only work on functional components (useStyles() hooks are obtained via makeStyles() instead of withStyles()). You apply HOC withStyles(YourComponent) to your class component not your styles, so you can access const {classes, ...rest} = this.props; in the render() method.
It should look like this:
const styles = theme => ({
formControl: {
width: 500
},
selectEmpty: {
marginTop: theme.spacing(2),
},});
class YourComponent extends PureComponent {
//...
render(){
const {classes, ...rest} = this.props;
// now your can access classes.formControl ...
}
}
export withStyles(styles)(YourComponent);
I'm building an app using function based component. I found the sidebar menu template from Material Ui in classes and want to convert it to functional component. But after converting click button doesn't work. I've only changed the menu icon to another.
Any help will be appreciated.
Here is the default component in classes
import React from "react";
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 IconButton from "#material-ui/core/IconButton";
import MenuIcon from "#material-ui/icons/Menu";
import { NavDrawer } from "./NavDrawer";
class NavBar extends React.Component {
constructor(props) {
super(props);
this.state = {
drawerOpened: false
};
}
toggleDrawer = booleanValue => () => {
this.setState({
drawerOpened: booleanValue
});
};
render() {
return (
<div className="App">
<AppBar position="static">
<Toolbar>
<IconButton
color="secondary"
aria-label="Menu"
onClick={this.toggleDrawer(true)}
>
<MenuIcon />
</IconButton>
<Typography variant="h6" color="inherit">
News
</Typography>
<Button color="inherit">Login</Button>
</Toolbar>
</AppBar>
<NavDrawer
drawerOpened={this.state.drawerOpened}
toggleDrawer={this.toggleDrawer}
/>
</div>
);
}
}
export default NavBar
Here I'm trying to convert
import React, { useState } from 'react'
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 NavDrawer from './NavDrawer'
import AddShoppingCartIcon from '#material-ui/icons/AddShoppingCart'
function NavBar(props) {
const [drawerOpened, setDrawerOpened] = useState(false)
const toggleDrawer = booleanValue => () => {
setDrawerOpened(booleanValue)
}
return (
<div className="App">
<AppBar position="static">
<Toolbar>
<IconButton
aria-label="AddShoppingCartIcon"
onClick={() => toggleDrawer(true)}
>
<AddShoppingCartIcon style={{ fontSize: 30 }} color="secondary" />
</IconButton>
<Typography variant="h6" color="inherit"></Typography>
</Toolbar>
</AppBar>
<NavDrawer drawerOpened={drawerOpened} toggleDrawer={toggleDrawer} />
</div>
)
}
export default NavBar
Have a look at React hooks, there ae two approaches:
const [toggleDrawer, setToggleDrawer] = useState(false); // set variable
<button onClick={() => setToggleDrawer(!toggleDrawer}>
Of you can useEffect to perform some logic after the component is initially rendered, preventing a max error:
const toggleDrawer = false;
useEffect(() => { // update variable
checkDrawOpened(toggleDrawer)
}, toggleDrawer);]
With the one click
onClick={toggleDrawer} // use variable
You can do this instead for toggling actions.
const toggleDrawer = () => {
setDrawerOpened(!drawerOpened)
}
And in the return
onClick={toggleDrawer}
Your function is stacking. On onclick, you try to call function to call function. Just use the const instead.
on toggleDrawer const, you should set setDrawerOpened to whenever the opposite of value it is to get toggling effect.