diff --git a/src/components/FunctionalArea/Modal/EditOverlayGroupModal/EditOverlayGroupModal.component.test.tsx b/src/components/FunctionalArea/Modal/EditOverlayGroupModal/EditOverlayGroupModal.component.test.tsx index 1f019a3935e5d7156b45f605cb0a33ad3d7d2154..c96ff7ee872ec2911fd37fd8f1f921aadb310f3f 100644 --- a/src/components/FunctionalArea/Modal/EditOverlayGroupModal/EditOverlayGroupModal.component.test.tsx +++ b/src/components/FunctionalArea/Modal/EditOverlayGroupModal/EditOverlayGroupModal.component.test.tsx @@ -54,10 +54,7 @@ describe('EditOverlayModal - component', () => { overviewImagesState: {}, errorReportState: {}, layerFactoryState: { id: undefined }, - layerImageObjectFactoryState: undefined, - layerTextFactoryState: undefined, - layerRectFactoryState: undefined, - layerOvalFactoryState: undefined, + layerObjectFactoryState: undefined, }, }); @@ -78,10 +75,7 @@ describe('EditOverlayModal - component', () => { overviewImagesState: {}, errorReportState: {}, layerFactoryState: { id: undefined }, - layerImageObjectFactoryState: undefined, - layerTextFactoryState: undefined, - layerRectFactoryState: undefined, - layerOvalFactoryState: undefined, + layerObjectFactoryState: undefined, }, }); @@ -115,10 +109,7 @@ describe('EditOverlayModal - component', () => { overviewImagesState: {}, errorReportState: {}, layerFactoryState: { id: undefined }, - layerImageObjectFactoryState: undefined, - layerTextFactoryState: undefined, - layerRectFactoryState: undefined, - layerOvalFactoryState: undefined, + layerObjectFactoryState: undefined, }, overlays: OVERLAYS_INITIAL_STATE_MOCK, }); @@ -164,10 +155,7 @@ describe('EditOverlayModal - component', () => { overviewImagesState: {}, errorReportState: {}, layerFactoryState: { id: undefined }, - layerImageObjectFactoryState: undefined, - layerTextFactoryState: undefined, - layerRectFactoryState: undefined, - layerOvalFactoryState: undefined, + layerObjectFactoryState: undefined, }, overlays: OVERLAYS_INITIAL_STATE_MOCK, }); @@ -207,10 +195,7 @@ describe('EditOverlayModal - component', () => { overviewImagesState: {}, errorReportState: {}, layerFactoryState: { id: undefined }, - layerImageObjectFactoryState: undefined, - layerTextFactoryState: undefined, - layerRectFactoryState: undefined, - layerOvalFactoryState: undefined, + layerObjectFactoryState: undefined, }, overlays: OVERLAYS_INITIAL_STATE_MOCK, }); @@ -256,10 +241,7 @@ describe('EditOverlayModal - component', () => { overviewImagesState: {}, errorReportState: {}, layerFactoryState: { id: undefined }, - layerImageObjectFactoryState: undefined, - layerTextFactoryState: undefined, - layerRectFactoryState: undefined, - layerOvalFactoryState: undefined, + layerObjectFactoryState: undefined, }, overlays: OVERLAYS_INITIAL_STATE_MOCK, }); @@ -291,10 +273,7 @@ describe('EditOverlayModal - component', () => { overviewImagesState: {}, errorReportState: {}, layerFactoryState: { id: undefined }, - layerImageObjectFactoryState: undefined, - layerTextFactoryState: undefined, - layerRectFactoryState: undefined, - layerOvalFactoryState: undefined, + layerObjectFactoryState: undefined, }, }); diff --git a/src/components/FunctionalArea/Modal/EditOverlayGroupModal/hooks/useEditOverlayGroup.test.ts b/src/components/FunctionalArea/Modal/EditOverlayGroupModal/hooks/useEditOverlayGroup.test.ts index ba24d62a145425165110b5cb9313a8debdbd158f..8f627f2cf21b441b9010cb1b1c0cabb98af9b387 100644 --- a/src/components/FunctionalArea/Modal/EditOverlayGroupModal/hooks/useEditOverlayGroup.test.ts +++ b/src/components/FunctionalArea/Modal/EditOverlayGroupModal/hooks/useEditOverlayGroup.test.ts @@ -29,10 +29,7 @@ describe('useEditOverlayGroup', () => { overviewImagesState: {}, errorReportState: {}, layerFactoryState: { id: undefined }, - layerImageObjectFactoryState: undefined, - layerTextFactoryState: undefined, - layerRectFactoryState: undefined, - layerOvalFactoryState: undefined, + layerObjectFactoryState: undefined, }, }); @@ -72,10 +69,7 @@ describe('useEditOverlayGroup', () => { overviewImagesState: {}, errorReportState: {}, layerFactoryState: { id: undefined }, - layerImageObjectFactoryState: undefined, - layerTextFactoryState: undefined, - layerRectFactoryState: undefined, - layerOvalFactoryState: undefined, + layerObjectFactoryState: undefined, }, }); @@ -118,10 +112,7 @@ describe('useEditOverlayGroup', () => { overviewImagesState: {}, errorReportState: {}, layerFactoryState: { id: undefined }, - layerImageObjectFactoryState: undefined, - layerTextFactoryState: undefined, - layerRectFactoryState: undefined, - layerOvalFactoryState: undefined, + layerObjectFactoryState: undefined, }, }); @@ -160,10 +151,7 @@ describe('useEditOverlayGroup', () => { overviewImagesState: {}, errorReportState: {}, layerFactoryState: { id: undefined }, - layerImageObjectFactoryState: undefined, - layerTextFactoryState: undefined, - layerRectFactoryState: undefined, - layerOvalFactoryState: undefined, + layerObjectFactoryState: undefined, }, }); @@ -203,10 +191,7 @@ describe('useEditOverlayGroup', () => { overviewImagesState: {}, errorReportState: {}, layerFactoryState: { id: undefined }, - layerImageObjectFactoryState: undefined, - layerTextFactoryState: undefined, - layerRectFactoryState: undefined, - layerOvalFactoryState: undefined, + layerObjectFactoryState: undefined, }, }); diff --git a/src/components/FunctionalArea/Modal/EditOverlayModal/EditOverlayModal.component.test.tsx b/src/components/FunctionalArea/Modal/EditOverlayModal/EditOverlayModal.component.test.tsx index 496e23d588027855a84b069a8c0cf48c30a791e1..484ce41b9ca6a374e0c5d10042134a29e388c302 100644 --- a/src/components/FunctionalArea/Modal/EditOverlayModal/EditOverlayModal.component.test.tsx +++ b/src/components/FunctionalArea/Modal/EditOverlayModal/EditOverlayModal.component.test.tsx @@ -56,10 +56,7 @@ describe('EditOverlayModal - component', () => { overviewImagesState: {}, errorReportState: {}, layerFactoryState: { id: undefined }, - layerImageObjectFactoryState: undefined, - layerTextFactoryState: undefined, - layerRectFactoryState: undefined, - layerOvalFactoryState: undefined, + layerObjectFactoryState: undefined, }, }); @@ -80,10 +77,7 @@ describe('EditOverlayModal - component', () => { overviewImagesState: {}, errorReportState: {}, layerFactoryState: { id: undefined }, - layerImageObjectFactoryState: undefined, - layerTextFactoryState: undefined, - layerRectFactoryState: undefined, - layerOvalFactoryState: undefined, + layerObjectFactoryState: undefined, }, }); @@ -117,10 +111,7 @@ describe('EditOverlayModal - component', () => { overviewImagesState: {}, errorReportState: {}, layerFactoryState: { id: undefined }, - layerImageObjectFactoryState: undefined, - layerTextFactoryState: undefined, - layerRectFactoryState: undefined, - layerOvalFactoryState: undefined, + layerObjectFactoryState: undefined, }, overlays: OVERLAYS_INITIAL_STATE_MOCK, }); @@ -159,10 +150,7 @@ describe('EditOverlayModal - component', () => { overviewImagesState: {}, errorReportState: {}, layerFactoryState: { id: undefined }, - layerImageObjectFactoryState: undefined, - layerTextFactoryState: undefined, - layerRectFactoryState: undefined, - layerOvalFactoryState: undefined, + layerObjectFactoryState: undefined, }, overlays: OVERLAYS_INITIAL_STATE_MOCK, }); @@ -202,10 +190,7 @@ describe('EditOverlayModal - component', () => { overviewImagesState: {}, errorReportState: {}, layerFactoryState: { id: undefined }, - layerImageObjectFactoryState: undefined, - layerTextFactoryState: undefined, - layerRectFactoryState: undefined, - layerOvalFactoryState: undefined, + layerObjectFactoryState: undefined, }, overlays: OVERLAYS_INITIAL_STATE_MOCK, }); @@ -251,10 +236,7 @@ describe('EditOverlayModal - component', () => { overviewImagesState: {}, errorReportState: {}, layerFactoryState: { id: undefined }, - layerImageObjectFactoryState: undefined, - layerTextFactoryState: undefined, - layerRectFactoryState: undefined, - layerOvalFactoryState: undefined, + layerObjectFactoryState: undefined, }, overlays: OVERLAYS_INITIAL_STATE_MOCK, }); @@ -284,10 +266,7 @@ describe('EditOverlayModal - component', () => { overviewImagesState: {}, errorReportState: {}, layerFactoryState: { id: undefined }, - layerImageObjectFactoryState: undefined, - layerTextFactoryState: undefined, - layerRectFactoryState: undefined, - layerOvalFactoryState: undefined, + layerObjectFactoryState: undefined, }, }); diff --git a/src/components/FunctionalArea/Modal/EditOverlayModal/hooks/useEditOverlay.test.ts b/src/components/FunctionalArea/Modal/EditOverlayModal/hooks/useEditOverlay.test.ts index d0c802fdae6c4e1968e3f879968ac9af7472c896..a0f6504ad1c95272b279f4341f2a90cd0c978649 100644 --- a/src/components/FunctionalArea/Modal/EditOverlayModal/hooks/useEditOverlay.test.ts +++ b/src/components/FunctionalArea/Modal/EditOverlayModal/hooks/useEditOverlay.test.ts @@ -28,10 +28,7 @@ describe('useEditOverlay', () => { overviewImagesState: {}, errorReportState: {}, layerFactoryState: { id: undefined }, - layerImageObjectFactoryState: undefined, - layerTextFactoryState: undefined, - layerRectFactoryState: undefined, - layerOvalFactoryState: undefined, + layerObjectFactoryState: undefined, }, }); @@ -71,10 +68,7 @@ describe('useEditOverlay', () => { overviewImagesState: {}, errorReportState: {}, layerFactoryState: { id: undefined }, - layerImageObjectFactoryState: undefined, - layerTextFactoryState: undefined, - layerRectFactoryState: undefined, - layerOvalFactoryState: undefined, + layerObjectFactoryState: undefined, }, }); @@ -117,10 +111,7 @@ describe('useEditOverlay', () => { overviewImagesState: {}, errorReportState: {}, layerFactoryState: { id: undefined }, - layerImageObjectFactoryState: undefined, - layerTextFactoryState: undefined, - layerRectFactoryState: undefined, - layerOvalFactoryState: undefined, + layerObjectFactoryState: undefined, }, }); @@ -160,10 +151,7 @@ describe('useEditOverlay', () => { overviewImagesState: {}, errorReportState: {}, layerFactoryState: { id: undefined }, - layerImageObjectFactoryState: undefined, - layerTextFactoryState: undefined, - layerRectFactoryState: undefined, - layerOvalFactoryState: undefined, + layerObjectFactoryState: undefined, }, }); @@ -203,10 +191,7 @@ describe('useEditOverlay', () => { overviewImagesState: {}, errorReportState: {}, layerFactoryState: { id: undefined }, - layerImageObjectFactoryState: undefined, - layerTextFactoryState: undefined, - layerRectFactoryState: undefined, - layerOvalFactoryState: undefined, + layerObjectFactoryState: undefined, }, }); diff --git a/src/components/FunctionalArea/Modal/LayerImageObjectModal/LayerImageObjectEditFactoryModal.component.test.tsx b/src/components/FunctionalArea/Modal/LayerImageObjectModal/LayerImageObjectEditFactoryModal.component.test.tsx index d4c3ae43c8307a73ba4401559c69d0f958014b92..7bfed87c90040deabb9981e9480bc7fd5539d52a 100644 --- a/src/components/FunctionalArea/Modal/LayerImageObjectModal/LayerImageObjectEditFactoryModal.component.test.tsx +++ b/src/components/FunctionalArea/Modal/LayerImageObjectModal/LayerImageObjectEditFactoryModal.component.test.tsx @@ -58,15 +58,12 @@ const renderComponent = ( overviewImagesState: {}, errorReportState: {}, layerFactoryState: { id: undefined }, - layerImageObjectFactoryState: { + layerObjectFactoryState: { x: 1, y: 1, width: 1, height: 1, }, - layerTextFactoryState: undefined, - layerRectFactoryState: undefined, - layerOvalFactoryState: undefined, }, models: { ...MODELS_DATA_MOCK_WITH_MAIN_MAP, diff --git a/src/components/FunctionalArea/Modal/LayerImageObjectModal/LayerImageObjectFactoryModal.component.test.tsx b/src/components/FunctionalArea/Modal/LayerImageObjectModal/LayerImageObjectFactoryModal.component.test.tsx index 0fef5ff57c78603b518f14e08359159de0935087..b14ea618617053ad92f36e12f3470c836ad7f9fc 100644 --- a/src/components/FunctionalArea/Modal/LayerImageObjectModal/LayerImageObjectFactoryModal.component.test.tsx +++ b/src/components/FunctionalArea/Modal/LayerImageObjectModal/LayerImageObjectFactoryModal.component.test.tsx @@ -52,15 +52,12 @@ const renderComponent = (): { store: StoreType } => { overviewImagesState: {}, errorReportState: {}, layerFactoryState: { id: undefined }, - layerImageObjectFactoryState: { + layerObjectFactoryState: { x: 1, y: 1, width: 1, height: 1, }, - layerTextFactoryState: undefined, - layerRectFactoryState: undefined, - layerOvalFactoryState: undefined, }, models: { ...MODELS_DATA_MOCK_WITH_MAIN_MAP, diff --git a/src/components/FunctionalArea/Modal/LayerImageObjectModal/LayerImageObjectFactoryModal.component.tsx b/src/components/FunctionalArea/Modal/LayerImageObjectModal/LayerImageObjectFactoryModal.component.tsx index ec4956590401f9c2a9a44423367e4c49d51ae2ef..040d2984f739d45d1a1b999fb68f232bfd7f4a0e 100644 --- a/src/components/FunctionalArea/Modal/LayerImageObjectModal/LayerImageObjectFactoryModal.component.tsx +++ b/src/components/FunctionalArea/Modal/LayerImageObjectModal/LayerImageObjectFactoryModal.component.tsx @@ -1,7 +1,7 @@ /* eslint-disable no-magic-numbers */ import React, { useState } from 'react'; import { useAppSelector } from '@/redux/hooks/useAppSelector'; -import { layerImageObjectFactoryStateSelector } from '@/redux/modal/modal.selector'; +import { layerObjectFactoryStateSelector } from '@/redux/modal/modal.selector'; import { useAppDispatch } from '@/redux/hooks/useAppDispatch'; import { currentModelIdSelector } from '@/redux/models/models.selectors'; import { @@ -23,7 +23,7 @@ import { mapEditToolsSetActiveAction } from '@/redux/mapEditTools/mapEditTools.s export const LayerImageObjectFactoryModal: React.FC = () => { const currentModelId = useAppSelector(currentModelIdSelector); const drawLayer = useAppSelector(layersDrawLayerSelector); - const layerImageObjectFactoryState = useAppSelector(layerImageObjectFactoryStateSelector); + const layerObjectFactoryState = useAppSelector(layerObjectFactoryStateSelector); const dispatch = useAppDispatch(); const maxZIndex = useAppSelector(state => maxObjectZIndexForLayerSelector(state, drawLayer)); const { mapInstance } = useMapInstance(); @@ -33,7 +33,7 @@ export const LayerImageObjectFactoryModal: React.FC = () => { const [isSending, setIsSending] = useState<boolean>(false); const handleSubmit = async (): Promise<void> => { - if (!layerImageObjectFactoryState || !drawLayer) { + if (!layerObjectFactoryState || !drawLayer) { return; } setIsSending(true); @@ -50,11 +50,11 @@ export const LayerImageObjectFactoryModal: React.FC = () => { addLayerImageObject({ modelId: currentModelId, layerId: drawLayer, - x: layerImageObjectFactoryState.x, - y: layerImageObjectFactoryState.y, + x: layerObjectFactoryState.x, + y: layerObjectFactoryState.y, z: maxZIndex + 1, - width: layerImageObjectFactoryState.width, - height: layerImageObjectFactoryState.height, + width: layerObjectFactoryState.width, + height: layerObjectFactoryState.height, glyph: glyphId, }), ).unwrap(); diff --git a/src/components/FunctionalArea/Modal/LayerOvalFactoryModal/LayerOvalEditFactoryModal.component.tsx b/src/components/FunctionalArea/Modal/LayerOvalFactoryModal/LayerOvalEditFactoryModal.component.tsx new file mode 100644 index 0000000000000000000000000000000000000000..bc36060983a2643c523bdad57a8758b50d79450f --- /dev/null +++ b/src/components/FunctionalArea/Modal/LayerOvalFactoryModal/LayerOvalEditFactoryModal.component.tsx @@ -0,0 +1,105 @@ +/* eslint-disable no-magic-numbers */ +import React, { useState } from 'react'; +import './LayerOvalFactoryModal.styles.css'; +import { LoadingIndicator } from '@/shared/LoadingIndicator'; +import { Button } from '@/shared/Button'; +import { useAppSelector } from '@/redux/hooks/useAppSelector'; +import { currentModelIdSelector } from '@/redux/models/models.selectors'; +import { Color } from '@/types/models'; +import { showToast } from '@/utils/showToast'; +import { closeModal } from '@/redux/modal/modal.slice'; +import { mapEditToolsSetLayerObject } from '@/redux/mapEditTools/mapEditTools.slice'; +import { SerializedError } from '@reduxjs/toolkit'; +import { useAppDispatch } from '@/redux/hooks/useAppDispatch'; +import { useMapInstance } from '@/utils/context/mapInstanceContext'; +import { mapEditToolsLayerObjectSelector } from '@/redux/mapEditTools/mapEditTools.selectors'; +import updateElement from '@/components/Map/MapViewer/utils/shapes/layer/utils/updateElement'; +import { LayerOvalFactoryForm } from '@/components/FunctionalArea/Modal/LayerOvalFactoryModal/LayerOvalFactory.types'; +import { LayerOvalForm } from '@/components/FunctionalArea/Modal/LayerOvalFactoryModal/LayerOvalForm.component'; +import { updateLayerOval } from '@/redux/layers/layers.thunks'; +import { layerUpdateOval } from '@/redux/layers/layers.slice'; + +export const LayerOvalEditFactoryModal: React.FC = () => { + const layerObject = useAppSelector(mapEditToolsLayerObjectSelector); + const currentModelId = useAppSelector(currentModelIdSelector); + const dispatch = useAppDispatch(); + const { mapInstance } = useMapInstance(); + + if (!layerObject || !('color' in layerObject && 'borderColor' in layerObject)) { + throw new Error('Invalid layer oval object'); + } + + const [isSending, setIsSending] = useState<boolean>(false); + const [data, setData] = useState<LayerOvalFactoryForm>({ + color: layerObject.color, + }); + + const handleSubmit = async (): Promise<void> => { + if (!layerObject) { + return; + } + try { + const layerOval = await dispatch( + updateLayerOval({ + modelId: currentModelId, + layerId: layerObject.layer, + id: layerObject.id, + x: layerObject.x, + y: layerObject.y, + z: layerObject.z, + width: layerObject.width, + height: layerObject.height, + color: data.color, + }), + ).unwrap(); + + if (!layerOval) { + showToast({ + type: 'error', + message: 'An error occurred while editing the oval.', + }); + return; + } + + dispatch(layerUpdateOval({ modelId: currentModelId, layerId: layerOval.layer, layerOval })); + dispatch(mapEditToolsSetLayerObject(layerOval)); + updateElement(mapInstance, layerOval.layer, layerOval); + showToast({ + type: 'success', + message: 'The oval has been successfully updated.', + }); + dispatch(closeModal()); + } catch (error) { + const typedError = error as SerializedError; + showToast({ + type: 'error', + message: typedError.message || 'An error occurred while editing the oval.', + }); + } finally { + setIsSending(false); + } + }; + + const changeValues = (value: string | number | Color, key: string): void => { + setData(prevData => ({ ...prevData, [key]: value })); + }; + + return ( + <div className="relative flex w-[300px] flex-col gap-4 rounded-b-lg border border-t-[#E1E0E6] bg-white p-[24px]"> + {isSending && ( + <div className="c-layer-oval-factory-modal-loader"> + <LoadingIndicator width={44} height={44} /> + </div> + )} + <LayerOvalForm onChange={changeValues} data={data} /> + <hr /> + <Button + type="button" + onClick={handleSubmit} + className="justify-center self-end justify-self-end text-base font-medium" + > + Submit + </Button> + </div> + ); +}; diff --git a/src/components/FunctionalArea/Modal/LayerOvalFactoryModal/LayerOvalFactoryModal.component.test.tsx b/src/components/FunctionalArea/Modal/LayerOvalFactoryModal/LayerOvalFactoryModal.component.test.tsx index 3e3d09603f14248bf5d8ded8aba25d79f59ccd19..3fdb2ca207a8e35065ec7f31d146502759b3254d 100644 --- a/src/components/FunctionalArea/Modal/LayerOvalFactoryModal/LayerOvalFactoryModal.component.test.tsx +++ b/src/components/FunctionalArea/Modal/LayerOvalFactoryModal/LayerOvalFactoryModal.component.test.tsx @@ -52,10 +52,7 @@ const renderComponent = (): { store: StoreType } => { overviewImagesState: {}, errorReportState: {}, layerFactoryState: { id: undefined }, - layerImageObjectFactoryState: undefined, - layerTextFactoryState: undefined, - layerRectFactoryState: undefined, - layerOvalFactoryState: { + layerObjectFactoryState: { x: 1, y: 1, width: 1, diff --git a/src/components/FunctionalArea/Modal/LayerOvalFactoryModal/LayerOvalFactoryModal.component.tsx b/src/components/FunctionalArea/Modal/LayerOvalFactoryModal/LayerOvalFactoryModal.component.tsx index 9031ee4d5364994eb36988b63f9e813bd82b0271..fb281163f5c4dac3e9a5fbcd3ee68f875957f857 100644 --- a/src/components/FunctionalArea/Modal/LayerOvalFactoryModal/LayerOvalFactoryModal.component.tsx +++ b/src/components/FunctionalArea/Modal/LayerOvalFactoryModal/LayerOvalFactoryModal.component.tsx @@ -13,7 +13,7 @@ import { } from '@/redux/layers/layers.selectors'; import { currentModelIdSelector } from '@/redux/models/models.selectors'; import { Color } from '@/types/models'; -import { layerOvalFactoryStateSelector } from '@/redux/modal/modal.selector'; +import { layerObjectFactoryStateSelector } from '@/redux/modal/modal.selector'; import { addLayerOval } from '@/redux/layers/layers.thunks'; import { showToast } from '@/utils/showToast'; import { layerAddOval } from '@/redux/layers/layers.slice'; @@ -27,7 +27,7 @@ import { useMapInstance } from '@/utils/context/mapInstanceContext'; export const LayerOvalFactoryModal: React.FC = () => { const drawLayer = useAppSelector(layersDrawLayerSelector); const currentModelId = useAppSelector(currentModelIdSelector); - const layerOvalFactoryState = useAppSelector(layerOvalFactoryStateSelector); + const layerObjectFactoryState = useAppSelector(layerObjectFactoryStateSelector); const maxZIndex = useAppSelector(state => maxObjectZIndexForLayerSelector(state, drawLayer)); const dispatch = useAppDispatch(); const { mapInstance } = useMapInstance(); @@ -38,7 +38,7 @@ export const LayerOvalFactoryModal: React.FC = () => { }); const handleSubmit = async (): Promise<void> => { - if (!layerOvalFactoryState || !drawLayer) { + if (!layerObjectFactoryState || !drawLayer) { return; } try { @@ -46,7 +46,7 @@ export const LayerOvalFactoryModal: React.FC = () => { addLayerOval({ modelId: currentModelId, layerId: drawLayer, - boundingBox: layerOvalFactoryState, + boundingBox: layerObjectFactoryState, ovalData: data, z: maxZIndex + 1, }), diff --git a/src/components/FunctionalArea/Modal/LayerRectFactoryModal/LayerRectFactoryModal.component.test.tsx b/src/components/FunctionalArea/Modal/LayerRectFactoryModal/LayerRectFactoryModal.component.test.tsx index 770755d8d12535fe8db4f3fdceab29aa252ebb7b..2e14dc505c4e18528e22c63192b2f3f12cfb2387 100644 --- a/src/components/FunctionalArea/Modal/LayerRectFactoryModal/LayerRectFactoryModal.component.test.tsx +++ b/src/components/FunctionalArea/Modal/LayerRectFactoryModal/LayerRectFactoryModal.component.test.tsx @@ -52,15 +52,12 @@ const renderComponent = (): { store: StoreType } => { overviewImagesState: {}, errorReportState: {}, layerFactoryState: { id: undefined }, - layerImageObjectFactoryState: undefined, - layerRectFactoryState: { + layerObjectFactoryState: { x: 1, y: 1, width: 1, height: 1, }, - layerTextFactoryState: undefined, - layerOvalFactoryState: undefined, }, models: { ...MODELS_DATA_MOCK_WITH_MAIN_MAP, diff --git a/src/components/FunctionalArea/Modal/LayerRectFactoryModal/LayerRectFactoryModal.component.tsx b/src/components/FunctionalArea/Modal/LayerRectFactoryModal/LayerRectFactoryModal.component.tsx index cbdfb2306342a41844b9f877ce9d6173727227c1..df43b969feebeb306358bd499ebee05ee37e8a3a 100644 --- a/src/components/FunctionalArea/Modal/LayerRectFactoryModal/LayerRectFactoryModal.component.tsx +++ b/src/components/FunctionalArea/Modal/LayerRectFactoryModal/LayerRectFactoryModal.component.tsx @@ -13,7 +13,7 @@ import { } from '@/redux/layers/layers.selectors'; import { currentModelIdSelector } from '@/redux/models/models.selectors'; import { Color } from '@/types/models'; -import { layerRectFactoryStateSelector } from '@/redux/modal/modal.selector'; +import { layerObjectFactoryStateSelector } from '@/redux/modal/modal.selector'; import { addLayerRect } from '@/redux/layers/layers.thunks'; import { showToast } from '@/utils/showToast'; import { layerAddRect } from '@/redux/layers/layers.slice'; @@ -27,7 +27,7 @@ import { useMapInstance } from '@/utils/context/mapInstanceContext'; export const LayerRectFactoryModal: React.FC = () => { const drawLayer = useAppSelector(layersDrawLayerSelector); const currentModelId = useAppSelector(currentModelIdSelector); - const layerRectFactoryState = useAppSelector(layerRectFactoryStateSelector); + const layerObjectFactoryState = useAppSelector(layerObjectFactoryStateSelector); const maxZIndex = useAppSelector(state => maxObjectZIndexForLayerSelector(state, drawLayer)); const dispatch = useAppDispatch(); const { mapInstance } = useMapInstance(); @@ -39,7 +39,7 @@ export const LayerRectFactoryModal: React.FC = () => { }); const handleSubmit = async (): Promise<void> => { - if (!layerRectFactoryState || !drawLayer) { + if (!layerObjectFactoryState || !drawLayer) { return; } try { @@ -47,7 +47,7 @@ export const LayerRectFactoryModal: React.FC = () => { addLayerRect({ modelId: currentModelId, layerId: drawLayer, - boundingBox: layerRectFactoryState, + boundingBox: layerObjectFactoryState, rectData: data, z: maxZIndex + 1, }), diff --git a/src/components/FunctionalArea/Modal/LayerTextFactoryModal/LayerTextFactoryModal.component.test.tsx b/src/components/FunctionalArea/Modal/LayerTextFactoryModal/LayerTextFactoryModal.component.test.tsx index 0cea2734380122ec11aa49549af2f3027843d1ad..a88c47d443f1da4db79b67ec19435314b3a27911 100644 --- a/src/components/FunctionalArea/Modal/LayerTextFactoryModal/LayerTextFactoryModal.component.test.tsx +++ b/src/components/FunctionalArea/Modal/LayerTextFactoryModal/LayerTextFactoryModal.component.test.tsx @@ -57,10 +57,7 @@ const renderComponent = (): { store: StoreType } => { overviewImagesState: {}, errorReportState: {}, layerFactoryState: { id: undefined }, - layerImageObjectFactoryState: undefined, - layerRectFactoryState: undefined, - layerOvalFactoryState: undefined, - layerTextFactoryState: { + layerObjectFactoryState: { x: 1, y: 1, width: 1, diff --git a/src/components/FunctionalArea/Modal/LayerTextFactoryModal/LayerTextFactoryModal.component.tsx b/src/components/FunctionalArea/Modal/LayerTextFactoryModal/LayerTextFactoryModal.component.tsx index b144615676f4973389f98abcb986f752540866e6..d6112dafcd6fcc121455f2fe14f9a84c95114724 100644 --- a/src/components/FunctionalArea/Modal/LayerTextFactoryModal/LayerTextFactoryModal.component.tsx +++ b/src/components/FunctionalArea/Modal/LayerTextFactoryModal/LayerTextFactoryModal.component.tsx @@ -12,7 +12,7 @@ import { import { LayerTextFactoryForm } from '@/components/FunctionalArea/Modal/LayerTextFactoryModal/LayerTextFactory.types'; import { Color } from '@/types/models'; import { useAppSelector } from '@/redux/hooks/useAppSelector'; -import { layerTextFactoryStateSelector } from '@/redux/modal/modal.selector'; +import { layerObjectFactoryStateSelector } from '@/redux/modal/modal.selector'; import { layersDrawLayerSelector, maxObjectZIndexForLayerSelector, @@ -32,7 +32,7 @@ import { mapEditToolsSetActiveAction } from '@/redux/mapEditTools/mapEditTools.s export const LayerTextFactoryModal: React.FC = () => { const drawLayer = useAppSelector(layersDrawLayerSelector); const currentModelId = useAppSelector(currentModelIdSelector); - const layerTextFactoryState = useAppSelector(layerTextFactoryStateSelector); + const layerObjectFactoryState = useAppSelector(layerObjectFactoryStateSelector); const dispatch = useAppDispatch(); const maxZIndex = useAppSelector(state => maxObjectZIndexForLayerSelector(state, drawLayer)); const { mapInstance } = useMapInstance(); @@ -48,7 +48,7 @@ export const LayerTextFactoryModal: React.FC = () => { }); const handleSubmit = async (): Promise<void> => { - if (!layerTextFactoryState || !drawLayer) { + if (!layerObjectFactoryState || !drawLayer) { return; } try { @@ -56,7 +56,7 @@ export const LayerTextFactoryModal: React.FC = () => { addLayerText({ modelId: currentModelId, layerId: drawLayer, - boundingBox: layerTextFactoryState, + boundingBox: layerObjectFactoryState, textData: data, z: maxZIndex + 1, }), diff --git a/src/components/FunctionalArea/Modal/Modal.component.tsx b/src/components/FunctionalArea/Modal/Modal.component.tsx index 47b95467a7d23b5292e08443163b4b1e2ff90fc6..38a0141484f1cff230bdb4b206351ad05a121e8a 100644 --- a/src/components/FunctionalArea/Modal/Modal.component.tsx +++ b/src/components/FunctionalArea/Modal/Modal.component.tsx @@ -15,6 +15,7 @@ import { LayerTextEditFactoryModal } from '@/components/FunctionalArea/Modal/Lay import { LayerRectFactoryModal } from '@/components/FunctionalArea/Modal/LayerRectFactoryModal/LayerRectFactoryModal.component'; import { LayerRectEditFactoryModal } from '@/components/FunctionalArea/Modal/LayerRectFactoryModal/LayerRectEditFactoryModal.component'; import { LayerOvalFactoryModal } from '@/components/FunctionalArea/Modal/LayerOvalFactoryModal/LayerOvalFactoryModal.component'; +import { LayerOvalEditFactoryModal } from '@/components/FunctionalArea/Modal/LayerOvalFactoryModal/LayerOvalEditFactoryModal.component'; import { EditOverlayModal } from './EditOverlayModal'; import { LoginModal } from './LoginModal'; import { ErrorReportModal } from './ErrorReportModal'; @@ -135,6 +136,11 @@ export const Modal = (): React.ReactNode => { <LayerOvalFactoryModal /> </ModalLayout> )} + {isOpen && modalName === 'layer-oval-edit-factory' && ( + <ModalLayout> + <LayerOvalEditFactoryModal /> + </ModalLayout> + )} </> ); }; diff --git a/src/components/FunctionalArea/Modal/ModalLayout/ModalLayout.component.tsx b/src/components/FunctionalArea/Modal/ModalLayout/ModalLayout.component.tsx index aa3c14657ab87d45dd940a95febd6b595af685ea..41ceda61f5115424eb965c61c72649bf8cdddb7d 100644 --- a/src/components/FunctionalArea/Modal/ModalLayout/ModalLayout.component.tsx +++ b/src/components/FunctionalArea/Modal/ModalLayout/ModalLayout.component.tsx @@ -34,7 +34,8 @@ export const ModalLayout = ({ children }: ModalLayoutProps): JSX.Element => { modalName === 'add-comment' && 'h-auto w-[400px]', modalName === 'error-report' && 'h-auto w-[800px]', modalName === 'layer-factory' && 'h-auto w-[400px]', - modalName === 'layer-oval-factory' && 'h-auto w-[300px] overflow-visible', + ['layer-oval-factory', 'layer-oval-edit-factory'].includes(modalName) && + 'h-auto w-[300px] overflow-visible', ['layer-rect-factory', 'layer-rect-edit-factory'].includes(modalName) && 'h-auto w-[400px] overflow-visible', ['layer-text-factory', 'layer-text-edit-factory'].includes(modalName) && @@ -47,9 +48,12 @@ export const ModalLayout = ({ children }: ModalLayoutProps): JSX.Element => { <div className={twMerge( 'flex items-center justify-between bg-white p-[24px] text-xl', - ['layer-rect-factory', 'layer-rect-edit-factory', 'layer-oval-factory'].includes( - modalName, - ) && 'rounded-t-lg', + [ + 'layer-rect-factory', + 'layer-rect-edit-factory', + 'layer-oval-factory', + 'layer-oval-edit-factory', + ].includes(modalName) && 'rounded-t-lg', )} > {(modalName === 'error-report' || modalName === 'access-denied') && ( diff --git a/src/components/Map/Drawer/LayersDrawer/LayerDrawerRectItem.component.tsx b/src/components/Map/Drawer/LayersDrawer/LayerDrawerRectItem.component.tsx index c36031e5fbaed61ed236e7ed8f4d6f6f1422c549..86af53e28cc1449c3ad756c50f8561f6e2dd22fe 100644 --- a/src/components/Map/Drawer/LayersDrawer/LayerDrawerRectItem.component.tsx +++ b/src/components/Map/Drawer/LayersDrawer/LayerDrawerRectItem.component.tsx @@ -30,12 +30,12 @@ export const LayersDrawerRectItem = ({ isLayerActive, }: LayersDrawerRectItemProps): JSX.Element | null => { const dispatch = useAppDispatch(); - const activeLayerImage = useAppSelector(mapEditToolsLayerObjectSelector); + const activeLayerObject = useAppSelector(mapEditToolsLayerObjectSelector); const hasPrivilegeToWriteProject = useAppSelector(hasPrivilegeToWriteProjectSelector); const showActions = useMemo(() => { - return activeLayerImage?.id === layerRect.id; - }, [activeLayerImage?.id, layerRect.id]); + return activeLayerObject?.id === layerRect.id; + }, [activeLayerObject?.id, layerRect.id]); const canSelectItem = useMemo(() => { return isLayerVisible && isLayerActive && hasPrivilegeToWriteProject; diff --git a/src/components/Map/Drawer/LayersDrawer/LayersDrawer.component.tsx b/src/components/Map/Drawer/LayersDrawer/LayersDrawer.component.tsx index 966ce7ed4ba679d9f5190fb7a2ccb696a3cb7e3b..6ae1ccf145b49caee0717a02fb7cf9c07a36bf47 100644 --- a/src/components/Map/Drawer/LayersDrawer/LayersDrawer.component.tsx +++ b/src/components/Map/Drawer/LayersDrawer/LayersDrawer.component.tsx @@ -43,7 +43,8 @@ export const LayersDrawer = (): JSX.Element => { const layerObjectElement = document.getElementById(`layer-image-item-${mapEditToolsLayerObject.id}`) || document.getElementById(`layer-text-item-${mapEditToolsLayerObject.id}`) || - document.getElementById(`layer-rect-item-${mapEditToolsLayerObject.id}`); + document.getElementById(`layer-rect-item-${mapEditToolsLayerObject.id}`) || + document.getElementById(`layer-oval-item-${mapEditToolsLayerObject.id}`); if (!layerObjectElement) { return; } diff --git a/src/components/Map/Drawer/LayersDrawer/LayersDrawerObjectActions.component.tsx b/src/components/Map/Drawer/LayersDrawer/LayersDrawerObjectActions.component.tsx index a97189ea9e305dc1516882818b345143d12d2bc7..83c0441fc9a1e4a7404759b4bd6fca28bd7d47f5 100644 --- a/src/components/Map/Drawer/LayersDrawer/LayersDrawerObjectActions.component.tsx +++ b/src/components/Map/Drawer/LayersDrawer/LayersDrawerObjectActions.component.tsx @@ -1,4 +1,4 @@ -import { JSX } from 'react'; +import { JSX, useEffect } from 'react'; import { IconButton } from '@/shared/IconButton'; interface LayersDrawerObjectActionsProps { @@ -16,6 +16,19 @@ export const LayersDrawerObjectActions = ({ centerObject, editObject, }: LayersDrawerObjectActionsProps): JSX.Element | null => { + useEffect(() => { + const handleKeyDown = (event: KeyboardEvent): void => { + if (event.key === 'Delete') { + removeObject(); + } + }; + + window.addEventListener('keydown', handleKeyDown); + return () => { + window.removeEventListener('keydown', handleKeyDown); + }; + }, [removeObject]); + return ( <div className="flex shrink-0 gap-2"> <IconButton diff --git a/src/components/Map/Drawer/LayersDrawer/LayersDrawerObjectsList.component.tsx b/src/components/Map/Drawer/LayersDrawer/LayersDrawerObjectsList.component.tsx index 8d96d72f465b338fb5715f0878231d48addca823..c5386ec4820f047075c05a02782737ff444a5a19 100644 --- a/src/components/Map/Drawer/LayersDrawer/LayersDrawerObjectsList.component.tsx +++ b/src/components/Map/Drawer/LayersDrawer/LayersDrawerObjectsList.component.tsx @@ -11,24 +11,28 @@ import { LayersDrawerTextItem } from '@/components/Map/Drawer/LayersDrawer/Layer import QuestionModal from '@/components/FunctionalArea/Modal/QuestionModal/QustionModal.component'; import { removeLayerImage, + removeLayerOval, removeLayerRect, removeLayerText, updateLayerImageObject, + updateLayerOval, updateLayerRect, updateLayerText, } from '@/redux/layers/layers.thunks'; import { layerDeleteImage, + layerDeleteOval, layerDeleteRect, layerDeleteText, layerUpdateImage, + layerUpdateOval, layerUpdateRect, layerUpdateText, } from '@/redux/layers/layers.slice'; import removeElementFromLayer from '@/components/Map/MapViewer/utils/shapes/layer/utils/removeElementFromLayer'; import { showToast } from '@/utils/showToast'; import { SerializedError } from '@reduxjs/toolkit'; -import { LayerImage, LayerRect, LayerText } from '@/types/models'; +import { LayerImage, LayerOval, LayerRect, LayerText } from '@/types/models'; import { useAppDispatch } from '@/redux/hooks/useAppDispatch'; import { useMapInstance } from '@/utils/context/mapInstanceContext'; import { mapModelIdSelector } from '@/redux/map/map.selectors'; @@ -40,6 +44,7 @@ import { usePointToProjection } from '@/utils/map/usePointToProjection'; import { Coordinate } from 'ol/coordinate'; import { openLayerImageObjectEditFactoryModal, + openLayerOvalEditFactoryModal, openLayerRectEditFactoryModal, openLayerTextEditFactoryModal, } from '@/redux/modal/modal.slice'; @@ -68,6 +73,11 @@ const removeObjectConfig = { successMessage: 'The layer rectangle has been successfully removed.', errorMessage: 'An error occurred while removing the layer rectangle.', }, + oval: { + question: 'Are you sure you want to remove the oval?', + successMessage: 'The layer oval has been successfully removed.', + errorMessage: 'An error occurred while removing the layer oval.', + }, }; export const LayersDrawerObjectsList = ({ @@ -80,25 +90,27 @@ export const LayersDrawerObjectsList = ({ const minZIndex = useAppSelector(state => minObjectZIndexForLayerSelector(state, layerId)); const layer = useAppSelector(state => layerByIdSelector(state, layerId)); const mapEditToolsLayerImageObject = useAppSelector(mapEditToolsLayerObjectSelector); - const [removeModalState, setRemoveModalState] = useState<undefined | 'text' | 'image' | 'rect'>( - undefined, - ); + const [removeModalState, setRemoveModalState] = useState< + undefined | 'text' | 'image' | 'rect' | 'oval' + >(undefined); const [layerObjectToRemove, setLayerObjectToRemove] = useState< - LayerImage | LayerText | LayerRect | null + LayerImage | LayerText | LayerRect | LayerOval | null >(null); const dispatch = useAppDispatch(); const setBounds = useSetBounds(); const pointToProjection = usePointToProjection(); const { mapInstance } = useMapInstance(); - const removeObject = (layerObject: LayerImage | LayerText | LayerRect): void => { + const removeObject = (layerObject: LayerImage | LayerText | LayerRect | LayerOval): void => { setLayerObjectToRemove(layerObject); if ('glyph' in layerObject) { setRemoveModalState('image'); } else if ('notes' in layerObject) { setRemoveModalState('text'); - } else { + } else if ('fillColor' in layerObject && 'borderColor' in layerObject) { setRemoveModalState('rect'); + } else { + setRemoveModalState('oval'); } }; @@ -142,7 +154,7 @@ export const LayersDrawerObjectsList = ({ imageId: layerObjectToRemove.id, }), ); - } else { + } else if (removeModalState === 'rect') { await dispatch( removeLayerRect({ modelId: currentModelId, @@ -157,6 +169,21 @@ export const LayersDrawerObjectsList = ({ rectId: layerObjectToRemove.id, }), ); + } else { + await dispatch( + removeLayerOval({ + modelId: currentModelId, + layerId: layerObjectToRemove.layer, + ovalId: layerObjectToRemove.id, + }), + ).unwrap(); + dispatch( + layerDeleteOval({ + modelId: currentModelId, + layerId: layerObjectToRemove.layer, + ovalId: layerObjectToRemove.id, + }), + ); } removeElementFromLayer({ mapInstance, @@ -291,7 +318,48 @@ export const LayersDrawerObjectsList = ({ await updateRectZIndex({ zIndex: minZIndex - 1, layerRect }); }; - const centerObject = (layerObject: LayerImage | LayerText | LayerRect): void => { + const updateOvalZIndex = async ({ + zIndex, + layerOval, + }: { + zIndex: number; + layerOval: LayerOval; + }): Promise<void> => { + const newLayerOval = await dispatch( + updateLayerOval({ + modelId: currentModelId, + layerId: layerOval.layer, + id: layerOval.id, + x: layerOval.x, + y: layerOval.y, + z: zIndex, + width: layerOval.width, + height: layerOval.height, + color: layerOval.color, + }), + ).unwrap(); + if (newLayerOval) { + dispatch( + layerUpdateOval({ + modelId: currentModelId, + layerId: newLayerOval.layer, + layerOval: newLayerOval, + }), + ); + dispatch(mapEditToolsSetLayerObject(newLayerOval)); + updateElement(mapInstance, newLayerOval.layer, newLayerOval); + } + }; + + const moveOvalToFront = async (layerOval: LayerOval): Promise<void> => { + await updateOvalZIndex({ zIndex: maxZIndex + 1, layerOval }); + }; + + const moveOvalToBack = async (layerOval: LayerOval): Promise<void> => { + await updateOvalZIndex({ zIndex: minZIndex - 1, layerOval }); + }; + + const centerObject = (layerObject: LayerImage | LayerText | LayerRect | LayerOval): void => { if (mapEditToolsLayerImageObject && mapEditToolsLayerImageObject.id === layerObject.id) { const point1 = pointToProjection({ x: layerObject.x, y: layerObject.y }); const point2 = pointToProjection({ @@ -314,6 +382,10 @@ export const LayersDrawerObjectsList = ({ dispatch(openLayerRectEditFactoryModal()); }; + const editOval = (): void => { + dispatch(openLayerOvalEditFactoryModal()); + }; + if (!layer) { return null; } @@ -370,7 +442,17 @@ export const LayersDrawerObjectsList = ({ /> ))} {Object.values(layer.ovals).map(layerOval => ( - <LayersDrawerOvalItem layerOval={layerOval} key={layerOval.id} /> + <LayersDrawerOvalItem + layerOval={layerOval} + key={layerOval.id} + moveToFront={() => moveOvalToFront(layerOval)} + moveToBack={() => moveOvalToBack(layerOval)} + removeObject={() => removeObject(layerOval)} + centerObject={() => centerObject(layerOval)} + editObject={() => editOval()} + isLayerVisible={isLayerVisible} + isLayerActive={isLayerActive} + /> ))} </div> ); diff --git a/src/components/Map/Drawer/LayersDrawer/LayersDrawerOvalItem.component.tsx b/src/components/Map/Drawer/LayersDrawer/LayersDrawerOvalItem.component.tsx index 5a4176fa4908971dc7ba4d712a6e406ec2297b1c..a1f2e368445be4a8e327193e2a5699790a2977b5 100644 --- a/src/components/Map/Drawer/LayersDrawer/LayersDrawerOvalItem.component.tsx +++ b/src/components/Map/Drawer/LayersDrawer/LayersDrawerOvalItem.component.tsx @@ -1,23 +1,80 @@ -import React, { JSX } from 'react'; +import React, { JSX, useMemo } from 'react'; import { LayerOval } from '@/types/models'; import { Icon } from '@/shared/Icon'; +import { useAppDispatch } from '@/redux/hooks/useAppDispatch'; +import { useAppSelector } from '@/redux/hooks/useAppSelector'; +import { mapEditToolsLayerObjectSelector } from '@/redux/mapEditTools/mapEditTools.selectors'; +import { hasPrivilegeToWriteProjectSelector } from '@/redux/user/user.selectors'; +import { mapEditToolsSetLayerObject } from '@/redux/mapEditTools/mapEditTools.slice'; +import { LayersDrawerObjectActions } from '@/components/Map/Drawer/LayersDrawer/LayersDrawerObjectActions.component'; interface LayersDrawerOvalItemProps { layerOval: LayerOval; + moveToFront: () => void; + moveToBack: () => void; + removeObject: () => void; + centerObject: () => void; + editObject: () => void; + isLayerVisible: boolean; + isLayerActive: boolean; } export const LayersDrawerOvalItem = ({ layerOval, + moveToFront, + moveToBack, + removeObject, + centerObject, + editObject, + isLayerVisible, + isLayerActive, }: LayersDrawerOvalItemProps): JSX.Element | null => { + const dispatch = useAppDispatch(); + const activeLayerObject = useAppSelector(mapEditToolsLayerObjectSelector); + const hasPrivilegeToWriteProject = useAppSelector(hasPrivilegeToWriteProjectSelector); + + const showActions = useMemo(() => { + return activeLayerObject?.id === layerOval.id; + }, [activeLayerObject?.id, layerOval.id]); + + const canSelectItem = useMemo(() => { + return isLayerVisible && isLayerActive && hasPrivilegeToWriteProject; + }, [isLayerVisible, isLayerActive, hasPrivilegeToWriteProject]); + + const selectItem = useMemo(() => { + return (): void => { + if (canSelectItem) { + dispatch(mapEditToolsSetLayerObject(layerOval)); + } + }; + }, [canSelectItem, dispatch, layerOval]); + + const handleKeyPress = (): void => {}; + return ( <div className="flex min-h-[24px] items-center justify-between gap-2" id={`layer-oval-item-${layerOval.id}`} > - <div className="flex gap-2"> + <div + className={`flex gap-2 ${canSelectItem ? 'cursor-pointer' : 'cursor-default'}`} + onClick={selectItem} + tabIndex={0} + onKeyDown={handleKeyPress} + role="button" + > <Icon name="oval" className="shrink-0" /> <span className="truncate">oval - {layerOval.id}</span> </div> + {showActions && ( + <LayersDrawerObjectActions + moveToFront={moveToFront} + moveToBack={moveToBack} + removeObject={removeObject} + centerObject={centerObject} + editObject={editObject} + /> + )} </div> ); }; diff --git a/src/components/Map/MapViewer/utils/config/additionalLayers/useOlMapAdditionalLayers.ts b/src/components/Map/MapViewer/utils/config/additionalLayers/useOlMapAdditionalLayers.ts index 524145b459c71b8c72ea7e043229e35958caf165..0d31cdb6452766c70efae6c4459a5d0b38d6446f 100644 --- a/src/components/Map/MapViewer/utils/config/additionalLayers/useOlMapAdditionalLayers.ts +++ b/src/components/Map/MapViewer/utils/config/additionalLayers/useOlMapAdditionalLayers.ts @@ -76,6 +76,7 @@ export const useOlMapAdditionalLayers = (mapInstance: MapInstance): void => { features.push(...vectorLayer.get('imagesFeatures')); features.push(...vectorLayer.get('rectsFeatures')); features.push(...vectorLayer.get('textsFeatures')); + features.push(...vectorLayer.get('ovalsFeatures')); return features; }; diff --git a/src/components/Map/MapViewer/utils/shapes/layer/Layer.ts b/src/components/Map/MapViewer/utils/shapes/layer/Layer.ts index 64972ab519ad0408d83710e0bcb1ce3cb42cfaae..77075f320769409ee5dd79f52aff2dcfe6556d3e 100644 --- a/src/components/Map/MapViewer/utils/shapes/layer/Layer.ts +++ b/src/components/Map/MapViewer/utils/shapes/layer/Layer.ts @@ -116,7 +116,8 @@ export default class Layer { const imagesFeatures = this.getImagesFeatures(); this.vectorSource.addFeatures(imagesFeatures); - this.vectorSource.addFeatures(this.getOvalsFeatures()); + const ovalsFeatures = this.getOvalsFeatures(); + this.vectorSource.addFeatures(ovalsFeatures); const { linesFeatures, arrowsFeatures } = this.getLinesFeatures(); this.vectorSource.addFeatures(linesFeatures); @@ -135,6 +136,7 @@ export default class Layer { this.vectorLayer.set('imagesFeatures', imagesFeatures); this.vectorLayer.set('textsFeatures', textsFeatures); this.vectorLayer.set('rectsFeatures', rectsFeatures); + this.vectorLayer.set('ovalsFeatures', ovalsFeatures); this.vectorLayer.set('drawImage', this.drawImage.bind(this)); this.vectorLayer.set('drawText', this.drawText.bind(this)); this.vectorLayer.set('drawOval', this.drawOval.bind(this)); diff --git a/src/components/Map/MapViewer/utils/shapes/layer/elements/LayerOval.ts b/src/components/Map/MapViewer/utils/shapes/layer/elements/LayerOval.ts index a9ba0467224a2ee3f4a5628cc6b7469bb1102fac..8fb0635d1200ea715e0f51ed43e726d92157850b 100644 --- a/src/components/Map/MapViewer/utils/shapes/layer/elements/LayerOval.ts +++ b/src/components/Map/MapViewer/utils/shapes/layer/elements/LayerOval.ts @@ -18,6 +18,12 @@ import { LAYER_ELEMENT_TYPES, TRANSPARENT_COLOR, } from '@/components/Map/MapViewer/MapViewer.constants'; +import { BoundingBox } from '@/components/Map/MapViewer/MapViewer.types'; +import { store } from '@/redux/store'; +import { updateLayerOval } from '@/redux/layers/layers.thunks'; +import { layerUpdateOval } from '@/redux/layers/layers.slice'; +import { mapEditToolsSetLayerObject } from '@/redux/mapEditTools/mapEditTools.slice'; +import getBoundingBoxPolygon from '@/components/Map/MapViewer/utils/shapes/elements/getBoundingBoxPolygon'; export interface LayerOvalProps { elementId: number; @@ -58,7 +64,9 @@ export default class LayerOval { style: Style = new Style(); - polygon: Polygon = new Polygon([]); + ovalPolygon: Polygon = new Polygon([]); + + boundingBoxPolygon: Polygon = new Polygon([]); strokeStyle: Stroke = new Stroke(); @@ -106,15 +114,17 @@ export default class LayerOval { this.setStyles(); this.feature = new Feature({ - geometry: this.polygon, + geometry: this.boundingBoxPolygon, layer, elementType: LAYER_ELEMENT_TYPES.OVAL, }); this.feature.setId(this.elementId); this.feature.set('getObjectData', this.getData.bind(this)); this.feature.set('setCoordinates', this.setCoordinates.bind(this)); + this.feature.set('setOvalCoordinates', this.setOvalCoordinates.bind(this)); this.feature.set('refreshPolygon', this.refreshPolygon.bind(this)); this.feature.set('updateElement', this.updateElement.bind(this)); + this.feature.set('save', this.save.bind(this)); this.feature.setStyle(this.getStyle.bind(this)); } @@ -133,6 +143,29 @@ export default class LayerOval { }; } + private async save({ + modelId, + boundingBox, + }: { + modelId: number; + boundingBox: BoundingBox; + }): Promise<void> { + const { dispatch } = store; + const layerOval = await dispatch( + updateLayerOval({ + modelId, + layerId: this.layer, + ...this.getData(), + ...boundingBox, + }), + ).unwrap(); + if (layerOval) { + dispatch(layerUpdateOval({ modelId, layerId: layerOval.layer, layerOval })); + dispatch(mapEditToolsSetLayerObject(layerOval)); + this.updateElement(layerOval); + } + } + private drawPolygon(): void { const coords = getEllipseCoords({ x: this.x + this.width / 2, @@ -140,14 +173,21 @@ export default class LayerOval { height: this.height, width: this.width, pointToProjection: this.pointToProjection, - points: 30, + points: 60, + }); + this.ovalPolygon = new Polygon([coords]); + this.boundingBoxPolygon = getBoundingBoxPolygon({ + x: this.x, + y: this.y, + width: this.width, + height: this.height, + pointToProjection: this.pointToProjection, }); - this.polygon = new Polygon([coords]); } private refreshPolygon(): void { this.drawPolygon(); - this.feature.setGeometry(this.polygon); + this.feature.setGeometry(this.boundingBoxPolygon); this.feature.changed(); } @@ -157,7 +197,7 @@ export default class LayerOval { width: this.lineWidth, }); this.style = getStyle({ - geometry: this.polygon, + geometry: this.ovalPolygon, borderColor: this.borderColor, fillColor: TRANSPARENT_COLOR, lineWidth: this.lineWidth, @@ -181,9 +221,16 @@ export default class LayerOval { } private setCoordinates(coords: Coordinate[][]): void { - const geometry = this.style.getGeometry(); - if (geometry && geometry instanceof Polygon) { - geometry.setCoordinates(coords); + const boundingBoxGeometry = this.feature.getGeometry(); + if (boundingBoxGeometry) { + boundingBoxGeometry.setCoordinates(coords); + } + } + + private setOvalCoordinates(ellipseCoords: Coordinate[][]): void { + const ovalGeometry = this.style.getGeometry(); + if (ovalGeometry && ovalGeometry instanceof Polygon) { + ovalGeometry.setCoordinates(ellipseCoords); } } diff --git a/src/components/Map/MapViewer/utils/shapes/layer/interaction/getTransformInteraction.ts b/src/components/Map/MapViewer/utils/shapes/layer/interaction/getTransformInteraction.ts index c1c8565c2fedda6278186bda9ec2a28c5996105f..7c55f39c3d5f07d9bed6c0b0313591109938f7e3 100644 --- a/src/components/Map/MapViewer/utils/shapes/layer/interaction/getTransformInteraction.ts +++ b/src/components/Map/MapViewer/utils/shapes/layer/interaction/getTransformInteraction.ts @@ -10,6 +10,8 @@ import { MapSize } from '@/redux/map/map.types'; import { Extent } from 'ol/extent'; import { mapEditToolsSetLayerObject } from '@/redux/mapEditTools/mapEditTools.slice'; import { openDrawer } from '@/redux/drawer/drawer.slice'; +import { LAYER_ELEMENT_TYPES } from '@/components/Map/MapViewer/MapViewer.constants'; +import getEllipseCoords from '@/components/Map/MapViewer/utils/shapes/coords/getEllipseCoords'; export default function getTransformInteraction( dispatch: AppDispatch, @@ -22,7 +24,7 @@ export default function getTransformInteraction( features: featuresCollection, scale: true, rotate: false, - stretch: false, + stretch: true, keepRectangle: true, translate: true, translateBBox: true, @@ -44,10 +46,18 @@ export default function getTransformInteraction( restrictionExtent[2] - width, Math.max(restrictionExtent[0], minX), ); + const correctedMaxX = Math.min( + restrictionExtent[2], + Math.max(restrictionExtent[0] + width, maxX), + ); const correctedMinY = Math.min( restrictionExtent[3] - height, Math.max(restrictionExtent[1], minY), ); + const correctedMaxY = Math.min( + restrictionExtent[3], + Math.max(restrictionExtent[1] + height, maxY), + ); const dx = correctedMinX - minX; const dy = correctedMinY - minY; @@ -57,6 +67,19 @@ export default function getTransformInteraction( geometry.changed(); transform.setSelection(new Collection([feature])); } + if (feature.get('elementType') === LAYER_ELEMENT_TYPES.OVAL) { + const setOvalCoordinates = feature.get('setOvalCoordinates'); + const ellipseCoords = getEllipseCoords({ + x: (correctedMinX + correctedMaxX) / 2, + y: (correctedMinY + correctedMaxY) / 2, + height, + width, + points: 20, + }); + if (setOvalCoordinates instanceof Function) { + setOvalCoordinates([ellipseCoords]); + } + } } }); @@ -64,11 +87,9 @@ export default function getTransformInteraction( const transformEvent = event as unknown as { feature: Feature }; const { feature } = transformEvent; const geometry = feature.getGeometry(); - if (!geometry) { return; } - const extent = geometry.getExtent(); const [minX, minY, maxX, maxY] = extent; const newMinX = Math.max(minX, restrictionExtent[0]); @@ -79,6 +100,19 @@ export default function getTransformInteraction( const hasChanged = newExtent.some((value, index) => value !== extent[index]); + if (feature.get('elementType') === LAYER_ELEMENT_TYPES.OVAL) { + const setOvalCoordinates = feature.get('setOvalCoordinates'); + const ellipseCoords = getEllipseCoords({ + x: (newMinX + newMaxX) / 2, + y: (newMinY + newMaxY) / 2, + height: Math.abs(newMaxY - newMinY), + width: Math.abs(newMaxX - newMinX), + points: 30, + }); + if (setOvalCoordinates instanceof Function) { + setOvalCoordinates([ellipseCoords]); + } + } if (hasChanged) { const newGeometry = fromExtent(newExtent); newGeometry.scale(1, -1); diff --git a/src/components/Map/MapViewer/utils/shapes/layer/utils/updateElement.ts b/src/components/Map/MapViewer/utils/shapes/layer/utils/updateElement.ts index 4318381d22c3629031630fb53363ed1783fa8900..0e8e010c5e021b026b563566aeab872279d678b9 100644 --- a/src/components/Map/MapViewer/utils/shapes/layer/utils/updateElement.ts +++ b/src/components/Map/MapViewer/utils/shapes/layer/utils/updateElement.ts @@ -1,11 +1,11 @@ import VectorSource from 'ol/source/Vector'; -import { LayerImage, LayerRect, LayerText } from '@/types/models'; +import { LayerImage, LayerOval, LayerRect, LayerText } from '@/types/models'; import { MapInstance } from '@/types/map'; export default function updateElement( mapInstance: MapInstance, layerId: number, - layerObject: LayerImage | LayerText | LayerRect, + layerObject: LayerImage | LayerText | LayerRect | LayerOval, ): void { mapInstance?.getAllLayers().forEach(layer => { if (layer.get('id') === layerId) { diff --git a/src/components/Map/MapViewer/utils/websocket/processLayerOval.ts b/src/components/Map/MapViewer/utils/websocket/processLayerOval.ts index 0f3a7fd1e8d9fa58fa5d14217f192956b6bfb76b..a589b07ba61d98ac2ba130faa41724ea87ac4acf 100644 --- a/src/components/Map/MapViewer/utils/websocket/processLayerOval.ts +++ b/src/components/Map/MapViewer/utils/websocket/processLayerOval.ts @@ -4,6 +4,9 @@ import { ENTITY_OPERATION_TYPES } from '@/utils/websocket-entity-updates/webSock import { getLayerOval } from '@/redux/layers/layers.thunks'; import { MapInstance } from '@/types/map'; import drawElementOnLayer from '@/components/Map/MapViewer/utils/shapes/layer/utils/drawElementOnLayer'; +import { layerDeleteOval } from '@/redux/layers/layers.slice'; +import removeElementFromLayer from '@/components/Map/MapViewer/utils/shapes/layer/utils/removeElementFromLayer'; +import updateElement from '@/components/Map/MapViewer/utils/shapes/layer/utils/updateElement'; export default async function processLayerOval({ data, @@ -13,7 +16,10 @@ export default async function processLayerOval({ mapInstance: MapInstance; }): Promise<void> { const { dispatch } = store; - if (data.type === ENTITY_OPERATION_TYPES.ENTITY_CREATED) { + if ( + data.type === ENTITY_OPERATION_TYPES.ENTITY_CREATED || + data.type === ENTITY_OPERATION_TYPES.ENTITY_UPDATED + ) { const resultOval = await dispatch( getLayerOval({ modelId: data.mapId, @@ -31,6 +37,17 @@ export default async function processLayerOval({ object: resultOval, drawFunctionKey: 'drawOval', }); + } else { + updateElement(mapInstance, data.layerId, resultOval); } + } else if (data.type === ENTITY_OPERATION_TYPES.ENTITY_DELETED) { + dispatch( + layerDeleteOval({ + modelId: data.mapId, + layerId: data.layerId, + ovalId: data.entityId, + }), + ); + removeElementFromLayer({ mapInstance, layerId: data.layerId, featureId: data.entityId }); } } diff --git a/src/redux/apiPath.ts b/src/redux/apiPath.ts index 895d61e37d84814e4941a2c6847041d942612432..b5e25cb2a9f3f0f186d3f5f2f181926199982062 100644 --- a/src/redux/apiPath.ts +++ b/src/redux/apiPath.ts @@ -53,6 +53,10 @@ export const apiPath = { `projects/${PROJECT_ID}/maps/${modelId}/layers/${layerId}/ovals/${ovalId}`, addLayerOval: (modelId: number, layerId: number): string => `projects/${PROJECT_ID}/maps/${modelId}/layers/${layerId}/ovals/`, + updateLayerOval: (modelId: number, layerId: number, ovalId: number | string): string => + `projects/${PROJECT_ID}/maps/${modelId}/layers/${layerId}/ovals/${ovalId}`, + removeLayerOval: (modelId: number, layerId: number, ovalId: number | string): string => + `projects/${PROJECT_ID}/maps/${modelId}/layers/${layerId}/ovals/${ovalId}`, getLayerLines: (modelId: number, layerId: number): string => `projects/${PROJECT_ID}/maps/${modelId}/layers/${layerId}/lines/`, getLayerImages: (modelId: number, layerId: number): string => diff --git a/src/redux/layers/layers.reducers.ts b/src/redux/layers/layers.reducers.ts index c28e00cecdb2ecfa2bdf99cb61a27e78511ed6c9..e8ba229c4c781bc2ed7650313f91cf1fc7813723 100644 --- a/src/redux/layers/layers.reducers.ts +++ b/src/redux/layers/layers.reducers.ts @@ -338,3 +338,31 @@ export const layerAddOvalReducer = ( } setLayerOval({ layerId, layers: data.layers, layerOval }); }; + +export const layerUpdateOvalReducer = ( + state: LayersState, + action: PayloadAction<{ modelId: number; layerId: number; layerOval: LayerOval }>, +): void => { + const { modelId, layerId, layerOval } = action.payload; + const { data } = state[modelId]; + if (!data) { + return; + } + setLayerOval({ layerId, layers: data.layers, layerOval }); +}; + +export const layerDeleteOvalReducer = ( + state: LayersState, + action: PayloadAction<{ modelId: number; layerId: number; ovalId: number }>, +): void => { + const { modelId, layerId, ovalId } = action.payload; + const { data } = state[modelId]; + if (!data) { + return; + } + const layer = data.layers[layerId]; + if (!layer) { + return; + } + delete layer.ovals[ovalId]; +}; diff --git a/src/redux/layers/layers.slice.ts b/src/redux/layers/layers.slice.ts index 19375020c3feb4d3de2e2c84537f395ac04927b8..243b6ab7dfb6d9da15e3a50d80c0fba6ad24e012 100644 --- a/src/redux/layers/layers.slice.ts +++ b/src/redux/layers/layers.slice.ts @@ -20,6 +20,8 @@ import { layerAddOvalReducer, getLayerReducer, layerDeleteReducer, + layerUpdateOvalReducer, + layerDeleteOvalReducer, } from '@/redux/layers/layers.reducers'; export const layersSlice = createSlice({ @@ -41,6 +43,8 @@ export const layersSlice = createSlice({ layerUpdateRect: layerUpdateRectReducer, layerDeleteRect: layerDeleteRectReducer, layerAddOval: layerAddOvalReducer, + layerUpdateOval: layerUpdateOvalReducer, + layerDeleteOval: layerDeleteOvalReducer, }, extraReducers: builder => { getLayersForModelReducer(builder); @@ -66,6 +70,8 @@ export const { layerUpdateRect, layerDeleteRect, layerAddOval, + layerUpdateOval, + layerDeleteOval, } = layersSlice.actions; export default layersSlice.reducer; diff --git a/src/redux/layers/layers.thunks.ts b/src/redux/layers/layers.thunks.ts index ee499b382917795f7116b79cd5b0e2cfd378785d..82620656a23995d09397d1479429beb3289ca989 100644 --- a/src/redux/layers/layers.thunks.ts +++ b/src/redux/layers/layers.thunks.ts @@ -529,3 +529,53 @@ export const addLayerOval = createAsyncThunk< return Promise.reject(getError({ error })); } }); + +export const updateLayerOval = createAsyncThunk< + LayerOval | null, + { + modelId: number; + layerId: number; + id: number; + x: number; + y: number; + z: number; + width: number; + height: number; + color: Color; + }, + ThunkConfig +>('layers/updateLayerOval', async ({ modelId, layerId, id, x, y, z, width, height, color }) => { + try { + const { data } = await axiosInstanceNewAPI.put<LayerOval>( + apiPath.updateLayerOval(modelId, layerId, id), + { + x, + y, + z, + width, + height, + color, + }, + ); + const isDataValid = validateDataUsingZodSchema(data, layerOvalSchema); + if (isDataValid) { + return data; + } + return null; + } catch (error) { + return Promise.reject(getError({ error })); + } +}); + +export const removeLayerOval = createAsyncThunk< + null, + { modelId: number; layerId: number; ovalId: number }, + ThunkConfig +>('layers/removeLayerOval', async ({ modelId, layerId, ovalId }) => { + try { + await axiosInstanceNewAPI.delete<void>(apiPath.removeLayerOval(modelId, layerId, ovalId)); + return null; + } catch (error) { + return Promise.reject(getError({ error })); + } +}); diff --git a/src/redux/mapEditTools/mapEditTools.reducers.ts b/src/redux/mapEditTools/mapEditTools.reducers.ts index b85196087f6c2cee0a425aae5a2ce4202c7eeb25..98c871a5bcfa1b5eb99ced56a21a7236d6eaf620 100644 --- a/src/redux/mapEditTools/mapEditTools.reducers.ts +++ b/src/redux/mapEditTools/mapEditTools.reducers.ts @@ -2,7 +2,7 @@ import { PayloadAction } from '@reduxjs/toolkit'; import { MAP_EDIT_ACTIONS } from '@/redux/mapEditTools/mapEditTools.constants'; import { MapEditToolsState } from '@/redux/mapEditTools/mapEditTools.types'; -import { LayerImage, LayerRect, LayerText } from '@/types/models'; +import { LayerImage, LayerOval, LayerRect, LayerText } from '@/types/models'; export const mapEditToolsSetActiveActionReducer = ( state: MapEditToolsState, @@ -13,7 +13,7 @@ export const mapEditToolsSetActiveActionReducer = ( export const mapEditToolsSetLayerObjectReducer = ( state: MapEditToolsState, - action: PayloadAction<LayerImage | LayerText | LayerRect | null>, + action: PayloadAction<LayerImage | LayerText | LayerRect | LayerOval | null>, ): void => { state.layerObject = action.payload; }; diff --git a/src/redux/mapEditTools/mapEditTools.types.ts b/src/redux/mapEditTools/mapEditTools.types.ts index b9a012c8cd3937d19c247cc2379225bc16fcc28b..50f2b0f4273929e3e465af2935babd5f10bf9a9a 100644 --- a/src/redux/mapEditTools/mapEditTools.types.ts +++ b/src/redux/mapEditTools/mapEditTools.types.ts @@ -1,7 +1,7 @@ import { MAP_EDIT_ACTIONS } from '@/redux/mapEditTools/mapEditTools.constants'; -import { LayerImage, LayerRect, LayerText } from '@/types/models'; +import { LayerImage, LayerOval, LayerRect, LayerText } from '@/types/models'; export type MapEditToolsState = { activeAction: keyof typeof MAP_EDIT_ACTIONS | null; - layerObject: LayerImage | LayerText | LayerRect | null; + layerObject: LayerImage | LayerText | LayerRect | LayerOval | null; }; diff --git a/src/redux/modal/modal.constants.ts b/src/redux/modal/modal.constants.ts index 0d59538049b7269b6666a33eb1967b150f944396..e1bd16d6813dfa4e230cf419468277e7fbb82f15 100644 --- a/src/redux/modal/modal.constants.ts +++ b/src/redux/modal/modal.constants.ts @@ -15,8 +15,5 @@ export const MODAL_INITIAL_STATE: ModalState = { editOverlayGroupState: null, errorReportState: {}, layerFactoryState: { id: undefined }, - layerImageObjectFactoryState: undefined, - layerTextFactoryState: undefined, - layerRectFactoryState: undefined, - layerOvalFactoryState: undefined, + layerObjectFactoryState: undefined, }; diff --git a/src/redux/modal/modal.mock.ts b/src/redux/modal/modal.mock.ts index f2cfc3e2af84655ffd5072d5be8b21148cca5d71..26872d50cd57e6ff2f045d743f768115f47dfcd9 100644 --- a/src/redux/modal/modal.mock.ts +++ b/src/redux/modal/modal.mock.ts @@ -15,8 +15,5 @@ export const MODAL_INITIAL_STATE_MOCK: ModalState = { editOverlayGroupState: null, errorReportState: {}, layerFactoryState: { id: undefined }, - layerImageObjectFactoryState: undefined, - layerTextFactoryState: undefined, - layerRectFactoryState: undefined, - layerOvalFactoryState: undefined, + layerObjectFactoryState: undefined, }; diff --git a/src/redux/modal/modal.reducers.ts b/src/redux/modal/modal.reducers.ts index b3e114e2bbc7fb28592fe680468b4290c0a1e4f9..0dda3081ad656ab53db3a1e41c87abd34d21a89b 100644 --- a/src/redux/modal/modal.reducers.ts +++ b/src/redux/modal/modal.reducers.ts @@ -158,7 +158,7 @@ export const openLayerImageObjectFactoryModalReducer = ( state: ModalState, action: PayloadAction<BoundingBox>, ): void => { - state.layerImageObjectFactoryState = action.payload; + state.layerObjectFactoryState = action.payload; state.isOpen = true; state.modalName = 'layer-image-object-factory'; state.modalTitle = 'Select glyph or upload file'; @@ -174,7 +174,7 @@ export const openLayerTextFactoryModalReducer = ( state: ModalState, action: PayloadAction<BoundingBox>, ): void => { - state.layerTextFactoryState = action.payload; + state.layerObjectFactoryState = action.payload; state.modalName = 'layer-text-factory'; state.modalTitle = 'Add text'; state.isOpen = true; @@ -190,7 +190,7 @@ export const openLayerRectFactoryModalReducer = ( state: ModalState, action: PayloadAction<BoundingBox>, ): void => { - state.layerRectFactoryState = action.payload; + state.layerObjectFactoryState = action.payload; state.modalName = 'layer-rect-factory'; state.modalTitle = 'Add rectangle'; state.isOpen = true; @@ -206,8 +206,14 @@ export const openLayerOvalFactoryModalReducer = ( state: ModalState, action: PayloadAction<BoundingBox>, ): void => { - state.layerOvalFactoryState = action.payload; + state.layerObjectFactoryState = action.payload; state.modalName = 'layer-oval-factory'; state.modalTitle = 'Add oval'; state.isOpen = true; }; + +export const openLayerOvalEditFactoryModalReducer = (state: ModalState): void => { + state.isOpen = true; + state.modalName = 'layer-oval-edit-factory'; + state.modalTitle = 'Edit oval'; +}; diff --git a/src/redux/modal/modal.selector.ts b/src/redux/modal/modal.selector.ts index 1bd5e7e451349ac575ab6fde47daef6441cf9f06..7c5224193cac110b864fd44f76095ee0511086c9 100644 --- a/src/redux/modal/modal.selector.ts +++ b/src/redux/modal/modal.selector.ts @@ -36,22 +36,7 @@ export const currentErrorDataSelector = createSelector( modal => modal?.errorReportState.errorData || undefined, ); -export const layerImageObjectFactoryStateSelector = createSelector( +export const layerObjectFactoryStateSelector = createSelector( modalSelector, - modal => modal.layerImageObjectFactoryState, -); - -export const layerTextFactoryStateSelector = createSelector( - modalSelector, - modal => modal.layerTextFactoryState, -); - -export const layerRectFactoryStateSelector = createSelector( - modalSelector, - modal => modal.layerRectFactoryState, -); - -export const layerOvalFactoryStateSelector = createSelector( - modalSelector, - modal => modal.layerOvalFactoryState, + modal => modal.layerObjectFactoryState, ); diff --git a/src/redux/modal/modal.slice.ts b/src/redux/modal/modal.slice.ts index 7485f54908639ebc20e7cdab6f565b4e04abd002..1618ce0d702553a83f77530b49a29503d12df4d7 100644 --- a/src/redux/modal/modal.slice.ts +++ b/src/redux/modal/modal.slice.ts @@ -25,6 +25,7 @@ import { openLayerRectEditFactoryModalReducer, openLayerOvalFactoryModalReducer, openEditOverlayGroupModalReducer, + openLayerOvalEditFactoryModalReducer, } from './modal.reducers'; const modalSlice = createSlice({ @@ -55,6 +56,7 @@ const modalSlice = createSlice({ openLayerRectFactoryModal: openLayerRectFactoryModalReducer, openLayerRectEditFactoryModal: openLayerRectEditFactoryModalReducer, openLayerOvalFactoryModal: openLayerOvalFactoryModalReducer, + openLayerOvalEditFactoryModal: openLayerOvalEditFactoryModalReducer, }, }); @@ -83,6 +85,7 @@ export const { openLayerRectFactoryModal, openLayerRectEditFactoryModal, openLayerOvalFactoryModal, + openLayerOvalEditFactoryModal, } = modalSlice.actions; export default modalSlice.reducer; diff --git a/src/redux/modal/modal.types.ts b/src/redux/modal/modal.types.ts index 811dc988cbcef41b12b2df68c3c766d4d1edae91..a558bfaba7b998c90a0eb8a26f48eb394ef8fb8e 100644 --- a/src/redux/modal/modal.types.ts +++ b/src/redux/modal/modal.types.ts @@ -35,10 +35,7 @@ export interface ModalState { editOverlayState: EditOverlayState; editOverlayGroupState: EditOverlayGroupState; layerFactoryState: LayerFactoryState; - layerImageObjectFactoryState: LayerObjectFactoryBoundingBoxState; - layerTextFactoryState: LayerObjectFactoryBoundingBoxState; - layerRectFactoryState: LayerObjectFactoryBoundingBoxState; - layerOvalFactoryState: LayerObjectFactoryBoundingBoxState; + layerObjectFactoryState: LayerObjectFactoryBoundingBoxState; } export type OpenEditOverlayModalPayload = MapOverlay; diff --git a/src/types/modal.ts b/src/types/modal.ts index 7e95a59c68f6e91f56d079085f1e50fd9fb004ef..5efc956488c8a9902f2f2b1a9c66b477942d27ec 100644 --- a/src/types/modal.ts +++ b/src/types/modal.ts @@ -20,4 +20,5 @@ export type ModalName = | 'layer-text-edit-factory' | 'layer-rect-factory' | 'layer-rect-edit-factory' - | 'layer-oval-factory'; + | 'layer-oval-factory' + | 'layer-oval-edit-factory';