import { devlog } from "@frontend/kitui"; import { AnyTypedQuizQuestion } from "@model/questionTypes/shared"; import { Box, Button } from "@mui/material"; import { clearRuleForAll } from "@root/questions/actions"; import { useQuestionsStore } from "@root/questions/store"; import { updateRootContentId } from "@root/quizes/actions"; import { useCurrentQuiz } from "@root/quizes/hooks"; import { cleardragQuestionContentId, setModalQuestionParentContentId, setModalQuestionTargetContentId, updateModalInfoWhyCantCreate, updateOpenedModalSettingsId } from "@root/uiTools/actions"; import { useUiTools } from "@root/uiTools/store"; import { ProblemIcon } from "@ui_kit/ProblemIcon"; import type { Core } from "cytoscape"; import Cytoscape from "cytoscape"; import popper from "cytoscape-popper"; import { enqueueSnackbar } from "notistack"; import { useEffect, useLayoutEffect, useMemo, useRef } from "react"; import CytoscapeComponent from "react-cytoscapejs"; import { withErrorBoundary } from "react-error-boundary"; import { DeleteNodeModal } from "../DeleteNodeModal"; import { addNode, layoutOptions, storeToNodes } from "./helper"; import { usePopper } from "./hooks/usePopper"; import { useRemoveNode } from "./hooks/useRemoveNode"; import "./style/styles.css"; import { stylesheet } from "./style/stylesheet"; Cytoscape.use(popper); function CsComponent() { const desireToOpenABranchingModal = useUiTools(state => state.desireToOpenABranchingModal); const canCreatePublic = useUiTools(state => state.canCreatePublic); const modalQuestionParentContentId = useUiTools(state => state.modalQuestionParentContentId); const modalQuestionTargetContentId = useUiTools(state => state.modalQuestionTargetContentId); const trashQuestions = useQuestionsStore(state => state.questions); const cyRef = useRef(null); const { recreatePoppers, removeAllPoppers } = usePopper({ cyRef }); const { removeNode } = useRemoveNode({ cyRef }); const cyElements = useMemo(() => { const questions = trashQuestions.filter( (question): question is AnyTypedQuizQuestion => question.type !== null && question.type !== "result" ); return storeToNodes(questions); }, [trashQuestions]); useLayoutEffect(() => { const cy = cyRef?.current; if (desireToOpenABranchingModal) { setTimeout(() => { cy?.getElementById(desireToOpenABranchingModal)?.data("eroticeyeblink", true); }, 250); } else { cy?.elements().data("eroticeyeblink", false); } }, [desireToOpenABranchingModal]); useEffect(() => { if (modalQuestionTargetContentId.length !== 0 && modalQuestionParentContentId.length !== 0) { if (!cyRef.current) return; addNode({ parentNodeContentId: modalQuestionParentContentId, targetNodeContentId: modalQuestionTargetContentId, }); } setModalQuestionParentContentId(""); setModalQuestionTargetContentId(""); }, [modalQuestionTargetContentId]); useEffect(function onMount() { updateOpenedModalSettingsId(); document.addEventListener("pointerup", cleardragQuestionContentId); return () => { document.removeEventListener("pointerup", cleardragQuestionContentId); removeAllPoppers(); }; }, []); useEffect(function removePoppersOnDrag() { const cy = cyRef.current; if (!cy) return; let isPointerDown = false; let isDragging = false; const onPointerDown = () => { isPointerDown = true; }; const onPointerUp = () => { if (isDragging) { isDragging = false; recreatePoppers(); } isPointerDown = false; }; const handleMove = () => { if (isPointerDown) { isDragging = true; removeAllPoppers(); } }; cy.on("vmousedown", onPointerDown); cy.on("vmousemove", handleMove); document.addEventListener("pointerup", onPointerUp); return () => { cy.off("vmousedown", onPointerDown); cy.off("vmousemove", handleMove); document.removeEventListener("pointerup", onPointerUp); }; }, [recreatePoppers, removeAllPoppers]); useEffect(() => { cyRef.current?.layout(layoutOptions).run(); cyRef.current?.fit(undefined, 70); recreatePoppers(); }, [cyElements, recreatePoppers]); return ( <> updateModalInfoWhyCantCreate(true)} /> { cyRef.current = cy; }} autoungrabify={true} /> ); } function Clear() { const quiz = useCurrentQuiz(); if (quiz) { updateRootContentId(quiz?.id, ""); } clearRuleForAll(); return <>; } export default withErrorBoundary(CsComponent, { fallback: , onError: (error, info) => { enqueueSnackbar("Дерево порвалось"); devlog(info); devlog(error); }, });