diff --git a/src/components/FunctionalArea/Modal/AddCommentModal/AddCommentModal.component.tsx b/src/components/FunctionalArea/Modal/AddCommentModal/AddCommentModal.component.tsx index 7d4926025e73ab8674dd60f74de1f6782d7b3ab6..c675aa354aef3381408987e8b8cac22e4512a253 100644 --- a/src/components/FunctionalArea/Modal/AddCommentModal/AddCommentModal.component.tsx +++ b/src/components/FunctionalArea/Modal/AddCommentModal/AddCommentModal.component.tsx @@ -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; diff --git a/src/components/Map/MapViewer/utils/listeners/mapRightClick/onMapRightClick.test.ts b/src/components/Map/MapViewer/utils/listeners/mapRightClick/onMapRightClick.test.ts index 2992cfaae4300662cfb1b64fdfe74295738a29cc..bead3d12015b534bd89e5f5cc0beff50f93caeae 100644 --- a/src/components/Map/MapViewer/utils/listeners/mapRightClick/onMapRightClick.test.ts +++ b/src/components/Map/MapViewer/utils/listeners/mapRightClick/onMapRightClick.test.ts @@ -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'); }); }); diff --git a/src/components/Map/MapViewer/utils/listeners/mapRightClick/onMapRightClick.ts b/src/components/Map/MapViewer/utils/listeners/mapRightClick/onMapRightClick.ts index 2288c0c6deb6bedef430c00b506fbd67ff5c7fe8..d5d284892aeb7aeff9b263df4d8db19e93d50dfb 100644 --- a/src/components/Map/MapViewer/utils/listeners/mapRightClick/onMapRightClick.ts +++ b/src/components/Map/MapViewer/utils/listeners/mapRightClick/onMapRightClick.ts @@ -1,9 +1,12 @@ -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)); diff --git a/src/components/Map/MapViewer/utils/listeners/mapSingleClick/onMapSingleClick.ts b/src/components/Map/MapViewer/utils/listeners/mapSingleClick/onMapSingleClick.ts index cb09d0a5bccf2493ae96b6361ca3e5921ee8e9ef..e04f2880a546ad753225e2301de34487753f3c53 100644 --- a/src/components/Map/MapViewer/utils/listeners/mapSingleClick/onMapSingleClick.ts +++ b/src/components/Map/MapViewer/utils/listeners/mapSingleClick/onMapSingleClick.ts @@ -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; } diff --git a/src/redux/apiPath.ts b/src/redux/apiPath.ts index 822bce33141d58cb143a4658702d22541b8ba9db..680df4831e694e16ae91944fcf547065d059bb6e 100644 --- a/src/redux/apiPath.ts +++ b/src/redux/apiPath.ts @@ -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}/`, }; diff --git a/src/redux/comment/comment.selectors.ts b/src/redux/comment/comment.selectors.ts index 7af687a21dc94636d189bb663aba5750e9b7d20a..bce68955c250678337e8036e1ac033f5574b38c5 100644 --- a/src/redux/comment/comment.selectors.ts +++ b/src/redux/comment/comment.selectors.ts @@ -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 => { diff --git a/src/redux/comment/comment.types.ts b/src/redux/comment/comment.types.ts index 368782e8fbf8d5f7c2c0dc117e7eb4e39ae4c606..8cb0e4b59872fc53a0ddeb147b506628abf4f1af 100644 --- a/src/redux/comment/comment.types.ts +++ b/src/redux/comment/comment.types.ts @@ -1,6 +1,7 @@ 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; }; diff --git a/src/redux/comment/thunks/addComment.ts b/src/redux/comment/thunks/addComment.ts index 37afcf2c86fe6b9b8a7eaa80f558f19a79339e20..8db1cb940d7f91a1f0e7583488d77d20e8704539 100644 --- a/src/redux/comment/thunks/addComment.ts +++ b/src/redux/comment/thunks/addComment.ts @@ -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); diff --git a/src/redux/map/map.constants.ts b/src/redux/map/map.constants.ts index 70126c71e6dbd43d510b1662096b9178d20452f1..3b9e9e530e5ee7b93e2c5e7141b7d79b74ab72fc 100644 --- a/src/redux/map/map.constants.ts +++ b/src/redux/map/map.constants.ts @@ -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 }; diff --git a/src/redux/map/map.fixtures.ts b/src/redux/map/map.fixtures.ts index be022b6972ad0c42f4ff1c7c9e2c95351f47af4e..049bdc645285fcfcaa89883d21fe85fd86f6884e 100644 --- a/src/redux/map/map.fixtures.ts +++ b/src/redux/map/map.fixtures.ts @@ -1,4 +1,5 @@ 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 = { diff --git a/src/redux/map/map.reducers.ts b/src/redux/map/map.reducers.ts index c65bfe9746acc4cd2197cab5200fc891066ba834..f193e7536e94936d2662d7bb69f102f2149f569c 100644 --- a/src/redux/map/map.reducers.ts +++ b/src/redux/map/map.reducers.ts @@ -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); diff --git a/src/redux/map/map.slice.ts b/src/redux/map/map.slice.ts index 46f68b78379b43eea92e3897455d4ddd82f5668b..3106a118eaa14cdcc373ea0366b74c53e121dffb 100644 --- a/src/redux/map/map.slice.ts +++ b/src/redux/map/map.slice.ts @@ -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; diff --git a/src/redux/map/map.types.ts b/src/redux/map/map.types.ts index 727df76f71b29da80f9690edcc3e9e86c9888d12..72b600dcf1a42cc08ea329d65d82144db088abaa 100644 --- a/src/redux/map/map.types.ts +++ b/src/redux/map/map.types.ts @@ -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[]; diff --git a/src/redux/models/models.selectors.ts b/src/redux/models/models.selectors.ts index 99d94b7648a22f1d07d77ac63cdf69592d55c0f9..406e1f3c28623f2cff51abac303dd841016fb30b 100644 --- a/src/redux/models/models.selectors.ts +++ b/src/redux/models/models.selectors.ts @@ -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 || '',