diff --git a/src/components/Map/MapViewer/utils/listeners/mapSingleClick/handleFeaturesClick.ts b/src/components/Map/MapViewer/utils/listeners/mapSingleClick/handleFeaturesClick.ts index 7398de2bd42aeb31932767739beb972ed9a36c98..752d65715eb7ec29fc9bb913ac8a12fe72d32a4b 100644 --- a/src/components/Map/MapViewer/utils/listeners/mapSingleClick/handleFeaturesClick.ts +++ b/src/components/Map/MapViewer/utils/listeners/mapSingleClick/handleFeaturesClick.ts @@ -5,6 +5,7 @@ import { AppDispatch } from '@/redux/store'; import { PluginsEventBus } from '@/services/pluginsManager/pluginsEventBus'; import { FeatureLike } from 'ol/Feature'; import { Comment } from '@/types/models'; +import { getCommentElement } from '@/redux/comment/thunks/getComments'; interface HandleFeaturesClickResult { shouldBlockCoordSearch: boolean; @@ -28,15 +29,16 @@ export const handleFeaturesClick = ( } else if (pin.get('type') === FEATURE_TYPE.PIN_ICON_COMMENT) { const filteredComments = comments.filter(comment => comment.id === pinId); if (filteredComments.length > ZERO) { - const comment = filteredComments[ZERO]; - if (comment.type === 'ALIAS') { - dispatch(openBioEntityDrawerById(Number(comment.elementId))); - } else if (comment.type === 'REACTION') { - dispatch(openReactionDrawerById(Number(comment.elementId))); - } else if (comment.type === 'POINT') { + const { elementId, modelId, type } = filteredComments[ZERO]; + if (type === 'ALIAS') { + dispatch(getCommentElement({ elementId: Number(elementId), modelId })); + dispatch(openBioEntityDrawerById(Number(elementId))); + } else if (type === 'REACTION') { + dispatch(openReactionDrawerById(Number(elementId))); + } else if (type === 'POINT') { throw new Error(`Opening point comment is not implemented yet`); } else { - throw new Error(`Unknown comment type${comment.type}`); + throw new Error(`Unknown comment type${type}`); } } else { throw new Error(`Cannot find comment with id ${pinId}`); diff --git a/src/redux/apiPath.ts b/src/redux/apiPath.ts index 77d44039623eda3bb260adbc443ec0a7c28e07da..200b9a56cb1758b3956a06bc6137eac7c67d9d1b 100644 --- a/src/redux/apiPath.ts +++ b/src/redux/apiPath.ts @@ -20,6 +20,8 @@ const getPublicationsURLSearchParams = ( }; export const apiPath = { + getElementById: (elementId: number, modelId: number): string => + `projects/${PROJECT_ID}/models/${modelId}/bioEntities/elements/${elementId}`, getBioEntityContentsStringWithQuery: ({ searchQuery, isPerfectMatch, diff --git a/src/redux/bioEntity/bioEntity.selectors.ts b/src/redux/bioEntity/bioEntity.selectors.ts index ea4d544415b41e42bc602d9ca29d427b1883ea26..cdf19b29fc0214183d7318f6628e42acb2d7a9bb 100644 --- a/src/redux/bioEntity/bioEntity.selectors.ts +++ b/src/redux/bioEntity/bioEntity.selectors.ts @@ -1,10 +1,11 @@ -import { ONE, SIZE_OF_EMPTY_ARRAY, ZERO } from '@/constants/common'; import { rootSelector } from '@/redux/root/root.selectors'; +import { ONE, SIZE_OF_EMPTY_ARRAY, ZERO } from '@/constants/common'; import { BioEntityWithPinType } from '@/types/bioEntity'; import { ElementIdTabObj } from '@/types/elements'; import { MultiSearchData } from '@/types/fetchDataState'; import { BioEntity, BioEntityContent, MapModel } from '@/types/models'; import { createSelector } from '@reduxjs/toolkit'; +import { commentElementSelector } from '@/redux/comment/comment.selectors'; import { allChemicalsBioEntitesOfAllMapsSelector, allChemicalsBioEntitesOfCurrentMapSelector, @@ -256,9 +257,18 @@ export const allBioEntitiesElementsIdsSelector = createSelector( export const currentDrawerBioEntitySelector = createSelector( allBioEntitiesSelector, + commentElementSelector, currentSearchedBioEntityId, - (bioEntities, currentBioEntityId): BioEntity | undefined => - bioEntities.find(({ id }) => id === currentBioEntityId), + (bioEntities, commentElement, currentBioEntityId): BioEntity | undefined => { + // eslint-disable-next-line no-console + console.log(currentBioEntityId); + // eslint-disable-next-line no-console + console.log(commentElement); + if (commentElement && commentElement.id === currentBioEntityId) { + return commentElement; + } + return bioEntities.find(({ id }) => id === currentBioEntityId); + }, ); export const currentDrawerBioEntityRelatedSubmapSelector = createSelector( diff --git a/src/redux/comment/comment.constants.ts b/src/redux/comment/comment.constants.ts index 36914070334299cf7d027a2e225937c3a0f43d7d..b0600d4b22357af89486c357768c145e5d369145 100644 --- a/src/redux/comment/comment.constants.ts +++ b/src/redux/comment/comment.constants.ts @@ -12,4 +12,5 @@ export const COMMENT_INITIAL_STATE: CommentsState = { loading: 'idle', error: { name: '', message: '' }, isOpen: false, + commentElement: null, }; diff --git a/src/redux/comment/comment.mock.ts b/src/redux/comment/comment.mock.ts index e84f898da65376f1950279ff87e2c19366b8b148..0320d9aa45e4e24354a03d5c173486ea0136e0ef 100644 --- a/src/redux/comment/comment.mock.ts +++ b/src/redux/comment/comment.mock.ts @@ -6,4 +6,5 @@ export const COMMENT_INITIAL_STATE_MOCK: CommentsState = { loading: 'idle', error: DEFAULT_ERROR, isOpen: false, + commentElement: null, }; diff --git a/src/redux/comment/comment.reducers.ts b/src/redux/comment/comment.reducers.ts index df94d01485e1418dd595333e2955a5a47c5466de..c06fe01dc894f10bb7cba6304b05422d48ba50ba 100644 --- a/src/redux/comment/comment.reducers.ts +++ b/src/redux/comment/comment.reducers.ts @@ -1,6 +1,6 @@ import { ActionReducerMapBuilder } from '@reduxjs/toolkit'; import { CommentsState } from '@/redux/comment/comment.types'; -import { getComments } from '@/redux/comment/thunks/getComments'; +import { getCommentElement, getComments } from '@/redux/comment/thunks/getComments'; export const getCommentsReducer = (builder: ActionReducerMapBuilder<CommentsState>): void => { builder.addCase(getComments.pending, state => { @@ -17,6 +17,23 @@ export const getCommentsReducer = (builder: ActionReducerMapBuilder<CommentsStat }); }; +export const getCommentElementReducer = (builder: ActionReducerMapBuilder<CommentsState>): void => { + builder.addCase(getCommentElement.pending, state => { + state.loading = 'pending'; + state.commentElement = null; + }); + + builder.addCase(getCommentElement.fulfilled, (state, action) => { + state.loading = 'succeeded'; + state.commentElement = action.payload; + }); + + builder.addCase(getCommentElement.rejected, state => { + state.loading = 'failed'; + state.commentElement = null; + }); +}; + export const showCommentsReducer = (state: CommentsState): void => { state.isOpen = true; }; diff --git a/src/redux/comment/comment.selectors.ts b/src/redux/comment/comment.selectors.ts index 975e7139c52043c67234f2e5dc04306d41a4b6b7..da477218a8abbd104b45d147db70be1764403128 100644 --- a/src/redux/comment/comment.selectors.ts +++ b/src/redux/comment/comment.selectors.ts @@ -5,6 +5,11 @@ import { currentModelIdSelector } from '../models/models.selectors'; export const commentSelector = createSelector(rootSelector, state => state.comment); +export const commentElementSelector = createSelector( + commentSelector, + commentState => commentState.commentElement, +); + export const allCommentsSelectorOfCurrentMap = createSelector( commentSelector, currentModelIdSelector, diff --git a/src/redux/comment/comment.slice.ts b/src/redux/comment/comment.slice.ts index 2910a8727ddb8600ed1123571388441ef5a37cab..355346881a01417d7e777cf0b3fd496bd41badb2 100644 --- a/src/redux/comment/comment.slice.ts +++ b/src/redux/comment/comment.slice.ts @@ -1,6 +1,7 @@ import { createSlice } from '@reduxjs/toolkit'; import { COMMENT_INITIAL_STATE } from '@/redux/comment/comment.constants'; import { + getCommentElementReducer, getCommentsReducer, hideCommentsReducer, showCommentsReducer, @@ -15,6 +16,7 @@ export const commentsSlice = createSlice({ }, extraReducers: builder => { getCommentsReducer(builder); + getCommentElementReducer(builder); }, }); diff --git a/src/redux/comment/comment.types.ts b/src/redux/comment/comment.types.ts index b3ad54a431fd7a43fa9737bc6e7d6029968b81e3..f8d9648b02bbb1fc49da49d57dfd9e74e32c49c7 100644 --- a/src/redux/comment/comment.types.ts +++ b/src/redux/comment/comment.types.ts @@ -1,10 +1,16 @@ import { FetchDataState } from '@/types/fetchDataState'; -import { Comment } from '@/types/models'; +import { BioEntity, Comment } from '@/types/models'; import { PayloadAction } from '@reduxjs/toolkit'; export interface CommentsState extends FetchDataState<Comment[], []> { isOpen: boolean; + commentElement: BioEntity | null; } export type OpenCommentByIdPayload = number | string; export type OpenCommentByIdAction = PayloadAction<OpenCommentByIdPayload>; + +export type GetElementProps = { + elementId: number; + modelId: number; +}; diff --git a/src/redux/comment/thunks/getComments.ts b/src/redux/comment/thunks/getComments.ts index 5bc9013c661cc45207280e260897cc346d9f6b23..663bca4eb8f85f3e8fa2fdd8197396b53a8bf470 100644 --- a/src/redux/comment/thunks/getComments.ts +++ b/src/redux/comment/thunks/getComments.ts @@ -1,11 +1,13 @@ import { commentSchema } from '@/models/commentSchema'; import { apiPath } from '@/redux/apiPath'; -import { axiosInstance } from '@/services/api/utils/axiosInstance'; +import { axiosInstance, axiosInstanceNewAPI } from '@/services/api/utils/axiosInstance'; import { ThunkConfig } from '@/types/store'; import { validateDataUsingZodSchema } from '@/utils/validateDataUsingZodSchema'; import { createAsyncThunk } from '@reduxjs/toolkit'; -import { Comment } from '@/types/models'; +import { BioEntity, Comment } from '@/types/models'; import { z } from 'zod'; +import { bioEntitySchema } from '@/models/bioEntitySchema'; +import { GetElementProps } from '@/redux/comment/comment.types'; export const getComments = createAsyncThunk<Comment[], void, ThunkConfig>( 'project/getComments', @@ -21,3 +23,20 @@ export const getComments = createAsyncThunk<Comment[], void, ThunkConfig>( } }, ); + +export const getCommentElement = createAsyncThunk<BioEntity | null, GetElementProps, ThunkConfig>( + 'project/getCommentElement', + async ({ elementId, modelId }) => { + try { + const response = await axiosInstanceNewAPI.get<BioEntity>( + apiPath.getElementById(elementId, modelId), + ); + + const isDataValid = validateDataUsingZodSchema(response.data, bioEntitySchema); + + return isDataValid ? response.data : null; + } catch (error) { + return Promise.reject(error); + } + }, +);