Merge branch 'dev' into startpage-preview-fix
This commit is contained in:
commit
965c0bc757
@ -18,6 +18,7 @@ export const QUIZ_QUESTION_BASE: Omit<QuizQuestionBase, "id" | "backendId"> = {
|
||||
video: "",
|
||||
},
|
||||
rule: {
|
||||
children: [],
|
||||
main: [] as QuestionBranchingRuleMain[],
|
||||
parentId: "",
|
||||
default: ""
|
||||
|
@ -23,6 +23,7 @@ export interface QuestionBranchingRuleMain {
|
||||
}
|
||||
export interface QuestionBranchingRule {
|
||||
|
||||
children: string[],
|
||||
//список условий
|
||||
main: QuestionBranchingRuleMain[];
|
||||
parentId: string | null | "root";
|
||||
|
@ -7,7 +7,7 @@ import { useCurrentQuiz } from "@root/quizes/hooks";
|
||||
import { updateRootContentId } from "@root/quizes/actions"
|
||||
import { AnyTypedQuizQuestion } from "@model/questionTypes/shared"
|
||||
import { useQuestionsStore } from "@root/questions/store";
|
||||
import { cleardragQuestionContentId, updateQuestion, updateOpenedModalSettingsId, getQuestionByContentId, clearRuleForAll } from "@root/questions/actions";
|
||||
import { deleteQuestion, cleardragQuestionContentId, updateQuestion, updateOpenedModalSettingsId, getQuestionByContentId, clearRuleForAll } from "@root/questions/actions";
|
||||
import { withErrorBoundary } from "react-error-boundary";
|
||||
|
||||
import { storeToNodes } from "./helper";
|
||||
@ -112,13 +112,13 @@ interface Props {
|
||||
}
|
||||
|
||||
|
||||
function CsComponent ({
|
||||
function CsComponent({
|
||||
modalQuestionParentContentId,
|
||||
modalQuestionTargetContentId,
|
||||
setOpenedModalQuestions,
|
||||
setModalQuestionParentContentId,
|
||||
setModalQuestionTargetContentId
|
||||
}: Props) {
|
||||
}: Props) {
|
||||
const quiz = useCurrentQuiz();
|
||||
|
||||
const { dragQuestionContentId, desireToOpenABranchingModal } = useQuestionsStore()
|
||||
@ -187,18 +187,32 @@ function CsComponent ({
|
||||
}
|
||||
|
||||
const clearDataAfterAddNode = ({ parentNodeContentId, targetQuestion, parentNodeChildren }: { parentNodeContentId: string, targetQuestion: AnyTypedQuizQuestion, parentNodeChildren: number }) => {
|
||||
|
||||
const parentQuestion = { ...getQuestionByContentId(parentNodeContentId) } as AnyTypedQuizQuestion
|
||||
|
||||
|
||||
//смотрим не добавлен ли родителю result. Если да - убираем его. Веточкам result не нужен
|
||||
trashQuestions.forEach((targetQuestion) => {
|
||||
if (targetQuestion.type === "result" && targetQuestion.content.rule.parentId === parentQuestion.content.id) {
|
||||
deleteQuestion(targetQuestion.id);
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
//предупреждаем добавленный вопрос о том, кто его родитель
|
||||
updateQuestion(targetQuestion.content.id, question => {
|
||||
question.content.rule.parentId = parentNodeContentId
|
||||
question.content.rule.main = []
|
||||
})
|
||||
//предупреждаем родителя о новом потомке (если он ещё не знает о нём)
|
||||
if (!parentQuestion.content.rule.children.includes(targetQuestion.content.id)) updateQuestion(parentNodeContentId, question => {
|
||||
question.content.rule.children = [...question.content.rule.children, targetQuestion.content.id]
|
||||
})
|
||||
|
||||
|
||||
//Если детей больше 1 - предупреждаем стор вопросов об открытии модалки ветвления
|
||||
if (parentNodeChildren >= 1) {
|
||||
if (parentQuestion.content.rule.children >= 1) {
|
||||
updateOpenedModalSettingsId(targetQuestion.content.id)
|
||||
} else {
|
||||
//Если ребёнок первый - добавляем его родителю как дефолтный
|
||||
updateQuestion(parentNodeContentId, question => question.content.rule.default = targetQuestion.content.id)
|
||||
}
|
||||
}
|
||||
|
||||
@ -232,10 +246,18 @@ function CsComponent ({
|
||||
updateQuestion(targetNodeContentId, question => {
|
||||
question.content.rule.parentId = ""
|
||||
question.content.rule.main = []
|
||||
question.content.rule.children = []
|
||||
question.content.rule.default = ""
|
||||
})
|
||||
trashQuestions.forEach(q => {
|
||||
if (q.type === "result") {
|
||||
deleteQuestion(q.id);
|
||||
}
|
||||
});
|
||||
clearRuleForAll()
|
||||
|
||||
} else {
|
||||
|
||||
const parentQuestionContentId = cy?.$('edge[target = "' + targetNodeContentId + '"]')?.toArray()?.[0]?.data()?.source
|
||||
if (targetNodeContentId && parentQuestionContentId) {
|
||||
|
||||
@ -245,7 +267,7 @@ function CsComponent ({
|
||||
|
||||
}
|
||||
|
||||
//После всех манипуляций удаляем грани из CS и ноды из бекенда
|
||||
//После всех манипуляций удаляем грани и ноды из CS Чистим rule потомков на беке
|
||||
|
||||
deleteNodes.forEach((nodeId) => {//Ноды
|
||||
cy?.remove(cy?.$("#" + nodeId))
|
||||
@ -254,7 +276,10 @@ function CsComponent ({
|
||||
question.content.rule.parentId = ""
|
||||
question.content.rule.main = []
|
||||
question.content.rule.default = ""
|
||||
question.content.rule.children = []
|
||||
})
|
||||
|
||||
|
||||
})
|
||||
|
||||
deleteEdges.forEach((edge: any) => {//Грани
|
||||
@ -264,28 +289,41 @@ function CsComponent ({
|
||||
removeButtons(targetNodeContentId)
|
||||
cy?.data('changed', true)
|
||||
cy?.layout(lyopts).run()
|
||||
|
||||
//удаляем result всех потомков
|
||||
trashQuestions.forEach((qr) => {
|
||||
if (qr.type === "result") {
|
||||
if (deleteNodes.includes(qr.content.rule.parentId) || qr.content.rule.parentId === targetQuestion.content.id) {
|
||||
deleteQuestion(qr.id);
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
const clearDataAfterRemoveNode = ({ targetQuestionContentId, parentQuestionContentId }: { targetQuestionContentId: string, parentQuestionContentId: string }) => {
|
||||
|
||||
console.log("target ",targetQuestionContentId, "parent ", parentQuestionContentId)
|
||||
|
||||
|
||||
|
||||
console.log("target ", targetQuestionContentId, "parent ", parentQuestionContentId)
|
||||
|
||||
|
||||
updateQuestion(targetQuestionContentId, question => {
|
||||
question.content.rule.parentId = ""
|
||||
question.content.rule.children = []
|
||||
question.content.rule.main = []
|
||||
question.content.rule.default = ""
|
||||
})
|
||||
|
||||
|
||||
//чистим rule родителя
|
||||
const parentQuestion = getQuestionByContentId(parentQuestionContentId)
|
||||
console.log(parentQuestion.content.rule.parentId)
|
||||
const newRule = {}
|
||||
const newChildren = [...parentQuestion.content.rule.children]
|
||||
newChildren.splice(parentQuestion.content.rule.children.indexOf(targetQuestionContentId), 1);
|
||||
newRule.main = parentQuestion.content.rule.main.filter((data) => data.next !== targetQuestionContentId) //удаляем условия перехода от родителя к этому вопросу
|
||||
newRule.parentId = parentQuestion.content.rule.parentId
|
||||
newRule.default = questions.filter((q) => {
|
||||
return q.content.rule.parentId === parentQuestionContentId && q.content.id !== targetQuestionContentId
|
||||
})[0]?.content.id || ""
|
||||
//Если этот вопрос был дефолтным у родителя - чистим дефолт
|
||||
//Смотрим можем ли мы заменить id на один из main
|
||||
newRule.default = parentQuestion.content.rule.default === targetQuestionContentId ? "" : parentQuestion.content.rule.default
|
||||
newRule.children = newChildren
|
||||
|
||||
updateQuestion(parentQuestionContentId, (PQ) => {
|
||||
PQ.content.rule = newRule
|
||||
@ -335,7 +373,7 @@ function CsComponent ({
|
||||
positions: (e) => {
|
||||
if (!e.cy().data('changed')) {
|
||||
return e.data('oldPos')
|
||||
}
|
||||
}
|
||||
const id = e.id()
|
||||
const incomming = e.cy().edges(`[target="${id}"]`)
|
||||
const layer = 0
|
||||
@ -366,7 +404,7 @@ function CsComponent ({
|
||||
while (queue.length) {
|
||||
const task = queue.pop()
|
||||
if (task.children.length === 0) {
|
||||
task.parent.data('subtreeWidth', task.parent.height()+50)
|
||||
task.parent.data('subtreeWidth', task.parent.height() + 50)
|
||||
continue
|
||||
}
|
||||
const unprocessed = task?.children.filter(e => {
|
||||
@ -385,19 +423,19 @@ function CsComponent ({
|
||||
|
||||
const pos = { x: 0, y: 0 }
|
||||
e.data('oldPos', pos)
|
||||
|
||||
queue.push({task: children, parent: e})
|
||||
|
||||
queue.push({ task: children, parent: e })
|
||||
while (queue.length) {
|
||||
const task = queue.pop()
|
||||
const oldPos = task.parent.data('oldPos')
|
||||
let yoffset = oldPos.y - task.parent.data('subtreeWidth') / 2
|
||||
let yoffset = oldPos.y - task.parent.data('subtreeWidth') / 2
|
||||
task.task.forEach(n => {
|
||||
const width = n.data('subtreeWidth')
|
||||
|
||||
console.log('ORORORORO',n.data(), yoffset, width, oldPos, task.parent.data('subtreeWidth'))
|
||||
n.data('oldPos',{x: 250 * n.data('layer'),y: yoffset + width/2})
|
||||
yoffset+=width
|
||||
queue.push({task: n.cy().edges(`[source="${n.id()}"]`).targets(), parent: n})
|
||||
console.log('ORORORORO', n.data(), yoffset, width, oldPos, task.parent.data('subtreeWidth'))
|
||||
n.data('oldPos', { x: 250 * n.data('layer'), y: yoffset + width / 2 })
|
||||
yoffset += width
|
||||
queue.push({ task: n.cy().edges(`[source="${n.id()}"]`).targets(), parent: n })
|
||||
})
|
||||
}
|
||||
e.cy().data('changed', false)
|
||||
@ -407,7 +445,7 @@ function CsComponent ({
|
||||
const opos = e.data('oldPos')
|
||||
if (opos) {
|
||||
return opos
|
||||
}
|
||||
}
|
||||
}
|
||||
}, // map of (node id) => (position obj); or function(node){ return somPos; }
|
||||
zoom: undefined, // the zoom level to set (prob want fit = false if set)
|
||||
@ -425,7 +463,7 @@ function CsComponent ({
|
||||
useEffect(() => {
|
||||
document.querySelector("#root")?.addEventListener("mouseup", cleardragQuestionContentId);
|
||||
const cy = cyRef.current;
|
||||
const eles = cy?.add(storeToNodes(questions.filter((question:AnyTypedQuizQuestion) => (question.type !== "result" && question.type !== null))))
|
||||
const eles = cy?.add(storeToNodes(questions.filter((question: AnyTypedQuizQuestion) => (question.type !== "result" && question.type !== null))))
|
||||
cy.data('changed', true)
|
||||
// cy.data('changed', true)
|
||||
const elecs = eles.layout(lyopts).run()
|
||||
@ -693,23 +731,23 @@ function CsComponent ({
|
||||
|
||||
return (
|
||||
<>
|
||||
<Button
|
||||
sx={{
|
||||
mb: "20px",
|
||||
height: "27px",
|
||||
color: "#7E2AEA",
|
||||
textDecoration: "underline",
|
||||
fontSize: "16px",
|
||||
}}
|
||||
variant="text"
|
||||
onClick={() => {
|
||||
<Button
|
||||
sx={{
|
||||
mb: "20px",
|
||||
height: "27px",
|
||||
color: "#7E2AEA",
|
||||
textDecoration: "underline",
|
||||
fontSize: "16px",
|
||||
}}
|
||||
variant="text"
|
||||
onClick={() => {
|
||||
|
||||
//код сюда
|
||||
//код сюда
|
||||
|
||||
}}
|
||||
>
|
||||
Выровнять
|
||||
</Button>
|
||||
}}
|
||||
>
|
||||
Выровнять
|
||||
</Button>
|
||||
<CytoscapeComponent
|
||||
wheelSensitivity={0.1}
|
||||
elements={[]}
|
||||
@ -720,7 +758,7 @@ function CsComponent ({
|
||||
cy={(cy) => {
|
||||
cyRef.current = cy;
|
||||
}}
|
||||
autoungrabify={true}
|
||||
autoungrabify={true}
|
||||
/>
|
||||
<button onClick={() => {
|
||||
console.log("NODES____________________________")
|
||||
@ -736,15 +774,15 @@ function CsComponent ({
|
||||
);
|
||||
};
|
||||
|
||||
function Clear () {
|
||||
const quiz = useCurrentQuiz();
|
||||
updateRootContentId(quiz.id, "")
|
||||
clearRuleForAll()
|
||||
return <></>
|
||||
function Clear() {
|
||||
const quiz = useCurrentQuiz();
|
||||
updateRootContentId(quiz.id, "")
|
||||
clearRuleForAll()
|
||||
return <></>
|
||||
}
|
||||
|
||||
export default withErrorBoundary(CsComponent, {
|
||||
fallback: <Clear/>,
|
||||
fallback: <Clear />,
|
||||
onError: (error, info) => {
|
||||
enqueueSnackbar("Дерево порвалось")
|
||||
console.log(info)
|
||||
|
@ -46,20 +46,6 @@ export default function ButtonsOptions({
|
||||
updateOpenedModalSettingsId(question.id)
|
||||
};
|
||||
|
||||
const handleClickBranching = (_, value) => {
|
||||
const parentId = question.content.rule.parentId
|
||||
if (parentId.length === 0 ){
|
||||
return enqueueSnackbar("Вопрос не учавствует в ветвлении")
|
||||
}
|
||||
if (parentId === "root") {
|
||||
return enqueueSnackbar("У корня нет условий ветвления")
|
||||
}
|
||||
if (parentId.length !== 0) {
|
||||
// updateOpenBranchingPanel(value)
|
||||
openedModal()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const buttonSetting: {
|
||||
icon: JSX.Element;
|
||||
@ -300,7 +286,59 @@ export default function ButtonsOptions({
|
||||
// deleteTimeoutId: newTimeoutId,
|
||||
// });
|
||||
|
||||
deleteQuestion(question.id, quiz.id);
|
||||
if (question.type !== null) {
|
||||
if (question.content.rule.parentId === "root") { //удалить из стора root и очистить rule всем вопросам
|
||||
updateRootContentId(quiz.id, "")
|
||||
clearRuleForAll()
|
||||
questions.forEach(q => {
|
||||
if (q.type === "result") {
|
||||
deleteQuestion(q.id);
|
||||
}
|
||||
});
|
||||
deleteQuestion(question.id);
|
||||
} else if (question.content.rule.parentId.length > 0) { //удалить из стора вопрос из дерева и очистить его потомков
|
||||
const clearQuestions = [] as string[]
|
||||
|
||||
//записываем потомков , а их результаты удаляем
|
||||
const getChildren = (parentQuestion: AnyTypedQuizQuestion) => {
|
||||
questions.forEach((targetQuestion) => {
|
||||
if (targetQuestion.content.rule.parentId === parentQuestion.content.id) {//если у вопроса совпал родитель с родителем => он потомок, в кучу его
|
||||
if (targetQuestion.type === "result") {
|
||||
deleteQuestion(targetQuestion.id);
|
||||
} else {
|
||||
if (!clearQuestions.includes(targetQuestion.content.id)) clearQuestions.push(targetQuestion.content.id)
|
||||
getChildren(targetQuestion) //и ищем его потомков
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
getChildren(question)
|
||||
//чистим потомков от инфы ветвления
|
||||
clearQuestions.forEach((id) => {
|
||||
updateQuestion(id, question => {
|
||||
question.content.rule.parentId = ""
|
||||
question.content.rule.main = []
|
||||
question.content.rule.default = ""
|
||||
})
|
||||
})
|
||||
|
||||
//чистим rule родителя
|
||||
const parentQuestion = getQuestionByContentId(question.content.rule.parentId)
|
||||
const newRule = {}
|
||||
newRule.main = parentQuestion.content.rule.main.filter((data) => data.next !== question.content.id) //удаляем условия перехода от родителя к этому вопросу
|
||||
newRule.parentId = parentQuestion.content.rule.parentId
|
||||
newRule.default = parentQuestion.content.rule.parentId === question.content.id ? "" : parentQuestion.content.rule.parentId
|
||||
newRule.children = [...parentQuestion.content.rule.children].splice(parentQuestion.content.rule.children.indexOf(question.content.id), 1);
|
||||
|
||||
updateQuestion(question.content.rule.parentId, (PQ) => {
|
||||
PQ.content.rule = newRule
|
||||
})
|
||||
deleteQuestion(question.id)
|
||||
}
|
||||
|
||||
deleteQuestion(question.id)
|
||||
|
||||
}
|
||||
}}
|
||||
data-cy="delete-question"
|
||||
>
|
||||
|
@ -10,7 +10,7 @@ import {
|
||||
useMediaQuery,
|
||||
useTheme,
|
||||
} from "@mui/material";
|
||||
import { copyQuestion, deleteQuestion, updateQuestion } from "@root/questions/actions";
|
||||
import { copyQuestion, deleteQuestion, updateQuestion, clearRuleForAll, getQuestionByContentId } from "@root/questions/actions";
|
||||
import MiniButtonSetting from "@ui_kit/MiniButtonSetting";
|
||||
import { ReallyChangingModal } from "@ui_kit/Modal/ReallyChangingModal/ReallyChangingModal";
|
||||
import { useEffect, useState } from "react";
|
||||
@ -27,6 +27,7 @@ import { updateOpenBranchingPanel, updateDesireToOpenABranchingModal } from "@ro
|
||||
import { useQuestionsStore } from "@root/questions/store";
|
||||
import { enqueueSnackbar } from "notistack";
|
||||
import { useCurrentQuiz } from "@root/quizes/hooks";
|
||||
import { updateRootContentId } from "@root/quizes/actions";
|
||||
|
||||
|
||||
interface Props {
|
||||
@ -46,7 +47,7 @@ export default function ButtonsOptionsAndPict({
|
||||
const theme = useTheme();
|
||||
const isMobile = useMediaQuery(theme.breakpoints.down(790));
|
||||
const isIconMobile = useMediaQuery(theme.breakpoints.down(1050));
|
||||
const { openBranchingPanel } = useQuestionsStore.getState()
|
||||
const { questions } = useQuestionsStore.getState()
|
||||
const quiz = useCurrentQuiz();
|
||||
|
||||
useEffect(() => {
|
||||
@ -323,7 +324,59 @@ export default function ButtonsOptionsAndPict({
|
||||
// deleteTimeoutId: newTimeoutId,
|
||||
// });
|
||||
|
||||
deleteQuestion(question.id, quiz?.id);
|
||||
if (question.type !== null) {
|
||||
if (question.content.rule.parentId === "root") { //удалить из стора root и очистить rule всем вопросам
|
||||
updateRootContentId(quiz.id, "")
|
||||
clearRuleForAll()
|
||||
questions.forEach(q => {
|
||||
if (q.type === "result") {
|
||||
deleteQuestion(q.id);
|
||||
}
|
||||
});
|
||||
deleteQuestion(question.id);
|
||||
} else if (question.content.rule.parentId.length > 0) { //удалить из стора вопрос из дерева и очистить его потомков
|
||||
const clearQuestions = [] as string[]
|
||||
|
||||
//записываем потомков , а их результаты удаляем
|
||||
const getChildren = (parentQuestion: AnyTypedQuizQuestion) => {
|
||||
questions.forEach((targetQuestion) => {
|
||||
if (targetQuestion.content.rule.parentId === parentQuestion.content.id) {//если у вопроса совпал родитель с родителем => он потомок, в кучу его
|
||||
if (targetQuestion.type === "result") {
|
||||
deleteQuestion(targetQuestion.id);
|
||||
} else {
|
||||
if (!clearQuestions.includes(targetQuestion.content.id)) clearQuestions.push(targetQuestion.content.id)
|
||||
getChildren(targetQuestion) //и ищем его потомков
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
getChildren(question)
|
||||
//чистим потомков от инфы ветвления
|
||||
clearQuestions.forEach((id) => {
|
||||
updateQuestion(id, question => {
|
||||
question.content.rule.parentId = ""
|
||||
question.content.rule.main = []
|
||||
question.content.rule.default = ""
|
||||
})
|
||||
})
|
||||
|
||||
//чистим rule родителя
|
||||
const parentQuestion = getQuestionByContentId(question.content.rule.parentId)
|
||||
const newRule = {}
|
||||
newRule.main = parentQuestion.content.rule.main.filter((data) => data.next !== question.content.id) //удаляем условия перехода от родителя к этому вопросу
|
||||
newRule.parentId = parentQuestion.content.rule.parentId
|
||||
newRule.default = parentQuestion.content.rule.parentId === question.content.id ? "" : parentQuestion.content.rule.parentId
|
||||
newRule.children = [...parentQuestion.content.rule.children].splice(parentQuestion.content.rule.children.indexOf(question.content.id), 1);
|
||||
|
||||
updateQuestion(question.content.rule.parentId, (PQ) => {
|
||||
PQ.content.rule = newRule
|
||||
})
|
||||
deleteQuestion(question.id)
|
||||
}
|
||||
|
||||
deleteQuestion(question.id)
|
||||
|
||||
}
|
||||
}}
|
||||
data-cy="delete-question"
|
||||
>
|
||||
|
@ -29,7 +29,8 @@ import {
|
||||
useMediaQuery,
|
||||
useTheme,
|
||||
} from "@mui/material";
|
||||
import { copyQuestion, createUntypedQuestion, deleteQuestion, toggleExpandQuestion, updateQuestion, updateUntypedQuestion } from "@root/questions/actions";
|
||||
import { copyQuestion, createUntypedQuestion, deleteQuestion, clearRuleForAll, toggleExpandQuestion, updateQuestion, updateUntypedQuestion, getQuestionByContentId } from "@root/questions/actions";
|
||||
import { updateRootContentId } from "@root/quizes/actions";
|
||||
import { useRef, useState } from "react";
|
||||
import type { DraggableProvidedDragHandleProps } from "react-beautiful-dnd";
|
||||
import { useDebouncedCallback } from "use-debounce";
|
||||
@ -40,6 +41,7 @@ import { ChooseAnswerModal } from "./ChooseAnswerModal";
|
||||
import TypeQuestions from "../TypeQuestions";
|
||||
import { QuestionType } from "@model/question/question";
|
||||
import { useCurrentQuiz } from "@root/quizes/hooks";
|
||||
import { useQuestionsStore } from "@root/questions/store";
|
||||
|
||||
interface Props {
|
||||
question: AnyTypedQuizQuestion | UntypedQuizQuestion;
|
||||
@ -49,6 +51,7 @@ interface Props {
|
||||
}
|
||||
|
||||
export default function QuestionsPageCard({ question, draggableProps, isDragging, index }: Props) {
|
||||
const { questions } = useQuestionsStore()
|
||||
const [plusVisible, setPlusVisible] = useState<boolean>(false);
|
||||
const [open, setOpen] = useState<boolean>(false);
|
||||
const theme = useTheme();
|
||||
@ -254,8 +257,63 @@ export default function QuestionsPageCard({ question, draggableProps, isDragging
|
||||
// ...question,
|
||||
// deleteTimeoutId: newTimeoutId,
|
||||
// });
|
||||
console.log(question.type)
|
||||
if (question.type !== null) {
|
||||
if (question.content.rule.parentId === "root") { //удалить из стора root и очистить rule всем вопросам
|
||||
updateRootContentId(quiz.id, "")
|
||||
clearRuleForAll()
|
||||
deleteQuestion(question.id);
|
||||
questions.forEach(q => {
|
||||
if (q.type === "result") {
|
||||
deleteQuestion(q.id);
|
||||
}
|
||||
});
|
||||
} else if (question.content.rule.parentId.length > 0) { //удалить из стора вопрос из дерева и очистить его потомков
|
||||
const clearQuestions = [] as string[]
|
||||
|
||||
deleteQuestion(question.id, quiz.id);
|
||||
//записываем потомков , а их результаты удаляем
|
||||
const getChildren = (parentQuestion: AnyTypedQuizQuestion) => {
|
||||
questions.forEach((targetQuestion) => {
|
||||
if (targetQuestion.content.rule.parentId === parentQuestion.content.id) {//если у вопроса совпал родитель с родителем => он потомок, в кучу его
|
||||
if (targetQuestion.type === "result") {
|
||||
deleteQuestion(targetQuestion.id);
|
||||
} else {
|
||||
if (!clearQuestions.includes(targetQuestion.content.id)) clearQuestions.push(targetQuestion.content.id)
|
||||
getChildren(targetQuestion) //и ищем его потомков
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
getChildren(question)
|
||||
//чистим потомков от инфы ветвления
|
||||
clearQuestions.forEach((id) => {
|
||||
updateQuestion(id, question => {
|
||||
question.content.rule.parentId = ""
|
||||
question.content.rule.main = []
|
||||
question.content.rule.default = ""
|
||||
})
|
||||
})
|
||||
|
||||
//чистим rule родителя
|
||||
const parentQuestion = getQuestionByContentId(question.content.rule.parentId)
|
||||
const newRule = {}
|
||||
newRule.main = parentQuestion.content.rule.main.filter((data) => data.next !== question.content.id) //удаляем условия перехода от родителя к этому вопросу
|
||||
newRule.parentId = parentQuestion.content.rule.parentId
|
||||
newRule.default = parentQuestion.content.rule.parentId === question.content.id ? "" : parentQuestion.content.rule.parentId
|
||||
newRule.children = [...parentQuestion.content.rule.children].splice(parentQuestion.content.rule.children.indexOf(question.content.id), 1);
|
||||
|
||||
updateQuestion(question.content.rule.parentId, (PQ) => {
|
||||
PQ.content.rule = newRule
|
||||
})
|
||||
deleteQuestion(question.id)
|
||||
}
|
||||
|
||||
|
||||
deleteQuestion(question.id)
|
||||
} else {
|
||||
console.log("удаляю безтипогово")
|
||||
deleteQuestion(question.id)
|
||||
}
|
||||
}}
|
||||
data-cy="delete-question"
|
||||
>
|
||||
|
@ -16,17 +16,18 @@ export const FirstEntry = () => {
|
||||
|
||||
const create = () => {
|
||||
if (quiz?.config.haveRoot) {
|
||||
if (questions.length === 0) {
|
||||
enqueueSnackbar("У вас не добавлено ни одного вопроса")
|
||||
return
|
||||
}
|
||||
console.log("createFrontResult")
|
||||
questions
|
||||
.filter((question:AnyTypedQuizQuestion) => question.type !== null && question.content.rule.parentId.length !== 0 && question.content.rule.default.length === 0)
|
||||
.filter((question:AnyTypedQuizQuestion) => {
|
||||
console.log(question)
|
||||
return question.type !== null && question.content.rule.parentId.length !== 0 && question.content.rule.children.length === 0
|
||||
})
|
||||
.forEach(question => {
|
||||
createFrontResult(quiz.id, question.content.id)
|
||||
})
|
||||
} else {
|
||||
createFrontResult(quiz.id)
|
||||
console.log("createFrontResult")
|
||||
createFrontResult(quiz.id, "line")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -14,9 +14,11 @@ import { ResultCard, checkEmptyData } from "./cards/ResultCard";
|
||||
import { EmailSettingsCard } from "./cards/EmailSettingsCard";
|
||||
import { useCurrentQuiz } from "@root/quizes/hooks"
|
||||
import { useQuestionsStore } from "@root/questions/store";
|
||||
import { createFrontResult, deleteQuestion } from "@root/questions/actions";
|
||||
import { QuizQuestionResult } from "@model/questionTypes/result";
|
||||
|
||||
export const ResultSettings = () => {
|
||||
const { questions } = useQuestionsStore()
|
||||
const quiz = useCurrentQuiz()
|
||||
const results = useQuestionsStore().questions.filter((q): q is QuizQuestionResult => q.type === "result")
|
||||
console.log("опросник ", quiz)
|
||||
|
@ -1,18 +1,12 @@
|
||||
import * as React from "react";
|
||||
|
||||
import { updateQuiz } from "@root/quizes/actions"
|
||||
import { getQuestionByContentId, updateQuestion, uploadQuestionImage } from "@root/questions/actions"
|
||||
import { useCurrentQuiz } from "@root/quizes/hooks"
|
||||
|
||||
import { SwitchSetting } from "../SwichResult";
|
||||
|
||||
|
||||
import CustomTextField from "@ui_kit/CustomTextField";
|
||||
import { CropModal, useCropModalState } from "@ui_kit/Modal/CropModal";
|
||||
import { useDebouncedCallback } from "use-debounce";
|
||||
import type { QuizQuestionPage } from "../../../model/questionTypes/page";
|
||||
import { UploadImageModal } from "../../Questions/UploadImage/UploadImageModal";
|
||||
import { UploadVideoModal } from "../../Questions/UploadVideoModal";
|
||||
import { useDisclosure } from "../../../utils/useDisclosure";
|
||||
import AddOrEditImageButton from "@ui_kit/AddOrEditImageButton";
|
||||
|
||||
@ -32,11 +26,8 @@ import MiniButtonSetting from "@ui_kit/MiniButtonSetting";
|
||||
|
||||
import ExpandLessIconBG from "@icons/ExpandLessIconBG";
|
||||
import ExpandLessIcon from "@mui/icons-material/ExpandLess";
|
||||
import { OneIcon } from "@icons/questionsPage/OneIcon";
|
||||
import { DeleteIcon } from "@icons/questionsPage/deleteIcon";
|
||||
import Trash from "@icons/trash";
|
||||
import Info from "@icons/Info";
|
||||
import ImageAndVideoButtons from "../DescriptionForm/ImageAndVideoButtons";
|
||||
import SettingIcon from "@icons/questionsPage/settingIcon";
|
||||
import { QuizQuestionResult } from "@model/questionTypes/result";
|
||||
import { MutableRefObject } from "react";
|
||||
@ -77,11 +68,6 @@ const InfoView = ({ resultData }: { resultData: QuizQuestionResult }) => {
|
||||
const open = Boolean(anchorEl);
|
||||
const id = open ? 'simple-popover' : undefined;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
<Info
|
||||
@ -115,7 +101,11 @@ const InfoView = ({ resultData }: { resultData: QuizQuestionResult }) => {
|
||||
}}
|
||||
>
|
||||
<Typography>
|
||||
Заголовок вопроса, после которого появится результат: "{question?.title || "нет заголовка"}"
|
||||
{resultData?.content.rule.parentId === "line" ? "Единый результат в конце прохождения опросника без ветвления"
|
||||
:
|
||||
`Заголовок вопроса, после которого появится результат: "${question?.title || "нет заголовка"}"`
|
||||
}
|
||||
|
||||
</Typography>
|
||||
{checkEmpty &&
|
||||
<Typography color="red">
|
||||
@ -140,7 +130,7 @@ export const ResultCard = ({ resultContract, resultData }: Props) => {
|
||||
|
||||
const [expand, setExpand] = React.useState(true)
|
||||
const [resultCardSettings, setResultCardSettings] = React.useState(false)
|
||||
const [buttonPlus, setButtonPlus] = React.useState(false)
|
||||
const [buttonPlus, setButtonPlus] = React.useState(true)
|
||||
|
||||
React.useEffect(() => {
|
||||
setExpand(true)
|
||||
|
@ -1,11 +1,12 @@
|
||||
import DatePicker from "react-datepicker";
|
||||
import { DatePicker } from "@mui/x-date-pickers";
|
||||
import { Box, Typography } from "@mui/material";
|
||||
|
||||
import { useQuizViewStore, updateAnswer } from "@root/quizView";
|
||||
|
||||
import "react-datepicker/dist/react-datepicker.css";
|
||||
// import "react-datepicker/dist/react-datepicker.css";
|
||||
|
||||
import type { QuizQuestionDate } from "../../../model/questionTypes/date";
|
||||
import CalendarIcon from "@icons/CalendarIcon";
|
||||
|
||||
type DateProps = {
|
||||
currentQuestion: QuizQuestionDate;
|
||||
@ -31,6 +32,9 @@ export const Date = ({ currentQuestion }: DateProps) => {
|
||||
}}
|
||||
>
|
||||
<DatePicker
|
||||
slots={{
|
||||
openPickerIcon: () => <CalendarIcon />,
|
||||
}}
|
||||
selected={
|
||||
answer
|
||||
? new window.Date(`${month}.${day}.${year}`)
|
||||
@ -48,6 +52,30 @@ export const Date = ({ currentQuestion }: DateProps) => {
|
||||
)
|
||||
)
|
||||
}
|
||||
slotProps={{
|
||||
openPickerButton: {
|
||||
sx: {
|
||||
p: 0,
|
||||
},
|
||||
"data-cy": "open-datepicker",
|
||||
},
|
||||
}}
|
||||
sx={{
|
||||
"& .MuiInputBase-root": {
|
||||
backgroundColor: "#F2F3F7",
|
||||
borderRadius: "10px",
|
||||
maxWidth: "250px",
|
||||
pr: "22px",
|
||||
"& input": {
|
||||
py: "11px",
|
||||
pl: "20px",
|
||||
lineHeight: "19px",
|
||||
},
|
||||
"& fieldset": {
|
||||
borderColor: "#9A9AAF",
|
||||
},
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
|
@ -76,6 +76,62 @@ export const Number = ({ currentQuestion }: NumberProps) => {
|
||||
marginTop: "20px",
|
||||
}}
|
||||
>
|
||||
|
||||
<Slider
|
||||
value={
|
||||
currentQuestion.content.chooseRange
|
||||
? answer?.split("—").length || 0 > 1
|
||||
? answer?.split("—").map((item) => window.Number(item))
|
||||
: [min, min + 1]
|
||||
: window.Number(answer || 1)
|
||||
}
|
||||
min={min}
|
||||
max={max}
|
||||
step={currentQuestion.content.step || 1}
|
||||
sx={{
|
||||
color: theme.palette.brightPurple.main,
|
||||
padding: "0",
|
||||
marginTop: "75px",
|
||||
"& .MuiSlider-valueLabel":{
|
||||
background: theme.palette.brightPurple.main,
|
||||
borderRadius: "8px",
|
||||
width: "60px",
|
||||
height: "36px"
|
||||
},
|
||||
"& .MuiSlider-valueLabel::before": {
|
||||
width: "6px",
|
||||
height: "2px",
|
||||
transform: "translate(-50%, 50%) rotate(90deg)",
|
||||
bottom: "-5px"
|
||||
},
|
||||
"& .MuiSlider-rail": {
|
||||
backgroundColor: "#F2F3F7",
|
||||
border: `1px solid #9A9AAF`,
|
||||
height: "12px"
|
||||
},
|
||||
"& .MuiSlider-thumb": {
|
||||
border: "3px #f2f3f7 solid",
|
||||
height: "23px",
|
||||
width: "23px"
|
||||
},
|
||||
"& .MuiSlider-track": {
|
||||
height: "12px"
|
||||
}
|
||||
}}
|
||||
onChange={(_, value) => {
|
||||
const range = String(value).replace(",", "—");
|
||||
updateAnswer(currentQuestion.content.id, range);
|
||||
}}
|
||||
onChangeCommitted={(_, value) => {
|
||||
if (currentQuestion.content.chooseRange) {
|
||||
const range = value as number[];
|
||||
|
||||
setMinRange(String(range[0]));
|
||||
setMaxRange(String(range[1]));
|
||||
}
|
||||
}}
|
||||
/>
|
||||
|
||||
{!currentQuestion.content.chooseRange && (
|
||||
<CustomTextField
|
||||
placeholder="0"
|
||||
@ -96,6 +152,7 @@ export const Number = ({ currentQuestion }: NumberProps) => {
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
{currentQuestion.content.chooseRange && (
|
||||
<Box
|
||||
sx={{
|
||||
@ -123,6 +180,9 @@ export const Number = ({ currentQuestion }: NumberProps) => {
|
||||
"& .MuiInputBase-input": { textAlign: "center" },
|
||||
}}
|
||||
/>
|
||||
|
||||
до
|
||||
|
||||
<CustomTextField
|
||||
placeholder="0"
|
||||
value={maxRange}
|
||||
@ -144,35 +204,7 @@ export const Number = ({ currentQuestion }: NumberProps) => {
|
||||
/>
|
||||
</Box>
|
||||
)}
|
||||
<Slider
|
||||
value={
|
||||
currentQuestion.content.chooseRange
|
||||
? answer?.split("—").length || 0 > 1
|
||||
? answer?.split("—").map((item) => window.Number(item))
|
||||
: [min, min + 1]
|
||||
: window.Number(answer || 1)
|
||||
}
|
||||
min={min}
|
||||
max={max}
|
||||
step={currentQuestion.content.step || 1}
|
||||
sx={{
|
||||
color: theme.palette.brightPurple.main,
|
||||
padding: "0",
|
||||
marginTop: "25px",
|
||||
}}
|
||||
onChange={(_, value) => {
|
||||
const range = String(value).replace(",", "—");
|
||||
updateAnswer(currentQuestion.content.id, range);
|
||||
}}
|
||||
onChangeCommitted={(_, value) => {
|
||||
if (currentQuestion.content.chooseRange) {
|
||||
const range = value as number[];
|
||||
|
||||
setMinRange(String(range[0]));
|
||||
setMaxRange(String(range[1]));
|
||||
}
|
||||
}}
|
||||
/>
|
||||
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
|
@ -341,7 +341,7 @@ export const createTypedQuestion = async (
|
||||
}
|
||||
});
|
||||
|
||||
export const deleteQuestion = async (questionId: string, quizId: string) => requestQueue.enqueue(async () => {
|
||||
export const deleteQuestion = async (questionId: string) => requestQueue.enqueue(async () => {
|
||||
|
||||
const question = useQuestionsStore.getState().questions.find(q => q.id === questionId);
|
||||
if (!question) return;
|
||||
@ -355,45 +355,7 @@ export const deleteQuestion = async (questionId: string, quizId: string) => requ
|
||||
|
||||
try {
|
||||
await questionApi.delete(question.backendId);
|
||||
if (question.content.rule.parentId === "root") { //удалить из стора root и очистить rule всем вопросам
|
||||
updateRootContentId(quizId, "");
|
||||
clearRuleForAll();
|
||||
} else if (question.content.rule.parentId.length > 0) { //удалить из стора вопрос из дерева и очистить его потомков
|
||||
const clearQuestions = [] as string[];
|
||||
|
||||
const getChildren = (parentQuestion: AnyTypedQuizQuestion) => {
|
||||
questions.forEach((targetQuestion) => {
|
||||
if (targetQuestion.content.rule.parentId === parentQuestion.content.id) {//если у вопроса совпал родитель с родителем => он потомок, в кучу его
|
||||
if (!clearQuestions.includes(targetQuestion.content.id)) clearQuestions.push(targetQuestion.content.id);
|
||||
getChildren(targetQuestion); //и ищем его потомков
|
||||
}
|
||||
});
|
||||
};
|
||||
getChildren(question);
|
||||
//чистим потомков от инфы ветвления
|
||||
clearQuestions.forEach((id) => {
|
||||
updateQuestion(id, question => {
|
||||
question.content.rule.parentId = "";
|
||||
question.content.rule.main = [];
|
||||
question.content.rule.default = "";
|
||||
});
|
||||
});
|
||||
|
||||
//чистим rule родителя
|
||||
const parentQuestion = getQuestionByContentId(question.content.rule.parentId);
|
||||
const newRule = {};
|
||||
newRule.main = parentQuestion.content.rule.main.filter((data) => data.next !== question.content.id); //удаляем условия перехода от родителя к этому вопросу
|
||||
newRule.parentId = parentQuestion.content.rule.parentId;
|
||||
newRule.default = questions.filter((q) => {
|
||||
return q.content.rule.parentId === question.content.rule.parentId && q.content.id !== question.content.id;
|
||||
})[0]?.content.id || "";
|
||||
//Если этот вопрос был дефолтным у родителя - чистим дефолт
|
||||
//Смотрим можем ли мы заменить id на один из main
|
||||
|
||||
updateQuestion(question.content.rule.parentId, (PQ) => {
|
||||
PQ.content.rule = newRule;
|
||||
});
|
||||
}
|
||||
|
||||
removeQuestion(questionId);
|
||||
|
||||
updateQuestionOrders();
|
||||
@ -411,6 +373,7 @@ export const copyQuestion = async (questionId: string, quizId: number) => reques
|
||||
if (question.type === null) {
|
||||
const copiedQuestion = structuredClone(question);
|
||||
copiedQuestion.id = frontId;
|
||||
copiedQuestion.content.id = frontId;
|
||||
|
||||
setProducedState(state => {
|
||||
state.questions.push(copiedQuestion);
|
||||
@ -430,7 +393,7 @@ export const copyQuestion = async (questionId: string, quizId: number) => reques
|
||||
copiedQuestion.backendId = newQuestionId;
|
||||
copiedQuestion.id = frontId;
|
||||
copiedQuestion.content.id = frontId;
|
||||
copiedQuestion.content.rule = { main: [], parentId: "", default: "" };
|
||||
copiedQuestion.content.rule = { main: [], parentId: "", default: "", children: [] };
|
||||
|
||||
setProducedState(state => {
|
||||
state.questions.push(copiedQuestion);
|
||||
|
Loading…
Reference in New Issue
Block a user