Skip to content

Commit b82877d

Browse files
author
Emile Frey
committed
adds alertcontext and validationmesage errors to login
1 parent 065c256 commit b82877d

File tree

5 files changed

+77
-20
lines changed

5 files changed

+77
-20
lines changed

frontend/src/App.tsx

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
1-
import React, { Dispatch } from 'react';
1+
import React, { Dispatch, useContext } from 'react';
22
import Router from './routes/Router';
33
import Layout from './components/Layout/Layout';
44
import { connect } from 'react-redux';
55
import * as actions from './auth/authActions';
66
import { PrivateRouteProps } from './routes/PrivateRoute';
7-
import { ThemeProvider } from '@material-ui/core';
7+
import { Snackbar, ThemeProvider } from '@material-ui/core';
88
import { theme } from './Theme'
9+
import { AlertContext } from './contexts/AlertContext';
10+
import Alert from '@material-ui/lab/Alert';
911
export interface AuthProps {
1012
logout: Function
1113
setAuthenticatedIfRequired: Function
@@ -25,6 +27,8 @@ export interface AppProps extends AuthProps, PrivateRouteProps { }
2527

2628
function App(props: AppProps) {
2729

30+
const { alertType, openAlert, alertMessage, handleAlertClose } = useContext(AlertContext);
31+
2832
React.useEffect(() => {
2933
props.setAuthenticatedIfRequired();
3034
}, [props]);
@@ -35,6 +39,11 @@ function App(props: AppProps) {
3539
<Layout {...props}>
3640
<Router {...props} />
3741
</Layout>
42+
<Snackbar id="appAlertSnackbar" open={openAlert} autoHideDuration={6000} onClose={handleAlertClose}>
43+
<Alert onClose={handleAlertClose} severity={alertType}>
44+
{alertMessage}
45+
</Alert>
46+
</Snackbar>
3847
</ThemeProvider>
3948
</div>
4049
);

frontend/src/components/Login/Login.tsx

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,7 @@ import * as actions from '../../auth/authActions';
1414

1515
import { useHistory, useLocation } from "react-router-dom";
1616
import { AppProps } from '../../App';
17-
import MuiAlert from '@material-ui/lab/Alert';
18-
17+
import validationErrorMessages from '../../helpers/validationErrorMessages'
1918

2019
const useStyles = makeStyles((theme) => ({
2120
paper: {
@@ -48,7 +47,6 @@ function Login(props: AppProps) {
4847
const classes = useStyles();
4948
const [username, setuserName] = useState("");
5049
const [password, setPassword] = useState("");
51-
const [validationErrors, setValidationErrors] = useState<string[]>([])
5250

5351
let history = useHistory();
5452
let location = useLocation<LocationState>();
@@ -58,32 +56,19 @@ function Login(props: AppProps) {
5856
if (props.isAuthenticated) { history.replace(from) };
5957
});
6058

61-
useEffect(() => {
62-
setValidationErrors(props.error.response.data.non_field_errors)
63-
}, [props.error])
64-
65-
6659
const handleFormFieldChange = (event: React.ChangeEvent<HTMLInputElement>) => {
6760
switch (event.target.id) {
6861
case 'username': setuserName(event.target.value); break;
6962
case 'password': setPassword(event.target.value); break;
7063
default: return null;
7164
}
72-
7365
};
7466

7567
const handleSubmit = (e: React.ChangeEvent<HTMLFormElement>) => {
7668
e.preventDefault();
7769
props.onAuth(username, password);
7870
}
7971

80-
const validationErrorMessages = (
81-
validationErrors.map((value, index) => (
82-
<MuiAlert key={index} elevation={6} variant="filled" severity="warning" id="Validation-Message">{value}</MuiAlert>
83-
))
84-
);
85-
86-
8772
return (
8873
<Container component="main" maxWidth="xs">
8974
<CssBaseline />
@@ -119,6 +104,7 @@ function Login(props: AppProps) {
119104
autoComplete="current-password"
120105
onChange={handleFormFieldChange}
121106
/>
107+
{validationErrorMessages(props.error ? props.error.response.data.non_field_errors : [])}
122108
<Button
123109
type="submit"
124110
fullWidth
@@ -134,7 +120,6 @@ function Login(props: AppProps) {
134120
);
135121
}
136122

137-
138123
const mapDispatchToProps = (dispatch: Dispatch<any>) => {
139124
return {
140125
onAuth: (username: string, password: string) => dispatch(actions.authLogin(username, password))
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import React, { createContext, useState } from 'react';
2+
import { Color } from '@material-ui/lab/Alert';
3+
4+
export type AlertContextProps = {
5+
TSAlert: (message: string, severity: Color) => void,
6+
openAlert: boolean,
7+
alertMessage: string,
8+
alertType: Color,
9+
handleAlertClose: (event?: React.SyntheticEvent<Element, Event> | undefined, reason?: string | undefined) => void
10+
};
11+
12+
export const AlertContext = createContext<AlertContextProps>({
13+
TSAlert: () => {},
14+
openAlert: false,
15+
alertMessage: '',
16+
alertType: 'info',
17+
handleAlertClose: () => {}
18+
});
19+
20+
const AlertContextProvider = (props: any) => {
21+
const [openAlert, setOpenAlert] = useState(false);
22+
const [alertMessage, setAlertMessage] = useState('');
23+
const [alertType, setAlertType] = useState<Color>('error');
24+
25+
const TSAlert = (message: string, severity: Color = 'info') => {
26+
setAlertMessage(message);
27+
setAlertType(severity);
28+
setOpenAlert(true);
29+
}
30+
31+
const handleAlertClose = (event?: React.SyntheticEvent, reason?: string) => {
32+
if (reason === 'clickaway') {
33+
return;
34+
}
35+
setOpenAlert(false);
36+
};
37+
38+
return (
39+
<AlertContext.Provider value={{
40+
TSAlert,
41+
openAlert,
42+
alertMessage,
43+
alertType,
44+
handleAlertClose
45+
}}>
46+
{props.children}
47+
</AlertContext.Provider>
48+
)
49+
}
50+
51+
export default AlertContextProvider;
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import React from 'react'
2+
import MuiAlert from '@material-ui/lab/Alert';
3+
4+
const validationErrorMessages = (validationErrors: string[]) =>
5+
validationErrors.map((value, index) =>
6+
<MuiAlert key={index} elevation={6} variant="filled" severity="warning" id="Validation-Message">{value}</MuiAlert>
7+
);
8+
9+
export default validationErrorMessages

frontend/src/index.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { combineReducers, createStore, compose, applyMiddleware } from 'redux';
77
import { Provider } from 'react-redux';
88
import thunk from 'redux-thunk';
99
import authReducer from './auth/authReducer';
10+
import AlertContextProvider from './contexts/AlertContext'
1011

1112
const reducer = combineReducers({ auth: authReducer }); // Using Combine Reducers here although only one reducer is present.
1213
// Official explaination here: https://react-redux.js.org/using-react-redux/connect-mapstate#mapstatetoprops-will-not-run-if-the-store-state-is-the-same
@@ -18,7 +19,9 @@ const store = createStore(reducer, composeEnhanced(applyMiddleware(thunk))); //
1819
ReactDOM.render(
1920
<React.StrictMode>
2021
<Provider store={store}>
21-
<App />
22+
<AlertContextProvider>
23+
<App />
24+
</AlertContextProvider>
2225
</Provider>
2326
</React.StrictMode>,
2427
document.getElementById('root')

0 commit comments

Comments
 (0)