I want this notifications display above modal but it didnt. I try to change zIndex but its not useful. Please help me make the notification show on top of other components. In the Header, I create a button that trigger modal have register/login form and fot password, I pass a set alert to login component to set alert for notifications because if notifications place in modal, its will be affected by modal size Here my code: -Snackbar:
import { Snackbar, Alert } from "@mui/material";
/**
* NotificationSnackbar
* Display message, notifications
*/
export default function NotificationSnackbar({ alert, onClose }) {
return (
<Snackbar
open={alert.open}
autoHideDuration={3000}
onClose={onClose}
anchorOrigin={{
vertical: "top",
horizontal: "right",
}}
sx={{
top: { xs: 64, sm: "70px" },
width: { xs: "90%", sm: "auto" },
zIndex: 1501,
position: "fixed"
}}
>
<Alert
severity={alert.severity || "info"}
onClose={onClose}
sx={{
fontWeight: "bold",
border: "2px solid",
borderColor:
alert.severity === "success"
? "#05ce80"
: alert.severity === "error"
? "#d32f2f"
: "#ff9800",
boxShadow: 2,
marginTop: { xs: 2, sm: 8 },
width: { xs: "100%", sm: "auto" },
}}
>
{alert.message || "Something went wrong!"}
</Alert>
</Snackbar>
);
}
And Header:
import React from "react";
import { AppBar, Toolbar, Box, Button, Divider, Stack, Modal, IconButton, Drawer, List, ListItem } from "@mui/material";
import { Link } from "react-router-dom";
import { Menu as MenuIcon } from "@mui/icons-material";
import logo from "../../assets/logo.png";
import UserMenu from "../User/UserMenu";
import { ModalClose, ModalDialog } from "@mui/joy";
import Login from "../User/Login";
import Register from "../User/Register";
import * as Mui from "@mui/material";
import { useMediaQuery } from "@mui/material";
import { useState } from "react";
import NotificationSnackbar from "./NotificationSnackbar";
const Header = () => {
const [alert, setAlert] = useState({ open: false, message: "", severity: "success" });
const isLoggedIn = Boolean(localStorage.getItem("role"));
const [open, setOpen] = React.useState(false);
const [drawerOpen, setDrawerOpen] = React.useState(false);
const isMobile = useMediaQuery("(max-width: 768px)"); // Check if screen width is less than 768px
const handleOpen = () => setOpen(true);
const handleClose = () => setOpen(false);
const toggleDrawer = () => setDrawerOpen(!drawerOpen);
return (
<AppBar position="sticky" color="transparent" elevation={1} sx={{ backgroundColor: "white" }}>
<Toolbar sx={{ justifyContent: "space-between", mx: "auto", maxWidth: "1200px", width: "100%", py: 1, px: 2, boxSizing: "border-box", }}>
{/* Logo */}
<Box>
<Link to="/" style={{ textDecoration: "none" }}>
<img src={logo} alt="logo" style={{ maxWidth: isMobile ? "150px" : "250px", height: "auto" }} />
</Link>
</Box>
{/* Desktop Menu */}
{!isMobile ? (
<Stack direction="row" spacing={3} alignItems="center">
<Link to="/aboutus" style={{ textDecoration: "none" }}>
<Button sx={{ fontWeight: 500, textTransform: "none", color: "black", "&:hover": { color: "#05ce80" } }}>
About Karental
</Button>
</Link>
<Divider orientation="vertical" flexItem />
{!isLoggedIn ? (
<>
<Button onClick={handleOpen} id="open-register-button" sx={{ fontWeight: 500, textTransform: "none", color: "black", "&:hover": { color: "#05ce80" } }}>
Sign Up
</Button>
<Divider orientation="vertical" flexItem sx={{ width: "1px", height: "25px", alignSelf: "center" }} />
<Button onClick={handleOpen} id="open-login-button" variant="outlined" sx={{ px: 4, py: 1.5, borderRadius: 2, borderColor: "black", color: "black", fontWeight: 500, textTransform: "none", "&:hover": { borderColor: "#05ce80", color: "#05ce80" } }}>
Login
</Button>
</>
) : (
<UserMenu />
)}
</Stack>
) : (
// Mobile Menu Button
<IconButton onClick={toggleDrawer} sx={{ color: "black" }}>
<MenuIcon />
</IconButton>
)}
{/* Mobile Drawer */}
<Drawer anchor="right" open={drawerOpen} onClose={toggleDrawer}>
<List sx={{ width: "250px" }}>
<ListItem button component={Link} to="/aboutus" onClick={toggleDrawer}>
About Karental
</ListItem>
{!isLoggedIn ? (
<>
<ListItem button onClick={handleOpen}>Sign Up</ListItem>
<ListItem button onClick={handleOpen}>Login</ListItem>
</>
) : (
<UserMenu />
)}
</List>
</Drawer>
{/* Login/Register Modal */}
<Modal open={open} onClose={handleClose}>
<ModalDialog sx={{ width: "65vw", maxWidth: "lg", maxHeight: "100vh", overflowY: "auto", zIndex: 1200, }}>
<ModalClose onClick={handleClose} />
<Mui.Container sx={{ display: "flex", flexDirection: isMobile ? "column" : "row", gap: 2 }}>
<Login onLoginSuccess={handleClose} setAlert={setAlert} />
{!isMobile && <Mui.Divider orientation="vertical" flexItem />}
<Register onRegisterSucess={handleClose} setAlert={setAlert} />
</Mui.Container>
</ModalDialog>
</Modal>
{/* Notification Snackbar */}
<NotificationSnackbar alert={alert} onClose={() => setAlert({ ...alert, open: false })} disablePortal={false} // Thử để false để snackbar render trong cùng DOM
sx={{ zIndex: 2000 }} />
</Toolbar>
</AppBar>
);
};
export default Header;
And last is Login component:
import * as React from "react";
import * as Mui from "@mui/material";
import normalForm from "../../styles/FormStyles.js";
import { fotPasswordEmailFunction, login } from '../../services/UserServices.js';
import * as Icons from "@mui/icons-material";
import { useState } from "react";
import { ModalClose, ModalDialog } from '@mui/joy';
import { useNavigate } from "react-router-dom";
const Login = ({ onLoginSuccess, setAlert }) => {
const [formLogin, setFormLogin] = useState({
email: "",
password: "",
});
const handleChange = (e) => {
setFormLogin({
...formLogin,
[e.target.name]: e.target.value
})
}
// state for showing password or not
const [showPassword, setShowPassword] = useState(false);
const handleClickShowPassword = () => setShowPassword((show) => !show);
const nav = useNavigate();
const handleSubmit = async (event) => {
event.preventDefault();
try {
const response = await login(formLogin); // Await the login call
console.log("Login Response:", response);
//set role into localStorage
if (response.code === 1000) {
localStorage.setItem("role", response.data.userRole);
localStorage.setItem("name", response.data.fullName);
localStorage.setItem("csrfToken", response.data.csrfToken);
setAlert({ open: true, message: "Welcome to Our Community", severity: "success" });
setTimeout(() => {
nav("/", { replace: true });
onLoginSuccess();
}, 1000);
} else {
setAlert({ open: true, message: response.message, severity: "error" });
}
} catch (error) {
console.log(error)
}
}
const handleMouseUp = (event) => {
event.preventDefault();
};
const handleMouseDown = (event) => {
event.preventDefault();
};
const [openModalFot, setOpenModalFot] = useState(false)
const [fotPasswordEmail, setFotPasswordEmail] = useState("");
const handleFotPassword = async () => {
console.log("Fot password clicked, email:", fotPasswordEmail);
if (!fotPasswordEmail) {
setAlert({ open: true, message: "Please enter your email", severity: "warning" });
return;
}
try {
const response = await fotPasswordEmailFunction(fotPasswordEmail);
console.log("Fot Password Response:", response);
if (response?.message) {
setAlert({ open: true, message: response.data.message, severity: "success" });
} else {
setAlert({ open: true, message: "Failed to send email. Try again.", severity: "error" });
}
setOpenModalFot(false); // Đóng modal sau khi gửi email thành công
} catch (error) {
console.error("Fot password error:", error);
setAlert({ open: true, message: error.message || "An error occurred", severity: "error" });
}
};
return (
<>
<Mui.Box component="form" sx={normalForm}>
<Mui.Typography
variant="h5"
textAlign={"center"}
sx={{ color: "#05ce80" }}
>
LOG IN USING YOUR ACCOUNT
</Mui.Typography>
<Mui.Box sx={{ display: "flex", flexDirection: "column", gap: 2, alignItems: "start" }}>
<Mui.TextField
id="login-email"
name="email"
variant="standard"
label="Your email address"
//error={!!errors.name}
//helperText={errors.name}
value={formLogin.email}
onChange={handleChange}
fullWidth
/>
<Mui.TextField
id="login-password"
name="password"
variant="standard"
label="Password"
//error={!!errors.password}
//helperText={errors.password}
value={formLogin.password}
onChange={handleChange}
type={showPassword ? "text" : "password"}
fullWidth
required
InputProps={{
endAdornment: (
<Mui.InputAdornment position="end">
<Mui.IconButton
onClick={handleClickShowPassword}
onMouseUp={handleMouseUp}
onMouseDown={handleMouseDown}
>
{showPassword ? (
<Icons.VisibilityOff />
) : (
<Icons.Visibility />
)}
</Mui.IconButton>
</Mui.InputAdornment>
),
}}
/>
<Mui.Link id="login-fotPassword" href="#"
onClick={(e) => {
setOpenModalFot(true);
e.preventDefault();
}}>
Fot your password?</Mui.Link>
<Mui.Modal open={openModalFot} >
<ModalDialog>
<ModalClose onClick={() => setOpenModalFot(false)} />
<Mui.Box textAlign={"center"}>
<Mui.Typography variant={"h6"}>Fot your password?</Mui.Typography>
<Mui.TextField variant='standard' onChange={(e) => (setFotPasswordEmail(e.target.value))} label="Your email" value={fotPasswordEmail}></Mui.TextField>
<br />
<Mui.Button
sx={{
width: 150,
height: 50,
borderRadius: 2,
border: "solid white",
backgroundColor: "#05ce80",
marginInline: 2,
color: "white",
transition: " 0.3s",
"&:hover": {
backgroundColor: "white",
borderRadius: 2,
borderColor: "#05ce80",
color: "#05ce80",
},
}}
onClick={handleFotPassword}
>
Send Email
</Mui.Button>
</Mui.Box>
</ModalDialog>
</Mui.Modal>
<Mui.Box sx={{ display: "flex", justifyContent: "center", width: "100%" }}>
<Mui.Button
id="login"
variant="outlined"
onClick={handleSubmit}
sx={{
width: '150px',
borderRadius: 2,
borderColor: "black",
color: "black",
fontWeight: 500,
textTransform: "none",
transition: " 0.3s",
"&:hover": {
borderColor: "#05ce80",
color: "#05ce80",
},
}}
>
LOGIN
</Mui.Button>
</Mui.Box>
</Mui.Box>
</Mui.Box>
</>
);
};
export default Login;
notifications covered by backdrop