diff --git a/apps/frontend/src/features/login/LoginPage.tsx b/apps/frontend/src/features/login/LoginPage.tsx index b1fa97d796..6e5a5ff2e1 100644 --- a/apps/frontend/src/features/login/LoginPage.tsx +++ b/apps/frontend/src/features/login/LoginPage.tsx @@ -114,8 +114,13 @@ export const LoginPage = (): JSX.Element => { return t('features.login.LoginPage.forbidden') case StatusCodes.UNAUTHORIZED.toString(): return t('features.login.LoginPage.expiredSession') - default: + default: { + const code = parseInt(statusCode ?? '') + if (code >= 500 && code < 600) { + return t('features.common.errors.serverError') + } return t('features.common.errors.generic') + } } }, [statusCode]) diff --git a/apps/frontend/src/features/login/SelectProfilePage.tsx b/apps/frontend/src/features/login/SelectProfilePage.tsx index 03e5b08450..1a327e1e63 100644 --- a/apps/frontend/src/features/login/SelectProfilePage.tsx +++ b/apps/frontend/src/features/login/SelectProfilePage.tsx @@ -29,7 +29,7 @@ import { DASHBOARD_ROUTE, LOGIN_ROUTE } from '~constants/routes' import { useIsMobile } from '~hooks/useIsMobile' import { useLocalStorage } from '~hooks/useLocalStorage' import { useToast } from '~hooks/useToast' -import { ApiService } from '~services/ApiService' +import { ApiService, HttpError } from '~services/ApiService' import Button from '~components/Button' import { ModalCloseButton } from '~components/Modal' @@ -132,7 +132,23 @@ export const SelectProfilePage = (): JSX.Element => { // If redirected back here but already authed, redirect to dashboard. if (user) window.location.replace(DASHBOARD_ROUTE) // User doesn't have any profiles, should reattempt to login - if (profilesResponse.error) window.location.replace(LOGIN_ROUTE) + + if (profilesResponse.error) { + if ( + (profilesResponse.error as HttpError).code === StatusCodes.UNAUTHORIZED + ) { + // 401 — session invalid, redirect quietly + window.location.replace(LOGIN_ROUTE) + } else { + // all other errors (5xx, network failure, etc.) — redirect with status + // so LoginPage can surface the generic error toast on arrival. + // Fall back to 500 for network failures where no status code is present. + const statusCode = + (profilesResponse.error as HttpError).code ?? + StatusCodes.INTERNAL_SERVER_ERROR + window.location.replace(`${LOGIN_ROUTE}?status=${statusCode}`) + } + } useEffect(() => { if (profilesResponse.data?.profiles.length === 0) { diff --git a/apps/frontend/src/i18n/locales/features/common/en-sg.ts b/apps/frontend/src/i18n/locales/features/common/en-sg.ts index 9523252f33..99b890f741 100644 --- a/apps/frontend/src/i18n/locales/features/common/en-sg.ts +++ b/apps/frontend/src/i18n/locales/features/common/en-sg.ts @@ -62,6 +62,7 @@ export const enSG: Common = { }, pageNotFound: 'This page could not be found.', generic: 'Something went wrong. Please try again later.', + serverError: 'A server error occurred. Please try again later.', }, tooltip: { deleteField: 'Delete field', diff --git a/apps/frontend/src/i18n/locales/features/common/index.ts b/apps/frontend/src/i18n/locales/features/common/index.ts index ec4e0fa352..9e4a6192e6 100644 --- a/apps/frontend/src/i18n/locales/features/common/index.ts +++ b/apps/frontend/src/i18n/locales/features/common/index.ts @@ -62,6 +62,7 @@ export interface Common { } pageNotFound: string generic: string + serverError: string } tooltip: { deleteField: string