Newer
Older
/* eslint-disable no-magic-numbers */
import { useAppSelector } from '@/redux/hooks/useAppSelector';
import {
highestZIndexSelector,
layerByIdSelector,
lowestZIndexSelector,
} from '@/redux/layers/layers.selectors';
import { JSX, useState } from 'react';
import { LayersDrawerImageItem } from '@/components/Map/Drawer/LayersDrawer/LayersDrawerImageItem.component';
import { LayersDrawerTextItem } from '@/components/Map/Drawer/LayersDrawer/LayerDrawerTextItem.component';
import QuestionModal from '@/components/FunctionalArea/Modal/QuestionModal/QustionModal.component';
Miłosz Grocholewski
committed
import {
removeLayerImage,
removeLayerText,
updateLayerImageObject,
Miłosz Grocholewski
committed
updateLayerText,
Miłosz Grocholewski
committed
} from '@/redux/layers/layers.thunks';
Miłosz Grocholewski
committed
import {
layerDeleteImage,
layerDeleteText,
layerUpdateImage,
layerUpdateText,
} from '@/redux/layers/layers.slice';
import removeElementFromLayer from '@/components/Map/MapViewer/utils/shapes/elements/removeElementFromLayer';
import { showToast } from '@/utils/showToast';
import { SerializedError } from '@reduxjs/toolkit';
Miłosz Grocholewski
committed
import { LayerImage, LayerText } from '@/types/models';
import { useAppDispatch } from '@/redux/hooks/useAppDispatch';
import { useMapInstance } from '@/utils/context/mapInstanceContext';
import { mapModelIdSelector } from '@/redux/map/map.selectors';
import { mapEditToolsSetLayerObject } from '@/redux/mapEditTools/mapEditTools.slice';
Miłosz Grocholewski
committed
import updateElement from '@/components/Map/MapViewer/utils/shapes/layer/utils/updateElement';
import { useSetBounds } from '@/utils/map/useSetBounds';
Miłosz Grocholewski
committed
import { mapEditToolsLayerObjectSelector } from '@/redux/mapEditTools/mapEditTools.selectors';
import { usePointToProjection } from '@/utils/map/usePointToProjection';
import { Coordinate } from 'ol/coordinate';
Miłosz Grocholewski
committed
import {
openLayerImageObjectEditFactoryModal,
openLayerTextEditFactoryModal,
} from '@/redux/modal/modal.slice';
interface LayersDrawerObjectsListProps {
layerId: number;
isLayerVisible: boolean;
isLayerActive: boolean;
}
Miłosz Grocholewski
committed
const removeObjectConfig = {
image: {
question: 'Are you sure you want to remove the image?',
successMessage: 'The layer image has been successfully removed',
errorMessage: 'An error occurred while removing the layer text',
},
text: {
question: 'Are you sure you want to remove the text?',
successMessage: 'The layer text has been successfully removed',
errorMessage: 'An error occurred while removing the layer text',
},
};
export const LayersDrawerObjectsList = ({
layerId,
isLayerVisible,
isLayerActive,
}: LayersDrawerObjectsListProps): JSX.Element | null => {
const currentModelId = useAppSelector(mapModelIdSelector);
const highestZIndex = useAppSelector(highestZIndexSelector);
const lowestZIndex = useAppSelector(lowestZIndexSelector);
const layer = useAppSelector(state => layerByIdSelector(state, layerId));
Miłosz Grocholewski
committed
const mapEditToolsLayerImageObject = useAppSelector(mapEditToolsLayerObjectSelector);
const [removeModalState, setRemoveModalState] = useState<undefined | 'text' | 'image'>(undefined);
const [layerObjectToRemove, setLayerObjectToRemove] = useState<LayerImage | LayerText | null>(
null,
);
const dispatch = useAppDispatch();
const setBounds = useSetBounds();
const pointToProjection = usePointToProjection();
const { mapInstance } = useMapInstance();
Miłosz Grocholewski
committed
const removeObject = (layerObject: LayerImage | LayerText): void => {
setLayerObjectToRemove(layerObject);
if ('glyph' in layerObject) {
setRemoveModalState('image');
} else {
setRemoveModalState('text');
}
Miłosz Grocholewski
committed
const rejectRemove = (): void => {
setRemoveModalState(undefined);
Miłosz Grocholewski
committed
const confirmRemove = async (): Promise<void> => {
if (!layerObjectToRemove || !removeModalState) {
Miłosz Grocholewski
committed
Miłosz Grocholewski
committed
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
if (removeModalState === 'text') {
await dispatch(
removeLayerText({
modelId: currentModelId,
layerId: layerObjectToRemove.layer,
textId: layerObjectToRemove.id,
}),
).unwrap();
dispatch(
layerDeleteText({
modelId: currentModelId,
layerId: layerObjectToRemove.layer,
textId: layerObjectToRemove.id,
}),
);
} else {
await dispatch(
removeLayerImage({
modelId: currentModelId,
layerId: layerObjectToRemove.layer,
imageId: layerObjectToRemove.id,
}),
).unwrap();
dispatch(
layerDeleteImage({
modelId: currentModelId,
layerId: layerObjectToRemove.layer,
imageId: layerObjectToRemove.id,
}),
);
}
removeElementFromLayer({
mapInstance,
Miłosz Grocholewski
committed
layerId: layerObjectToRemove.layer,
featureId: layerObjectToRemove.id,
});
showToast({
type: 'success',
Miłosz Grocholewski
committed
message: removeObjectConfig[removeModalState].successMessage,
Miłosz Grocholewski
committed
setRemoveModalState(undefined);
} catch (error) {
const typedError = error as SerializedError;
showToast({
type: 'error',
Miłosz Grocholewski
committed
message: typedError.message || removeObjectConfig[removeModalState].errorMessage,
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
});
}
};
const updateImageZIndex = async ({
zIndex,
layerImage,
}: {
zIndex: number;
layerImage: LayerImage;
}): Promise<void> => {
const newLayerImage = await dispatch(
updateLayerImageObject({
modelId: currentModelId,
layerId: layerImage.layer,
...layerImage,
z: zIndex,
}),
).unwrap();
if (newLayerImage) {
dispatch(
layerUpdateImage({
modelId: currentModelId,
layerId: newLayerImage.layer,
layerImage: newLayerImage,
}),
);
dispatch(mapEditToolsSetLayerObject(newLayerImage));
Miłosz Grocholewski
committed
updateElement(mapInstance, newLayerImage.layer, newLayerImage);
const bringImageToFront = async (layerImage: LayerImage): Promise<void> => {
await updateImageZIndex({ zIndex: highestZIndex + 1, layerImage });
const bringImageToBack = async (layerImage: LayerImage): Promise<void> => {
await updateImageZIndex({ zIndex: lowestZIndex - 1, layerImage });
Miłosz Grocholewski
committed
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
const updateTextZIndex = async ({
zIndex,
layerText,
}: {
zIndex: number;
layerText: LayerText;
}): Promise<void> => {
const newLayerText = await dispatch(
updateLayerText({
modelId: currentModelId,
layerId: layerText.layer,
...layerText,
z: zIndex,
}),
).unwrap();
if (newLayerText) {
dispatch(
layerUpdateText({
modelId: currentModelId,
layerId: newLayerText.layer,
layerText: newLayerText,
}),
);
dispatch(mapEditToolsSetLayerObject(newLayerText));
updateElement(mapInstance, newLayerText.layer, newLayerText);
}
};
const bringTextToFront = async (layerText: LayerText): Promise<void> => {
await updateTextZIndex({ zIndex: highestZIndex + 1, layerText });
Miłosz Grocholewski
committed
};
const bringTextToBack = async (layerText: LayerText): Promise<void> => {
await updateTextZIndex({ zIndex: lowestZIndex - 1, layerText });
Miłosz Grocholewski
committed
};
Miłosz Grocholewski
committed
const centerObject = (layerObject: LayerImage | LayerText): void => {
if (mapEditToolsLayerImageObject && mapEditToolsLayerImageObject.id === layerObject.id) {
const point1 = pointToProjection({ x: layerObject.x, y: layerObject.y });
const point2 = pointToProjection({
Miłosz Grocholewski
committed
x: layerObject.x + layerObject.width,
y: layerObject.y + layerObject.height,
});
setBounds([point1, point2] as Coordinate[]);
}
};
const editImage = (): void => {
dispatch(openLayerImageObjectEditFactoryModal());
};
Miłosz Grocholewski
committed
const editText = (): void => {
dispatch(openLayerTextEditFactoryModal());
};
if (!layer) {
return null;
}
return (
<div className={`${isLayerVisible ? 'opacity-100' : 'opacity-40'} flex flex-col gap-1 ps-3`}>
<QuestionModal
Miłosz Grocholewski
committed
isOpen={Boolean(removeModalState)}
onClose={rejectRemove}
onConfirm={confirmRemove}
question={
removeModalState
Miłosz Grocholewski
committed
? removeObjectConfig[removeModalState]?.question
Miłosz Grocholewski
committed
: 'Are you sure you want to remove the object'
}
/>
{Object.values(layer.texts).map(layerText => (
Miłosz Grocholewski
committed
<LayersDrawerTextItem
layerText={layerText}
key={layerText.id}
bringToFront={() => bringTextToFront(layerText)}
bringToBack={() => bringTextToBack(layerText)}
Miłosz Grocholewski
committed
removeObject={() => removeObject(layerText)}
centerObject={() => centerObject(layerText)}
Miłosz Grocholewski
committed
editObject={() => editText()}
Miłosz Grocholewski
committed
isLayerVisible={isLayerVisible}
isLayerActive={isLayerActive}
/>
))}
{Object.values(layer.images).map(layerImage => (
<LayersDrawerImageItem
layerImage={layerImage}
key={layerImage.id}
bringToFront={() => bringImageToFront(layerImage)}
bringToBack={() => bringImageToBack(layerImage)}
Miłosz Grocholewski
committed
removeObject={() => removeObject(layerImage)}
centerObject={() => centerObject(layerImage)}
editObject={() => editImage()}
isLayerVisible={isLayerVisible}
isLayerActive={isLayerActive}
/>
))}
</div>
);
};