#3 create-responsive-navbar

Zusammengeführt
stefan.stamenovic hat 3 Commits von create-responsive-navbar nach master vor 4 Jahren zusammengeführt

+ 4
- 2
src/AppRoutes.js Datei anzeigen

@@ -12,10 +12,12 @@ import {

// import LoginPage from './pages/LoginPage/LoginPage';
import LoginPage from './pages/LoginPage/LoginPageMUI';
import HomePage from './pages/HomePage/HomePage';
// import HomePage from './pages/HomePage/HomePage';
import HomePage from './pages/HomePage/HomePageMUI';
import NotFoundPage from './pages/ErrorPages/NotFoundPage';
import ErrorPage from './pages/ErrorPages/ErrorPage';
import ForgotPasswordPage from './pages/ForgotPasswordPage/ForgotPasswordPage';
// import ForgotPasswordPage from './pages/ForgotPasswordPage/ForgotPasswordPage';
import ForgotPasswordPage from './pages/ForgotPasswordPage/ForgotPasswordPageMUI';
import PrivateRoute from './components/Router/PrivateRoute';

const AppRoutes = () => (

+ 15
- 0
src/components/MUI/CustomErrorMessage.js Datei anzeigen

@@ -0,0 +1,15 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Typography } from '@mui/material';

const CustomErrorMessage = ({ error }) => (
<Typography variant="body1" color="error" my={2}>
{error}
</Typography>
);

CustomErrorMessage.propTypes = {
error: PropTypes.string.isRequired,
};

export default CustomErrorMessage;

+ 37
- 0
src/components/MUI/DrawerComponent.js Datei anzeigen

@@ -0,0 +1,37 @@
import React from 'react';
import PropTypes from 'prop-types';
import {
Drawer,
List,
ListItem,
ListItemButton,
ListItemIcon,
ListItemText,
} from '@mui/material';

const DrawerComponent = ({ open, toggleOpen }) => (
<Drawer anchor="right" open={open} onClose={toggleOpen}>
<List>
<ListItemButton divider onClick={toggleOpen}>
<ListItemIcon>
<ListItemText>Link 1</ListItemText>
</ListItemIcon>
</ListItemButton>
<ListItem divider onClick={toggleOpen}>
<ListItemIcon>
<ListItemText>Link 2</ListItemText>
</ListItemIcon>
</ListItem>
<ListItem divider onClick={toggleOpen}>
<ListItemText>Link 3</ListItemText>
</ListItem>
</List>
</Drawer>
);

DrawerComponent.propTypes = {
open: PropTypes.bool,
toggleOpen: PropTypes.func,
};

export default DrawerComponent;

+ 26
- 0
src/components/MUI/MenuList.js Datei anzeigen

@@ -0,0 +1,26 @@
import React, { useState } from 'react';
import { Button, Menu, MenuItem } from '@mui/material';

const MenuList = () => {
const [anchorEl, setAnchorEl] = useState(null);
const open = Boolean(anchorEl);
const handleClick = (event) => {
setAnchorEl(event.currentTarget);
};
const handleClose = () => {
setAnchorEl(null);
};

return (
<div>
<Button onClick={handleClick}>Menu List</Button>
<Menu id="menu-list" anchorEl={anchorEl} open={open} onClose={handleClose}>
<MenuItem onClick={handleClose}>Menu Item 1</MenuItem>
<MenuItem onClick={handleClose}>Menu Item 2</MenuItem>
<MenuItem onClick={handleClose}>Menu Item 3</MenuItem>
</Menu>
</div>
);
};

export default MenuList;

+ 106
- 0
src/components/MUI/Navbar.js Datei anzeigen

@@ -0,0 +1,106 @@
import React, { useState } from 'react';
import {
AppBar,
Badge,
Box,
IconButton,
Toolbar,
Typography,
useMediaQuery,
} from '@mui/material';
import { useTheme } from '@mui/system';
import MenuOutlinedIcon from '@mui/icons-material/MenuOutlined';
import ShoppingBasketIcon from '@mui/icons-material/ShoppingBasket';
import MenuList from './MenuList';
import Drawer from './DrawerComponent';

const Navbar = () => {
const [openDrawer, setOpenDrawer] = useState(false);
const theme = useTheme();
const matches = useMediaQuery(theme.breakpoints.down('sm'));

const handleToggleDrawer = () => {
setOpenDrawer(!openDrawer);
};

return (
<>
<AppBar elevation={2} sx={{ backgroundColor: 'background.default' }}>
<Toolbar>
<Box
component="div"
sx={{
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
width: '100%',
}}
>
{matches ? (
<Drawer open={openDrawer} toggleOpen={handleToggleDrawer} />
) : (
<Box sx={{ display: 'flex' }}>
<Typography
variant="h6"
sx={{
marginRight: 3,
cursor: 'pointer',
color: 'text.primary',
}}
>
Link 1
</Typography>
<Typography
variant="body1"
sx={{
marginRight: 3,
cursor: 'pointer',
color: 'text.primary',
}}
>
Link 2
</Typography>
<Typography
variant="subtitle1"
sx={{
marginRight: 3,
cursor: 'pointer',
color: 'text.primary',
}}
>
Link 3
</Typography>
</Box>
)}
<Box>
<MenuList />
</Box>
<Box
sx={{
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
}}
>
{matches ? (
<Box>
<IconButton onClick={handleToggleDrawer}>
<MenuOutlinedIcon />
</IconButton>
</Box>
) : (
<IconButton>
<Badge badgeContent={3} color="primary">
<ShoppingBasketIcon color="action" />
</Badge>
</IconButton>
)}
</Box>
</Box>
</Toolbar>
</AppBar>
</>
);
};

export default Navbar;

+ 4
- 1
src/i18n/resources/en.js Datei anzeigen

@@ -65,6 +65,8 @@ export default {
forgotPassword: {
title: 'Forgot Password',
label: 'Send email',
emailRequired: 'An email is required.',
emailFormat: 'Invalid email address format.',
forgotPassword: {
title: 'Forgot Password',
subtitle:
@@ -83,6 +85,7 @@ export default {
logout: 'Logout',
},
apiErrors:{
ClientIpAddressIsNullOrEmpty:"Client Ip address is null or empty"
ClientIpAddressIsNullOrEmpty:"Client Ip address is null or empty",
UsernameDoesNotExist: "Username does not exist"
}
};

+ 96
- 0
src/pages/ForgotPasswordPage/ForgotPasswordPageMUI.js Datei anzeigen

@@ -0,0 +1,96 @@
import React from 'react';
import { useFormik } from 'formik';
import { useTranslation } from 'react-i18next';
import * as Yup from 'yup';
import i18next from 'i18next';
import {
Box,
Container,
Typography,
Button,
TextField,
Link,
Grid,
} from '@mui/material';
import Backdrop from '../../components/MUI/CustomBackdrop';
import { LOGIN_PAGE } from '../../constants/pages';
import { NavLink } from 'react-router-dom';

const forgotPasswordValidationSchema = Yup.object().shape({
email: Yup.string()
.required(i18next.t('forgotPassword.emailRequired'))
.email(i18next.t('forgotPassword.emailFormat')),
});

const ForgotPasswordPage = () => {
const { t } = useTranslation();

const handleSubmit = (values) => {
console.log('Values', values);
};

const formik = useFormik({
initialValues: {
email: '',
},
validationSchema: forgotPasswordValidationSchema,
onSubmit: handleSubmit,
validateOnBlur: true,
enableReinitialize: true,
});

return (
<Container component="main" maxWidth="md">
<Box
sx={{
marginTop: 32,
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
}}
>
<Typography component="h1" variant="h5">
{t('forgotPassword.title')}
</Typography>
<Box
component="form"
onSubmit={formik.handleSubmit}
sx={{ position: 'relative', mt: 1, p: 1 }}
>
<Backdrop position="absolute" isLoading={false} />
<TextField
name="email"
label={t('login.forgotPasswordEmail')}
margin="normal"
value={formik.values.email}
onChange={formik.handleChange}
error={formik.touched.email && Boolean(formik.errors.email)}
helperText={formik.touched.email && formik.errors.email}
autoFocus
fullWidth
/>
<Button
type="submit"
variant="contained"
sx={{ mt: 3, mb: 2 }}
fullWidth
>
{t('forgotPassword.label')}
</Button>
<Grid container justifyContent="center">
<Link
to={LOGIN_PAGE}
component={NavLink}
variant="body2"
underline="hover"
>
{t('common.back')}
</Link>
</Grid>
</Box>
</Box>
</Container>
);
};

export default ForgotPasswordPage;

+ 10
- 0
src/pages/HomePage/HomePageMUI.js Datei anzeigen

@@ -0,0 +1,10 @@
import React from 'react';
import Navbar from '../../components/MUI/Navbar';

const HomePage = () => {
return (
<Navbar />
)
};

export default HomePage;

+ 23
- 10
src/pages/LoginPage/LoginPageMUI.js Datei anzeigen

@@ -1,3 +1,4 @@
/* eslint-disable */
import React, { useState } from 'react';
import PropTypes from 'prop-types';
import { useFormik } from 'formik';
@@ -10,7 +11,7 @@ import {
clearLoginErrors,
fetchUser,
} from '../../store/actions/login/loginActions';
// import { selectLoginError } from '../../store/selectors/loginSelectors';
import { selectLoginError } from '../../store/selectors/loginSelectors';
import { FORGOT_PASSWORD_PAGE, HOME_PAGE } from '../../constants/pages';
import {
Box,
@@ -25,6 +26,7 @@ import {
} from '@mui/material';
import { Visibility, VisibilityOff } from '@mui/icons-material';
import Backdrop from '../../components/MUI/CustomBackdrop';
import ErrorMessage from '../../components/MUI/CustomErrorMessage';
import { selectIsLoadingByActionType } from '../../store/selectors/loadingSelectors';
import { LOGIN_USER_LOADING } from '../../store/actions/login/loginActionConstants';

@@ -36,7 +38,7 @@ const LoginValidationSchema = Yup.object().shape({
const LoginPage = ({ history }) => {
const dispatch = useDispatch();
const { t } = useTranslation();
// const error = useSelector(selectLoginError);
const error = useSelector(selectLoginError);

const [showPassword, setShowPassword] = useState(false);
const handleClickShowPassword = () => setShowPassword(!showPassword);
@@ -58,12 +60,12 @@ const LoginPage = ({ history }) => {
);

const handleApiResponseSuccess = () => {
history.push({
pathname: HOME_PAGE,
state: {
from: history.location.pathname,
},
});
// history.push({
// pathname: HOME_PAGE,
// state: {
// from: history.location.pathname,
// },
// });
};

const handleSubmit = (values) => {
@@ -102,6 +104,7 @@ const LoginPage = ({ history }) => {
<Typography component="h1" variant="h5">
{t('login.logInTitle')}
</Typography>
{error && <ErrorMessage error={error} />}
<Box
component="form"
onSubmit={formik.handleSubmit}
@@ -151,7 +154,12 @@ const LoginPage = ({ history }) => {
{t('login.logIn')}
</Button>
<Grid container>
<Grid item xs>
<Grid
item
xs={12}
md={6}
sx={{ textAlign: { xs: 'center', md: 'left' } }}
>
<Link
to={FORGOT_PASSWORD_PAGE}
component={NavLink}
@@ -161,7 +169,12 @@ const LoginPage = ({ history }) => {
{t('login.forgotYourPassword')}
</Link>
</Grid>
<Grid item>
<Grid
item
xs={12}
md={6}
sx={{ textAlign: { xs: 'center', md: 'right' } }}
>
<Link
to="#"
component={NavLink}

+ 2
- 2
src/store/saga/loginSaga.js Datei anzeigen

@@ -63,8 +63,8 @@ function* fetchUser({ payload }) {
if (payload.handleApiResponseSuccess) {
yield call(payload.handleApiResponseSuccess);
}
// const errorMessage = yield call(rejectErrorCodeHelper, e);
// yield put(fetchUserError(errorMessage));
const errorMessage = yield call(rejectErrorCodeHelper, e);
yield put(fetchUserError(errorMessage));
}
}
}

Laden…
Abbrechen
Speichern