Skip to content

Commit

Permalink
Merge pull request #99 from tieme-ndo/bg-handle-network-failure
Browse files Browse the repository at this point in the history
bug(axios): handle network error globally
  • Loading branch information
Pav0l committed Sep 27, 2019
2 parents 5ff27bc + 8430467 commit 35b6549
Show file tree
Hide file tree
Showing 10 changed files with 142 additions and 86 deletions.
7 changes: 3 additions & 4 deletions src/components/App/App.js
@@ -1,5 +1,3 @@
/** @format */

import React, { useState, useEffect, useCallback } from 'react';
import { BrowserRouter as Router, Route } from 'react-router-dom';
import { Container } from 'semantic-ui-react';
Expand Down Expand Up @@ -28,6 +26,7 @@ import PageHeader from '../common/PageHeader/PageHeader';
import EditCollection from '../pages/EditCollection/EditCollection';
import { getAllChangeRequests } from '../../utils/handlers/changeRequestHandler';
import { getFarmerStatisticsHandler } from '../../utils/handlers/farmerHandlers';
import AxiosErrorInterceptor from '../hoc/axiosErrorHandler/AxiosErrorInterceptor'

function App() {
const [user, setUser] = useState(undefined);
Expand Down Expand Up @@ -195,7 +194,7 @@ function App() {
path="/reset-password"
isAllowed={isLoggedIn()}
redirectTo="/login"
render={props => <PasswordReset {...props} logOut={logOut} />}
render={props => <PasswordReset {...props}/>}
/>
<RestrictedRoute
exact
Expand All @@ -217,4 +216,4 @@ function App() {
);
}

export default App;
export default AxiosErrorInterceptor(App);
29 changes: 29 additions & 0 deletions src/components/hoc/axiosErrorHandler/AxiosErrorInterceptor.js
@@ -0,0 +1,29 @@
import React, { useEffect } from 'react';
import axios from 'axios';
import { toast } from 'react-toastify';

const AxiosErrorInterceptor = WrappedComponent => {
return function Handler() {
useEffect(() => {
const reqIn = axios.interceptors.request.use(req => req);
const resIn = axios.interceptors.response.use(
function(response) {
return response;
},
function(error) {
if (error.message === 'Network Error') {
toast.error('Network error, please check your internet connection');
}
return Promise.reject(error);
}
);
return () => {
axios.interceptors.request.eject(reqIn);
axios.interceptors.response.eject(resIn);
};
}, []);
return <WrappedComponent />;
};
};

export default AxiosErrorInterceptor;
25 changes: 15 additions & 10 deletions src/components/pages/AddFarmer/AddFarmer.js
@@ -1,5 +1,3 @@
/** @format */

import React, { useState, useEffect } from 'react';
import Input from '../../common/Input/Input';
import {
Expand All @@ -8,7 +6,10 @@ import {
guarantor,
farmInfo
} from '../../common/Input/addFarmerData';
import { addFarmerHandler, uploadImageHandler } from '../../../utils/handlers/farmerHandlers';
import {
addFarmerHandler,
uploadImageHandler
} from '../../../utils/handlers/farmerHandlers';
import { toast } from 'react-toastify';
import { Menu, Segment, Form, Button } from 'semantic-ui-react';

Expand Down Expand Up @@ -69,7 +70,6 @@ const AddFarmer = ({ history, appStateShouldUpdate }) => {
newEntry.selected = [...newEntry.selected, value];
}
} else if (type === 'file') {

// Remove the selected image file from the form's <img /> element if no file is selected
e.persist();
e.target.nextSibling.src = '';
Expand All @@ -84,7 +84,7 @@ const AddFarmer = ({ history, appStateShouldUpdate }) => {
);
try {
if (process.env.REACT_APP_CLOUDINARY_URL) {
const uploadResponseData = await uploadImageHandler(imageFile)
const uploadResponseData = await uploadImageHandler(imageFile);
const imageUrl = uploadResponseData.data.secure_url;

// Render the image in the form's <img /> element
Expand Down Expand Up @@ -148,12 +148,17 @@ const AddFarmer = ({ history, appStateShouldUpdate }) => {
history.push('/');
})
.catch(err => {
if (Array.isArray(err.response.data.errors)) {
err.response.data.errors.forEach(element => {
toast.error(element.message);
});
if (err.response) {
if (Array.isArray(err.response.data.errors)) {
err.response.data.errors.forEach(element => {
toast.error(element.message);
});
} else if (err.response.data.errors.message) {
toast.error(err.response.data.errors.message);
} else {
toast.error("There was a problem in your request");
}
}
toast.error(err.response.data.errors.message)
});
};
const inputCreator = (data, tabName) => {
Expand Down
68 changes: 37 additions & 31 deletions src/components/pages/AddStaff/AddStaff.js
Expand Up @@ -69,40 +69,46 @@ function AddStaff() {
}));
}

const response = await registrationHandler({
username: state.username,
password: state.password,
isAdmin: state.isAdmin
});

if (Array.isArray(response)) {
const [errors] = response;

toast.error(errors.message);

return updateState(prevState => ({
try {
const response = await registrationHandler({
username: state.username,
password: state.password,
isAdmin: state.isAdmin
});
if (Array.isArray(response)) {
const [errors] = response;

toast.error(errors.message);

return updateState(prevState => ({
...prevState,
createAccount: false
}));
} else if (response && response.message === 'username already exists') {
toast.error('username already exists');

return updateState(prevState => ({
...prevState,
createAccount: false,
errors: {}
}));
} else if (response === 'New user created') {
toast.success('New user created');

return updateState(prevState => ({
...prevState,
username: '',
password: '',
confirmPassword: '',
isAdmin: false,
createAccount: false
}));
}
} catch (error) {
updateState(prevState => ({
...prevState,
createAccount: false
}));
} else if (response && response.message === 'username already exists') {
toast.error('username already exists');

return updateState(prevState => ({
...prevState,
createAccount: false,
errors: {}
}));
} else if (response === 'New user created') {
toast.success('New user created');

return updateState(prevState => ({
...prevState,
username: '',
password: '',
confirmPassword: '',
isAdmin: false,
createAccount: false
}));
}
};

Expand Down
2 changes: 1 addition & 1 deletion src/components/pages/EditCollection/EditCollection.js
Expand Up @@ -62,7 +62,7 @@ const EditCollection = ({ match, history, appStateShouldUpdate }) => {
})
.catch(() => {
toast.error(
'Network Error when retrieving change request. Redirecting to Dashboard'
'Redirecting to Dashboard'
);
// If no request is found with that ID
history.push('/');
Expand Down
33 changes: 20 additions & 13 deletions src/components/pages/Login/Login.js
Expand Up @@ -43,22 +43,29 @@ function Login({ setUser, ...props }) {
loading: false
}));
}
// send request to server
const receivedUser = await loginHandler({
username: state.username,
password: state.password
});

// if the response has token => successful login
if (receivedUser.hasOwnProperty('token')) {
setUser(getUser());
try {
// send request to server
const receivedUser = await loginHandler({
username: state.username,
password: state.password
});
// if the response has token => successful login
if (receivedUser.hasOwnProperty('token')) {
setUser(getUser());

props.history.push('/');
} else {
// on unsuccessful login, render server error message
props.history.push('/');
} else {
// on unsuccessful login, render server error message
updateState(prevState => ({
...prevState,
errors: [{ error: receivedUser.message }],
loading: false
}));
}
} catch (error) {
updateState(prevState => ({
...prevState,
errors: [{ error: receivedUser.message }],
errors: {},
loading: false
}));
}
Expand Down
31 changes: 20 additions & 11 deletions src/components/pages/PasswordReset/PasswordReset.js
Expand Up @@ -6,7 +6,7 @@ import validateResetPassword from './resetPasswordValidation';
import PasswordResetForm from './PasswordResetForm';
import { changePasswordHandler } from '../../../utils/handlers/userHandlers';

const PasswordReset = ({ logOut }) => {
const PasswordReset = ({ history }) => {
const [state, updateState] = useState({
currentPassword: '',
newPassword: '',
Expand Down Expand Up @@ -43,26 +43,35 @@ const PasswordReset = ({ logOut }) => {
}));
}

changePasswordHandler(currentPassword, newPassword)
.then(res => {
toast.success('Password changed successfully');
try {
const responseMessage = await changePasswordHandler(
currentPassword,
newPassword
);

if (responseMessage) {
toast.success(responseMessage);

updateState(prevState => ({
...prevState,
errors: {},
resetting: false
}));

logOut();
})
.catch(error => {
history.push('/');
} else {
updateState(prevState => ({
...prevState,
errors: error,
resetting: false
}));
toast.error(error.message);
});
}
} catch (error) {
updateState(prevState => ({
...prevState,
errors: error,
resetting: false
}));
toast.error(error.message);
}
};

return (
Expand Down
2 changes: 1 addition & 1 deletion src/components/pages/PasswordReset/PasswordResetForm.js
Expand Up @@ -42,7 +42,7 @@ const PasswordResetForm = props => {
<Image src={logo} centered alt="tiemendo logo" size="small" />

<Header as="h3" style={{ marginBottom: '30px' }}>
Reset password
Change password
</Header>

<Form size="large" onSubmit={handleSubmit}>
Expand Down
21 changes: 10 additions & 11 deletions src/components/pages/UpdateFarmer/UpdateFarmer.js
Expand Up @@ -200,18 +200,17 @@ const UpdateFarmer = ({ location, history, appStateShouldUpdate, user }) => {
})
.catch(err => {
setStateLoading(false);
if (!err.response) {
toast.error(err.message);
toast.error(
'Looks like there is a problem with your connection. Please try again later'
);
}
if(err.response.status === 403){
toast.warn(err.response.data.message)
if (err.response) {
if (Array.isArray(err.response.data.errors)) {
err.response.data.errors.forEach(element => {
toast.error(element.message);
});
} else if (err.response.data.errors.message) {
toast.error(err.response.data.errors.message);
} else {
toast.error(err.response.data.message);
}
}
err.response.data.errors.forEach(element => {
toast.error(element.message);
});
});
};

Expand Down
10 changes: 6 additions & 4 deletions src/utils/handlers/userHandlers.js
Expand Up @@ -19,7 +19,7 @@ export const getUserHandler = userId => {
});
};

export const changePasswordHandler = ( currentPassword, newPassword ) => {
export const changePasswordHandler = (currentPassword, newPassword) => {
return axios
.put(
`${pathObj.changePasswordPath}`,
Expand All @@ -28,12 +28,14 @@ export const changePasswordHandler = ( currentPassword, newPassword ) => {
)
.then(res => {
if (res.data) {
return res.data.successMessage;
return res.data.message;
}
})

.catch(error => {
throw new Error(error.response.data.message);
if (error.response) {
throw new Error(error.response.data.message);
}
// "else" is already handled by HOC intercepting network errors, all other erros have response.
});
};

Expand Down

0 comments on commit 35b6549

Please sign in to comment.