I have reading material-ui documents and I have found this syntax : anchorEl: null | HTMLElement
I don't have any clue what is it for.
Any ideas?
import React from 'react';
import PropTypes from 'prop-types';
import { createStyles, withStyles, WithStyles } 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';
const styles = createStyles({
root: {
flexGrow: 1,
},
grow: {
flexGrow: 1,
},
menuButton: {
marginLeft: -12,
marginRight: 20,
},
});
export interface Props extends WithStyles<typeof styles> {}
export interface State {
auth: boolean;
anchorEl: null | HTMLElement;
}
class MenuAppBar extends React.Component<Props, State> {
state: State = {
auth: true,
anchorEl: null,
};
handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
this.setState({ auth: event.target.checked });
};
handleMenu = (event: React.MouseEvent<HTMLElement>) => {
this.setState({ anchorEl: event.currentTarget });
};
handleClose = () => {
this.setState({ anchorEl: null });
};
render() {
const { classes } = this.props;
const { auth, anchorEl } = this.state;
const open = Boolean(anchorEl);
return (
<div className={classes.root}>
<FormGroup>
<FormControlLabel
control={
<Switch checked={auth} onChange={this.handleChange} aria-label="LoginSwitch" />
}
label={auth ? 'Logout' : 'Login'}
/>
</FormGroup>
<AppBar position="static">
<Toolbar>
<IconButton className={classes.menuButton} color="inherit" aria-label="Menu">
<MenuIcon />
</IconButton>
<Typography variant="h6" color="inherit" className={classes.grow}>
Photos
</Typography>
{auth && (
<div>
<IconButton
aria-owns={open ? 'menu-appbar' : undefined}
aria-haspopup="true"
onClick={this.handleMenu}
color="inherit"
>
<AccountCircle />
</IconButton>
<Menu
id="menu-appbar"
anchorEl={anchorEl}
anchorOrigin={{
vertical: 'top',
horizontal: 'right',
}}
transformOrigin={{
vertical: 'top',
horizontal: 'right',
}}
open={open}
onClose={this.handleClose}
>
<MenuItem onClick={this.handleClose}>Profile</MenuItem>
<MenuItem onClick={this.handleClose}>My account</MenuItem>
</Menu>
</div>
)}
</Toolbar>
</AppBar>
</div>
);
}
}
(MenuAppBar as React.ComponentClass<Props>).propTypes = {
classes: PropTypes.object.isRequired,
} as any;
export default withStyles(styles)(MenuAppBar);
Related
I have a modal window / Cookies dialog that I want to be launched when I open my application, without having to press any buttons, before showing my Dashboard.
this is my dashboard:
import { getDocument } from '../actions/documentAction';
//
import Grid from '#mui/material/Grid';
import { ThemeProvider } from '#mui/material'
//
import theme from '../styles/theme'
import '../styles/styles.css'
//
import HeaderBar from './header-bar/HeaderBar'
import BodyGrid from './body-grid/BodyGrid';
import BottomBar from './botton-bar/BottonBar';
// -----------------------------------------------------------
export const Dashboard = () => {
const dispatch = useDispatch();
dispatch( getDocument( 'EIT5850', {} ) );
//dispatch( getPrintCenter( 'EIT5850' ) );
return (
<>
<ThemeProvider theme={theme}>
<div>
<HeaderBar/>
<Grid container xs={12}>
<BodyGrid/>
</Grid>
<Grid container xs={12} pt={4}>
<BottomBar/>
</Grid>
</div>
</ThemeProvider>
</>
)
}
This is my Cookies modal:
import * as React from 'react';
import Backdrop from '#mui/material/Backdrop';
import Box from '#mui/material/Box';
import Modal from '#mui/material/Modal';
import Fade from '#mui/material/Fade';
import Button from '#mui/material/Button';
import Typography from '#mui/material/Typography';
import {Stack, ThemeProvider } from '#mui/material'
import Tab from '#mui/material/Tab';
import TabContext from '#mui/lab/TabContext';
import TabList from '#mui/lab/TabList';
import TabPanel from '#mui/lab/TabPanel';
import { FormControlLabel, IconButton } from '#mui/material';
import CloseIcon from '#mui/icons-material/Close';
import PropTypes from 'prop-types';
import { styled } from '#mui/material/styles';
import Dialog from '#mui/material/Dialog';
import DialogTitle from '#mui/material/DialogTitle';
import DialogContent from '#mui/material/DialogContent';
import DialogActions from '#mui/material/DialogActions';
import theme from '../../styles/theme'
import '../../styles/styles.css'
const style = {
position: 'absolute',
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)',
width: 1800,
bgcolor: 'background.paper',
border: '2px solid #000',
boxShadow: 24,
p: 4,
};
const BootstrapDialog = styled(Dialog)(({ theme }) => ({
'& .MuiDialogContent-root': {
padding: theme.spacing(2),
},
'& .MuiDialogActions-root': {
padding: theme.spacing(1),
},
}));
const BootstrapDialogTitle = (props) => {
const { children, onClose, ...other } = props;
return (
<DialogTitle sx={{ m: 0, p: 2 }} {...other}>
{children}
{onClose ? (
<IconButton
aria-label="close"
onClick={onClose}
sx={{
position: 'absolute',
right: 8,
top: 8,
color: (theme) => theme.palette.grey[500],
}}
>
<CloseIcon />
</IconButton>
) : null}
</DialogTitle>
);
};
BootstrapDialogTitle.propTypes = {
children: PropTypes.node,
onClose: PropTypes.func.isRequired,
};
export default function ModalNonDocs() {
const handleOpen = () => setOpen(true);
const [open, setOpen] = React.useState(false);
const handleClickOpen = () => {
setOpen(true);
};
const handleClose = () => {
setOpen(false);
};
const handleNotClose = (event, reason) => {
if (reason && reason == "backdropClick")
return;
}
const [value, setValue] = React.useState('1');
const handleChange = (event, newValue) => {
setValue(newValue);
};
return (
<ThemeProvider theme={theme}>
<div>
<Fade in={open}>
<Box>
<BootstrapDialog
onClose={handleNotClose}
aria-labelledby="customized-dialog-title"
open={open}
closeAfterTransition
BackdropComponent={Backdrop}
BackdropProps={{
timeout: 500,
}}
>
<BootstrapDialogTitle id="customized-dialog-title" onClose={handleClose}>
</BootstrapDialogTitle>
<TabContext value={value}>
<Box sx={{ borderBottom: 1, borderColor: 'divider' }}>
<TabList onChange={handleChange} aria-label="lab API tabs example">
<Tab
label="Consentimiento"
value="1" />
<Tab
label="PolĂtica de Cookies"
value="2" />
<Tab
label="Acerca de las Cookies"
value="3" />
</TabList>
</Box>
<TabPanel value="1">
<p>Opcion 1</p>
</TabPanel>
<TabPanel value="2">
<p>Opcion 2</p>
</TabPanel>
<TabPanel value="3">
<p>Opcion 3</p>
</TabPanel>
</TabContext>
<Button
onClick={handleClose}
variant="contained"
color="secondary"
style={
{ borderRadius: 0 ,
fontFamily: 'Source Sans Pro'}
}
>
Aceptar
</Button>
</BootstrapDialog>
</Box>
</Fade>
</div>
</ThemeProvider>
);
}
and this is where I call my dashboard to launch it
import { Routes, Route, BrowserRouter } from 'react-router-dom';
import { Dashboard } from '../components/Dashboard';
import { PrivateRoute } from './PrivateRoute';
export const AppRouter = () => {
return (
<BrowserRouter>
<Routes>
<Route path="/*" element={
<PrivateRoute>
<Dashboard />
</PrivateRoute>
} />
</Routes>
</BrowserRouter>
)
}
Until now I launched my cookie modal through an informative button, but now I need it to be shown automatically when the application starts.
I can't find a way to do it without a button
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 am building a reactjs application -- and I am trying to make this popup component modular -so that I could have the button look like a badge/icon combination -- activate the popup menu on hover instead of clicks.
here is a sandbox -- but I need to create popover menus for each -- at the moment its displacing the buttons.
https://codesandbox.io/s/material-demo-forked-wrn2g?file=/demo.js
Here is the component as it is currently
http://jsfiddle.net/4benm6wo/
import React from 'react';
import Button from '#material-ui/core/Button';
import ClickAwayListener from '#material-ui/core/ClickAwayListener';
import Grow from '#material-ui/core/Grow';
import Paper from '#material-ui/core/Paper';
import Popper from '#material-ui/core/Popper';
import MenuItem from '#material-ui/core/MenuItem';
import MenuList from '#material-ui/core/MenuList';
import Badge from '#material-ui/core/Badge';
import PersonIcon from '#material-ui/icons/Person';
import './PopOverMenu.scss';
export default function MenuListComposition() {
const [open, setOpen] = React.useState(false);
const anchorRef = React.useRef(null);
const handleToggle = () => {
setOpen((prevOpen) => !prevOpen);
};
const handleClose = (event) => {
if (anchorRef.current && anchorRef.current.contains(event.target)) {
return;
}
setOpen(false);
};
function handleListKeyDown(event) {
if (event.key === 'Tab') {
event.preventDefault();
setOpen(false);
}
}
// return focus to the button when we transitioned from !open -> open
const prevOpen = React.useRef(open);
React.useEffect(() => {
if (prevOpen.current === true && open === false) {
anchorRef.current.focus();
}
prevOpen.current = open;
}, [open]);
return (
<div className="popover-menu">
<div>
<Button
ref={anchorRef}
aria-controls={open ? 'menu-list-grow' : undefined}
aria-haspopup="true"
onClick={handleToggle}
>
<Badge badgeContent={11} color="primary">
<PersonIcon />
</Badge>
</Button>
<Popper open={open} anchorEl={anchorRef.current} role={undefined} transition disablePortal>
{({ TransitionProps, placement }) => (
<Grow
{...TransitionProps}
style={{ transformOrigin: placement === 'bottom' ? 'center top' : 'center bottom' }}
>
<Paper>
<ClickAwayListener onClickAway={handleClose}>
<MenuList autoFocusItem={open} id="menu-list-grow" onKeyDown={handleListKeyDown}>
<MenuItem onClick={handleClose}>Profile</MenuItem>
<MenuItem onClick={handleClose}>My account</MenuItem>
<MenuItem onClick={handleClose}>Logout</MenuItem>
</MenuList>
</ClickAwayListener>
</Paper>
</Grow>
)}
</Popper>
</div>
</div>
);
}
but I want to create a popperMenu component -- where I push the icon, badge count into the poppup -- so I need help implement it with props and states.
this is my current attempt
http://jsfiddle.net/4benm6wo/1/
class MenuListComposition extends Component {
constructor(props, context) {
super(props, context);
this.state = { open: false };
}
render() {
return (
<div className="popover-menu">
<div>
<Button
ref={anchorRef}
aria-controls={open ? 'menu-list-grow' : undefined}
aria-haspopup="true"
onClick={handleToggle}
>
<Badge badgeContent={11} color="primary">
<PersonIcon />
</Badge>
</Button>
<Popper open={open} anchorEl={anchorRef.current} role={undefined} transition disablePortal>
{({ TransitionProps, placement }) => (
<Grow
{...TransitionProps}
style={{ transformOrigin: placement === 'bottom' ? 'center top' : 'center bottom' }}
>
<Paper>
<ClickAwayListener onClickAway={handleClose}>
<MenuList autoFocusItem={open} id="menu-list-grow" onKeyDown={handleListKeyDown}>
<MenuItem onClick={handleClose}>Profile</MenuItem>
<MenuItem onClick={handleClose}>My account</MenuItem>
<MenuItem onClick={handleClose}>Logout</MenuItem>
</MenuList>
</ClickAwayListener>
</Paper>
</Grow>
)}
</Popper>
</div>
</div>
)
}
}
export default MenuListComposition;
so I would create a button/badge popup kind of like this from the shell
<MenuListComposition badgeCount={10} icon={<PersonIcon />} menu={[{ "label": "Profile", "link": "user/1" }, { "label": "Logout", "link": "logout" }]} />
latest code
LoginButton.js
http://jsfiddle.net/z3L89x2e/
import React, { Component } from 'react'
import { withRouter } from 'react-router-dom';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import Button from '#material-ui/core/Button';
import PopOverMenu from '../_SharedGlobalComponents/PopOverMenu/PopOverMenu';
import MailIcon from '#material-ui/icons/Mail';
import NotificationsIcon from '#material-ui/icons/Notifications';
import PersonIcon from '#material-ui/icons/Person';
class LoggedInButtons extends Component {
/*
constructor(props, context) {
super(props, context);
}
*/
render() {
return (
<div className="login-badges">
<PopOverMenu
icon={<NotificationsIcon />}
badgecount="3"
menu={[
{ "label": "xxx", "value": "/" },
{ "label": "xxxx", "value": "/" },
{ "label": "xxxxx", "value": "/" },
]}
/>
<PopOverMenu
icon={<MailIcon />}
badgecount="5"
menu={[
{ "label": "xxx", "value": "/" },
{ "label": "xxxx", "value": "/" },
{ "label": "xxxxx", "value": "/" },
]}
/>
<PopOverMenu
icon={<PersonIcon />}
badgecount="2"
menu={[
{ "label": "Profile", "value": "/profile" },
{ "label": "My account", "value": "/my-account" },
{ "label": "Logout", "value": "/logout" },
]}
/>
<Button
variant="text"
color="default"
startIcon={<PersonIcon />}
href="/user/view/2"
>
User 2
</Button>
<Button variant="contained" color="secondary" href="/logout">
log out
</Button>
</div>
)
}
}
function mapStateToProps(state) {
return {
};
}
function mapDispatchToProps(dispatch) {
return bindActionCreators({ }, dispatch);
}
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(LoggedInButtons))
PopOverMenu.js
http://jsfiddle.net/z3L89x2e/2/
import React, { Component } from 'react';
import Button from '#material-ui/core/Button';
import ClickAwayListener from '#material-ui/core/ClickAwayListener';
import Grow from '#material-ui/core/Grow';
import Paper from '#material-ui/core/Paper';
import Popper from '#material-ui/core/Popper';
import MenuItem from '#material-ui/core/MenuItem';
import MenuList from '#material-ui/core/MenuList';
import Badge from '#material-ui/core/Badge';
//import './PopOverMenu.scss';
class PopOverMenu extends Component {
constructor(props, context) {
super(props, context);
this.state = { open: false };
this.anchorRef = React.createRef(null);
}
handleToggle = () => {
this.setState({open: !this.state.open});
};
handleClose = () => {
this.setState({open: false});
};
handleListKeyDown = (event) => {
if (event.key === 'Tab') {
event.preventDefault();
this.setState({open: false});
}
}
showMenuItems = () => (
this.props.menu.map((item, i) => (
<MenuItem onClick={this.handleClose}>{item.label}</MenuItem>
))
)
render() {
return (
<div style={{display:'inline', float:'left', marginLeft:'20px', marginTop:'10px'}} className="popover-menu">
<Button
ref={this.anchorRef}
aria-controls={this.state.open ? 'menu-list-grow' : null}
aria-haspopup="true"
onClick={this.handleToggle}
>
<Badge badgeContent={this.props.badgecount} color="primary">
{this.props.icon}
</Badge>
</Button>
<Popper style={{position: 'relative'}} open={this.state.open} role={undefined} transition disablePortal>
{({ TransitionProps, placement }) => (
<Grow
{...TransitionProps}
style={{ transformOrigin: placement === 'bottom' ? 'center top' : 'center bottom' }}
>
<Paper>
<ClickAwayListener onClickAway={this.handleClose}>
<MenuList autoFocusItem={this.state.open} id="menu-list-grow" onKeyDown={this.handleListKeyDown}>
{this.showMenuItems()}
</MenuList>
</ClickAwayListener>
</Paper>
</Grow>
)}
</Popper>
</div>
);
}
}
export default PopOverMenu;
this is the latest attempt - it nearly worked - but then I got errors in the ancor el
I am using material ui and the icon/badge modules. I started to get an error on hovering over the menu.
I've tried to follow something like this - of putting the ancor el into the state - but its not working.
How can I convert popover MATERIAL-UI functional component to class based component?
import React, { Component } from 'react';
import { NavLink } from 'react-router-dom';
import Button from '#material-ui/core/Button';
import ClickAwayListener from '#material-ui/core/ClickAwayListener';
import Grow from '#material-ui/core/Grow';
import Paper from '#material-ui/core/Paper';
import Popper from '#material-ui/core/Popper';
import MenuItem from '#material-ui/core/MenuItem';
import MenuList from '#material-ui/core/MenuList';
import Badge from '#material-ui/core/Badge';
import './PopOverMenu.scss';
class PopOverMenu extends Component {
constructor(props, context) {
super(props, context);
// this.state = { open: false};
// this.anchorRef = React.createRef(null);
this.state = { anchorEl: null, open: false };
}
handleToggle = (event) => {
this.setState({open: !this.state.open});
// this.state.ancherEl ? this.setState({ anchorEl: null }) : this.setState({ anchorEl: event.currentTarget });
};
handleOpen = (event) => {
this.setState({open: true});
console.log("event.currentTarget", event.currentTarget);
this.state.ancherEl ? this.setState({ anchorEl: null }) : this.setState({ anchorEl: event.currentTarget });
};
handleClose = () => {
this.setState({open: false});
//this.setState({ anchorEl: null })
};
handleListKeyDown = (event) => {
if (event.key === 'Tab') {
event.preventDefault();
this.setState({open: false});
}
}
showMenuItems = () => (
this.props.menu.map((item, i) => (
<MenuItem key={i} onClick={this.handleClose}>
<NavLink to={item.value}>{item.label}</NavLink>
</MenuItem>
))
)
render() {
//console.log("this.anchorRef", this.anchorRef)
return (
<div className="popover-menu">
<Button
//ref={this.anchorRef}
aria-controls={this.state.open ? 'menu-list-grow' : null}
aria-haspopup="true"
onClick={this.handleToggle}
onMouseOver={this.handleOpen}
onMouseLeave={this.handleClose}
>
<Badge badgeContent={this.props.badgecount} color="primary">
{this.props.icon}
</Badge>
</Button>
<Popper
className="popper-list"
//anchorEl={this.anchorRef}
open={this.state.open}
anchorEl={this.state.anchorEl}
//role={undefined}
transition
disablePortal
onMouseOver={this.handleOpen}
onMouseLeave={this.handleClose}
>
{({ TransitionProps, placement }) => (
<Grow
{...TransitionProps}
style={{ transformOrigin: placement === 'bottom' ? 'center top' : 'center bottom' }}
>
<Paper>
<ClickAwayListener onClickAway={this.handleClose}>
<MenuList autoFocusItem={this.state.open} id="menu-list-grow" onKeyDown={this.handleListKeyDown}>
{/*this.showMenuItems()*/}
</MenuList>
</ClickAwayListener>
</Paper>
</Grow>
)}
</Popper>
</div>
);
}
}
export default PopOverMenu;
.popover-menu{
width: 40px;
display: inline;
float: left;
//border: 1px solid red;
//background: blue;
padding: 5px;
.popper-list{
width: 160px;
position: relative!important;
//border: 1px solid blue;
}
}
Here is a working CodeSandbox
You are using the wrong ref.
You need to assign the ref to the Popper on click (see line 89).
To be able to do this, you need to set the ref using setState and not createRef.
for hover activation: You need to toggle it using onMouseEnter and onMouseLeave on parent div
Add onClick on button to toggle the popper
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.
I have an App Bar component, I'm using Material UI v1.0.0-beta.33
import React from "react";
import PropTypes from "prop-types";
import { withStyles } from "material-ui/styles";
import AppBar from "material-ui/AppBar";
import Toolbar from "material-ui/Toolbar";
import Typography from "material-ui/Typography";
import Button from "material-ui/Button";
import IconButton from "material-ui/IconButton";
import MenuIcon from "material-ui-icons/Menu";
import TemporaryDrawer from "./Drawer";
const styles = {
root: {
width: "100%"
},
flex: {
flex: 1
},
menuButton: {
marginLeft: -12,
marginRight: 20
},
};
function ButtonAppBar(props) {
const { classes } = props;
return (
<div className={classes.root}>
<TemporaryDrawer/>
<AppBar position="static">
<Toolbar>
<IconButton className={classes.menuButton} color="inherit" aria-label="Menu">
<MenuIcon />
</IconButton>
<Typography variant="title" color="inherit" className={classes.flex}>
Title
</Typography>
<Button onClick={} color="inherit">User Name</Button>
</Toolbar>
</AppBar>
</div>
);
}
ButtonAppBar.propTypes = {
classes: PropTypes.object.isRequired
};
export default withStyles(styles)(ButtonAppBar);
As you can see I'm importing another component called TemporaryDrawer, in the code of that component there's a method called "toggleDrawer" that triggers the Drawer.
My questions is how can I use the toggleDrawer method from TemporaryDrawer in the above code, I have a button with the onClick method empty.
For reference, I put the code from TemporaryDrawer below:
import React from "react";
import PropTypes from "prop-types";
import { withStyles } from "material-ui/styles";
import Drawer from "material-ui/Drawer";
import List from "material-ui/List";
import Divider from "material-ui/Divider";
const styles = {
list: {
width: 250
},
listFull: {
width: "auto"
}
};
class TemporaryDrawer extends React.Component {
state = {
left: false
};
toggleDrawer = (side, open) => () => {
this.setState({
[side]: open
});
};
render() {
const { classes } = this.props;
const sideList = (
<div className={classes.list}>
<List>AA</List>
<List>BB</List>
<List>CC</List>
<Divider />
<List>AA1</List>
<List>BB1</List>
<List>CB1</List>
</div>
);
return (
<div>
<Drawer open={this.state.left} onClose={this.toggleDrawer("left", false)}>
<div
tabIndex={0}
role="button"
onClick={this.toggleDrawer("left", false)}
onKeyDown={this.toggleDrawer("left", false)}
>
{sideList}
</div>
</Drawer>
</div>
);
}
}
TemporaryDrawer.propTypes = {
classes: PropTypes.object.isRequired,
};
export default withStyles(styles)(TemporaryDrawer);
Thanks in advance.
Looking at the toggleDrawer method in TemporaryDrawer component
the method can simply be "litfed" into the parent component ButtonAppBar
updated ButtonAppBar turned in the class component:
class ButtonAppBar extends Component {
constructor(props) {
super(props);
this.state {
isDrawerOpen: false
}
this.closeDrawer = this.closeDrawer.bind(this);
}
closeDrawer() {
this.setState({ isDrawerOpen: false });
}
render() {
const { classes } = props;
return (
<div className={classes.root}>
<TemporaryDrawer open={this.state.isDrawerOpen} onDrawerClose={this.closeDrawer} />
<AppBar position="static">
<Toolbar>
<IconButton className={classes.menuButton} color="inherit" aria-label="Menu">
<MenuIcon />
</IconButton>
<Typography variant="title" color="inherit" className={classes.flex}></Typography>
<Button onClick={} color="inherit">User Name</Button>
</Toolbar>
</AppBar>
</div>
);
}
}
And then TemporaryDrawer component can be:
class TemporaryDrawer extends Component {
constructor(props) {
super(props);
}
render() {
return (
<Drawer open={this.props.isDrawerOpen} onClose={this.props.onDrawerClose}>
...
</Drawer>
)
}
}