From 5175edb39cb9c518dfc3895847aaad080e07a4f2 Mon Sep 17 00:00:00 2001
From: Piotr Gawron <p.gawron@atcomp.pl>
Date: Fri, 7 Jun 2024 11:27:35 +0200
Subject: [PATCH] add comment

---
 .../AddCommentModal.component.tsx               | 11 ++++++++---
 .../mapRightClick/onMapRightClick.test.ts       |  5 +++--
 .../listeners/mapRightClick/onMapRightClick.ts  | 10 +++++++++-
 .../mapSingleClick/onMapSingleClick.ts          | 10 +++++++++-
 src/redux/apiPath.ts                            |  3 ++-
 src/redux/comment/comment.selectors.ts          |  2 ++
 src/redux/comment/comment.types.ts              |  2 ++
 src/redux/comment/thunks/addComment.ts          | 11 +++++++----
 src/redux/map/map.constants.ts                  | 14 ++++++++++++++
 src/redux/map/map.fixtures.ts                   | 15 +++++++++++++++
 src/redux/map/map.reducers.ts                   | 17 +++++++++++++++++
 src/redux/map/map.slice.ts                      |  6 ++++++
 src/redux/map/map.types.ts                      | 15 +++++++++++++++
 src/redux/models/models.selectors.ts            |  6 ++++++
 14 files changed, 115 insertions(+), 12 deletions(-)

diff --git a/src/components/FunctionalArea/Modal/AddCommentModal/AddCommentModal.component.tsx b/src/components/FunctionalArea/Modal/AddCommentModal/AddCommentModal.component.tsx
index 7d492602..c675aa35 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 2992cfaa..bead3d12 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 2288c0c6..d5d28489 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 cb09d0a5..e04f2880 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 822bce33..680df483 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 7af687a2..bce68955 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 368782e8..8cb0e4b5 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 37afcf2c..8db1cb94 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 70126c71..3b9e9e53 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 be022b69..049bdc64 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 c65bfe97..f193e753 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 46f68b78..3106a118 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 727df76f..72b600dc 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 99d94b76..406e1f3c 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 || '',
-- 
GitLab