Skip to content

Commit

Permalink
feat(routing): 11991 - redirect to base url if faced 403 on bivariate…
Browse files Browse the repository at this point in the history
… color manager page

- history added to have possiblity to interact with history in atoms
- tests for history
- 403 response is parsed in getProblemFromError (was unknown previously)
  • Loading branch information
propakov committed Aug 31, 2022
1 parent 3023811 commit 00c9620
Show file tree
Hide file tree
Showing 9 changed files with 75 additions and 22 deletions.
13 changes: 7 additions & 6 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@
"react-lazily": "^0.9.0",
"react-markdown": "^7.1.0",
"react-router": "^5.2.1",
"history": "^4.9.0",
"react-router-cache-route": "^1.11.1",
"react-router-dom": "^5.3.0",
"react-transition-group": "^4.4.2",
Expand Down
8 changes: 8 additions & 0 deletions src/RoutePaths.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import config from '~core/app_config';

export const ROUTE_PATHS = {
base: config.baseUrl,
reports: config.baseUrl + 'reports',
reportPage: config.baseUrl + 'reports/:reportId',
bivariateManager: config.baseUrl + 'bivariate-manager',
};
21 changes: 5 additions & 16 deletions src/Routes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,10 @@ import { matchPath } from 'react-router';
import { lazily } from 'react-lazily';
import { useHistory } from 'react-router';
import { CacheRoute, CacheSwitch } from 'react-router-cache-route';
import {
BrowserRouter as Router,
Route,
useLocation,
Redirect,
} from 'react-router-dom';
import { Router, Route, useLocation, Redirect } from 'react-router-dom';
import { useAtom } from '@reatom/react';
import { i18n } from '~core/localization';
import config from '~core/app_config';
import history from '~core/history';
import { OriginalLogo } from '~components/KonturLogo/KonturLogo';
import { VisibleLogo } from '~components/KonturLogo/KonturLogo';
import { userResourceAtom } from '~core/auth/atoms/userResource';
Expand All @@ -21,6 +16,7 @@ import { AppFeature } from '~core/auth/types';
import { currentApplicationAtom } from '~core/shared_state';
import { initUrlStore } from '~core/url_store';
import s from './views/Main/Main.module.css';
import { ROUTE_PATHS as ROUTES } from './RoutePaths';
import type { UserDataModel } from '~core/auth';
const { MainView } = lazily(() => import('~views/Main/Main'));
const { Reports } = lazily(() => import('~views/Reports/Reports'));
Expand All @@ -29,20 +25,13 @@ const { BivariateManagerPage } = lazily(
() => import('~views/BivariateManager/BivariateManager'),
);

const ROUTES = {
base: config.baseUrl,
reports: config.baseUrl + 'reports',
reportPage: config.baseUrl + 'reports/:reportId',
bivariateManager: config.baseUrl + 'bivariate-manager',
};

export function RoutedApp() {
const [{ data: userModel, loading }] = useAtom(userResourceAtom);
return (
<StrictMode>
<OriginalLogo />

<Router>
<Router history={history}>
<CommonRoutesFeatures userModel={userModel} />
{userModel && !loading && (
<CacheSwitch>
Expand Down Expand Up @@ -184,7 +173,7 @@ const getHeaderTitle = (pathname: string): JSX.Element | string => {

const LinkableTitle = ({ title }: { title: string }) => {
const history = useHistory();
const goBase = () => history.push(config.baseUrl);
const goBase = () => history.push(ROUTES.base);

return (
<Text type="short-l">
Expand Down
15 changes: 15 additions & 0 deletions src/core/apiClientInstance.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import { matchPath } from 'react-router';
import { enableMocking } from '~utils/axios/axiosMockUtils';
import history from '~core/history';
import { setupDefaultLayersMocking } from '~utils/axios/setupTemporaryMocking';
import { ROUTE_PATHS } from '../RoutePaths';
import { ApiClient } from './api_client';
import config from './app_config';
import { i18n } from './localization';
Expand All @@ -12,6 +15,7 @@ ApiClient.init({
loginApiPath: `${config.keycloakUrl}/auth/realms/${config.keycloakRealm}/protocol/openid-connect/token`,
refreshTokenApiPath: `${config.keycloakUrl}/auth/realms/${config.keycloakRealm}/protocol/openid-connect/token`,
translationService: i18n,
unauthorizedCallback: apiClientUnauthorizedCallback,
});
const apiClientInstance = ApiClient.getInstance();

Expand All @@ -38,4 +42,15 @@ ApiClient.init({
translationService: i18n,
});

export function apiClientUnauthorizedCallback() {
if (
matchPath(history.location.pathname, {
path: ROUTE_PATHS.bivariateManager,
exact: true,
})
) {
history.push(config.baseUrl);
}
}

export const reportsClient = ApiClient.getInstance('reports');
1 change: 1 addition & 0 deletions src/core/api_client/apiClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ export class ApiClient {
this.refreshTokenApiPath = refreshTokenApiPath;
this.disableAuth = disableAuth;
this.storage = storage;
this.unauthorizedCallback = unauthorizedCallback;

// Will deleted by terser
if (import.meta?.env?.DEV) {
Expand Down
34 changes: 34 additions & 0 deletions src/core/history.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/**
* @vitest-environment happy-dom
*/
import * as React from 'react';
import { test, expect } from 'vitest';
import sinon from 'sinon';
import history from './history';
import { Router } from 'react-router-dom';
import { useHistory } from 'react-router';
import { fireEvent, render } from '@testing-library/react';

const TestRoute = () => {
const history = useHistory();
return (
<div>
<button onClick={() => history.push('/test')} />
</div>
);
};

test('~core/history obj is used inside <Router> correctly', async () => {
const spy = sinon.spy(history, 'push');

const { getByRole } = render(
<Router history={history}>
<TestRoute />
</Router>,
);

fireEvent.click(getByRole('button'));
expect(spy.callCount).toBe(1);
expect(history.location.pathname).toBe('/test');
spy.restore();
});
2 changes: 2 additions & 0 deletions src/core/history.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
import { createBrowserHistory } from 'history';
export default createBrowserHistory();
2 changes: 2 additions & 0 deletions src/utils/axios/apisauce/apisauce.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ export type PROBLEM_CODE =
| typeof UNKNOWN_ERROR
| typeof CANCEL_ERROR;

const BAD_REQUEST_ERROR_CODES = ['ERR_BAD_REQUEST'];
const TIMEOUT_ERROR_CODES = ['ECONNABORTED'];
const NODEJS_CONNECTION_ERROR_CODES = [
'ENOTFOUND',
Expand Down Expand Up @@ -140,6 +141,7 @@ export const getProblemFromError = (error) => {

// then check the specific error code
if (!error.code) return getProblemFromStatus(error.response.status);
if (BAD_REQUEST_ERROR_CODES.includes(error.code)) return CLIENT_ERROR;
if (TIMEOUT_ERROR_CODES.includes(error.code)) return TIMEOUT_ERROR;
if (NODEJS_CONNECTION_ERROR_CODES.includes(error.code))
return CONNECTION_ERROR;
Expand Down

0 comments on commit 00c9620

Please sign in to comment.