Skip to content
Snippets Groups Projects
Commit 5175edb3 authored by Piotr Gawron's avatar Piotr Gawron
Browse files

add comment

parent 8e5adaf5
No related branches found
No related tags found
2 merge requests!223reset the pin numbers before search results are fetch (so the results will be...,!202Resolve "[MIN-264] Right click - Add comment"
Showing
with 115 additions and 12 deletions
......@@ -5,14 +5,19 @@ import React from 'react';
import { addComment } from '@/redux/comment/thunks/addComment';
import { useAppSelector } from '@/redux/hooks/useAppSelector';
import { currentModelIdSelector } from '@/redux/models/models.selectors';
import { lastRightClickSelector } from '@/redux/models/models.selectors';
import { closeModal } from '@/redux/modal/modal.slice';
export const AddCommentModal: React.FC = () => {
const dispatch = useAppDispatch();
const modelId = useAppSelector(currentModelIdSelector);
const lastClick = useAppSelector(lastRightClickSelector);
const [data, setData] = React.useState({ email: '', content: '', modelId });
const [data, setData] = React.useState({
email: '',
content: '',
modelId: lastClick.modelId,
position: lastClick.position,
});
const handleChange = (e: React.ChangeEvent<HTMLInputElement>): void => {
const { name, value } = e.target;
......
......@@ -8,7 +8,7 @@ import {
ELEMENT_SEARCH_RESULT_MOCK_REACTION,
} from '@/models/mocks/elementSearchResultMock';
import { waitFor } from '@testing-library/react';
import { FIRST_ARRAY_ELEMENT, SIZE_OF_EMPTY_ARRAY } from '@/constants/common';
import { FIRST_ARRAY_ELEMENT, SECOND_ARRAY_ELEMENT, SIZE_OF_EMPTY_ARRAY } from '@/constants/common';
import { onMapRightClick } from './onMapRightClick';
import * as handleDataReset from '../mapSingleClick/handleDataReset';
import * as handleSearchResultForRightClickAction from './handleSearchResultForRightClickAction';
......@@ -58,7 +58,8 @@ describe('onMapRightClick - util', () => {
it('should fire open context menu handler', async () => {
const actions = store.getActions();
expect(actions.length).toBeGreaterThan(SIZE_OF_EMPTY_ARRAY);
expect(actions[FIRST_ARRAY_ELEMENT].type).toEqual('contextMenu/openContextMenu');
expect(actions[FIRST_ARRAY_ELEMENT].type).toEqual('map/updateLastRightClick');
expect(actions[SECOND_ARRAY_ELEMENT].type).toEqual('contextMenu/openContextMenu');
});
});
......
import { SIZE_OF_EMPTY_ARRAY } from '@/constants/common';
import { openContextMenu } from '@/redux/contextMenu/contextMenu.slice';
import { SIZE_OF_EMPTY_ARRAY } from '@/constants/common';
import { MapSize } from '@/redux/map/map.types';
import { AppDispatch } from '@/redux/store';
import { Coordinate } from 'ol/coordinate';
import { Pixel } from 'ol/pixel';
import { updateLastRightClick } from '@/redux/map/map.slice';
import { toLonLat } from 'ol/proj';
import { latLngToPoint } from '@/utils/map/latLngToPoint';
import { getSearchResults } from '../mapSingleClick/getSearchResults';
import { handleDataReset } from '../mapSingleClick/handleDataReset';
import { handleSearchResultForRightClickAction } from './handleSearchResultForRightClickAction';
......@@ -11,6 +14,11 @@ import { handleSearchResultForRightClickAction } from './handleSearchResultForRi
/* prettier-ignore */
export const onMapRightClick =
(mapSize: MapSize, modelId: number, dispatch: AppDispatch) => async (coordinate: Coordinate, pixel: Pixel): Promise<void> => {
const [lng, lat] = toLonLat(coordinate);
const point = latLngToPoint([lat, lng], mapSize);
dispatch(updateLastRightClick({coordinates:point, modelId}));
dispatch(handleDataReset);
dispatch(openContextMenu(pixel));
......
......@@ -4,6 +4,9 @@ import { AppDispatch } from '@/redux/store';
import { Map, MapBrowserEvent } from 'ol';
import { FeatureLike } from 'ol/Feature';
import { Comment } from '@/types/models';
import { updateLastClick } from '@/redux/map/map.slice';
import { toLonLat } from 'ol/proj';
import { latLngToPoint } from '@/utils/map/latLngToPoint';
import { getSearchResults } from './getSearchResults';
import { handleDataReset } from './handleDataReset';
import { handleFeaturesClick } from './handleFeaturesClick';
......@@ -14,6 +17,11 @@ export const onMapSingleClick =
(mapSize: MapSize, modelId: number, dispatch: AppDispatch, searchDistance: string | undefined, maxZoom: number, zoom: number, isResultDrawerOpen: boolean,
comments: Comment[]) =>
async ({ coordinate, pixel }: Pick<MapBrowserEvent<UIEvent>, 'coordinate' | 'pixel'>, mapInstance: Map): Promise<void> => {
const [lng, lat] = toLonLat(coordinate);
const point = latLngToPoint([lat, lng], mapSize);
dispatch(updateLastClick({coordinates:point, modelId}));
const featuresAtPixel: FeatureLike[] = [];
mapInstance.forEachFeatureAtPixel(pixel, (feature) => featuresAtPixel.push(feature));
const { shouldBlockCoordSearch } = handleFeaturesClick(featuresAtPixel, dispatch, comments);
......@@ -26,7 +34,7 @@ export const onMapSingleClick =
// so we need to reset all the data before updating
dispatch(handleDataReset);
const {searchResults, point} = await getSearchResults({ coordinate, mapSize, modelId });
const {searchResults} = await getSearchResults({ coordinate, mapSize, modelId });
if (!searchResults || searchResults.length === SIZE_OF_EMPTY_ARRAY) {
return;
}
......
......@@ -99,5 +99,6 @@ export const apiPath = {
logout: (): string => `doLogout`,
userPrivileges: (login: string): string => `users/${login}?columns=privileges`,
getComments: (): string => `projects/${PROJECT_ID}/comments/models/*/`,
addComment: (modelId: number): string => `projects/${PROJECT_ID}/comments/models/${modelId}/`,
addComment: (modelId: number, x: number, y: number): string =>
`projects/${PROJECT_ID}/comments/models/${modelId}/points/${x},${y}/`,
};
......@@ -23,6 +23,8 @@ export const allCommentsSelectorOfCurrentMap = createSelector(
return [];
}
// eslint-disable-next-line no-console
console.log(commentState.data);
return (commentState.data || [])
.filter(comment => comment.modelId === currentModelId)
.map(comment => {
......
import { FetchDataState } from '@/types/fetchDataState';
import { BioEntity, Comment, Reaction } from '@/types/models';
import { PayloadAction } from '@reduxjs/toolkit';
import { Point } from '@/types/map';
export interface CommentsState extends FetchDataState<Comment[], []> {
isOpen: boolean;
......@@ -20,4 +21,5 @@ export type AddCommentProps = {
email: string;
content: string;
modelId: number;
position: Point;
};
......@@ -8,11 +8,14 @@ import { Comment } from '@/types/models';
import { AddCommentProps } from '@/redux/comment/comment.types';
export const addComment = createAsyncThunk<Comment | null, AddCommentProps, ThunkConfig>(
'project/getComments',
async ({ email, content, modelId }) => {
'project/addComment',
async ({ email, content, modelId, position }) => {
try {
const payload = { email, content };
const response = await axiosInstance.post<Comment>(apiPath.addComment(modelId), payload);
const payload = new URLSearchParams({ email, content });
const response = await axiosInstance.post<Comment>(
apiPath.addComment(modelId, Math.trunc(position.x), Math.trunc(position.y)),
payload,
);
const isDataValid = validateDataUsingZodSchema(response.data, commentSchema);
......
......@@ -39,6 +39,20 @@ export const MAP_DATA_INITIAL_STATE: MapData = {
minZoom: DEFAULT_MIN_ZOOM,
maxZoom: DEFAULT_MAX_ZOOM,
},
lastClick: {
modelId: MODEL_ID_DEFAULT,
position: {
x: 0,
y: 0,
},
},
lastRightClick: {
modelId: MODEL_ID_DEFAULT,
position: {
x: 0,
y: 0,
},
},
};
export const DEFAULT_POSITION: Point = { x: 0, y: 0, z: 0 };
......
import { DEFAULT_ERROR } from '@/constants/errors';
import { MODEL_ID_DEFAULT } from '@/redux/map/map.constants';
import { MapData, MapState, OppenedMap } from './map.types';
export const openedMapsInitialValueFixture: OppenedMap[] = [
......@@ -32,6 +33,20 @@ export const initialMapDataFixture: MapData = {
minZoom: 2,
maxZoom: 9,
},
lastClick: {
modelId: MODEL_ID_DEFAULT,
position: {
x: 0,
y: 0,
},
},
lastRightClick: {
modelId: MODEL_ID_DEFAULT,
position: {
x: 0,
y: 0,
},
},
};
export const initialMapStateFixture: MapState = {
......
......@@ -15,6 +15,7 @@ import {
OpenMapAndSetActiveAction,
SetActiveMapAction,
SetBackgroundAction,
SetLastClickPositionAction,
SetLastPositionZoomAction,
SetLastPositionZoomWithDeltaAction,
SetMapDataAction,
......@@ -100,6 +101,22 @@ export const setLastPositionZoomReducer = (
state.data.position.initial.z = zoom;
};
export const updateLastClickReducer = (
state: MapState,
action: SetLastClickPositionAction,
): void => {
state.data.lastClick.modelId = action.payload.modelId;
state.data.lastClick.position = action.payload.coordinates;
};
export const updateLastRightClickReducer = (
state: MapState,
action: SetLastClickPositionAction,
): void => {
state.data.lastRightClick.modelId = action.payload.modelId;
state.data.lastRightClick.position = action.payload.coordinates;
};
const updateLastPositionOfCurrentlyActiveMap = (state: MapState): void => {
const currentMapId = state.data.modelId;
const currentOpenedMap = state.openedMaps.find(openedMap => openedMap.modelId === currentMapId);
......
......@@ -14,6 +14,8 @@ import {
setMapBackgroundReducer,
setMapDataReducer,
setMapPositionReducer,
updateLastClickReducer,
updateLastRightClickReducer,
varyPositionZoomReducer,
} from './map.reducers';
......@@ -31,6 +33,8 @@ const mapSlice = createSlice({
setMapBackground: setMapBackgroundReducer,
openMapAndOrSetActiveIfSelected: openMapAndOrSetActiveIfSelectedReducer,
setLastPositionZoom: setLastPositionZoomReducer,
updateLastClick: updateLastClickReducer,
updateLastRightClick: updateLastRightClickReducer,
},
extraReducers: builder => {
initMapPositionReducers(builder);
......@@ -51,6 +55,8 @@ export const {
varyPositionZoom,
openMapAndOrSetActiveIfSelected,
setLastPositionZoom,
updateLastClick,
updateLastRightClick,
} = mapSlice.actions;
export default mapSlice.reducer;
......@@ -30,6 +30,14 @@ export type MapData = {
overlaysIds: number[];
size: MapSize;
position: Position;
lastClick: {
position: Point;
modelId: number;
};
lastRightClick: {
position: Point;
modelId: number;
};
show: {
legend: boolean;
comments: boolean;
......@@ -101,6 +109,13 @@ export type SetLastPositionZoomActionPayload = {
export type SetLastPositionZoomAction = PayloadAction<SetLastPositionZoomActionPayload>;
export type SetLastClickPositionActionPayload = {
modelId: number;
coordinates: Point;
};
export type SetLastClickPositionAction = PayloadAction<SetLastClickPositionActionPayload>;
export type InitMapDataActionPayload = {
data: GetUpdatedMapDataResult | object;
openedMaps: OppenedMap[];
......
......@@ -33,6 +33,12 @@ export const currentModelIdSelector = createSelector(
model => model?.idObject || MODEL_ID_DEFAULT,
);
export const lastClickSelector = createSelector(mapDataSelector, mapData => mapData.lastClick);
export const lastRightClickSelector = createSelector(
mapDataSelector,
mapData => mapData.lastRightClick,
);
export const currentModelNameSelector = createSelector(
currentModelSelector,
model => model?.name || '',
......
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