Skip to content
Snippets Groups Projects
Commit 793ecb9b authored by Miłosz Grocholewski's avatar Miłosz Grocholewski
Browse files

feat(vector-map): add spinner when diagram is loading

parent 68d6ca25
No related branches found
No related tags found
1 merge request!314feat(vector-map): add spinner when diagram is loading
......@@ -2,6 +2,7 @@
import { Drawer } from '@/components/Map/Drawer';
import { Legend } from '@/components/Map/Legend';
import { MapViewer } from '@/components/Map/MapViewer';
import { MapLoader } from '@/components/Map/MapLoader/MapLoader.component';
import { MapAdditionalActions } from './MapAdditionalActions';
import { MapAdditionalOptions } from './MapAdditionalOptions';
import { PluginsDrawer } from './PluginsDrawer';
......@@ -18,6 +19,7 @@ export const Map = (): JSX.Element => {
<PluginsDrawer />
<Legend />
<MapAdditionalActions />
<MapLoader />
</div>
);
};
import React from 'react';
import { render, screen } from '@testing-library/react';
import {
getReduxWrapperWithStore,
InitialStoreState,
} from '@/utils/testing/getReduxWrapperWithStore';
import { StoreType } from '@/redux/store';
import { useAppSelector } from '@/redux/hooks/useAppSelector';
import { newReactionsLoadingSelector } from '@/redux/newReactions/newReactions.selectors';
import { modelElementsLoadingSelector } from '@/redux/modelElements/modelElements.selector';
import { isDrawerOpenSelector } from '@/redux/drawer/drawer.selectors';
import { vectorRenderingSelector } from '@/redux/models/models.selectors';
import {
arrowTypesLoadingSelector,
bioShapesLoadingSelector,
lineTypesLoadingSelector,
} from '@/redux/shapes/shapes.selectors';
import { layersLoadingSelector } from '@/redux/layers/layers.selectors';
import { MapLoader } from './MapLoader.component';
jest.mock('../../../redux/hooks/useAppSelector', () => ({
useAppSelector: jest.fn(),
}));
type SelectorFunction = (state: never) => string | boolean;
const renderComponent = (initialStore?: InitialStoreState): { store: StoreType } => {
const { Wrapper, store } = getReduxWrapperWithStore(initialStore);
return (
render(
<Wrapper>
<MapLoader />
</Wrapper>,
),
{
store,
}
);
};
describe('MapLoader', () => {
const mockUseAppSelector = useAppSelector as jest.Mock;
afterEach(() => {
jest.clearAllMocks();
});
it('should not render the LoadingIndicator when no data is loading', () => {
mockUseAppSelector.mockImplementation(selector => {
const selectorMap = new Map<SelectorFunction, string | boolean>([
[newReactionsLoadingSelector, 'succeeded'],
[modelElementsLoadingSelector, 'succeeded'],
[vectorRenderingSelector, true],
[bioShapesLoadingSelector, 'succeeded'],
[lineTypesLoadingSelector, 'succeeded'],
[arrowTypesLoadingSelector, 'succeeded'],
[layersLoadingSelector, 'succeeded'],
[isDrawerOpenSelector, false],
]);
return selectorMap.get(selector) ?? false;
});
renderComponent();
expect(screen.queryByTestId('loading-indicator')).not.toBeInTheDocument();
});
it('should render the LoadingIndicator when vectorRendering is true and data is loading', () => {
mockUseAppSelector.mockImplementation(selector => {
const selectorMap = new Map<SelectorFunction, string | boolean>([
[newReactionsLoadingSelector, 'pending'],
[modelElementsLoadingSelector, 'succeeded'],
[vectorRenderingSelector, true],
[bioShapesLoadingSelector, 'succeeded'],
[lineTypesLoadingSelector, 'succeeded'],
[arrowTypesLoadingSelector, 'succeeded'],
[layersLoadingSelector, 'succeeded'],
[isDrawerOpenSelector, false],
]);
return selectorMap.get(selector) ?? false;
});
renderComponent();
expect(screen.queryByTestId('loading-indicator')).toBeInTheDocument();
});
it('should not render the LoadingIndicator when vectorRendering is false even when data is loading', () => {
mockUseAppSelector.mockImplementation(selector => {
const selectorMap = new Map<SelectorFunction, string | boolean>([
[newReactionsLoadingSelector, 'pending'],
[modelElementsLoadingSelector, 'succeeded'],
[vectorRenderingSelector, false],
[bioShapesLoadingSelector, 'succeeded'],
[lineTypesLoadingSelector, 'succeeded'],
[arrowTypesLoadingSelector, 'succeeded'],
[layersLoadingSelector, 'succeeded'],
[isDrawerOpenSelector, false],
]);
return selectorMap.get(selector) ?? false;
});
renderComponent();
expect(screen.queryByTestId('loading-indicator')).not.toBeInTheDocument();
});
});
import { LoadingIndicator } from '@/shared/LoadingIndicator';
import { useMemo } from 'react';
import { newReactionsLoadingSelector } from '@/redux/newReactions/newReactions.selectors';
import { modelElementsLoadingSelector } from '@/redux/modelElements/modelElements.selector';
import { vectorRenderingSelector } from '@/redux/models/models.selectors';
import {
arrowTypesLoadingSelector,
bioShapesLoadingSelector,
lineTypesLoadingSelector,
} from '@/redux/shapes/shapes.selectors';
import { layersLoadingSelector } from '@/redux/layers/layers.selectors';
import './MapLoader.styles.css';
import { isDrawerOpenSelector } from '@/redux/drawer/drawer.selectors';
import { useAppSelector } from '@/redux/hooks/useAppSelector';
export const MapLoader = (): JSX.Element => {
const reactionsFetching = useAppSelector(newReactionsLoadingSelector);
const modelElementsFetching = useAppSelector(modelElementsLoadingSelector);
const vectorRendering = useAppSelector(vectorRenderingSelector);
const bioShapesFetching = useAppSelector(bioShapesLoadingSelector);
const lineTypesFetching = useAppSelector(lineTypesLoadingSelector);
const arrowTypesFetching = useAppSelector(arrowTypesLoadingSelector);
const layersLoading = useAppSelector(layersLoadingSelector);
const isDrawerOpen = useAppSelector(isDrawerOpenSelector);
const showLoader = useMemo(() => {
return [
reactionsFetching,
modelElementsFetching,
bioShapesFetching,
lineTypesFetching,
arrowTypesFetching,
layersLoading,
].includes('pending');
}, [
reactionsFetching,
modelElementsFetching,
bioShapesFetching,
lineTypesFetching,
arrowTypesFetching,
layersLoading,
]);
return (
<div className={`map-loader transition-all duration-500 ${isDrawerOpen ? 'move-right' : ''}`}>
{vectorRendering && showLoader && <LoadingIndicator width={48} height={48} />}
</div>
);
};
.map-loader {
position: absolute;
left: 120px;
top: 128px;
}
.map-loader.move-right {
left: 550px;
}
......@@ -62,8 +62,10 @@ export const useOlMapReactionsLayer = ({
const pointToProjection = usePointToProjection();
useEffect(() => {
dispatch(getModelElements(currentModelId));
dispatch(getNewReactions(currentModelId));
if (currentModelId) {
dispatch(getModelElements(currentModelId));
dispatch(getNewReactions(currentModelId));
}
}, [currentModelId, dispatch]);
const groupedElementsOverlays = useMemo(() => {
......
......@@ -474,6 +474,7 @@ export const CORE_PD_MODEL_MOCK: MapModel = {
modificationDates: [],
minZoom: 2,
maxZoom: 9,
vectorRendering: true,
};
export const MODEL_WITH_DESCRIPTION: MapModel = {
......
......@@ -6,6 +6,8 @@ export const layersSelector = createSelector(
state => state.layers?.data?.layers || [],
);
export const layersLoadingSelector = createSelector(rootSelector, state => state.layers.loading);
export const layersVisibilitySelector = createSelector(
rootSelector,
state => state.layers?.data?.layersVisibility || {},
......
......@@ -5,3 +5,8 @@ export const modelElementsSelector = createSelector(
rootSelector,
state => state.modelElements.data,
);
export const modelElementsLoadingSelector = createSelector(
rootSelector,
state => state.modelElements.loading,
);
......@@ -3,6 +3,11 @@ import { rootSelector } from '../root/root.selectors';
export const newReactionsSelector = createSelector(rootSelector, state => state.newReactions);
export const newReactionsLoadingSelector = createSelector(
newReactionsSelector,
state => state.loading,
);
export const newReactionsDataSelector = createSelector(
newReactionsSelector,
reactions => reactions.data || [],
......
......@@ -8,12 +8,27 @@ export const bioShapesSelector = createSelector(
shapes => shapes.bioShapesState.data,
);
export const bioShapesLoadingSelector = createSelector(
shapesSelector,
shapes => shapes.bioShapesState.loading,
);
export const lineTypesSelector = createSelector(
shapesSelector,
shapes => shapes.lineTypesState.data || {},
);
export const lineTypesLoadingSelector = createSelector(
shapesSelector,
shapes => shapes.lineTypesState.loading,
);
export const arrowTypesSelector = createSelector(
shapesSelector,
shapes => shapes.arrowTypesState.data || {},
);
export const arrowTypesLoadingSelector = createSelector(
shapesSelector,
shapes => shapes.arrowTypesState.loading,
);
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment