Merge branch 'dev' into backend-integration
This commit is contained in:
commit
f07d7ab3e2
19001
package-lock.json
generated
Normal file
19001
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -30,7 +30,6 @@ async function getQuestionList(body?: Partial<GetQuestionListRequest>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function editQuestion(body: EditQuestionRequest, signal?: AbortSignal) {
|
function editQuestion(body: EditQuestionRequest, signal?: AbortSignal) {
|
||||||
console.log("`${baseUrl}/question/edit` start")
|
|
||||||
return makeRequest<EditQuestionRequest, EditQuestionResponse>({
|
return makeRequest<EditQuestionRequest, EditQuestionResponse>({
|
||||||
url: `${baseUrl}/question/edit`,
|
url: `${baseUrl}/question/edit`,
|
||||||
body,
|
body,
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { MessageIcon } from "@icons/messagIcon";
|
import { MessageIcon } from "@icons/messagIcon";
|
||||||
import { PointsIcon } from "@icons/questionsPage/PointsIcon";
|
import { PointsIcon } from "@icons/questionsPage/PointsIcon";
|
||||||
import { DeleteIcon } from "@icons/questionsPage/deleteIcon";
|
import { DeleteIcon } from "@icons/questionsPage/deleteIcon";
|
||||||
import TextareaAutosize from "@mui/base/TextareaAutosize";
|
import {TextareaAutosize} from "@mui/base/TextareaAutosize";
|
||||||
import {
|
import {
|
||||||
Box,
|
Box,
|
||||||
FormControl,
|
FormControl,
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { useEffect, useRef, useState } from "react";
|
import { useEffect, useLayoutEffect, useRef, useState } from "react";
|
||||||
import Cytoscape from "cytoscape";
|
import Cytoscape from "cytoscape";
|
||||||
import CytoscapeComponent from "react-cytoscapejs";
|
import CytoscapeComponent from "react-cytoscapejs";
|
||||||
import popper from "cytoscape-popper";
|
import popper from "cytoscape-popper";
|
||||||
@ -122,16 +122,19 @@ export const CsComponent = ({
|
|||||||
const crossesContainer = useRef<HTMLDivElement | null>(null);
|
const crossesContainer = useRef<HTMLDivElement | null>(null);
|
||||||
const gearsContainer = useRef<HTMLDivElement | null>(null);
|
const gearsContainer = useRef<HTMLDivElement | null>(null);
|
||||||
|
|
||||||
|
useLayoutEffect(() => {
|
||||||
|
updateOpenedModalSettingsId()
|
||||||
|
}, [])
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (modalQuestionTargetContentId.length !== 0 && modalQuestionParentContentId.length !== 0) {
|
if (modalQuestionTargetContentId.length !== 0 && modalQuestionParentContentId.length !== 0) {
|
||||||
console.log("был выбран вопрос " + modalQuestionTargetContentId)
|
addNode({ parentNodeContentId: modalQuestionParentContentId, targetNodeContentId: modalQuestionTargetContentId })
|
||||||
addNode({ parentNodeContentId:modalQuestionParentContentId, targetNodeContentId:modalQuestionTargetContentId })
|
|
||||||
}
|
}
|
||||||
|
setModalQuestionParentContentId("")
|
||||||
|
setModalQuestionTargetContentId("")
|
||||||
|
|
||||||
}, [modalQuestionTargetContentId])
|
}, [modalQuestionTargetContentId])
|
||||||
|
|
||||||
const addNode = ({ parentNodeContentId, targetNodeContentId }: { parentNodeContentId: string, targetNodeContentId?: string }) => {
|
const addNode = ({ parentNodeContentId, targetNodeContentId }: { parentNodeContentId: string, targetNodeContentId?: string }) => {
|
||||||
console.log("dragQuestionContentId " + dragQuestionContentId)
|
|
||||||
const cy = cyRef?.current
|
const cy = cyRef?.current
|
||||||
const parentNodeChildren = cy?.$('edge[source = "' + parentNodeContentId + '"]')?.length
|
const parentNodeChildren = cy?.$('edge[source = "' + parentNodeContentId + '"]')?.length
|
||||||
//если есть инфо о выбранном вопросе из модалки - берём родителя из инфо модалки. Иначе из значения дропа
|
//если есть инфо о выбранном вопросе из модалки - берём родителя из инфо модалки. Иначе из значения дропа
|
||||||
@ -139,7 +142,7 @@ export const CsComponent = ({
|
|||||||
|
|
||||||
if (Object.keys(targetQuestion).length !== 0 && Object.keys(targetQuestion).length !== 0 && parentNodeContentId && parentNodeChildren !== undefined) {
|
if (Object.keys(targetQuestion).length !== 0 && Object.keys(targetQuestion).length !== 0 && parentNodeContentId && parentNodeChildren !== undefined) {
|
||||||
clearDataAfterAddNode({ parentNodeContentId, targetQuestion, parentNodeChildren })
|
clearDataAfterAddNode({ parentNodeContentId, targetQuestion, parentNodeChildren })
|
||||||
cy?.data('changed',true)
|
cy?.data('changed', true)
|
||||||
cy?.add([
|
cy?.add([
|
||||||
{
|
{
|
||||||
data: {
|
data: {
|
||||||
@ -161,8 +164,6 @@ export const CsComponent = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const clearDataAfterAddNode = ({ parentNodeContentId, targetQuestion, parentNodeChildren }: { parentNodeContentId: string, targetQuestion: AnyTypedQuizQuestion, parentNodeChildren: number }) => {
|
const clearDataAfterAddNode = ({ parentNodeContentId, targetQuestion, parentNodeChildren }: { parentNodeContentId: string, targetQuestion: AnyTypedQuizQuestion, parentNodeChildren: number }) => {
|
||||||
console.log("записываю на бек ид родителя")
|
|
||||||
console.log({ parentNodeContentId, targetQuestion, parentNodeChildren })
|
|
||||||
//предупреждаем добавленный вопрос о том, кто его родитель
|
//предупреждаем добавленный вопрос о том, кто его родитель
|
||||||
updateQuestion(targetQuestion.content.id, question => {
|
updateQuestion(targetQuestion.content.id, question => {
|
||||||
question.content.rule.parentId = parentNodeContentId
|
question.content.rule.parentId = parentNodeContentId
|
||||||
@ -170,8 +171,8 @@ export const CsComponent = ({
|
|||||||
})
|
})
|
||||||
|
|
||||||
//Если детей больше 1 - предупреждаем стор вопросов об открытии модалки ветвления
|
//Если детей больше 1 - предупреждаем стор вопросов об открытии модалки ветвления
|
||||||
if (parentNodeChildren > 1) {
|
if (parentNodeChildren >= 1) {
|
||||||
updateOpenedModalSettingsId(parentNodeContentId)
|
updateOpenedModalSettingsId(targetQuestion.content.id)
|
||||||
} else {
|
} else {
|
||||||
//Если ребёнок первый - добавляем его родителю как дефолтный
|
//Если ребёнок первый - добавляем его родителю как дефолтный
|
||||||
updateQuestion(parentNodeContentId, question => question.content.rule.default = targetQuestion.content.id)
|
updateQuestion(parentNodeContentId, question => question.content.rule.default = targetQuestion.content.id)
|
||||||
@ -179,9 +180,8 @@ export const CsComponent = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const removeNode = ({ targetNodeContentId }: { targetNodeContentId: string }) => {
|
const removeNode = ({ targetNodeContentId }: { targetNodeContentId: string }) => {
|
||||||
const deleteNodes = [] as string[]
|
const deleteNodes = [] as string[]
|
||||||
const deleteEdges:any = []
|
const deleteEdges: any = []
|
||||||
console.log("remove")
|
|
||||||
const cy = cyRef?.current
|
const cy = cyRef?.current
|
||||||
|
|
||||||
const findChildrenToDelete = (node) => {
|
const findChildrenToDelete = (node) => {
|
||||||
@ -205,60 +205,51 @@ export const CsComponent = ({
|
|||||||
const targetQuestion = getQuestionByContentId(targetNodeContentId)
|
const targetQuestion = getQuestionByContentId(targetNodeContentId)
|
||||||
|
|
||||||
if (targetQuestion.content.rule.parentId === "root" && quiz) {
|
if (targetQuestion.content.rule.parentId === "root" && quiz) {
|
||||||
console.log("click ROOT")
|
updateRootContentId(quiz?.id, "")
|
||||||
updateQuestion(targetNodeContentId, question => {
|
updateQuestion(targetNodeContentId, question => {
|
||||||
question.content.rule.parentId = ""
|
question.content.rule.parentId = ""
|
||||||
question.content.rule.main = []
|
question.content.rule.main = []
|
||||||
question.content.rule.default = ""
|
question.content.rule.default = ""
|
||||||
})
|
})
|
||||||
updateRootContentId(quiz?.id, false)
|
|
||||||
} else {
|
} else {
|
||||||
console.log("click not ROOT")
|
|
||||||
const parentQuestionContentId = cy?.$('edge[target = "' + targetNodeContentId + '"]')?.toArray()?.[0]?.data()?.source
|
const parentQuestionContentId = cy?.$('edge[target = "' + targetNodeContentId + '"]')?.toArray()?.[0]?.data()?.source
|
||||||
if (targetNodeContentId && parentQuestionContentId) {
|
if (targetNodeContentId && parentQuestionContentId) {
|
||||||
|
|
||||||
clearDataAfterRemoveNode({ targetQuestionContentId: targetNodeContentId, parentQuestionContentId })
|
clearDataAfterRemoveNode({ targetQuestionContentId: targetNodeContentId, parentQuestionContentId })
|
||||||
cy?.remove(cy?.$('#' + targetNodeContentId)).layout(lyopts).run()
|
cy?.remove(cy?.$('#' + targetNodeContentId)).layout(lyopts).run()
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(deleteNodes, deleteEdges)
|
|
||||||
//После всех манипуляций удаляем грани из CS и ноды из бекенда
|
|
||||||
|
|
||||||
deleteNodes.forEach((nodeId) => {//Ноды
|
|
||||||
cy?.remove(cy?.$("#" + nodeId))
|
|
||||||
removeButtons(nodeId)
|
|
||||||
updateQuestion(nodeId, question => {
|
|
||||||
question.content.rule.parentId = ""
|
|
||||||
question.content.rule.main = []
|
|
||||||
question.content.rule.default = ""
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
deleteEdges.forEach((edge:any) => {//Грани
|
|
||||||
cy?.remove(edge)
|
|
||||||
})
|
|
||||||
|
|
||||||
removeButtons(targetNodeContentId)
|
|
||||||
cy?.data('changed',true)
|
|
||||||
cy?.layout(lyopts).run()
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//После всех манипуляций удаляем грани из CS и ноды из бекенда
|
||||||
|
|
||||||
|
deleteNodes.forEach((nodeId) => {//Ноды
|
||||||
|
cy?.remove(cy?.$("#" + nodeId))
|
||||||
|
removeButtons(nodeId)
|
||||||
|
updateQuestion(nodeId, question => {
|
||||||
|
question.content.rule.parentId = ""
|
||||||
|
question.content.rule.main = []
|
||||||
|
question.content.rule.default = ""
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
deleteEdges.forEach((edge: any) => {//Грани
|
||||||
|
cy?.remove(edge)
|
||||||
|
})
|
||||||
|
|
||||||
|
removeButtons(targetNodeContentId)
|
||||||
|
cy?.data('changed', true)
|
||||||
|
cy?.layout(lyopts).run()
|
||||||
}
|
}
|
||||||
const clearDataAfterRemoveNode = ({ targetQuestionContentId, parentQuestionContentId }: { targetQuestionContentId: string, parentQuestionContentId: string }) => {
|
const clearDataAfterRemoveNode = ({ targetQuestionContentId, parentQuestionContentId }: { targetQuestionContentId: string, parentQuestionContentId: string }) => {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
console.log({ targetQuestionContentId, parentQuestionContentId })
|
|
||||||
|
|
||||||
updateQuestion(targetQuestionContentId, question => {
|
updateQuestion(targetQuestionContentId, question => {
|
||||||
question.content.rule.parentId = ""
|
question.content.rule.parentId = ""
|
||||||
question.content.rule.main = []
|
question.content.rule.main = []
|
||||||
question.content.rule.default = ""
|
question.content.rule.default = ""
|
||||||
})
|
})
|
||||||
|
|
||||||
updateQuestion(parentQuestionContentId, question => {
|
updateQuestion(parentQuestionContentId, question => {
|
||||||
console.log("parent default " + question.content.rule.default)
|
//Заменяем id удаляемого вопроса либо на id одного из оставшихся, либо на пустую строку
|
||||||
console.log("target ID " + targetQuestionContentId)
|
|
||||||
console.log(question.content.rule.default === targetQuestionContentId)
|
|
||||||
if (question.content.rule.default === targetQuestionContentId) question.content.rule.default = ""
|
if (question.content.rule.default === targetQuestionContentId) question.content.rule.default = ""
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -282,22 +273,20 @@ export const CsComponent = ({
|
|||||||
|
|
||||||
|
|
||||||
const readyLO = (e) => {
|
const readyLO = (e) => {
|
||||||
console.log(e.cy.data('firstNode'),"SKEEER",e.cy.data('changed'))
|
|
||||||
if (e.cy.data('firstNode') === 'nonroot') {
|
if (e.cy.data('firstNode') === 'nonroot') {
|
||||||
e.cy.data('firstNode','root')
|
e.cy.data('firstNode', 'root')
|
||||||
e.cy.nodes().sort((a,b) => (a.data('root')?1:-1)).layout(lyopts).run()
|
e.cy.nodes().sort((a, b) => (a.data('root') ? 1 : -1)).layout(lyopts).run()
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
|
} else {
|
||||||
e.cy.data('changed', false)
|
|
||||||
e.cy.removeData('firstNode')
|
|
||||||
}
|
e.cy.data('changed', false)
|
||||||
|
e.cy.removeData('firstNode')
|
||||||
|
}
|
||||||
|
|
||||||
//удаляем иконки
|
//удаляем иконки
|
||||||
e.cy.nodes().forEach((ele: any) => {
|
e.cy.nodes().forEach((ele: any) => {
|
||||||
const data = ele.data()
|
const data = ele.data()
|
||||||
console.log(data)
|
|
||||||
data.id && removeButtons(data.id);
|
data.id && removeButtons(data.id);
|
||||||
})
|
})
|
||||||
initialPopperIcons(e)
|
initialPopperIcons(e)
|
||||||
@ -307,11 +296,9 @@ console.log(e.cy.data('firstNode'),"SKEEER",e.cy.data('changed'))
|
|||||||
name: 'preset',
|
name: 'preset',
|
||||||
|
|
||||||
positions: (e) => {
|
positions: (e) => {
|
||||||
console.log('BBBBBBBBBBBBBBB', e.cy().data('changed'))
|
|
||||||
if (!e.cy().data('changed')) {
|
if (!e.cy().data('changed')) {
|
||||||
return e.data('oldPos')
|
return e.data('oldPos')
|
||||||
} else {e.removeData('oldPos')}
|
} else { e.removeData('oldPos') }
|
||||||
console.log('POSITIIIIIIIONS')
|
|
||||||
const id = e.id()
|
const id = e.id()
|
||||||
const incomming = e.cy().edges(`[target="${id}"]`)
|
const incomming = e.cy().edges(`[target="${id}"]`)
|
||||||
const layer = 0
|
const layer = 0
|
||||||
@ -319,7 +306,7 @@ console.log(e.cy.data('firstNode'),"SKEEER",e.cy.data('changed'))
|
|||||||
|
|
||||||
if (incomming.length === 0) {
|
if (incomming.length === 0) {
|
||||||
if (e.cy().data('firstNode') === undefined)
|
if (e.cy().data('firstNode') === undefined)
|
||||||
e.cy().data('firstNode','root')
|
e.cy().data('firstNode', 'root')
|
||||||
e.data('root', true)
|
e.data('root', true)
|
||||||
const children = e.cy().edges(`[source="${id}"]`).targets()
|
const children = e.cy().edges(`[source="${id}"]`).targets()
|
||||||
e.data('layer', layer)
|
e.data('layer', layer)
|
||||||
@ -331,14 +318,14 @@ console.log(e.cy.data('firstNode'),"SKEEER",e.cy.data('changed'))
|
|||||||
while (queue.length) {
|
while (queue.length) {
|
||||||
const task = queue.pop()
|
const task = queue.pop()
|
||||||
task.task.data('layer', task.layer)
|
task.task.data('layer', task.layer)
|
||||||
console.log('SAMSHIIIIT',task.layer,task.task.data().layer)
|
task.task.removeData('subtreeWidth')
|
||||||
const children = e.cy().edges(`[source="${task.task.id()}"]`).targets()
|
const children = e.cy().edges(`[source="${task.task.id()}"]`).targets()
|
||||||
task.task.data('children', children.length)
|
task.task.data('children', children.length)
|
||||||
if (children.length !== 0) {
|
if (children.length !== 0) {
|
||||||
children.forEach(n => queue.push({ task: n, layer: task.layer + 1 }))
|
children.forEach(n => queue.push({ task: n, layer: task.layer + 1 }))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
queue.push({ parent: e, children: children.targets() })
|
queue.push({ parent: e, children: children })
|
||||||
while (queue.length) {
|
while (queue.length) {
|
||||||
const task = queue.pop()
|
const task = queue.pop()
|
||||||
if (task.children.length === 0) {
|
if (task.children.length === 0) {
|
||||||
@ -359,23 +346,20 @@ console.log(e.cy.data('firstNode'),"SKEEER",e.cy.data('changed'))
|
|||||||
task?.parent.data('subtreeWidth', task.children.reduce((p, n) => p + n.data('subtreeWidth'), 0))
|
task?.parent.data('subtreeWidth', task.children.reduce((p, n) => p + n.data('subtreeWidth'), 0))
|
||||||
}
|
}
|
||||||
const pos = { x: 0, y: 0 }
|
const pos = { x: 0, y: 0 }
|
||||||
console.log(e.data())
|
|
||||||
e.data('oldPos', pos)
|
e.data('oldPos', pos)
|
||||||
return pos
|
return pos
|
||||||
} else {
|
} else {
|
||||||
console.log(e.cy().data('firstNode'))
|
if (e.cy().data('firstNode') !== 'root') {
|
||||||
if (e.cy().data('firstNode') !== 'root') {
|
e.cy().data('firstNode', 'nonroot')
|
||||||
e.cy().data('firstNode','nonroot')
|
return { x: 0, y: 0 }
|
||||||
return {x:0,y:0}
|
|
||||||
}
|
}
|
||||||
if (e.cy().data('firstNode') === undefined)
|
if (e.cy().data('firstNode') === undefined)
|
||||||
e.cy().data('firstNode','nonroot')
|
e.cy().data('firstNode', 'nonroot')
|
||||||
const parent = e.cy().edges(`[target="${e.id()}"]`)[0].source()
|
const parent = e.cy().edges(`[target="${e.id()}"]`)[0].source()
|
||||||
const wing = (parent.data('children') === 1) ? 0 : parent.data('subtreeWidth') / 2 + 50
|
const wing = (parent.data('children') === 1) ? 0 : parent.data('subtreeWidth') / 2 + 50
|
||||||
const lastOffset = parent.data('lastChild')
|
const lastOffset = parent.data('lastChild')
|
||||||
const step = wing * 2 / (parent.data('children') - 1)
|
const step = wing * 2 / (parent.data('children') - 1)
|
||||||
//e.removeData('subtreeWidth')
|
//e.removeData('subtreeWidth')
|
||||||
console.log('AAAAAAAAAAa', e.data(), lastOffset, step, parent.position().y, wing)
|
|
||||||
if (lastOffset !== undefined) {
|
if (lastOffset !== undefined) {
|
||||||
parent.data('lastChild', lastOffset + step)
|
parent.data('lastChild', lastOffset + step)
|
||||||
const pos = { x: 250 * e.data('layer'), y: (lastOffset + step) }
|
const pos = { x: 250 * e.data('layer'), y: (lastOffset + step) }
|
||||||
@ -386,7 +370,7 @@ if (e.cy().data('firstNode') !== 'root') {
|
|||||||
const pos = { x: 250 * e.data('layer'), y: (parent.position().y - wing) }
|
const pos = { x: 250 * e.data('layer'), y: (parent.position().y - wing) }
|
||||||
e.data('oldPos', pos)
|
e.data('oldPos', pos)
|
||||||
return pos
|
return pos
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, // map of (node id) => (position obj); or function(node){ return somPos; }
|
}, // map of (node id) => (position obj); or function(node){ return somPos; }
|
||||||
zoom: undefined, // the zoom level to set (prob want fit = false if set)
|
zoom: undefined, // the zoom level to set (prob want fit = false if set)
|
||||||
@ -502,7 +486,7 @@ if (e.cy().data('firstNode') !== 'root') {
|
|||||||
layoutElement.classList.add("popper-layout");
|
layoutElement.classList.add("popper-layout");
|
||||||
layoutElement.setAttribute("data-id", item.id());
|
layoutElement.setAttribute("data-id", item.id());
|
||||||
layoutElement.addEventListener("mouseup", () => {
|
layoutElement.addEventListener("mouseup", () => {
|
||||||
//Узнаём грани, идущие от этой ноды
|
//Узнаём грани, идущие от этой ноды
|
||||||
setModalQuestionParentContentId(item.id())
|
setModalQuestionParentContentId(item.id())
|
||||||
setOpenedModalQuestions(true)
|
setOpenedModalQuestions(true)
|
||||||
});
|
});
|
||||||
@ -533,7 +517,7 @@ if (e.cy().data('firstNode') !== 'root') {
|
|||||||
plusElement.addEventListener("mouseup", () => {
|
plusElement.addEventListener("mouseup", () => {
|
||||||
setStartCreate(node.id());
|
setStartCreate(node.id());
|
||||||
});
|
});
|
||||||
|
|
||||||
plusesContainer.current?.appendChild(plusElement);
|
plusesContainer.current?.appendChild(plusElement);
|
||||||
|
|
||||||
return plusElement;
|
return plusElement;
|
||||||
@ -594,7 +578,6 @@ if (e.cy().data('firstNode') !== 'root') {
|
|||||||
gearElement.style.zIndex = "1"
|
gearElement.style.zIndex = "1"
|
||||||
gearsContainer.current?.appendChild(gearElement);
|
gearsContainer.current?.appendChild(gearElement);
|
||||||
gearElement.addEventListener("mouseup", (e) => {
|
gearElement.addEventListener("mouseup", (e) => {
|
||||||
console.log(item.id())
|
|
||||||
updateOpenedModalSettingsId(item.id())
|
updateOpenedModalSettingsId(item.id())
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -672,23 +655,27 @@ if (e.cy().data('firstNode') !== 'root') {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<CytoscapeComponent
|
<CytoscapeComponent
|
||||||
wheelSensitivity={0.1}
|
wheelSensitivity={0.1}
|
||||||
elements={[]}
|
elements={[]}
|
||||||
// elements={createGraphElements(tree, quiz)}
|
// elements={createGraphElements(tree, quiz)}
|
||||||
style={{ height: "480px", background: "#F2F3F7" }}
|
style={{ height: "480px", background: "#F2F3F7" }}
|
||||||
stylesheet={stylesheet}
|
stylesheet={stylesheet}
|
||||||
layout={(lyopts)}
|
layout={(lyopts)}
|
||||||
cy={(cy) => {
|
cy={(cy) => {
|
||||||
cyRef.current = cy;
|
cyRef.current = cy;
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<button onClick={() => {
|
{/* <button onClick={() => {
|
||||||
console.log("ELEMENTS____________________________")
|
console.log("NODES____________________________")
|
||||||
cyRef.current?.elements().forEach((ele:any) => {
|
cyRef.current?.elements().forEach((ele: any) => {
|
||||||
console.log(ele.data())
|
console.log(ele.data())
|
||||||
})
|
})
|
||||||
}}>elements</button>
|
}}>nodes</button>
|
||||||
|
<button onClick={() => {
|
||||||
|
console.log("ELEMENTS____________________________")
|
||||||
|
console.log(questions)
|
||||||
|
}}>elements</button> */}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -2,8 +2,8 @@ import { Box } from "@mui/material"
|
|||||||
import { useEffect, useRef, useState } from "react";
|
import { useEffect, useRef, useState } from "react";
|
||||||
import { updateDragQuestionContentId, updateQuestion } from "@root/questions/actions"
|
import { updateDragQuestionContentId, updateQuestion } from "@root/questions/actions"
|
||||||
import { updateRootContentId } from "@root/quizes/actions"
|
import { updateRootContentId } from "@root/quizes/actions"
|
||||||
|
import { useCurrentQuiz } from "@root/quizes/hooks"
|
||||||
import { useQuestionsStore } from "@root/questions/store"
|
import { useQuestionsStore } from "@root/questions/store"
|
||||||
import { useCurrentQuiz } from "@root/quizes/hooks";
|
|
||||||
import { enqueueSnackbar } from "notistack";
|
import { enqueueSnackbar } from "notistack";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@ -11,17 +11,14 @@ interface Props {
|
|||||||
modalQuestionTargetContentId: string;
|
modalQuestionTargetContentId: string;
|
||||||
}
|
}
|
||||||
export const FirstNodeField = ({ setOpenedModalQuestions, modalQuestionTargetContentId }: Props) => {
|
export const FirstNodeField = ({ setOpenedModalQuestions, modalQuestionTargetContentId }: Props) => {
|
||||||
const { dragQuestionContentId } = useQuestionsStore()
|
|
||||||
const Container = useRef<HTMLDivElement | null>(null);
|
|
||||||
const quiz = useCurrentQuiz();
|
const quiz = useCurrentQuiz();
|
||||||
console.log(dragQuestionContentId)
|
const { dragQuestionContentId, questions } = useQuestionsStore()
|
||||||
|
const Container = useRef<HTMLDivElement | null>(null);
|
||||||
|
|
||||||
const modalOpen = () => setOpenedModalQuestions(true)
|
const modalOpen = () => setOpenedModalQuestions(true)
|
||||||
|
|
||||||
const newRootNode = () => {
|
const newRootNode = () => {
|
||||||
if (quiz) {
|
if (quiz) {
|
||||||
console.log(dragQuestionContentId)
|
|
||||||
|
|
||||||
if (dragQuestionContentId) {
|
if (dragQuestionContentId) {
|
||||||
updateRootContentId(quiz?.id, dragQuestionContentId)
|
updateRootContentId(quiz?.id, dragQuestionContentId)
|
||||||
updateQuestion(dragQuestionContentId, (question) => question.content.rule.parentId = "root")
|
updateQuestion(dragQuestionContentId, (question) => question.content.rule.parentId = "root")
|
||||||
@ -29,6 +26,7 @@ export const FirstNodeField = ({ setOpenedModalQuestions, modalQuestionTargetCon
|
|||||||
} else {
|
} else {
|
||||||
enqueueSnackbar("Нет информации о взятом опроснике")
|
enqueueSnackbar("Нет информации о взятом опроснике")
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -53,6 +51,7 @@ export const FirstNodeField = ({ setOpenedModalQuestions, modalQuestionTargetCon
|
|||||||
|
|
||||||
}, [modalQuestionTargetContentId])
|
}, [modalQuestionTargetContentId])
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
ref={Container}
|
ref={Container}
|
||||||
|
@ -15,11 +15,9 @@ interface Edges {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const storeToNodes = (questions: AnyTypedQuizQuestion[]) => {
|
export const storeToNodes = (questions: AnyTypedQuizQuestion[]) => {
|
||||||
console.log(questions)
|
|
||||||
const nodes: Nodes[] = []
|
const nodes: Nodes[] = []
|
||||||
const edges: Edges[] = []
|
const edges: Edges[] = []
|
||||||
questions.forEach((question) => {
|
questions.forEach((question) => {
|
||||||
console.log(question)
|
|
||||||
if (question.content.rule.parentId) {
|
if (question.content.rule.parentId) {
|
||||||
nodes.push({data: {
|
nodes.push({data: {
|
||||||
id: question.content.id,
|
id: question.content.id,
|
||||||
@ -38,6 +36,5 @@ export const storeToNodes = (questions: AnyTypedQuizQuestion[]) => {
|
|||||||
}})
|
}})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
console.log([...nodes, ...edges])
|
|
||||||
return [...nodes, ...edges];
|
return [...nodes, ...edges];
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,8 @@ export const BranchingMap = () => {
|
|||||||
const [modalQuestionTargetContentId, setModalQuestionTargetContentId] = useState<string>("")
|
const [modalQuestionTargetContentId, setModalQuestionTargetContentId] = useState<string>("")
|
||||||
const [openedModalQuestions, setOpenedModalQuestions] = useState<boolean>(false)
|
const [openedModalQuestions, setOpenedModalQuestions] = useState<boolean>(false)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
id="cytoscape-container"
|
id="cytoscape-container"
|
||||||
|
@ -32,34 +32,32 @@ export default function BranchingQuestions() {
|
|||||||
|
|
||||||
const { openedModalSettingsId } = useQuestionsStore();
|
const { openedModalSettingsId } = useQuestionsStore();
|
||||||
const [targetQuestion, setTargetQuestion] = useState<AnyTypedQuizQuestion | null>(getQuestionById(openedModalSettingsId) || getQuestionByContentId(openedModalSettingsId))
|
const [targetQuestion, setTargetQuestion] = useState<AnyTypedQuizQuestion | null>(getQuestionById(openedModalSettingsId) || getQuestionByContentId(openedModalSettingsId))
|
||||||
console.log(targetQuestion)
|
|
||||||
const [parentQuestion, setParentQuestion] = useState<AnyTypedQuizQuestion | null>(getQuestionByContentId(targetQuestion?.content.rule.parentId))
|
const [parentQuestion, setParentQuestion] = useState<AnyTypedQuizQuestion | null>(getQuestionByContentId(targetQuestion?.content.rule.parentId))
|
||||||
console.log(parentQuestion)
|
|
||||||
|
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
if (parentQuestion.content.rule.main.length === 0) updateQuestion(parentQuestion.id, question => question.content.rule.main.push({
|
if (parentQuestion === null) return
|
||||||
next: targetQuestion.content.id,
|
if (parentQuestion.content.rule.main.length === 0) {
|
||||||
or: true,
|
let mutate = JSON.parse(JSON.stringify(parentQuestion))
|
||||||
rules: [{
|
mutate.content.rule.main = [{
|
||||||
question: parentQuestion.content.id,
|
next: targetQuestion.content.id,
|
||||||
answers: []
|
or: true,
|
||||||
|
rules: [{
|
||||||
|
question: parentQuestion.content.id,
|
||||||
|
answers: []
|
||||||
|
}]
|
||||||
}]
|
}]
|
||||||
}))
|
setParentQuestion(mutate)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (targetQuestion === null || parentQuestion === null) {
|
if (targetQuestion === null || parentQuestion === null) {
|
||||||
|
|
||||||
console.log(openedModalSettingsId)
|
|
||||||
enqueueSnackbar("Невозможно найти данные ветвления для этого вопроса")
|
enqueueSnackbar("Невозможно найти данные ветвления для этого вопроса")
|
||||||
return <></>
|
return <></>
|
||||||
}
|
}
|
||||||
|
|
||||||
const saveData = () => {
|
const saveData = () => {
|
||||||
console.log(parentQuestion)
|
|
||||||
if (parentQuestion !== null) {
|
if (parentQuestion !== null) {
|
||||||
updateQuestion(parentQuestion.content.id, question => question.content = parentQuestion.content)
|
updateQuestion(parentQuestion.content.id, question => question.content = parentQuestion.content)
|
||||||
}
|
}
|
||||||
handleClose()
|
handleClose()
|
||||||
|
|
||||||
@ -148,11 +146,11 @@ export default function BranchingQuestions() {
|
|||||||
marginBottom: "10px",
|
marginBottom: "10px",
|
||||||
cursor: "pointer"
|
cursor: "pointer"
|
||||||
}}
|
}}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
const mutate = JSON.parse(JSON.stringify(parentQuestion))
|
const mutate = JSON.parse(JSON.stringify(parentQuestion))
|
||||||
mutate.content.rule.main.push(createBranchingRuleMain(targetQuestion.content.id, parentQuestion.content.id))
|
mutate.content.rule.main.push(createBranchingRuleMain(targetQuestion.content.id, parentQuestion.content.id))
|
||||||
setParentQuestion(mutate)
|
setParentQuestion(mutate)
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Добавить условие
|
Добавить условие
|
||||||
</Link>
|
</Link>
|
||||||
@ -163,7 +161,7 @@ export default function BranchingQuestions() {
|
|||||||
sx={{
|
sx={{
|
||||||
margin: 0
|
margin: 0
|
||||||
}}
|
}}
|
||||||
checked={parentQuestion.content.rule.default === targetQuestion.id}
|
checked={parentQuestion.content.rule.default === targetQuestion.content.id}
|
||||||
|
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
let mutate = JSON.parse(JSON.stringify(parentQuestion))
|
let mutate = JSON.parse(JSON.stringify(parentQuestion))
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Box, MenuItem, FormControl, Checkbox, FormControlLabel, Radio, RadioGroup, Typography, useTheme, Select, Chip, IconButton, TextField } from "@mui/material"
|
import { Box, MenuItem, FormControl, Checkbox, FormControlLabel, Radio, RadioGroup, Typography, useTheme, Select, useMediaQuery, IconButton, TextField } from "@mui/material"
|
||||||
import RadioCheck from "@ui_kit/RadioCheck"
|
import RadioCheck from "@ui_kit/RadioCheck"
|
||||||
import RadioIcon from "@ui_kit/RadioIcon"
|
import RadioIcon from "@ui_kit/RadioIcon"
|
||||||
import { QuizQuestionBase } from "model/questionTypes/shared"
|
import { QuizQuestionBase } from "model/questionTypes/shared"
|
||||||
@ -8,7 +8,10 @@ import { useQuestionsStore } from "@root/questions/store";
|
|||||||
import { updateQuestion, getQuestionById } from "@root/questions/actions";
|
import { updateQuestion, getQuestionById } from "@root/questions/actions";
|
||||||
import { AnyTypedQuizQuestion } from "../../../model/questionTypes/shared"
|
import { AnyTypedQuizQuestion } from "../../../model/questionTypes/shared"
|
||||||
import { SelectChangeEvent } from '@mui/material/Select';
|
import { SelectChangeEvent } from '@mui/material/Select';
|
||||||
|
import CalendarIcon from "@icons/CalendarIcon";
|
||||||
|
import { DatePicker } from "@mui/x-date-pickers";
|
||||||
|
import * as dayjs from 'dayjs'
|
||||||
|
import { TimePicker } from '@mui/x-date-pickers/TimePicker';
|
||||||
import InfoIcon from "@icons/Info";
|
import InfoIcon from "@icons/Info";
|
||||||
import { DeleteIcon } from "@icons/questionsPage/deleteIcon";
|
import { DeleteIcon } from "@icons/questionsPage/deleteIcon";
|
||||||
|
|
||||||
@ -26,7 +29,6 @@ interface Props {
|
|||||||
|
|
||||||
//Этот компонент вызывается 1 раз на каждое условие родителя для перехода к этому вопросу. Поэтому для изменения стора мы знаем индекс
|
//Этот компонент вызывается 1 раз на каждое условие родителя для перехода к этому вопросу. Поэтому для изменения стора мы знаем индекс
|
||||||
export const TypeSwitch = ({ parentQuestion, targetQuestion, ruleIndex, setParentQuestion }: Props) => {
|
export const TypeSwitch = ({ parentQuestion, targetQuestion, ruleIndex, setParentQuestion }: Props) => {
|
||||||
console.log("index " + ruleIndex)
|
|
||||||
|
|
||||||
switch (parentQuestion.type) {
|
switch (parentQuestion.type) {
|
||||||
// case 'nonselected':
|
// case 'nonselected':
|
||||||
@ -45,11 +47,10 @@ export const TypeSwitch = ({ parentQuestion, targetQuestion, ruleIndex, setParen
|
|||||||
)
|
)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "date":
|
case "date":
|
||||||
// return <DateInputsType targetQuestion={targetQuestion} parentQuestion={parentQuestion} ruleIndex={ruleIndex} setParentQuestion={setParentQuestion} />
|
return <DateInputsType targetQuestion={targetQuestion} parentQuestion={parentQuestion} ruleIndex={ruleIndex} setParentQuestion={setParentQuestion} />
|
||||||
return <></>
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "number":
|
case "number":
|
||||||
return <NumberInputsType targetQuestion={targetQuestion} parentQuestion={parentQuestion} ruleIndex={ruleIndex} setParentQuestion={setParentQuestion} />
|
return <NumberInputsType targetQuestion={targetQuestion} parentQuestion={parentQuestion} ruleIndex={ruleIndex} setParentQuestion={setParentQuestion} />
|
||||||
@ -57,7 +58,6 @@ export const TypeSwitch = ({ parentQuestion, targetQuestion, ruleIndex, setParen
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case "page":
|
case "page":
|
||||||
case "date":
|
|
||||||
return <BlockRule text={"У такого родителя может быть только один потомок"} />
|
return <BlockRule text={"У такого родителя может быть только один потомок"} />
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -96,7 +96,6 @@ export const BlockRule = ({ text }: { text: string }) => {
|
|||||||
const SelectorType = ({ parentQuestion, targetQuestion, ruleIndex, setParentQuestion }: Props) => {
|
const SelectorType = ({ parentQuestion, targetQuestion, ruleIndex, setParentQuestion }: Props) => {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const quizId = Number(useParams().quizId);
|
const quizId = Number(useParams().quizId);
|
||||||
console.log(parentQuestion)
|
|
||||||
return (
|
return (
|
||||||
|
|
||||||
<Box
|
<Box
|
||||||
@ -148,15 +147,12 @@ const SelectorType = ({ parentQuestion, targetQuestion, ruleIndex, setParentQues
|
|||||||
</Box>
|
</Box>
|
||||||
<Select
|
<Select
|
||||||
multiple
|
multiple
|
||||||
value={parentQuestion.content.rule.main[ruleIndex].rules[0].answers || []}
|
value={parentQuestion.content?.rule?.main[ruleIndex]?.rules[0]?.answers || []}
|
||||||
onChange={(event: SelectChangeEvent) => {
|
onChange={(event: SelectChangeEvent) => {
|
||||||
|
|
||||||
let newParentQuestion = JSON.parse(JSON.stringify(parentQuestion))
|
let newParentQuestion = JSON.parse(JSON.stringify(parentQuestion))
|
||||||
newParentQuestion.content.rule.main[ruleIndex].rules[0].answers = (event.target as HTMLSelectElement).value
|
newParentQuestion.content.rule.main[ruleIndex].rules[0].answers = (event.target as HTMLSelectElement).value
|
||||||
setParentQuestion(newParentQuestion)
|
setParentQuestion(newParentQuestion)
|
||||||
console.log(parentQuestion.content.rule.main[ruleIndex])
|
|
||||||
console.log(parentQuestion.content.rule.main[ruleIndex].rules[0])
|
|
||||||
console.log(parentQuestion.content.rule.main[ruleIndex].rules[0].answers)
|
|
||||||
}}
|
}}
|
||||||
sx={{
|
sx={{
|
||||||
width: "100%",
|
width: "100%",
|
||||||
@ -209,8 +205,257 @@ const SelectorType = ({ parentQuestion, targetQuestion, ruleIndex, setParentQues
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
const DateInputsType = ({ parentQuestion, targetQuestion, ruleIndex, setParentQuestion }: Props) => {
|
const DateInputsType = ({ parentQuestion, targetQuestion, ruleIndex, setParentQuestion }: Props) => {
|
||||||
|
const theme = useTheme();
|
||||||
|
const upLg = useMediaQuery(theme.breakpoints.up("md"));
|
||||||
|
|
||||||
return <></>
|
const time = dayjs(new Date)
|
||||||
|
|
||||||
|
const [firstDate, setFirstDate] = useState(time)
|
||||||
|
const [secondDate, setSecondDate] = useState(time)
|
||||||
|
const [firstTime, setFirstTime] = useState(time)
|
||||||
|
const [secondTime, setSecondTime] = useState(time)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
let newParentQuestion = JSON.parse(JSON.stringify(parentQuestion))
|
||||||
|
|
||||||
|
newParentQuestion.content.rule.main[ruleIndex].rules[0].answers[0] = time
|
||||||
|
if (newParentQuestion.content.dateRange) parentQuestion.content.rule.main[ruleIndex].rules[0].answers[1] = time
|
||||||
|
|
||||||
|
setParentQuestion(newParentQuestion)
|
||||||
|
|
||||||
|
}, [firstDate, secondDate, firstTime, secondTime])
|
||||||
|
|
||||||
|
// {/* //dateRange выбор диапазона дат */}
|
||||||
|
// {/* time выбор времени */}
|
||||||
|
return <Box
|
||||||
|
sx={{
|
||||||
|
padding: "20px",
|
||||||
|
margin: "20px",
|
||||||
|
borderRadius: "8px",
|
||||||
|
bgcolor: "#F2F3F7",
|
||||||
|
height: "280px",
|
||||||
|
overflow: "auto"
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: "flex",
|
||||||
|
justifyContent: "space-between",
|
||||||
|
alignItems: "center",
|
||||||
|
pb: "5px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography sx={{ color: "#4D4D4D", fontWeight: "500" }}>
|
||||||
|
Новое условие
|
||||||
|
</Typography>
|
||||||
|
<IconButton
|
||||||
|
sx={{ borderRadius: "6px", padding: "2px" }}
|
||||||
|
onClick={() => {
|
||||||
|
let newParentQuestion = JSON.parse(JSON.stringify(parentQuestion))
|
||||||
|
newParentQuestion.content.rule.main.splice(ruleIndex, 1)
|
||||||
|
setParentQuestion(newParentQuestion)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<DeleteIcon color={"#4D4D4D"} />
|
||||||
|
</IconButton>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
|
pb: "10px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography sx={{ color: "#4D4D4D", fontWeight: "500" }}>
|
||||||
|
Дан ответ
|
||||||
|
</Typography>
|
||||||
|
<Typography sx={{ color: "#7E2AEA", pl: "10px" }}>
|
||||||
|
(Укажите один или несколько вариантов)
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
backgroundColor: "#E8EAEE",
|
||||||
|
margin: "10px"
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{
|
||||||
|
parentQuestion.content.dateRange &&
|
||||||
|
<Typography sx={{ color: "#4D4D4D", p: "10px" }}>
|
||||||
|
(Начало периода)
|
||||||
|
</Typography>
|
||||||
|
}
|
||||||
|
<DatePicker
|
||||||
|
value={parentQuestion.content.rule.main[ruleIndex].rules[0].answers[0]}
|
||||||
|
onChange={(e) => console.log(e)}
|
||||||
|
slots={{
|
||||||
|
openPickerIcon: () => <CalendarIcon />,
|
||||||
|
}}
|
||||||
|
slotProps={{
|
||||||
|
openPickerButton: {
|
||||||
|
sx: {
|
||||||
|
p: 0,
|
||||||
|
},
|
||||||
|
"data-cy": "open-datepicker",
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
sx={{
|
||||||
|
p: "10px",
|
||||||
|
"& .MuiInputBase-root": {
|
||||||
|
minWidth: "325px",
|
||||||
|
backgroundColor: "#F2F3F7",
|
||||||
|
borderRadius: "10px",
|
||||||
|
pr: "31px",
|
||||||
|
"& input": {
|
||||||
|
py: "11px",
|
||||||
|
pl: upLg ? "20px" : "13px",
|
||||||
|
lineHeight: "19px",
|
||||||
|
},
|
||||||
|
"& fieldset": {
|
||||||
|
borderColor: "#9A9AAF",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{parentQuestion.content.time &&
|
||||||
|
<TimePicker
|
||||||
|
value={parentQuestion.content.rule.main[ruleIndex].rules[0].answers[0]}
|
||||||
|
sx={{
|
||||||
|
p: "10px",
|
||||||
|
"& .MuiInputBase-root": {
|
||||||
|
minWidth: "325px",
|
||||||
|
backgroundColor: "#F2F3F7",
|
||||||
|
borderRadius: "10px",
|
||||||
|
pr: "22px",
|
||||||
|
"& input": {
|
||||||
|
py: "11px",
|
||||||
|
pl: upLg ? "20px" : "13px",
|
||||||
|
lineHeight: "19px",
|
||||||
|
},
|
||||||
|
"& fieldset": {
|
||||||
|
borderColor: "#9A9AAF",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
{parentQuestion.content.dateRange &&
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
backgroundColor: "#E8EAEE",
|
||||||
|
margin: "10px"
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{
|
||||||
|
parentQuestion.content.dateRange &&
|
||||||
|
<Typography sx={{ color: "#4D4D4D", p: "10px" }}>
|
||||||
|
(Конец периода)
|
||||||
|
</Typography>
|
||||||
|
}
|
||||||
|
<DatePicker
|
||||||
|
value={parentQuestion.content.rule.main[ruleIndex].rules[0].answers[1]}
|
||||||
|
onChange={() => { }}
|
||||||
|
slots={{
|
||||||
|
openPickerIcon: () => <CalendarIcon />,
|
||||||
|
}}
|
||||||
|
slotProps={{
|
||||||
|
openPickerButton: {
|
||||||
|
sx: {
|
||||||
|
p: 0,
|
||||||
|
},
|
||||||
|
"data-cy": "open-datepicker",
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
sx={{
|
||||||
|
p: "10px",
|
||||||
|
"& .MuiInputBase-root": {
|
||||||
|
minWidth: "325px",
|
||||||
|
backgroundColor: "#F2F3F7",
|
||||||
|
borderRadius: "10px",
|
||||||
|
pr: "31px",
|
||||||
|
"& input": {
|
||||||
|
py: "11px",
|
||||||
|
pl: upLg ? "20px" : "13px",
|
||||||
|
lineHeight: "19px",
|
||||||
|
},
|
||||||
|
"& fieldset": {
|
||||||
|
borderColor: "#9A9AAF",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{parentQuestion.content.time &&
|
||||||
|
<TimePicker
|
||||||
|
value={parentQuestion.content.rule.main[ruleIndex].rules[0].answers[1]}
|
||||||
|
sx={{
|
||||||
|
p: "10px",
|
||||||
|
"& .MuiInputBase-root": {
|
||||||
|
minWidth: "325px",
|
||||||
|
backgroundColor: "#F2F3F7",
|
||||||
|
borderRadius: "10px",
|
||||||
|
pr: "22px",
|
||||||
|
"& input": {
|
||||||
|
py: "11px",
|
||||||
|
pl: upLg ? "20px" : "13px",
|
||||||
|
lineHeight: "19px",
|
||||||
|
},
|
||||||
|
"& fieldset": {
|
||||||
|
borderColor: "#9A9AAF",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
</Box>
|
||||||
|
}
|
||||||
|
|
||||||
|
{/* <TextField
|
||||||
|
sx={{
|
||||||
|
marginTop: "20px",
|
||||||
|
width: "100%"
|
||||||
|
}}
|
||||||
|
|
||||||
|
placeholder="от"
|
||||||
|
value={parentQuestion.content.rule.main[ruleIndex].rules[0].answers[0]}
|
||||||
|
onChange={(event: React.FormEvent<HTMLInputElement>) => {
|
||||||
|
|
||||||
|
let newParentQuestion = JSON.parse(JSON.stringify(parentQuestion))
|
||||||
|
newParentQuestion.content.rule.main[ruleIndex].rules[0].answers[0] = Number((event.target as HTMLInputElement).value.replace(/[^0-9,\s]/g, ""))
|
||||||
|
if (newParentQuestion.content.rule.main[ruleIndex].rules[0].answers[1] === undefined) newParentQuestion.content.rule.main[ruleIndex].rules[0].answers[1] = 0
|
||||||
|
setParentQuestion(newParentQuestion)
|
||||||
|
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{parentQuestion.content.chooseRange &&
|
||||||
|
<TextField
|
||||||
|
placeholder="до"
|
||||||
|
sx={{
|
||||||
|
marginTop: "20px",
|
||||||
|
width: "100%"
|
||||||
|
}}
|
||||||
|
|
||||||
|
value={parentQuestion.content.rule.main[ruleIndex].rules[0].answers[1]}
|
||||||
|
onChange={(event: React.FormEvent<HTMLInputElement>) => {
|
||||||
|
|
||||||
|
let newParentQuestion = JSON.parse(JSON.stringify(parentQuestion))
|
||||||
|
newParentQuestion.content.rule.main[ruleIndex].rules[0].answers[1] = Number((event.target as HTMLInputElement).value.replace(/[^0-9,\s]/g, ""))
|
||||||
|
if (newParentQuestion.content.rule.main[ruleIndex].rules[0].answers[0] === undefined) newParentQuestion.content.rule.main[ruleIndex].rules[0].answers[0] = 0
|
||||||
|
setParentQuestion(newParentQuestion)
|
||||||
|
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
} */}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</Box >
|
||||||
}
|
}
|
||||||
const NumberInputsType = ({ parentQuestion, targetQuestion, ruleIndex, setParentQuestion }: Props) => {
|
const NumberInputsType = ({ parentQuestion, targetQuestion, ruleIndex, setParentQuestion }: Props) => {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
@ -264,21 +509,43 @@ const NumberInputsType = ({ parentQuestion, targetQuestion, ruleIndex, setParent
|
|||||||
(Укажите один или несколько вариантов)
|
(Укажите один или несколько вариантов)
|
||||||
</Typography>
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
{/* <TextField
|
<TextField
|
||||||
sx={{
|
sx={{
|
||||||
marginTop: "20px",
|
marginTop: "20px",
|
||||||
width: "100%"
|
width: "100%"
|
||||||
}}
|
}}
|
||||||
|
|
||||||
|
placeholder="от"
|
||||||
value={parentQuestion.content.rule.main[ruleIndex].rules[0].answers[0]}
|
value={parentQuestion.content.rule.main[ruleIndex].rules[0].answers[0]}
|
||||||
onChange={(event: React.FormEvent<HTMLInputElement>) => {
|
onChange={(event: React.FormEvent<HTMLInputElement>) => {
|
||||||
|
|
||||||
let newParentQuestion = JSON.parse(JSON.stringify(parentQuestion))
|
let newParentQuestion = JSON.parse(JSON.stringify(parentQuestion))
|
||||||
newParentQuestion.content.rule.main[ruleIndex].rules[0].answers = [(event.target as HTMLInputElement).value.replace(/[^0-9,\s]/g, "")]
|
newParentQuestion.content.rule.main[ruleIndex].rules[0].answers[0] = Number((event.target as HTMLInputElement).value.replace(/[^0-9,\s]/g, ""))
|
||||||
|
if (newParentQuestion.content.rule.main[ruleIndex].rules[0].answers[1] === undefined) newParentQuestion.content.rule.main[ruleIndex].rules[0].answers[1] = 0
|
||||||
setParentQuestion(newParentQuestion)
|
setParentQuestion(newParentQuestion)
|
||||||
|
|
||||||
}}
|
}}
|
||||||
/> */}
|
/>
|
||||||
|
{parentQuestion.content.chooseRange &&
|
||||||
|
<TextField
|
||||||
|
placeholder="до"
|
||||||
|
sx={{
|
||||||
|
marginTop: "20px",
|
||||||
|
width: "100%"
|
||||||
|
}}
|
||||||
|
|
||||||
|
value={parentQuestion.content.rule.main[ruleIndex].rules[0].answers[1]}
|
||||||
|
onChange={(event: React.FormEvent<HTMLInputElement>) => {
|
||||||
|
|
||||||
|
let newParentQuestion = JSON.parse(JSON.stringify(parentQuestion))
|
||||||
|
newParentQuestion.content.rule.main[ruleIndex].rules[0].answers[1] = Number((event.target as HTMLInputElement).value.replace(/[^0-9,\s]/g, ""))
|
||||||
|
if (newParentQuestion.content.rule.main[ruleIndex].rules[0].answers[0] === undefined) newParentQuestion.content.rule.main[ruleIndex].rules[0].answers[0] = 0
|
||||||
|
setParentQuestion(newParentQuestion)
|
||||||
|
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -338,7 +605,7 @@ const TextInputsType = ({ parentQuestion, targetQuestion, ruleIndex, setParentQu
|
|||||||
(Укажите текст, при совпадении с которым пользователь попадёт на этот вопрос)
|
(Укажите текст, при совпадении с которым пользователь попадёт на этот вопрос)
|
||||||
</Typography>
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
{/* <TextField
|
<TextField
|
||||||
sx={{
|
sx={{
|
||||||
marginTop: "20px",
|
marginTop: "20px",
|
||||||
width: "100%"
|
width: "100%"
|
||||||
@ -351,7 +618,7 @@ const TextInputsType = ({ parentQuestion, targetQuestion, ruleIndex, setParentQu
|
|||||||
setParentQuestion(newParentQuestion)
|
setParentQuestion(newParentQuestion)
|
||||||
|
|
||||||
}}
|
}}
|
||||||
/> */}
|
/>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -475,10 +742,10 @@ const RatingInputsType = ({ parentQuestion, targetQuestion, ruleIndex, setParent
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Typography sx={{ color: "#7E2AEA", pl: "10px", fontSize: "12px" }}>
|
<Typography sx={{ color: "#7E2AEA", pl: "10px", fontSize: "12px" }}>
|
||||||
(Ожидаемое количество ячеек)
|
Ожидаемое количество ячеек(не более доступного количества)
|
||||||
</Typography>
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
{/* <TextField
|
<TextField
|
||||||
sx={{
|
sx={{
|
||||||
marginTop: "20px",
|
marginTop: "20px",
|
||||||
width: "100%"
|
width: "100%"
|
||||||
@ -487,11 +754,13 @@ const RatingInputsType = ({ parentQuestion, targetQuestion, ruleIndex, setParent
|
|||||||
onChange={(event: React.FormEvent<HTMLInputElement>) => {
|
onChange={(event: React.FormEvent<HTMLInputElement>) => {
|
||||||
|
|
||||||
let newParentQuestion = JSON.parse(JSON.stringify(parentQuestion))
|
let newParentQuestion = JSON.parse(JSON.stringify(parentQuestion))
|
||||||
newParentQuestion.content.rule.main[ruleIndex].rules[0].answers = [(event.target as HTMLInputElement).value.replace(/[^0-9,\s]/g, "")]
|
let valueNumber = Number((event.target as HTMLInputElement).value.replace(/[^0-9,\s]/g, ""))
|
||||||
|
valueNumber = valueNumber > parentQuestion.content.steps ? parentQuestion.content.steps : valueNumber
|
||||||
|
newParentQuestion.content.rule.main[ruleIndex].rules[0].answers = [valueNumber]
|
||||||
setParentQuestion(newParentQuestion)
|
setParentQuestion(newParentQuestion)
|
||||||
|
|
||||||
}}
|
}}
|
||||||
/> */}
|
/>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -499,23 +768,3 @@ const RatingInputsType = ({ parentQuestion, targetQuestion, ruleIndex, setParent
|
|||||||
</Box >
|
</Box >
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// {
|
|
||||||
// content: {
|
|
||||||
// rule: {
|
|
||||||
// main: [
|
|
||||||
// {
|
|
||||||
// next: "id of next question", // 2 string
|
|
||||||
// or: true // 3 boolean
|
|
||||||
// rules: [
|
|
||||||
// {
|
|
||||||
// question: "question id", string
|
|
||||||
// answers: [] // ответы на вопросы. для вариантов выбора - конкретные айдишники, для полей ввода текста - текст по полному совпадению, для ввода файла ии ещё какой подобной дичи - просто факт того что файл ввели, т.е. boolean
|
|
||||||
// }
|
|
||||||
// ]
|
|
||||||
// }
|
|
||||||
// ],
|
|
||||||
// default: ID string
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
@ -23,7 +23,6 @@ type AnyQuestion = UntypedQuizQuestion | AnyTypedQuizQuestion
|
|||||||
|
|
||||||
export const QuestionsList = () => {
|
export const QuestionsList = () => {
|
||||||
const { questions } = useQuestionsStore()
|
const { questions } = useQuestionsStore()
|
||||||
console.log(questions)
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box sx={{ padding: "15px" }}>
|
<Box sx={{ padding: "15px" }}>
|
||||||
|
@ -1,15 +1,13 @@
|
|||||||
import { Box, Typography, Switch, useTheme } from "@mui/material";
|
import { Box, Typography, Switch, useTheme } from "@mui/material";
|
||||||
|
|
||||||
import { QuestionsList } from "./QuestionsList";
|
import { QuestionsList } from "./QuestionsList";
|
||||||
|
import { updateOpenBranchingPanel } from "@root/questions/actions";
|
||||||
|
import {useQuestionsStore} from "@root/questions/store";
|
||||||
|
|
||||||
type BranchingPanelProps = {
|
|
||||||
active: boolean;
|
|
||||||
setActive: (active: boolean) => void;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const BranchingPanel = ({ active, setActive }: BranchingPanelProps) => {
|
export const BranchingPanel = () => {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
const {openBranchingPanel} = useQuestionsStore.getState()
|
||||||
return (
|
return (
|
||||||
<Box sx={{ userSelect: "none", maxWidth: "350px", width: "100%" }}>
|
<Box sx={{ userSelect: "none", maxWidth: "350px", width: "100%" }}>
|
||||||
<Box
|
<Box
|
||||||
@ -24,8 +22,10 @@ export const BranchingPanel = ({ active, setActive }: BranchingPanelProps) => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Switch
|
<Switch
|
||||||
value={active}
|
value={openBranchingPanel}
|
||||||
onChange={(_, value) => setTimeout(() => setActive(value), 10)}
|
onChange={(_, value) => {
|
||||||
|
updateOpenBranchingPanel(!value)
|
||||||
|
}}
|
||||||
sx={{
|
sx={{
|
||||||
width: 50,
|
width: 50,
|
||||||
height: 30,
|
height: 30,
|
||||||
@ -79,7 +79,7 @@ export const BranchingPanel = ({ active, setActive }: BranchingPanelProps) => {
|
|||||||
</Typography>
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
{ active && <QuestionsList /> }
|
{ openBranchingPanel === true && <QuestionsList /> }
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -1,24 +1,30 @@
|
|||||||
import { useParams } from "react-router-dom";
|
|
||||||
import { Box, Modal, Button, Typography } from "@mui/material";
|
import { Box, Modal, Button, Typography } from "@mui/material";
|
||||||
import { useQuestionsStore } from "@root/questions/store";
|
import { useQuestionsStore } from "@root/questions/store";
|
||||||
import { AnyTypedQuizQuestion, UntypedQuizQuestion } from "@model/questionTypes/shared";
|
import { AnyTypedQuizQuestion } from "@model/questionTypes/shared";
|
||||||
|
|
||||||
type AnyQuestion = UntypedQuizQuestion | AnyTypedQuizQuestion
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
openedModalQuestions: boolean;
|
openedModalQuestions: boolean;
|
||||||
setModalQuestionTargetContentId: (contentId:string) => void;
|
setModalQuestionTargetContentId: (contentId: string) => void;
|
||||||
setOpenedModalQuestions: (open:boolean) => void;
|
setOpenedModalQuestions: (open: boolean) => void;
|
||||||
|
setModalQuestionParentContentId: (open: string) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const BranchingQuestionsModal = ({ openedModalQuestions, setOpenedModalQuestions, setModalQuestionTargetContentId}:Props) => {
|
export const BranchingQuestionsModal = ({
|
||||||
const quizId = Number(useParams().quizId);
|
openedModalQuestions,
|
||||||
|
setOpenedModalQuestions,
|
||||||
|
setModalQuestionTargetContentId,
|
||||||
|
setModalQuestionParentContentId
|
||||||
|
}: Props) => {
|
||||||
const { questions } = useQuestionsStore();
|
const { questions } = useQuestionsStore();
|
||||||
|
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
setOpenedModalQuestions(false);
|
setOpenedModalQuestions(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const typedQuestions: AnyTypedQuizQuestion[] = questions.filter(
|
||||||
|
(question) => question.type && !question.content.rule.parentId
|
||||||
|
) as AnyTypedQuizQuestion[];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal open={openedModalQuestions} onClose={handleClose}>
|
<Modal open={openedModalQuestions} onClose={handleClose}>
|
||||||
<Box
|
<Box
|
||||||
@ -37,11 +43,11 @@ export const BranchingQuestionsModal = ({ openedModalQuestions, setOpenedModalQu
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Box sx={{ margin: "0 auto", maxWidth: "350px" }}>
|
<Box sx={{ margin: "0 auto", maxWidth: "350px" }}>
|
||||||
{questions.filter((q:AnyQuestion) => (q.type && !q.content.rule.parentId)).map((question: AnyTypedQuizQuestion, index:number) => (
|
{typedQuestions.map((question) => (
|
||||||
<Button
|
<Button
|
||||||
key={question.content.id}
|
key={question.content.id}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setModalQuestionTargetContentId(question.content.id)
|
setModalQuestionTargetContentId(question.content.id);
|
||||||
handleClose();
|
handleClose();
|
||||||
}}
|
}}
|
||||||
sx={{
|
sx={{
|
||||||
|
@ -11,7 +11,7 @@ import {
|
|||||||
useMediaQuery,
|
useMediaQuery,
|
||||||
useTheme,
|
useTheme,
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
import { copyQuestion, deleteQuestion, updateQuestion } from "@root/questions/actions";
|
import {copyQuestion, deleteQuestion, updateOpenBranchingPanel, updateQuestion} from "@root/questions/actions";
|
||||||
import MiniButtonSetting from "@ui_kit/MiniButtonSetting";
|
import MiniButtonSetting from "@ui_kit/MiniButtonSetting";
|
||||||
import { CopyIcon } from "../../assets/icons/questionsPage/CopyIcon";
|
import { CopyIcon } from "../../assets/icons/questionsPage/CopyIcon";
|
||||||
import Branching from "../../assets/icons/questionsPage/branching";
|
import Branching from "../../assets/icons/questionsPage/branching";
|
||||||
@ -20,6 +20,9 @@ import { HideIcon } from "../../assets/icons/questionsPage/hideIcon";
|
|||||||
import SettingIcon from "../../assets/icons/questionsPage/settingIcon";
|
import SettingIcon from "../../assets/icons/questionsPage/settingIcon";
|
||||||
import type { AnyTypedQuizQuestion } from "../../model/questionTypes/shared";
|
import type { AnyTypedQuizQuestion } from "../../model/questionTypes/shared";
|
||||||
import { updateOpenedModalSettingsId } from "@root/questions/actions";
|
import { updateOpenedModalSettingsId } from "@root/questions/actions";
|
||||||
|
import { useCurrentQuiz } from "@root/quizes/hooks";
|
||||||
|
import {enqueueSnackbar} from "notistack";
|
||||||
|
import {useQuestionsStore} from "@root/questions/store";
|
||||||
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@ -37,11 +40,28 @@ export default function ButtonsOptions({
|
|||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const isMobile = useMediaQuery(theme.breakpoints.down(790));
|
const isMobile = useMediaQuery(theme.breakpoints.down(790));
|
||||||
const isWrappMiniButtonSetting = useMediaQuery(theme.breakpoints.down(920));
|
const isWrappMiniButtonSetting = useMediaQuery(theme.breakpoints.down(920));
|
||||||
|
const quiz = useCurrentQuiz();
|
||||||
|
|
||||||
|
const {openBranchingPanel} = useQuestionsStore.getState()
|
||||||
const openedModal = () => {
|
const openedModal = () => {
|
||||||
updateOpenedModalSettingsId(question.id)
|
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: {
|
const buttonSetting: {
|
||||||
icon: JSX.Element;
|
icon: JSX.Element;
|
||||||
title: string;
|
title: string;
|
||||||
@ -78,7 +98,7 @@ export default function ButtonsOptions({
|
|||||||
),
|
),
|
||||||
title: "Ветвление",
|
title: "Ветвление",
|
||||||
value: "branching",
|
value: "branching",
|
||||||
myFunc: openedModal,
|
myFunc: () => handleClickBranching(question.id, openBranchingPanel),
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
@ -277,7 +297,7 @@ export default function ButtonsOptions({
|
|||||||
// deleteTimeoutId: newTimeoutId,
|
// deleteTimeoutId: newTimeoutId,
|
||||||
// });
|
// });
|
||||||
|
|
||||||
deleteQuestion(question.id);
|
deleteQuestion(question.id, quiz.id);
|
||||||
}}
|
}}
|
||||||
data-cy="delete-question"
|
data-cy="delete-question"
|
||||||
>
|
>
|
||||||
|
@ -23,6 +23,10 @@ import ImgIcon from "../../assets/icons/questionsPage/imgIcon";
|
|||||||
import SettingIcon from "../../assets/icons/questionsPage/settingIcon";
|
import SettingIcon from "../../assets/icons/questionsPage/settingIcon";
|
||||||
import { QuizQuestionVariant } from "@model/questionTypes/variant";
|
import { QuizQuestionVariant } from "@model/questionTypes/variant";
|
||||||
import { updateOpenedModalSettingsId } from "@root/questions/actions";
|
import { updateOpenedModalSettingsId } from "@root/questions/actions";
|
||||||
|
import { updateOpenBranchingPanel } from "@root/questions/actions";
|
||||||
|
import {useQuestionsStore} from "@root/questions/store";
|
||||||
|
import { enqueueSnackbar } from "notistack";
|
||||||
|
import { useCurrentQuiz } from "@root/quizes/hooks";
|
||||||
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@ -42,6 +46,8 @@ export default function ButtonsOptionsAndPict({
|
|||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const isMobile = useMediaQuery(theme.breakpoints.down(790));
|
const isMobile = useMediaQuery(theme.breakpoints.down(790));
|
||||||
const isIconMobile = useMediaQuery(theme.breakpoints.down(1050));
|
const isIconMobile = useMediaQuery(theme.breakpoints.down(1050));
|
||||||
|
const {openBranchingPanel} = useQuestionsStore.getState()
|
||||||
|
const quiz = useCurrentQuiz();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (question.deleteTimeoutId) {
|
if (question.deleteTimeoutId) {
|
||||||
@ -49,6 +55,22 @@ export default function ButtonsOptionsAndPict({
|
|||||||
}
|
}
|
||||||
}, [question]);
|
}, [question]);
|
||||||
|
|
||||||
|
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)
|
||||||
|
updateOpenedModalSettingsId(question.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
@ -184,7 +206,7 @@ export default function ButtonsOptionsAndPict({
|
|||||||
onMouseEnter={() => setButtonHover("branching")}
|
onMouseEnter={() => setButtonHover("branching")}
|
||||||
onMouseLeave={() => setButtonHover("")}
|
onMouseLeave={() => setButtonHover("")}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
updateOpenedModalSettingsId(question.id)
|
handleClickBranching(question.id, openBranchingPanel)
|
||||||
}}
|
}}
|
||||||
sx={{
|
sx={{
|
||||||
height: "30px",
|
height: "30px",
|
||||||
@ -316,7 +338,7 @@ export default function ButtonsOptionsAndPict({
|
|||||||
// deleteTimeoutId: newTimeoutId,
|
// deleteTimeoutId: newTimeoutId,
|
||||||
// });
|
// });
|
||||||
|
|
||||||
deleteQuestion(question.id);
|
deleteQuestion(question.id, quiz?.id);
|
||||||
}}
|
}}
|
||||||
data-cy="delete-question"
|
data-cy="delete-question"
|
||||||
>
|
>
|
||||||
|
@ -39,7 +39,7 @@ import SwitchQuestionsPage from "../SwitchQuestionsPage";
|
|||||||
import { ChooseAnswerModal } from "./ChooseAnswerModal";
|
import { ChooseAnswerModal } from "./ChooseAnswerModal";
|
||||||
import TypeQuestions from "../TypeQuestions";
|
import TypeQuestions from "../TypeQuestions";
|
||||||
import { QuestionType } from "@model/question/question";
|
import { QuestionType } from "@model/question/question";
|
||||||
|
import { useCurrentQuiz } from "@root/quizes/hooks"
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
question: AnyTypedQuizQuestion | UntypedQuizQuestion;
|
question: AnyTypedQuizQuestion | UntypedQuizQuestion;
|
||||||
@ -55,6 +55,7 @@ export default function QuestionsPageCard({ question, draggableProps, isDragging
|
|||||||
const isTablet = useMediaQuery(theme.breakpoints.down(1000));
|
const isTablet = useMediaQuery(theme.breakpoints.down(1000));
|
||||||
const isMobile = useMediaQuery(theme.breakpoints.down(790));
|
const isMobile = useMediaQuery(theme.breakpoints.down(790));
|
||||||
const anchorRef = useRef(null);
|
const anchorRef = useRef(null);
|
||||||
|
const quiz = useCurrentQuiz();
|
||||||
|
|
||||||
const setTitle = useDebouncedCallback((title) => {
|
const setTitle = useDebouncedCallback((title) => {
|
||||||
const updateQuestionFn = question.type === null ? updateUntypedQuestion : updateQuestion;
|
const updateQuestionFn = question.type === null ? updateUntypedQuestion : updateQuestion;
|
||||||
@ -237,7 +238,7 @@ export default function QuestionsPageCard({ question, draggableProps, isDragging
|
|||||||
margin: "0 5px 0 10px",
|
margin: "0 5px 0 10px",
|
||||||
}}
|
}}
|
||||||
onClick={() => { // TODO
|
onClick={() => { // TODO
|
||||||
// const removedId = question.id;
|
const removedId = question.id;
|
||||||
// if (question.deleteTimeoutId) {
|
// if (question.deleteTimeoutId) {
|
||||||
// clearTimeout(question.deleteTimeoutId);
|
// clearTimeout(question.deleteTimeoutId);
|
||||||
// }
|
// }
|
||||||
@ -253,7 +254,7 @@ export default function QuestionsPageCard({ question, draggableProps, isDragging
|
|||||||
// deleteTimeoutId: newTimeoutId,
|
// deleteTimeoutId: newTimeoutId,
|
||||||
// });
|
// });
|
||||||
|
|
||||||
deleteQuestion(question.id);
|
deleteQuestion(question.id, quiz.id);
|
||||||
}}
|
}}
|
||||||
data-cy="delete-question"
|
data-cy="delete-question"
|
||||||
>
|
>
|
||||||
|
@ -5,22 +5,19 @@ import {
|
|||||||
import { DraggableList } from "./DraggableList";
|
import { DraggableList } from "./DraggableList";
|
||||||
import { BranchingPanel } from "./BranchingPanel";
|
import { BranchingPanel } from "./BranchingPanel";
|
||||||
import { BranchingMap } from "./BranchingMap";
|
import { BranchingMap } from "./BranchingMap";
|
||||||
|
import { updateOpenBranchingPanel } from "@root/questions/actions";
|
||||||
|
import {useQuestionsStore} from "@root/questions/store";
|
||||||
|
|
||||||
interface Props {
|
|
||||||
settingBranching: boolean;
|
|
||||||
setSettingBranching: (active: boolean) => void
|
|
||||||
}
|
|
||||||
|
|
||||||
export const QuestionSwitchWindowTool = ({settingBranching, setSettingBranching}:Props) => {
|
|
||||||
|
|
||||||
|
export const QuestionSwitchWindowTool = () => {
|
||||||
|
const {openBranchingPanel} = useQuestionsStore.getState()
|
||||||
return (
|
return (
|
||||||
<Box sx={{ display: "flex", gap: "20px", flexWrap: "wrap" }}>
|
<Box sx={{ display: "flex", gap: "20px", flexWrap: "wrap" }}>
|
||||||
<Box sx={{ flexBasis: "796px" }}>
|
<Box sx={{ flexBasis: "796px" }}>
|
||||||
{settingBranching ? <BranchingMap /> : <DraggableList />}
|
{openBranchingPanel? <BranchingMap /> : <DraggableList />}
|
||||||
</Box>
|
</Box>
|
||||||
<BranchingPanel
|
<BranchingPanel
|
||||||
active={settingBranching}
|
|
||||||
setActive={setSettingBranching}
|
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
)
|
)
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { useState, useEffect } from "react"
|
import { useState, useEffect, useLayoutEffect } from "react"
|
||||||
import {
|
import {
|
||||||
Box,
|
Box,
|
||||||
Button,
|
Button,
|
||||||
@ -17,6 +17,7 @@ import ArrowLeft from "../../assets/icons/questionsPage/arrowLeft";
|
|||||||
import BranchingQuestions from "./BranchingModal/BranchingQuestionsModal"
|
import BranchingQuestions from "./BranchingModal/BranchingQuestionsModal"
|
||||||
import { QuestionSwitchWindowTool } from "./QuestionSwitchWindowTool";
|
import { QuestionSwitchWindowTool } from "./QuestionSwitchWindowTool";
|
||||||
import { useQuestionsStore } from "@root/questions/store";
|
import { useQuestionsStore } from "@root/questions/store";
|
||||||
|
import { updateOpenBranchingPanel } from "@root/questions/actions";
|
||||||
|
|
||||||
|
|
||||||
export default function QuestionsPage() {
|
export default function QuestionsPage() {
|
||||||
@ -24,10 +25,14 @@ export default function QuestionsPage() {
|
|||||||
const { openedModalSettingsId } = useQuestionsStore();
|
const { openedModalSettingsId } = useQuestionsStore();
|
||||||
const isMobile = useMediaQuery(theme.breakpoints.down(660));
|
const isMobile = useMediaQuery(theme.breakpoints.down(660));
|
||||||
const quiz = useCurrentQuiz();
|
const quiz = useCurrentQuiz();
|
||||||
|
const {openBranchingPanel} = useQuestionsStore.getState()
|
||||||
|
useLayoutEffect(() => {
|
||||||
|
updateOpenBranchingPanel(true)
|
||||||
|
},[])
|
||||||
|
|
||||||
const [settingBranching, setSettingBranching] = useState<boolean>(false);
|
|
||||||
if (!quiz) return null;
|
if (!quiz) return null;
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Box
|
<Box
|
||||||
@ -42,7 +47,7 @@ export default function QuestionsPage() {
|
|||||||
<Typography variant={"h5"}>Заголовок квиза</Typography>
|
<Typography variant={"h5"}>Заголовок квиза</Typography>
|
||||||
<Button
|
<Button
|
||||||
sx={{
|
sx={{
|
||||||
display: settingBranching ? "none" : "flex",
|
display: openBranchingPanel ? "none" : "flex",
|
||||||
fontSize: "16px",
|
fontSize: "16px",
|
||||||
lineHeight: "19px",
|
lineHeight: "19px",
|
||||||
padding: 0,
|
padding: 0,
|
||||||
@ -55,7 +60,7 @@ export default function QuestionsPage() {
|
|||||||
Свернуть всё
|
Свернуть всё
|
||||||
</Button>
|
</Button>
|
||||||
</Box>
|
</Box>
|
||||||
<QuestionSwitchWindowTool settingBranching={settingBranching} setSettingBranching={setSettingBranching} />
|
<QuestionSwitchWindowTool/>
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
display: "flex",
|
display: "flex",
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
import { useState, useEffect } from "react";
|
import { useState, useEffect } from "react";
|
||||||
import { Box, Typography, Button, useTheme } from "@mui/material";
|
import { Box, Typography, Button, useTheme } from "@mui/material";
|
||||||
|
|
||||||
import { useQuizViewStore, getAnswersByQuestionId } from "@root/quizView";
|
import { useQuizViewStore } from "@root/quizView";
|
||||||
|
|
||||||
import type { AnyTypedQuizQuestion, QuizQuestionBase } from "../../model/questionTypes/shared";
|
import type {
|
||||||
|
AnyTypedQuizQuestion,
|
||||||
|
QuizQuestionBase,
|
||||||
|
} from "../../model/questionTypes/shared";
|
||||||
import { getQuestionByContentId } from "@root/questions/actions";
|
import { getQuestionByContentId } from "@root/questions/actions";
|
||||||
import { enqueueSnackbar } from "notistack";
|
import { enqueueSnackbar } from "notistack";
|
||||||
|
|
||||||
@ -12,10 +15,7 @@ type FooterProps = {
|
|||||||
question: QuizQuestionBase;
|
question: QuizQuestionBase;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const Footer = ({
|
export const Footer = ({ setCurrentQuestion, question }: FooterProps) => {
|
||||||
setCurrentQuestion,
|
|
||||||
question,
|
|
||||||
}: FooterProps) => {
|
|
||||||
const [disabledQuestionsId, setDisabledQuestionsId] = useState<Set<string>>(
|
const [disabledQuestionsId, setDisabledQuestionsId] = useState<Set<string>>(
|
||||||
new Set()
|
new Set()
|
||||||
);
|
);
|
||||||
@ -24,60 +24,59 @@ export const Footer = ({
|
|||||||
|
|
||||||
const followPreviousStep = () => {
|
const followPreviousStep = () => {
|
||||||
if (question?.content.rule.parentId !== "root") {
|
if (question?.content.rule.parentId !== "root") {
|
||||||
const parent = getQuestionByContentId(question?.content.rule.parentId)
|
const parent = getQuestionByContentId(question?.content.rule.parentId);
|
||||||
if (parent) {
|
if (parent) {
|
||||||
setCurrentQuestion(parent)
|
setCurrentQuestion(parent);
|
||||||
} else {
|
} else {
|
||||||
enqueueSnackbar("не могу получить предыдущий вопрос")
|
enqueueSnackbar("не могу получить предыдущий вопрос");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
enqueueSnackbar("вы находитесь на первом вопросе")
|
enqueueSnackbar("вы находитесь на первом вопросе");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const followNextStep = () => {
|
const followNextStep = () => {
|
||||||
const answers = getAnswersByQuestionId(question.content.id) || []
|
if (answers.length) {
|
||||||
console.log(answers)
|
let readyBeNextQuestion = "";
|
||||||
if (answers) {
|
|
||||||
|
|
||||||
let readyBeNextQuestion = ""
|
|
||||||
question.content.rule.main.forEach(({ next, rules }) => {
|
question.content.rule.main.forEach(({ next, rules }) => {
|
||||||
console.log({ next, rules })
|
|
||||||
|
|
||||||
console.log("[storeAnswers] ", rules[0].answers)
|
let longerArray = Math.max(
|
||||||
console.log("[answers.answer] ", [answers.answer])
|
rules[0].answers.length,
|
||||||
|
[answers.at(-1)?.answer].length
|
||||||
|
);
|
||||||
|
|
||||||
let longerArray = Math.max(rules[0].answers.length, [answers.answer].length)
|
for (
|
||||||
|
var i = 0;
|
||||||
for (var i = 0; i < longerArray; i++) // Цикл по всем элементам бОльшего массива
|
i < longerArray;
|
||||||
if (rules[0].answers[i] !== [answers.answer][i]) readyBeNextQuestion = next; // Если хоть один элемент отличается, массивы не равны
|
i++ // Цикл по всем элементам бОльшего массива
|
||||||
|
) {
|
||||||
|
if (rules[0].answers[i] === answers.at(-1)?.answer) {
|
||||||
})
|
readyBeNextQuestion = next; // Если хоть один элемент отличается, массивы не равны
|
||||||
if (readyBeNextQuestion) {
|
|
||||||
console.log("мы нашли совпадение в " + readyBeNextQuestion)
|
|
||||||
|
|
||||||
const nextQuestion = getQuestionByContentId(readyBeNextQuestion)
|
|
||||||
console.log("next question ", nextQuestion)
|
|
||||||
if (nextQuestion) {
|
|
||||||
console.log("я устанавливаю следующий вопрос " + question.title)
|
|
||||||
setCurrentQuestion(nextQuestion)
|
|
||||||
return
|
|
||||||
} else {
|
|
||||||
enqueueSnackbar("не могу получить последующий вопрос")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
const nextQuestion = getQuestionByContentId(question.content.rule.default)
|
|
||||||
console.log("я устанавливаю дефолтный вопрос")
|
|
||||||
if (nextQuestion) {
|
|
||||||
setCurrentQuestion(nextQuestion)
|
|
||||||
} else {
|
|
||||||
enqueueSnackbar("не могу получить последующий вопрос (дефолтный)")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
if (readyBeNextQuestion) {
|
||||||
|
|
||||||
|
const nextQuestion = getQuestionByContentId(readyBeNextQuestion);
|
||||||
|
|
||||||
|
if (nextQuestion) {
|
||||||
|
setCurrentQuestion(nextQuestion);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
enqueueSnackbar("не могу получить последующий вопрос");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const nextQuestion = getQuestionByContentId(
|
||||||
|
question.content.rule.default
|
||||||
|
);
|
||||||
|
if (nextQuestion) {
|
||||||
|
setCurrentQuestion(nextQuestion);
|
||||||
|
} else {
|
||||||
|
enqueueSnackbar("не могу получить последующий вопрос (дефолтный)");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -44,7 +44,6 @@ export const Question = ({
|
|||||||
}: QuestionProps) => {
|
}: QuestionProps) => {
|
||||||
const quiz = useCurrentQuiz();
|
const quiz = useCurrentQuiz();
|
||||||
const [currentQuestion, setCurrentQuestion] = useState(getQuestionByContentId(quiz?.config.haveRoot || ""))
|
const [currentQuestion, setCurrentQuestion] = useState(getQuestionByContentId(quiz?.config.haveRoot || ""))
|
||||||
console.log("root " + quiz?.config.haveRoot)
|
|
||||||
if (!currentQuestion) return <>не смог отобразить вопрос</>
|
if (!currentQuestion) return <>не смог отобразить вопрос</>
|
||||||
|
|
||||||
const QuestionComponent =
|
const QuestionComponent =
|
||||||
|
@ -11,8 +11,6 @@ import type { AnyTypedQuizQuestion } from "../../model/questionTypes/shared";
|
|||||||
export const ViewPage = () => {
|
export const ViewPage = () => {
|
||||||
const quiz = useCurrentQuiz();
|
const quiz = useCurrentQuiz();
|
||||||
const { questions } = useQuestions();
|
const { questions } = useQuestions();
|
||||||
console.log(questions)
|
|
||||||
|
|
||||||
const [visualStartPage, setVisualStartPage] = useState<boolean>(!quiz?.config.noStartPage);
|
const [visualStartPage, setVisualStartPage] = useState<boolean>(!quiz?.config.noStartPage);
|
||||||
|
|
||||||
|
|
||||||
|
@ -126,7 +126,6 @@ export const updateQuestion = <T extends AnyTypedQuizQuestion>(
|
|||||||
questionIndex: number,
|
questionIndex: number,
|
||||||
recipe: (question: T) => void,
|
recipe: (question: T) => void,
|
||||||
) => setProducedState(state => {
|
) => setProducedState(state => {
|
||||||
console.log("начинаю отправку fire квиза " )
|
|
||||||
const question = state.listQuestions[quizId][questionIndex] as T;
|
const question = state.listQuestions[quizId][questionIndex] as T;
|
||||||
|
|
||||||
recipe(question);
|
recipe(question);
|
||||||
|
@ -10,6 +10,8 @@ import { nanoid } from "nanoid";
|
|||||||
import { enqueueSnackbar } from "notistack";
|
import { enqueueSnackbar } from "notistack";
|
||||||
import { isAxiosCanceledError } from "../../utils/isAxiosCanceledError";
|
import { isAxiosCanceledError } from "../../utils/isAxiosCanceledError";
|
||||||
import { RequestQueue } from "../../utils/requestQueue";
|
import { RequestQueue } from "../../utils/requestQueue";
|
||||||
|
import { updateRootContentId } from "@root/quizes/actions"
|
||||||
|
import { useCurrentQuiz } from "@root/quizes/hooks"
|
||||||
import { QuestionsStore, useQuestionsStore } from "./store";
|
import { QuestionsStore, useQuestionsStore } from "./store";
|
||||||
|
|
||||||
|
|
||||||
@ -138,10 +140,8 @@ export const updateQuestion = (
|
|||||||
// requestTimeoutId = setTimeout(() => {
|
// requestTimeoutId = setTimeout(() => {
|
||||||
requestQueue.enqueue(async () => {
|
requestQueue.enqueue(async () => {
|
||||||
const q = useQuestionsStore.getState().questions.find(q => q.id === questionId) || useQuestionsStore.getState().questions.find(q => q.type !== null && q.content.id === questionId);
|
const q = useQuestionsStore.getState().questions.find(q => q.id === questionId) || useQuestionsStore.getState().questions.find(q => q.type !== null && q.content.id === questionId);
|
||||||
console.log("мы пытаемся найти вопрос ");
|
|
||||||
if (!q) return;
|
if (!q) return;
|
||||||
if (q.type === null) throw new Error("Cannot send update request for untyped question");
|
if (q.type === null) throw new Error("Cannot send update request for untyped question");
|
||||||
console.log(q.title);
|
|
||||||
|
|
||||||
const response = await questionApi.edit(questionToEditQuestionRequest(q));
|
const response = await questionApi.edit(questionToEditQuestionRequest(q));
|
||||||
|
|
||||||
@ -261,8 +261,13 @@ export const changeQuestionType = (
|
|||||||
type: QuestionType,
|
type: QuestionType,
|
||||||
) => {
|
) => {
|
||||||
updateQuestion(questionId, question => {
|
updateQuestion(questionId, question => {
|
||||||
|
const oldId = question.content.id
|
||||||
|
const oldRule = question.content.rule
|
||||||
|
oldRule.main = []
|
||||||
question.type = type;
|
question.type = type;
|
||||||
question.content = defaultQuestionByType[type].content;
|
question.content = defaultQuestionByType[type].content;
|
||||||
|
question.content.id = oldId
|
||||||
|
question.content.rule = oldRule
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -302,7 +307,8 @@ export const createTypedQuestion = async (
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
export const deleteQuestion = async (questionId: string) => requestQueue.enqueue(async () => {
|
export const deleteQuestion = async (questionId: string, quizId: string) => requestQueue.enqueue(async () => {
|
||||||
|
|
||||||
const question = useQuestionsStore.getState().questions.find(q => q.id === questionId);
|
const question = useQuestionsStore.getState().questions.find(q => q.id === questionId);
|
||||||
if (!question) return;
|
if (!question) return;
|
||||||
|
|
||||||
@ -313,6 +319,10 @@ export const deleteQuestion = async (questionId: string) => requestQueue.enqueue
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
await questionApi.delete(question.backendId);
|
await questionApi.delete(question.backendId);
|
||||||
|
if (question.content.rule.parentId === "root") { //удалить из стора root и очистить rule всем вопросам
|
||||||
|
updateRootContentId(quizId, "")
|
||||||
|
clearRoleForAll()
|
||||||
|
}
|
||||||
|
|
||||||
removeQuestion(questionId);
|
removeQuestion(questionId);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -325,9 +335,11 @@ export const copyQuestion = async (questionId: string, quizId: number) => reques
|
|||||||
const question = useQuestionsStore.getState().questions.find(q => q.id === questionId);
|
const question = useQuestionsStore.getState().questions.find(q => q.id === questionId);
|
||||||
if (!question) return;
|
if (!question) return;
|
||||||
|
|
||||||
|
const frontId = nanoid();
|
||||||
if (question.type === null) {
|
if (question.type === null) {
|
||||||
const copiedQuestion = structuredClone(question);
|
const copiedQuestion = structuredClone(question);
|
||||||
copiedQuestion.id = nanoid();
|
copiedQuestion.id = frontId
|
||||||
|
copiedQuestion.content.id = frontId
|
||||||
|
|
||||||
setProducedState(state => {
|
setProducedState(state => {
|
||||||
state.questions.push(copiedQuestion);
|
state.questions.push(copiedQuestion);
|
||||||
@ -345,7 +357,9 @@ export const copyQuestion = async (questionId: string, quizId: number) => reques
|
|||||||
|
|
||||||
const copiedQuestion = structuredClone(question);
|
const copiedQuestion = structuredClone(question);
|
||||||
copiedQuestion.backendId = newQuestionId;
|
copiedQuestion.backendId = newQuestionId;
|
||||||
copiedQuestion.id = nanoid();
|
copiedQuestion.id = frontId
|
||||||
|
copiedQuestion.content.id = frontId
|
||||||
|
copiedQuestion.content.rule = { main: [], parentId: "", default: "" }
|
||||||
|
|
||||||
setProducedState(state => {
|
setProducedState(state => {
|
||||||
state.questions.push(copiedQuestion);
|
state.questions.push(copiedQuestion);
|
||||||
@ -377,19 +391,30 @@ export const getQuestionById = (questionId: string | null) => {
|
|||||||
return useQuestionsStore.getState().questions.find(q => q.id === questionId) || null;
|
return useQuestionsStore.getState().questions.find(q => q.id === questionId) || null;
|
||||||
};
|
};
|
||||||
export const getQuestionByContentId = (questionContentId: string | null) => {
|
export const getQuestionByContentId = (questionContentId: string | null) => {
|
||||||
console.log("questionContentId " + questionContentId);
|
|
||||||
if (questionContentId === null) return null;
|
if (questionContentId === null) return null;
|
||||||
return useQuestionsStore.getState().questions.find(q => {
|
return useQuestionsStore.getState().questions.find(q => {
|
||||||
if (q.type === null) return false;
|
if (q.type === null) return false;
|
||||||
|
|
||||||
console.log(q.content.id);
|
|
||||||
console.log(q.content.id === questionContentId);
|
|
||||||
return (q.content.id === questionContentId);
|
return (q.content.id === questionContentId);
|
||||||
}) || null;
|
}) || null;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const updateOpenedModalSettingsId = (id?: string) => useQuestionsStore.setState({ openedModalSettingsId: id ? id : null });
|
export const updateOpenedModalSettingsId = (id?: string) => useQuestionsStore.setState({ openedModalSettingsId: id ? id : null });
|
||||||
export const updateDragQuestionContentId = (contentId?: string) => {
|
export const updateDragQuestionContentId = (contentId?: string) => {
|
||||||
console.log("contentId " + contentId);
|
|
||||||
useQuestionsStore.setState({ dragQuestionContentId: contentId ? contentId : null });
|
useQuestionsStore.setState({ dragQuestionContentId: contentId ? contentId : null });
|
||||||
};
|
}
|
||||||
|
|
||||||
|
export const clearRoleForAll = () => {
|
||||||
|
const { questions } = useQuestionsStore.getState()
|
||||||
|
questions.forEach(question => {
|
||||||
|
if (question.type !== null && (question.content.rule.main.length > 0 || question.content.rule.default.length > 0 || question.content.rule.parentId.length > 0)) {
|
||||||
|
updateQuestion(question.content.id, question => {
|
||||||
|
question.content.rule.parentId = ""
|
||||||
|
question.content.rule.main = []
|
||||||
|
question.content.rule.default = ""
|
||||||
|
})
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export const updateOpenBranchingPanel = (value: boolean) => useQuestionsStore.setState({openBranchingPanel: !value});
|
||||||
|
@ -7,12 +7,14 @@ export type QuestionsStore = {
|
|||||||
questions: (AnyTypedQuizQuestion | UntypedQuizQuestion)[];
|
questions: (AnyTypedQuizQuestion | UntypedQuizQuestion)[];
|
||||||
openedModalSettingsId: string | null;
|
openedModalSettingsId: string | null;
|
||||||
dragQuestionContentId: string | null;
|
dragQuestionContentId: string | null;
|
||||||
|
openBranchingPanel: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
const initialState: QuestionsStore = {
|
const initialState: QuestionsStore = {
|
||||||
questions: [],
|
questions: [],
|
||||||
openedModalSettingsId: null as null,
|
openedModalSettingsId: null as null,
|
||||||
dragQuestionContentId: null,
|
dragQuestionContentId: null,
|
||||||
|
openBranchingPanel: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useQuestionsStore = create<QuestionsStore>()(
|
export const useQuestionsStore = create<QuestionsStore>()(
|
||||||
|
@ -33,9 +33,3 @@ export const updateAnswer = (questionId: string, answer: string) => {
|
|||||||
|
|
||||||
useQuizViewStore.setState({ answers });
|
useQuizViewStore.setState({ answers });
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getAnswersByQuestionId = (questionId: string) => {
|
|
||||||
if (questionId === null) return null;
|
|
||||||
const answers = [...useQuizViewStore.getState().answers];
|
|
||||||
return answers.find(a => a.questionId === questionId) || null;
|
|
||||||
}
|
|
@ -10,6 +10,7 @@ import { isAxiosCanceledError } from "../../utils/isAxiosCanceledError";
|
|||||||
import { RequestQueue } from "../../utils/requestQueue";
|
import { RequestQueue } from "../../utils/requestQueue";
|
||||||
import { QuizStore, useQuizStore } from "./store";
|
import { QuizStore, useQuizStore } from "./store";
|
||||||
import { createUntypedQuestion } from "@root/questions/actions";
|
import { createUntypedQuestion } from "@root/questions/actions";
|
||||||
|
import { useCurrentQuiz } from "./hooks"
|
||||||
|
|
||||||
|
|
||||||
export const setEditQuizId = (quizId: number | null) => setProducedState(state => {
|
export const setEditQuizId = (quizId: number | null) => setProducedState(state => {
|
||||||
@ -178,10 +179,11 @@ export const deleteQuiz = async (quizId: string) => requestQueue.enqueue(async (
|
|||||||
export const updateRootContentId = (quizId: string, id:string) => updateQuiz(
|
export const updateRootContentId = (quizId: string, id:string) => updateQuiz(
|
||||||
quizId,
|
quizId,
|
||||||
quiz => {
|
quiz => {
|
||||||
quiz.config.haveRoot = id;
|
quiz.config.haveRoot = id
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
// TODO copy quiz
|
// TODO copy quiz
|
||||||
|
|
||||||
export const uploadQuizImage = async (
|
export const uploadQuizImage = async (
|
||||||
|
@ -42,8 +42,6 @@ export default function Rating({ question }: Props) {
|
|||||||
const isMobile = useMediaQuery(theme.breakpoints.down(790));
|
const isMobile = useMediaQuery(theme.breakpoints.down(790));
|
||||||
const [selectedRating, setSelectedRating] = useState<number>(0);
|
const [selectedRating, setSelectedRating] = useState<number>(0);
|
||||||
|
|
||||||
console.log(question);
|
|
||||||
|
|
||||||
const RatingIconComponent =
|
const RatingIconComponent =
|
||||||
ratingIconComponentByType[question.content.form as RatingIconType];
|
ratingIconComponentByType[question.content.form as RatingIconType];
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user