import { useParams } from "react-router-dom"; import { getUserData } from "../../../../../functions/getUserData"; import { useSceneContext } from "../../../sceneContext"; import { useSocketStore } from "../../../../../store/socket/useSocketStore"; import useAssetResponseHandler from "../../../../builder/asset/responseHandler/useAssetResponseHandler"; import { upsertProductOrEventApi } from "../../../../../services/simulation/products/UpsertProductOrEventApi"; import { setAssetsApi } from "../../../../../services/factoryBuilder/asset/floorAsset/setAssetsApi"; import { deleteFloorAssetApi } from "../../../../../services/factoryBuilder/asset/floorAsset/deleteFloorAssetApi"; function use3DUndoHandler() { const { undoRedo3DStore, productStore, eventStore, versionStore } = useSceneContext(); const { deleteEvent, selectedProduct } = productStore(); const { addEvent, removeEvent } = eventStore(); const { addAssetToScene, removeAssetFromScene, updateAssetInScene } = useAssetResponseHandler(); const { undo3D, peekUndo3D } = undoRedo3DStore(); const { selectedVersion } = versionStore(); const { userId, organization } = getUserData(); const { projectId } = useParams(); const { builderSocket } = useSocketStore(); const updateBackend = (productName: string, productUuid: string, projectId: string, eventData: EventsSchema) => { upsertProductOrEventApi({ productName: productName, productUuid: productUuid, projectId: projectId, eventDatas: eventData, versionId: selectedVersion?.versionId || "", }); }; const handleUndo = () => { const unDoData = peekUndo3D(); if (!unDoData) return; if (unDoData.type === "Scene") { const { actions } = unDoData; actions.forEach((action) => { const { actionType } = action; if ("asset" in action) { const asset = action.asset; if (actionType === "Asset-Add") { handleDelete(asset); } else if (actionType === "Asset-Delete") { handleAdd(asset); } else if (actionType === "Asset-Update") { handleUpdate(asset); } else if (actionType === "Asset-Copied") { handleCopy(asset); } else if (actionType === "Asset-Duplicated") { handleDuplicate(asset); } } else if ("assets" in action) { const assets = action.assets; if (actionType === "Assets-Add") { assets.forEach(handleDelete); } else if (actionType === "Assets-Delete") { assets.forEach(handleAdd); } else if (actionType === "Assets-Update") { assets.forEach(handleUpdate); } else if (actionType === "Assets-Copied") { assets.forEach(handleCopy); } else if (actionType === "Assets-Duplicated") { assets.forEach(handleDuplicate); } } }); } else if (unDoData.type === "UI") { // Handle UI actions if needed } undo3D(); }; const handleAdd = (asset: AssetData) => { switch (asset.type) { case "Asset": addAssetToBackend(asset.assetData); break; case "WallAsset": addWallAssetToBackend(asset.assetData); break; } }; const handleDelete = (asset: AssetData) => { switch (asset.type) { case "Asset": deleteAssetToBackend(asset.assetData); break; case "WallAsset": deleteWallAssetToBackend(asset.assetData); break; } }; const handleUpdate = (asset: AssetData) => { switch (asset.type) { case "Asset": updateAssetToBackend(asset.assetData.modelUuid, asset.assetData); break; case "WallAsset": updateWallAssetToBackend(asset.assetData.modelUuid, asset.assetData); break; } }; const handleCopy = (asset: AssetData) => { switch (asset.type) { case "Asset": copyAssetToBackend(asset.assetData); break; case "WallAsset": copyWallAssetToBackend(asset.assetData); break; } }; const handleDuplicate = (asset: AssetData) => { switch (asset.type) { case "Asset": duplicateAssetToBackend(asset.assetData); break; case "WallAsset": duplicateWallAssetToBackend(asset.assetData); break; } }; const addAssetToBackend = (assetData: Asset) => { if (projectId) { const data = { organization, modelUuid: assetData.modelUuid, modelName: assetData.modelName, assetId: assetData.assetId, position: assetData.position, rotation: { x: assetData.rotation[0], y: assetData.rotation[1], z: assetData.rotation[2] }, isLocked: false, isVisible: true, eventData: {}, socketId: builderSocket?.id, versionId: selectedVersion?.versionId || "", projectId, userId, }; if (assetData.eventData) { data.eventData = assetData.eventData; addEvent(assetData.eventData as EventsSchema); } if (!builderSocket?.connected) { // REST setAssetsApi({ modelUuid: assetData.modelUuid, modelName: assetData.modelName, assetId: assetData.assetId, position: assetData.position, rotation: { x: assetData.rotation[0], y: assetData.rotation[1], z: assetData.rotation[2] }, isLocked: false, isVisible: true, eventData: data.eventData, versionId: selectedVersion?.versionId || "", projectId: projectId, }).then((data) => { if (!data.message || !data.data) { echo.error(`Error adding asset`); return; } if (data.message === "Model created successfully" && data.data) { const model: Asset = { modelUuid: data.data.modelUuid, modelName: data.data.modelName, assetId: data.data.assetId, position: data.data.position, rotation: [data.data.rotation.x, data.data.rotation.y, data.data.rotation.z], isLocked: data.data.isLocked, isCollidable: true, isVisible: data.data.isVisible, opacity: 1, ...(data.data.eventData ? { eventData: data.data.eventData } : {}), }; addAssetToScene(model, () => { echo.log(`Added asset: ${model.modelName}`); }); } else { removeAssetFromScene(data.data.modelUuid, () => { echo.error(`Error adding asset: ${data?.data?.modelName}`); }); } }); } else { // SOCKET builderSocket.emit("v1:model-asset:add", data); } } }; const deleteAssetToBackend = (assetData: Asset) => { if (!builderSocket?.connected) { // REST deleteFloorAssetApi({ modelUuid: assetData.modelUuid, modelName: assetData.modelName, versionId: selectedVersion?.versionId || "", projectId: projectId || "", }).then((data) => { if (!data.message || !data.data) { echo.error(`Error removing asset`); return; } if (data.message === "Model deleted successfully") { removeAssetFromScene(data.data.modelUuid, () => { echo.log(`Removed asset: ${data.data.modelName}`); }); } else { echo.error(`Error removing asset: ${data?.data?.modelName}`); } }); } else { // SOCKET const data = { organization, modelUuid: assetData.modelUuid, modelName: assetData.modelName, socketId: builderSocket.id, userId, versionId: selectedVersion?.versionId || "", projectId, }; builderSocket.emit("v1:model-asset:delete", data); } removeEvent(assetData.modelUuid); const updatedEvents = deleteEvent(assetData.modelUuid); updatedEvents.forEach((event) => { updateBackend(selectedProduct.productName, selectedProduct.productUuid, projectId || "", event); }); }; const updateAssetToBackend = (modelUuid: string, updatedData: Asset) => { if (projectId) { const data = { organization, modelUuid: modelUuid, modelName: updatedData.modelName, assetId: updatedData.assetId, position: updatedData.position, rotation: { x: updatedData.rotation[0], y: updatedData.rotation[1], z: updatedData.rotation[2] }, isLocked: false, isVisible: true, socketId: builderSocket?.id, versionId: selectedVersion?.versionId || "", projectId, userId, }; if (!builderSocket?.connected) { // REST setAssetsApi({ modelUuid: modelUuid, modelName: updatedData.modelName, assetId: updatedData.assetId, position: updatedData.position, rotation: { x: updatedData.rotation[0], y: updatedData.rotation[1], z: updatedData.rotation[2] }, isLocked: false, isVisible: true, versionId: selectedVersion?.versionId || "", projectId: projectId, }).then((data) => { if (!data.message || !data.data) { echo.error(`Error updating asset`); return; } if (data.message === "Model updated successfully" && data.data) { const model: Asset = { modelUuid: data.data.modelUuid, modelName: data.data.modelName, assetId: data.data.assetId, position: data.data.position, rotation: [data.data.rotation.x, data.data.rotation.y, data.data.rotation.z], isLocked: data.data.isLocked, isCollidable: true, isVisible: data.data.isVisible, opacity: 1, ...(data.data.eventData ? { eventData: data.data.eventData } : {}), }; updateAssetInScene(model, () => { echo.log(`Updated asset: ${model.modelName}`); }); } else { removeAssetFromScene(data.data.modelUuid, () => { echo.error(`Error updating asset: ${data?.data?.modelName}`); }); } }); } else { // SOCKET builderSocket.emit("v1:model-asset:add", data); } } }; const copyAssetToBackend = (assetData: Asset) => { if (!builderSocket?.connected) { // REST deleteFloorAssetApi({ modelUuid: assetData.modelUuid, modelName: assetData.modelName, versionId: selectedVersion?.versionId || "", projectId: projectId || "", }).then((data) => { if (!data.message || !data.data) { echo.error(`Error removing asset`); return; } if (data.message === "Model deleted successfully") { removeAssetFromScene(data.data.modelUuid, () => { echo.log(`Removed asset: ${data.data.modelName}`); }); } else { echo.error(`Error removing asset: ${data?.data?.modelName}`); } }); } else { // SOCKET const data = { organization, modelUuid: assetData.modelUuid, modelName: assetData.modelName, socketId: builderSocket.id, userId, versionId: selectedVersion?.versionId || "", projectId, }; builderSocket.emit("v1:model-asset:delete", data); } removeEvent(assetData.modelUuid); const updatedEvents = deleteEvent(assetData.modelUuid); updatedEvents.forEach((event) => { updateBackend(selectedProduct.productName, selectedProduct.productUuid, projectId || "", event); }); }; const duplicateAssetToBackend = (assetData: Asset) => { if (!builderSocket?.connected) { // REST deleteFloorAssetApi({ modelUuid: assetData.modelUuid, modelName: assetData.modelName, versionId: selectedVersion?.versionId || "", projectId: projectId || "", }).then((data) => { if (!data.message || !data.data) { echo.error(`Error removing asset`); return; } if (data.message === "Model deleted successfully") { removeAssetFromScene(data.data.modelUuid, () => { echo.log(`Removed asset: ${data.data.modelName}`); }); } else { echo.error(`Error removing asset: ${data?.data?.modelName}`); } }); } else { // SOCKET const data = { organization, modelUuid: assetData.modelUuid, modelName: assetData.modelName, socketId: builderSocket.id, userId, versionId: selectedVersion?.versionId || "", projectId, }; builderSocket.emit("v1:model-asset:delete", data); } removeEvent(assetData.modelUuid); const updatedEvents = deleteEvent(assetData.modelUuid); updatedEvents.forEach((event) => { updateBackend(selectedProduct.productName, selectedProduct.productUuid, projectId || "", event); }); }; const addWallAssetToBackend = (assetData: WallAsset) => {}; const deleteWallAssetToBackend = (assetData: WallAsset) => {}; const updateWallAssetToBackend = (modelUuid: string, updatedData: WallAsset) => {}; const copyWallAssetToBackend = (assetData: WallAsset) => {}; const duplicateWallAssetToBackend = (assetData: WallAsset) => {}; return { handleUndo }; } export default use3DUndoHandler;