From 09a39a009b14080763760a5e08052430eb92d083 Mon Sep 17 00:00:00 2001 From: KamranTaslim Date: Mon, 26 May 2025 16:09:55 +0530 Subject: [PATCH] Fix #1504: Display appropriate error messages for common errors like server unavailable and 403 access denied --- .env | 1 + package.json | 5 +- src/common/utils/ErrorMessageUtil.js | 54 + src/common/utils/httpClient.js | 23 +- src/dataEntryApp/ErrorFallback.js | 27 +- yarn.lock | 7339 ++++++++++++++------------ 6 files changed, 3935 insertions(+), 3514 deletions(-) diff --git a/.env b/.env index 4e23915f7..887388f2e 100644 --- a/.env +++ b/.env @@ -1,2 +1,3 @@ NODE_PATH=src/ SKIP_PREFLIGHT_CHECK=true +BACKEND_URL="http://localhost:8021" \ No newline at end of file diff --git a/package.json b/package.json index cf4a400ae..7274b341c 100644 --- a/package.json +++ b/package.json @@ -79,7 +79,7 @@ }, "scripts": { "analyze": "source-map-explorer 'build/static/js/*.js'", - "start": "BACKEND_URL=http://localhost:8021 react-scripts --max_old_space_size=2048 --openssl-legacy-provider start", + "start": "cross-env BACKEND_URL=http://localhost:8021 react-scripts --max_old_space_size=2048 --openssl-legacy-provider start", "start-with-staging": "BACKEND_URL=https://staging.avniproject.org react-scripts --max_old_space_size=2048 --openssl-legacy-provider start", "start-with-prerelease": "BACKEND_URL=https://prerelease.avniproject.org react-scripts --max_old_space_size=2048 --openssl-legacy-provider start", "start-with-prod": "BACKEND_URL=https://app.avniproject.org react-scripts --max_old_space_size=2048 --openssl-legacy-provider start", @@ -108,12 +108,13 @@ "not op_mini all" ], "devDependencies": { - "@babel/runtime": "^7.22.15", "@babel/helper-environment-visitor": "7.22.20", "@babel/helper-string-parser": "7.22.5", + "@babel/runtime": "^7.22.15", "@fortawesome/fontawesome-free": "^5.1.0", "@types/jest": "^26.0.19", "chai": "^4.2.0", + "cross-env": "^7.0.3", "cypress": "^5.6.0", "html-webpack-plugin": "^3.2.0", "http-proxy-middleware": "2.0.6", diff --git a/src/common/utils/ErrorMessageUtil.js b/src/common/utils/ErrorMessageUtil.js index 92653e6ce..2a07db7d4 100644 --- a/src/common/utils/ErrorMessageUtil.js +++ b/src/common/utils/ErrorMessageUtil.js @@ -44,6 +44,60 @@ class ErrorMessageUtil { return { message: `${error.message}. Something went wrong please try later`, display: true }; } + // New method to get user-friendly error messages based on HTTP status codes + static getUserFriendlyErrorMessage(error) { + const status = _.get(error, "response.status") || _.get(error, "status"); + + // Define specific messages for common error codes + switch (status) { + case 403: + return { + message: "You don't have permission to access this resource. Please contact your administrator if you need access.", + title: "Access Denied", + display: true + }; + case 404: + return { + message: "The resource you're looking for could not be found.", + title: "Not Found", + display: true + }; + case 500: + return { + message: "The server encountered an error. Please try again later.", + title: "Server Error", + display: true + }; + case 503: + return { + message: "The server is currently unavailable. Please try again later.", + title: "Server Unavailable", + display: true + }; + default: + // Check for network errors (when server is completely unreachable) + if ( + error.message && + (error.message.includes("Network Error") || + error.message.includes("Failed to fetch") || + error.message.includes("ERR_CONNECTION_REFUSED")) + ) { + return { + message: "Cannot connect to server. Please check your internet connection and try again.", + title: "Connection Error", + display: true + }; + } + + // Default fallback error message + return { + message: "An unexpected error occurred. Please try again later.", + title: "Error", + display: true + }; + } + } + static fromWindowUnhandledError(error, callback) { const unhandledError = new UnhandledRejectionError(error); if (error.promise) { diff --git a/src/common/utils/httpClient.js b/src/common/utils/httpClient.js index 8b8f0b675..7beb9450c 100644 --- a/src/common/utils/httpClient.js +++ b/src/common/utils/httpClient.js @@ -9,6 +9,7 @@ import querystring from "querystring"; import IdpDetails from "../../rootApp/security/IdpDetails"; import CurrentUserService from "../service/CurrentUserService"; import _ from "lodash"; +import ErrorMessageUtil from "./ErrorMessageUtil"; // Add this import Error handling function getCsrfToken() { // eslint-disable-next-line no-useless-escape @@ -113,6 +114,15 @@ class HttpClient { if (error.status === 401 && this.idp.idpType === IdpDetails.keycloak) { this.idp.clearAccessToken(); } + + // Use the new error handling method + const errorDetails = ErrorMessageUtil.getUserFriendlyErrorMessage(error); + + // You can either handle the error display here or pass the error details up + // For now, we'll just enrich the error with our friendly message + error.friendlyMessage = errorDetails.message; + error.title = errorDetails.title; + throw error; }); } @@ -143,7 +153,18 @@ class HttpClient { _wrapAxiosMethod(methodName) { return async (...args) => { await this.setTokenAndOrgUuidHeaders(); - return axios[methodName](...args); + return axios[methodName](...args).catch(error => { + // Use the new error handling method + const errorDetails = ErrorMessageUtil.getUserFriendlyErrorMessage(error); + + // Create an enhanced error object + const enhancedError = new Error(errorDetails.message); + enhancedError.originalError = error; + enhancedError.title = errorDetails.title; + enhancedError.display = errorDetails.display; + + throw enhancedError; + }); }; } diff --git a/src/dataEntryApp/ErrorFallback.js b/src/dataEntryApp/ErrorFallback.js index 8fc6431cc..c41b5d262 100644 --- a/src/dataEntryApp/ErrorFallback.js +++ b/src/dataEntryApp/ErrorFallback.js @@ -42,6 +42,10 @@ const useStyles = makeStyles(theme => ({ border: "2px solid #d1d2d2", borderRadius: 5, marginTop: "10px" + }, + errorTitle: { + color: "#d32f2f", // Red color for error title + marginBottom: theme.spacing(2) } })); @@ -86,6 +90,10 @@ export function ErrorFallback({ error, onClose }) { appHome(); }; + // Get the friendly error information + const errorTitle = error.title || "Error"; + const friendlyMessage = error.friendlyMessage || error.message; + return (
@@ -96,25 +104,22 @@ export function ErrorFallback({ error, onClose }) {
- - oops! + + {errorTitle} - - There was a problem when loading this page. Please contact administrator. + + {friendlyMessage} {!showError && ( )} {showError && (