Merge branch 'image-modals' into 'main'
Image modals See merge request frontend/squiz!82
This commit is contained in:
commit
7ee8c89172
@ -6,7 +6,7 @@
|
|||||||
"@craco/craco": "^7.0.0",
|
"@craco/craco": "^7.0.0",
|
||||||
"@emotion/react": "^11.10.5",
|
"@emotion/react": "^11.10.5",
|
||||||
"@emotion/styled": "^11.10.5",
|
"@emotion/styled": "^11.10.5",
|
||||||
"@frontend/kitui": "^1.0.54",
|
"@frontend/kitui": "^1.0.55",
|
||||||
"@mui/icons-material": "^5.10.14",
|
"@mui/icons-material": "^5.10.14",
|
||||||
"@mui/material": "^5.10.14",
|
"@mui/material": "^5.10.14",
|
||||||
"@mui/x-date-pickers": "^6.16.1",
|
"@mui/x-date-pickers": "^6.16.1",
|
||||||
|
118
src/App.tsx
118
src/App.tsx
@ -16,8 +16,8 @@ import { ResultSettings } from "./pages/ResultPage/ResultSettings";
|
|||||||
import MyQuizzesFull from "./pages/createQuize/MyQuizzesFull";
|
import MyQuizzesFull from "./pages/createQuize/MyQuizzesFull";
|
||||||
import Main from "./pages/main";
|
import Main from "./pages/main";
|
||||||
import EditPage from "./pages/startPage/EditPage";
|
import EditPage from "./pages/startPage/EditPage";
|
||||||
import { clearAuthToken, getMessageFromFetchError, useUserFetcher } from "@frontend/kitui";
|
import { clearAuthToken, getMessageFromFetchError, useUserAccountFetcher, useUserFetcher } from "@frontend/kitui";
|
||||||
import { clearUserData, setUser, useUserStore } from "@root/user";
|
import { clearUserData, setUser, setUserAccount, useUserStore } from "@root/user";
|
||||||
import { enqueueSnackbar } from "notistack";
|
import { enqueueSnackbar } from "notistack";
|
||||||
import PrivateRoute from "@ui_kit/PrivateRoute";
|
import PrivateRoute from "@ui_kit/PrivateRoute";
|
||||||
|
|
||||||
@ -26,59 +26,75 @@ import { Restore } from "./pages/startPage/Restore";
|
|||||||
dayjs.locale("ru");
|
dayjs.locale("ru");
|
||||||
|
|
||||||
const routeslink = [
|
const routeslink = [
|
||||||
{ path: "/list", page: <MyQuizzesFull />, header: false, sidebar: false },
|
{ path: "/list", page: <MyQuizzesFull />, header: false, sidebar: false },
|
||||||
{ path: "/questions/:quizId", page: <QuestionsPage />, header: true, sidebar: true },
|
{ path: "/questions/:quizId", page: <QuestionsPage />, header: true, sidebar: true },
|
||||||
{ path: "/contacts", page: <ContactFormPage />, header: true, sidebar: true },
|
{ path: "/contacts", page: <ContactFormPage />, header: true, sidebar: true },
|
||||||
{ path: "/result", page: <Result />, header: true, sidebar: true },
|
{ path: "/result", page: <Result />, header: true, sidebar: true },
|
||||||
{ path: "/settings", page: <ResultSettings />, header: true, sidebar: true },
|
{ path: "/settings", page: <ResultSettings />, header: true, sidebar: true },
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
export default function App() {
|
export default function App() {
|
||||||
const userId = useUserStore((state) => state.userId);
|
const userId = useUserStore((state) => state.userId);
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
useUserFetcher({
|
useUserFetcher({
|
||||||
url: `https://hub.pena.digital/user/${userId}`,
|
url: `https://hub.pena.digital/user/${userId}`,
|
||||||
userId,
|
userId,
|
||||||
onNewUser: setUser,
|
onNewUser: setUser,
|
||||||
onError: (error) => {
|
onError: (error) => {
|
||||||
const errorMessage = getMessageFromFetchError(error);
|
const errorMessage = getMessageFromFetchError(error);
|
||||||
if (errorMessage) {
|
if (errorMessage) {
|
||||||
enqueueSnackbar(errorMessage);
|
enqueueSnackbar(errorMessage);
|
||||||
clearUserData();
|
clearUserData();
|
||||||
clearAuthToken();
|
clearAuthToken();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
if (location.state?.redirectTo)
|
|
||||||
return <Navigate to={location.state.redirectTo} replace state={{ backgroundLocation: location }} />;
|
|
||||||
|
|
||||||
return (
|
useUserAccountFetcher({
|
||||||
<>
|
url: "https://squiz.pena.digital/customer/account",
|
||||||
<ContactFormModal />
|
userId,
|
||||||
{location.state?.backgroundLocation && (
|
onNewUserAccount: setUserAccount,
|
||||||
<Routes>
|
onError: (error) => {
|
||||||
<Route path="/signin" element={<SigninDialog />} />
|
const errorMessage = getMessageFromFetchError(error);
|
||||||
<Route path="/signup" element={<SignupDialog />} />
|
if (errorMessage) {
|
||||||
<Route path="/restore" element={<Restore />} />
|
enqueueSnackbar(errorMessage);
|
||||||
</Routes>
|
clearUserData();
|
||||||
)}
|
clearAuthToken();
|
||||||
<Routes location={location.state?.backgroundLocation || location}>
|
navigate("/signin");
|
||||||
<Route path="/" element={<Landing />} />
|
}
|
||||||
<Route path="/signin" element={<Navigate to="/" replace state={{ redirectTo: "/signin" }} />} />
|
},
|
||||||
<Route path="/signup" element={<Navigate to="/" replace state={{ redirectTo: "/signup" }} />} />
|
});
|
||||||
<Route path="/restore" element={<Navigate to="/" replace state={{ redirectTo: "/restore" }} />} />
|
|
||||||
<Route element={<PrivateRoute />}>
|
|
||||||
{routeslink.map((e, i) => (
|
|
||||||
<Route key={i} path={e.path} element={<Main page={e.page} header={e.header} sidebar={e.sidebar} />} />
|
|
||||||
))}
|
|
||||||
|
|
||||||
<Route path="edit" element={<EditPage />} />
|
if (location.state?.redirectTo)
|
||||||
<Route path="crop" element={<ImageCrop />} />
|
return <Navigate to={location.state.redirectTo} replace state={{ backgroundLocation: location }} />;
|
||||||
<Route path="/view" element={<ViewPage />} />
|
|
||||||
</Route>
|
return (
|
||||||
</Routes>
|
<>
|
||||||
</>
|
<ContactFormModal />
|
||||||
);
|
{location.state?.backgroundLocation && (
|
||||||
|
<Routes>
|
||||||
|
<Route path="/signin" element={<SigninDialog />} />
|
||||||
|
<Route path="/signup" element={<SignupDialog />} />
|
||||||
|
<Route path="/restore" element={<Restore />} />
|
||||||
|
</Routes>
|
||||||
|
)}
|
||||||
|
<Routes location={location.state?.backgroundLocation || location}>
|
||||||
|
<Route path="/" element={<Landing />} />
|
||||||
|
<Route path="/signin" element={<Navigate to="/" replace state={{ redirectTo: "/signin" }} />} />
|
||||||
|
<Route path="/signup" element={<Navigate to="/" replace state={{ redirectTo: "/signup" }} />} />
|
||||||
|
<Route path="/restore" element={<Navigate to="/" replace state={{ redirectTo: "/restore" }} />} />
|
||||||
|
<Route element={<PrivateRoute />}>
|
||||||
|
{routeslink.map((e, i) => (
|
||||||
|
<Route key={i} path={e.path} element={<Main page={e.page} header={e.header} sidebar={e.sidebar} />} />
|
||||||
|
))}
|
||||||
|
|
||||||
|
<Route path="edit" element={<EditPage />} />
|
||||||
|
<Route path="crop" element={<ImageCrop />} />
|
||||||
|
<Route path="/view" element={<ViewPage />} />
|
||||||
|
</Route>
|
||||||
|
</Routes>
|
||||||
|
</>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,6 @@ function createQuestion(body: CreateQuestionRequest) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function getQuestionList(body?: Partial<GetQuestionListRequest>) {
|
async function getQuestionList(body?: Partial<GetQuestionListRequest>) {
|
||||||
console.log("body" , body)
|
|
||||||
if (!body?.quiz_id) return null;
|
if (!body?.quiz_id) return null;
|
||||||
|
|
||||||
const response = await makeRequest<GetQuestionListRequest, GetQuestionListResponse>({
|
const response = await makeRequest<GetQuestionListRequest, GetQuestionListResponse>({
|
||||||
|
@ -17,8 +17,6 @@ interface Props {
|
|||||||
export default function ButtonsNewField ({SSHC, switchState, type}:Props) {
|
export default function ButtonsNewField ({SSHC, switchState, type}:Props) {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const quiz = useCurrentQuiz()
|
const quiz = useCurrentQuiz()
|
||||||
console.log(quiz)
|
|
||||||
console.log(type)
|
|
||||||
const buttonSetting: {icon: JSX.Element; title: string; value: string} [] =[
|
const buttonSetting: {icon: JSX.Element; title: string; value: string} [] =[
|
||||||
{icon: <NameIcon color={switchState === 'name' ? '#ffffff' : theme.palette.grey3.main}/>, title: 'Имя', value: 'name'},
|
{icon: <NameIcon color={switchState === 'name' ? '#ffffff' : theme.palette.grey3.main}/>, title: 'Имя', value: 'name'},
|
||||||
{icon: <EmailIcon color={switchState === 'email' ? '#ffffff' : theme.palette.grey3.main}/>, title: 'Email', value: 'email'},
|
{icon: <EmailIcon color={switchState === 'email' ? '#ffffff' : theme.palette.grey3.main}/>, title: 'Email', value: 'email'},
|
||||||
|
@ -18,7 +18,6 @@ interface Props {
|
|||||||
|
|
||||||
export default function NewFieldParent({ drawerNewFieldHC, defaultValue, placeholderHelp, placeholderField, outerContainerSx: sx, children }: Props) {
|
export default function NewFieldParent({ drawerNewFieldHC, defaultValue, placeholderHelp, placeholderField, outerContainerSx: sx, children }: Props) {
|
||||||
const quiz = useCurrentQuiz()
|
const quiz = useCurrentQuiz()
|
||||||
console.log({ defaultValue, placeholderHelp, placeholderField, outerContainerSx: sx, children })
|
|
||||||
return (
|
return (
|
||||||
<Box sx={{ padding: '20px', display: 'flex', flexDirection: 'column', gap: '20px' }}>
|
<Box sx={{ padding: '20px', display: 'flex', flexDirection: 'column', gap: '20px' }}>
|
||||||
<Box sx={{ display: 'flex', flexDirection: 'column', gap: '15px' }}>
|
<Box sx={{ display: 'flex', flexDirection: 'column', gap: '15px' }}>
|
||||||
@ -73,7 +72,6 @@ export default function NewFieldParent({ drawerNewFieldHC, defaultValue, placeho
|
|||||||
<CustomCheckbox
|
<CustomCheckbox
|
||||||
checked={quiz.config.formContact[defaultValue].required}
|
checked={quiz.config.formContact[defaultValue].required}
|
||||||
handleChange={({ target }) => {
|
handleChange={({ target }) => {
|
||||||
console.log("click")
|
|
||||||
updateQuiz(quiz.id, (quiz) => {
|
updateQuiz(quiz.id, (quiz) => {
|
||||||
quiz.config.formContact[defaultValue].required = target.checked
|
quiz.config.formContact[defaultValue].required = target.checked
|
||||||
})
|
})
|
||||||
|
@ -14,7 +14,6 @@ interface Props {
|
|||||||
|
|
||||||
export default function SwitchNewField({switchState ='name', drawerNewFieldHC}: Props) {
|
export default function SwitchNewField({switchState ='name', drawerNewFieldHC}: Props) {
|
||||||
const [SwitchMask, setSwitchMask] = React.useState(false);
|
const [SwitchMask, setSwitchMask] = React.useState(false);
|
||||||
console.log(switchState)
|
|
||||||
const SwitchMaskHC = (bool:boolean) => {
|
const SwitchMaskHC = (bool:boolean) => {
|
||||||
setSwitchMask(bool)
|
setSwitchMask(bool)
|
||||||
}
|
}
|
||||||
|
@ -48,7 +48,6 @@ type BackgroundType = "text" | "video";
|
|||||||
|
|
||||||
export default function InstallQuiz() {
|
export default function InstallQuiz() {
|
||||||
const quiz = useCurrentQuiz()
|
const quiz = useCurrentQuiz()
|
||||||
console.log(quiz)
|
|
||||||
|
|
||||||
const [display, setDisplay] = React.useState("1");
|
const [display, setDisplay] = React.useState("1");
|
||||||
const handleChange = (event: SelectChangeEvent) => {
|
const handleChange = (event: SelectChangeEvent) => {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { useEffect, useLayoutEffect, useRef, useState } from "react";
|
import { useEffect, useLayoutEffect, useRef, useState } from "react";
|
||||||
import Cytoscape from "cytoscape";
|
import Cytoscape from "cytoscape";
|
||||||
import { Button } from "@mui/material";
|
import { Button, Box } from "@mui/material";
|
||||||
import CytoscapeComponent from "react-cytoscapejs";
|
import CytoscapeComponent from "react-cytoscapejs";
|
||||||
import popper from "cytoscape-popper";
|
import popper from "cytoscape-popper";
|
||||||
import { useCurrentQuiz } from "@root/quizes/hooks";
|
import { useCurrentQuiz } from "@root/quizes/hooks";
|
||||||
@ -8,9 +8,10 @@ import { updateRootContentId } from "@root/quizes/actions"
|
|||||||
import { AnyTypedQuizQuestion } from "@model/questionTypes/shared"
|
import { AnyTypedQuizQuestion } from "@model/questionTypes/shared"
|
||||||
import { useQuestionsStore } from "@root/questions/store";
|
import { useQuestionsStore } from "@root/questions/store";
|
||||||
import { deleteQuestion, updateQuestion, getQuestionByContentId, clearRuleForAll, createFrontResult } from "@root/questions/actions";
|
import { deleteQuestion, updateQuestion, getQuestionByContentId, clearRuleForAll, createFrontResult } from "@root/questions/actions";
|
||||||
import { updateOpenedModalSettingsId, } from "@root/uiTools/actions";
|
import { updateCanCreatePublic, updateModalInfoWhyCantCreate, updateOpenedModalSettingsId, } from "@root/uiTools/actions";
|
||||||
import { cleardragQuestionContentId } from "@root/uiTools/actions";
|
import { cleardragQuestionContentId } from "@root/uiTools/actions";
|
||||||
import { withErrorBoundary } from "react-error-boundary";
|
import { withErrorBoundary } from "react-error-boundary";
|
||||||
|
import { ProblemIcon } from "@ui_kit/ProblemIcon";
|
||||||
|
|
||||||
import { storeToNodes } from "./helper";
|
import { storeToNodes } from "./helper";
|
||||||
|
|
||||||
@ -115,6 +116,7 @@ interface Props {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function CsComponent({
|
function CsComponent({
|
||||||
modalQuestionParentContentId,
|
modalQuestionParentContentId,
|
||||||
modalQuestionTargetContentId,
|
modalQuestionTargetContentId,
|
||||||
@ -124,7 +126,7 @@ function CsComponent({
|
|||||||
}: Props) {
|
}: Props) {
|
||||||
const quiz = useCurrentQuiz();
|
const quiz = useCurrentQuiz();
|
||||||
|
|
||||||
const { dragQuestionContentId, desireToOpenABranchingModal } = useUiTools()
|
const { dragQuestionContentId, desireToOpenABranchingModal, canCreatePublic } = useUiTools()
|
||||||
const trashQuestions = useQuestionsStore().questions
|
const trashQuestions = useQuestionsStore().questions
|
||||||
const questions = trashQuestions.filter((question) => question.type !== "result" && question.type !== null)
|
const questions = trashQuestions.filter((question) => question.type !== "result" && question.type !== null)
|
||||||
const [startCreate, setStartCreate] = useState("");
|
const [startCreate, setStartCreate] = useState("");
|
||||||
@ -136,6 +138,13 @@ function 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);
|
||||||
|
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
return () => {
|
||||||
|
// if (!canCreatePublic) updateModalInfoWhyCantCreate(true)
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
const cy = cyRef?.current
|
const cy = cyRef?.current
|
||||||
if (desireToOpenABranchingModal) {
|
if (desireToOpenABranchingModal) {
|
||||||
@ -148,8 +157,8 @@ function CsComponent({
|
|||||||
}, [desireToOpenABranchingModal])
|
}, [desireToOpenABranchingModal])
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
updateOpenedModalSettingsId()
|
updateOpenedModalSettingsId()
|
||||||
// updateRootContentId(quiz.id, "")
|
// updateRootContentId(quiz.id, "")
|
||||||
// clearRuleForAll()
|
// clearRuleForAll()
|
||||||
}, [])
|
}, [])
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (modalQuestionTargetContentId.length !== 0 && modalQuestionParentContentId.length !== 0) {
|
if (modalQuestionTargetContentId.length !== 0 && modalQuestionParentContentId.length !== 0) {
|
||||||
@ -160,7 +169,7 @@ function CsComponent({
|
|||||||
}, [modalQuestionTargetContentId])
|
}, [modalQuestionTargetContentId])
|
||||||
|
|
||||||
const addNode = ({ parentNodeContentId, targetNodeContentId }: { parentNodeContentId: string, targetNodeContentId?: string }) => {
|
const addNode = ({ parentNodeContentId, targetNodeContentId }: { parentNodeContentId: string, targetNodeContentId?: string }) => {
|
||||||
|
|
||||||
//запрещаем работу родителя-ребенка если это один и тот же вопрос
|
//запрещаем работу родителя-ребенка если это один и тот же вопрос
|
||||||
if (parentNodeContentId === targetNodeContentId) return
|
if (parentNodeContentId === targetNodeContentId) return
|
||||||
|
|
||||||
@ -169,7 +178,7 @@ function CsComponent({
|
|||||||
const parentNodeChildren = cy?.$('edge[source = "' + parentNodeContentId + '"]')?.length
|
const parentNodeChildren = cy?.$('edge[source = "' + parentNodeContentId + '"]')?.length
|
||||||
//если есть инфо о выбранном вопросе из модалки - берём родителя из инфо модалки. Иначе из значения дропа
|
//если есть инфо о выбранном вопросе из модалки - берём родителя из инфо модалки. Иначе из значения дропа
|
||||||
const targetQuestion = { ...getQuestionByContentId(targetNodeContentId || dragQuestionContentId) } as AnyTypedQuizQuestion
|
const targetQuestion = { ...getQuestionByContentId(targetNodeContentId || dragQuestionContentId) } as AnyTypedQuizQuestion
|
||||||
if (Object.keys(targetQuestion).length !== 0 && parentNodeContentId && parentNodeChildren !== undefined) {
|
if (Object.keys(targetQuestion).length !== 0 && parentNodeContentId && parentNodeChildren !== undefined) {
|
||||||
clearDataAfterAddNode({ parentNodeContentId, targetQuestion, parentNodeChildren })
|
clearDataAfterAddNode({ parentNodeContentId, targetQuestion, parentNodeChildren })
|
||||||
cy?.data('changed', true)
|
cy?.data('changed', true)
|
||||||
createFrontResult(quiz.backendId, targetQuestion.content.id)
|
createFrontResult(quiz.backendId, targetQuestion.content.id)
|
||||||
@ -188,7 +197,6 @@ function CsComponent({
|
|||||||
}
|
}
|
||||||
])
|
])
|
||||||
cy?.layout(lyopts).run()
|
cy?.layout(lyopts).run()
|
||||||
console.log(es)
|
|
||||||
cy?.center(es)
|
cy?.center(es)
|
||||||
} else {
|
} else {
|
||||||
enqueueSnackbar("Добавляемый вопрос не найден")
|
enqueueSnackbar("Добавляемый вопрос не найден")
|
||||||
@ -203,7 +211,6 @@ function CsComponent({
|
|||||||
//смотрим не добавлен ли родителю result. Если да - убираем его. Веточкам result не нужен
|
//смотрим не добавлен ли родителю result. Если да - убираем его. Веточкам result не нужен
|
||||||
trashQuestions.forEach((targetQuestion) => {
|
trashQuestions.forEach((targetQuestion) => {
|
||||||
if (targetQuestion.type === "result" && targetQuestion.content.rule.parentId === parentQuestion.content.id) {
|
if (targetQuestion.type === "result" && targetQuestion.content.rule.parentId === parentQuestion.content.id) {
|
||||||
console.log('deleteQ', targetQuestion.id)
|
|
||||||
deleteQuestion(targetQuestion.id);
|
deleteQuestion(targetQuestion.id);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -228,7 +235,6 @@ function CsComponent({
|
|||||||
|
|
||||||
|
|
||||||
const removeNode = ({ targetNodeContentId }: { targetNodeContentId: string }) => {
|
const removeNode = ({ targetNodeContentId }: { targetNodeContentId: string }) => {
|
||||||
console.log("старт удаление")
|
|
||||||
const deleteNodes = [] as string[]
|
const deleteNodes = [] as string[]
|
||||||
const deleteEdges: any = []
|
const deleteEdges: any = []
|
||||||
const cy = cyRef?.current
|
const cy = cyRef?.current
|
||||||
@ -272,8 +278,8 @@ function CsComponent({
|
|||||||
|
|
||||||
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) {
|
||||||
if (cy?.edges(`[source="${parentQuestionContentId}"]`).length === 0)
|
if (cy?.edges(`[source="${parentQuestionContentId}"]`).length === 0)
|
||||||
createFrontResult(quiz.backendId, parentQuestionContentId)
|
createFrontResult(quiz.backendId, parentQuestionContentId)
|
||||||
clearDataAfterRemoveNode({ targetQuestionContentId: targetNodeContentId, parentQuestionContentId })
|
clearDataAfterRemoveNode({ targetQuestionContentId: targetNodeContentId, parentQuestionContentId })
|
||||||
cy?.remove(cy?.$('#' + targetNodeContentId)).layout(lyopts).run()
|
cy?.remove(cy?.$('#' + targetNodeContentId)).layout(lyopts).run()
|
||||||
}
|
}
|
||||||
@ -640,36 +646,35 @@ if (cy?.edges(`[source="${parentQuestionContentId}"]`).length === 0)
|
|||||||
return crossElement;
|
return crossElement;
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
let gearsPopper = null
|
let gearsPopper = null
|
||||||
if (node.data().root !== true) {
|
if (node.data().root !== true) {
|
||||||
gearsPopper = node.popper({
|
gearsPopper = node.popper({
|
||||||
popper: {
|
popper: {
|
||||||
placement: "left",
|
placement: "left",
|
||||||
modifiers: [{ name: "flip", options: { boundary: node } }],
|
modifiers: [{ name: "flip", options: { boundary: node } }],
|
||||||
},
|
},
|
||||||
content: ([item]) => {
|
content: ([item]) => {
|
||||||
const itemId = item.id();
|
const itemId = item.id();
|
||||||
|
|
||||||
const itemElement = gearsContainer.current?.querySelector(
|
const itemElement = gearsContainer.current?.querySelector(
|
||||||
`.popper-gear[data-id='${itemId}']`
|
`.popper-gear[data-id='${itemId}']`
|
||||||
);
|
);
|
||||||
if (itemElement) {
|
if (itemElement) {
|
||||||
return itemElement;
|
return itemElement;
|
||||||
}
|
}
|
||||||
|
|
||||||
const gearElement = document.createElement("div");
|
const gearElement = document.createElement("div");
|
||||||
gearElement.classList.add("popper-gear");
|
gearElement.classList.add("popper-gear");
|
||||||
gearElement.setAttribute("data-id", item.id());
|
gearElement.setAttribute("data-id", item.id());
|
||||||
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("up")
|
updateOpenedModalSettingsId(item.id())
|
||||||
updateOpenedModalSettingsId(item.id())
|
});
|
||||||
});
|
|
||||||
|
|
||||||
return gearElement;
|
return gearElement;
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
const update = async () => {
|
const update = async () => {
|
||||||
await plusesPopper.update();
|
await plusesPopper.update();
|
||||||
@ -786,23 +791,27 @@ let gearsPopper = null
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Button
|
<Box
|
||||||
sx={{
|
mb="20px">
|
||||||
mb: "20px",
|
<Button
|
||||||
height: "27px",
|
sx={{
|
||||||
color: "#7E2AEA",
|
height: "27px",
|
||||||
textDecoration: "underline",
|
color: "#7E2AEA",
|
||||||
fontSize: "16px",
|
textDecoration: "underline",
|
||||||
}}
|
fontSize: "16px",
|
||||||
variant="text"
|
}}
|
||||||
onClick={() => {
|
variant="text"
|
||||||
|
onClick={() => {
|
||||||
|
|
||||||
cyRef.current?.fit()
|
cyRef.current?.fit()
|
||||||
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Выровнять
|
Выровнять
|
||||||
</Button>
|
</Button>
|
||||||
|
<ProblemIcon blink={!canCreatePublic} onClick={() => updateModalInfoWhyCantCreate(true)} />
|
||||||
|
</Box>
|
||||||
|
|
||||||
<CytoscapeComponent
|
<CytoscapeComponent
|
||||||
wheelSensitivity={0.1}
|
wheelSensitivity={0.1}
|
||||||
elements={[]}
|
elements={[]}
|
||||||
@ -815,16 +824,6 @@ let gearsPopper = null
|
|||||||
}}
|
}}
|
||||||
autoungrabify={true}
|
autoungrabify={true}
|
||||||
/>
|
/>
|
||||||
{/* <button onClick={() => {
|
|
||||||
console.log("NODES____________________________")
|
|
||||||
cyRef.current?.elements().forEach((ele: any) => {
|
|
||||||
console.log(ele.data())
|
|
||||||
})
|
|
||||||
}}>nodes</button>
|
|
||||||
<button onClick={() => {
|
|
||||||
console.log("ELEMENTS____________________________")
|
|
||||||
console.log(questions)
|
|
||||||
}}>elements</button> */}
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -18,7 +18,6 @@ export const FirstNodeField = ({ setOpenedModalQuestions, modalQuestionTargetCon
|
|||||||
|
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
updateOpenedModalSettingsId()
|
updateOpenedModalSettingsId()
|
||||||
console.log("first render firstComponent")
|
|
||||||
updateRootContentId(quiz.id, "")
|
updateRootContentId(quiz.id, "")
|
||||||
clearRuleForAll()
|
clearRuleForAll()
|
||||||
}, [])
|
}, [])
|
||||||
|
@ -77,7 +77,7 @@ export const BranchingPanel = (sx?: SxProps<Theme>) => {
|
|||||||
/>
|
/>
|
||||||
<Box>
|
<Box>
|
||||||
<Typography ref={ref} sx={{ fontWeight: "bold", color: "#4D4D4D" }}>
|
<Typography ref={ref} sx={{ fontWeight: "bold", color: "#4D4D4D" }}>
|
||||||
Логика ветвления
|
Логика ветвления
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography sx={{ color: "#4D4D4D", fontSize: "12px" }}>
|
<Typography sx={{ color: "#4D4D4D", fontSize: "12px" }}>
|
||||||
Настройте связи между вопросами
|
Настройте связи между вопросами
|
||||||
|
@ -106,7 +106,6 @@ export default function ButtonsOptions({
|
|||||||
deleteQuestion(question.id);
|
deleteQuestion(question.id);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
console.log("удаляю безтипогово");
|
|
||||||
deleteQuestion(question.id);
|
deleteQuestion(question.id);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -149,7 +148,6 @@ export default function ButtonsOptions({
|
|||||||
title: "Ветвление",
|
title: "Ветвление",
|
||||||
value: "branching",
|
value: "branching",
|
||||||
myFunc: (question) => {
|
myFunc: (question) => {
|
||||||
console.log("buttons opiums")
|
|
||||||
updateOpenBranchingPanel(true);
|
updateOpenBranchingPanel(true);
|
||||||
updateDesireToOpenABranchingModal(question.content.id);
|
updateDesireToOpenABranchingModal(question.content.id);
|
||||||
}
|
}
|
||||||
|
@ -107,7 +107,6 @@ export default function ButtonsOptionsAndPict({
|
|||||||
deleteQuestion(question.id);
|
deleteQuestion(question.id);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
console.log("удаляю безтипогово");
|
|
||||||
deleteQuestion(question.id);
|
deleteQuestion(question.id);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -254,7 +253,6 @@ export default function ButtonsOptionsAndPict({
|
|||||||
onMouseEnter={() => setButtonHover("branching")}
|
onMouseEnter={() => setButtonHover("branching")}
|
||||||
onMouseLeave={() => setButtonHover("")}
|
onMouseLeave={() => setButtonHover("")}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
console.log("buttonsOptions")
|
|
||||||
updateOpenBranchingPanel(true);
|
updateOpenBranchingPanel(true);
|
||||||
updateDesireToOpenABranchingModal(question.content.id);
|
updateDesireToOpenABranchingModal(question.content.id);
|
||||||
}}
|
}}
|
||||||
|
@ -123,7 +123,6 @@ export default function QuestionsPageCard({ question, draggableProps, isDragging
|
|||||||
|
|
||||||
deleteQuestion(question.id);
|
deleteQuestion(question.id);
|
||||||
} else {
|
} else {
|
||||||
console.log("удаляю безтипогово");
|
|
||||||
deleteQuestion(question.id);
|
deleteQuestion(question.id);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -51,6 +51,7 @@ export default function QuestionsPageCard({ question, questionIndex, draggablePr
|
|||||||
});
|
});
|
||||||
}, 200);
|
}, 200);
|
||||||
|
|
||||||
|
console.log(question)
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Paper
|
<Paper
|
||||||
@ -85,7 +86,7 @@ export default function QuestionsPageCard({ question, questionIndex, draggablePr
|
|||||||
>
|
>
|
||||||
<CustomTextField
|
<CustomTextField
|
||||||
placeholder={`Заголовок ${questionIndex + 1} вопроса`}
|
placeholder={`Заголовок ${questionIndex + 1} вопроса`}
|
||||||
text={question.title}
|
value={question.title}
|
||||||
onChange={({ target }) => setTitle(target.value)}
|
onChange={({ target }) => setTitle(target.value)}
|
||||||
sx={{ width: "100%" }}
|
sx={{ width: "100%" }}
|
||||||
InputProps={{
|
InputProps={{
|
||||||
@ -224,4 +225,4 @@ const IconAndrom = (questionType: QuestionType | null) => {
|
|||||||
default:
|
default:
|
||||||
return <AnswerGroup color="#9A9AAF" sx={{ height: "22px", width: "20px" }} />;
|
return <AnswerGroup color="#9A9AAF" sx={{ height: "22px", width: "20px" }} />;
|
||||||
}
|
}
|
||||||
};
|
};
|
@ -6,8 +6,7 @@ import FormDraggableListItem from "./FormDraggableListItem";
|
|||||||
import { useQuestions } from "@root/questions/hooks";
|
import { useQuestions } from "@root/questions/hooks";
|
||||||
|
|
||||||
export const FormDraggableList = () => {
|
export const FormDraggableList = () => {
|
||||||
const { questions } = useQuestions();
|
const questions = useQuestions().questions.filter((q) => q.type !== "result");
|
||||||
|
|
||||||
const onDragEnd = ({ destination, source }: DropResult) => {
|
const onDragEnd = ({ destination, source }: DropResult) => {
|
||||||
if (destination) reorderQuestions(source.index, destination.index);
|
if (destination) reorderQuestions(source.index, destination.index);
|
||||||
};
|
};
|
||||||
|
@ -13,6 +13,7 @@ export default function FormQuestionsPage() {
|
|||||||
const quiz = useCurrentQuiz();
|
const quiz = useCurrentQuiz();
|
||||||
|
|
||||||
if (!quiz) return null;
|
if (!quiz) return null;
|
||||||
|
console.log("Анкета")
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
@ -14,8 +14,6 @@ export const QuestionSwitchWindowTool = () => {
|
|||||||
const {openBranchingPanel} = useUiTools()
|
const {openBranchingPanel} = useUiTools()
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const isMobile = useMediaQuery(theme.breakpoints.down(600));
|
const isMobile = useMediaQuery(theme.breakpoints.down(600));
|
||||||
console.log("questions ", questions)
|
|
||||||
console.log("rules ", questions.filter((q) => q.type !== null).map((q) => ({id: q.content.id, rule: q.content.rule})))
|
|
||||||
return (
|
return (
|
||||||
<Box sx={{ display: "flex", gap: "20px", flexWrap: "wrap", marginBottom: isMobile ? "20px" : undefined }}>
|
<Box sx={{ display: "flex", gap: "20px", flexWrap: "wrap", marginBottom: isMobile ? "20px" : undefined }}>
|
||||||
<Box sx={{ flexBasis: "796px" }}>
|
<Box sx={{ flexBasis: "796px" }}>
|
||||||
|
@ -12,7 +12,7 @@ import { useUiTools } from "@root/uiTools/store";
|
|||||||
export const SwitchBranchingPanel = () => {
|
export const SwitchBranchingPanel = () => {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const isMobile = useMediaQuery(theme.breakpoints.down(660));
|
const isMobile = useMediaQuery(theme.breakpoints.down(660));
|
||||||
const isTablet = useMediaQuery(theme.breakpoints.down(1000));
|
const isTablet = useMediaQuery(theme.breakpoints.down(1446));
|
||||||
|
|
||||||
const {openBranchingPanel} = useUiTools()
|
const {openBranchingPanel} = useUiTools()
|
||||||
const ref = useRef()
|
const ref = useRef()
|
||||||
|
@ -42,7 +42,6 @@ export const UploadImageModal: React.FC<ModalkaProps> = ({
|
|||||||
|
|
||||||
const acceptedFormats = accept ? accept.map((format) => "." + format).join(", ") : "";
|
const acceptedFormats = accept ? accept.map((format) => "." + format).join(", ") : "";
|
||||||
|
|
||||||
console.log(acceptedFormats);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
|
@ -120,7 +120,6 @@ const InfoView = ({ resultData }: { resultData: QuizQuestionResult }) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const ResultCard = ({ resultContract, resultData }: Props) => {
|
export const ResultCard = ({ resultContract, resultData }: Props) => {
|
||||||
console.log("resultData", resultData)
|
|
||||||
|
|
||||||
const quizQid = useCurrentQuiz()?.qid;
|
const quizQid = useCurrentQuiz()?.qid;
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
@ -78,7 +78,6 @@ export const Footer = ({ setCurrentQuestion, question, setShowContactForm, setSh
|
|||||||
}, [question, answers]);
|
}, [question, answers]);
|
||||||
|
|
||||||
const showResult = (nextQuestion) => {
|
const showResult = (nextQuestion) => {
|
||||||
console.log(nextQuestion);
|
|
||||||
|
|
||||||
if (nextQuestion && quiz?.config.resultInfo.when === "before") {
|
if (nextQuestion && quiz?.config.resultInfo.when === "before") {
|
||||||
setShowResultForm(true);
|
setShowResultForm(true);
|
||||||
@ -154,14 +153,9 @@ export const Footer = ({ setCurrentQuestion, question, setShowContactForm, setSh
|
|||||||
const questionIndex = questions.findIndex(({ id }) => id === question.id);
|
const questionIndex = questions.findIndex(({ id }) => id === question.id);
|
||||||
const nextQuestion = questions[questionIndex + 1];
|
const nextQuestion = questions[questionIndex + 1];
|
||||||
|
|
||||||
console.log("questionIndex ", questionIndex);
|
|
||||||
console.log(nextQuestion);
|
|
||||||
console.log(questions);
|
|
||||||
if (nextQuestion && nextQuestion.type !== "result") {
|
if (nextQuestion && nextQuestion.type !== "result") {
|
||||||
console.log("следующий вопрос результирующий ", nextQuestion.type === "result");
|
|
||||||
setCurrentQuestion(nextQuestion);
|
setCurrentQuestion(nextQuestion);
|
||||||
} else {
|
} else {
|
||||||
console.log("следующий вопрос результирующий ", nextQuestion.type === "result");
|
|
||||||
showResult(nextQuestion);
|
showResult(nextQuestion);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -173,7 +167,6 @@ export const Footer = ({ setCurrentQuestion, question, setShowContactForm, setSh
|
|||||||
if (nextQuestionId) {
|
if (nextQuestionId) {
|
||||||
const nextQuestion = getQuestionByContentId(nextQuestionId);
|
const nextQuestion = getQuestionByContentId(nextQuestionId);
|
||||||
|
|
||||||
console.log(nextQuestion);
|
|
||||||
if (nextQuestion?.type && nextQuestion.type !== "result") {
|
if (nextQuestion?.type && nextQuestion.type !== "result") {
|
||||||
setCurrentQuestion(nextQuestion);
|
setCurrentQuestion(nextQuestion);
|
||||||
return;
|
return;
|
||||||
|
@ -43,7 +43,8 @@ const QUESTIONS_MAP: any = {
|
|||||||
|
|
||||||
export const Question = ({ questions }: QuestionProps) => {
|
export const Question = ({ questions }: QuestionProps) => {
|
||||||
const quiz = useCurrentQuiz();
|
const quiz = useCurrentQuiz();
|
||||||
const [currentQuestion, setCurrentQuestion] = useState<AnyTypedQuizQuestion>();
|
const [currentQuestion, setCurrentQuestion] =
|
||||||
|
useState<AnyTypedQuizQuestion>();
|
||||||
const [showContactForm, setShowContactForm] = useState<boolean>(false);
|
const [showContactForm, setShowContactForm] = useState<boolean>(false);
|
||||||
const [showResultForm, setShowResultForm] = useState<boolean>(false);
|
const [showResultForm, setShowResultForm] = useState<boolean>(false);
|
||||||
|
|
||||||
@ -61,9 +62,9 @@ export const Question = ({ questions }: QuestionProps) => {
|
|||||||
|
|
||||||
if (!currentQuestion) return <>не смог отобразить вопрос</>;
|
if (!currentQuestion) return <>не смог отобразить вопрос</>;
|
||||||
|
|
||||||
const QuestionComponent = QUESTIONS_MAP[currentQuestion.type as Exclude<QuestionType, "nonselected">];
|
const QuestionComponent =
|
||||||
|
QUESTIONS_MAP[currentQuestion.type as Exclude<QuestionType, "nonselected">];
|
||||||
|
|
||||||
console.log("showResultForm " , showResultForm)
|
|
||||||
return (
|
return (
|
||||||
<Box>
|
<Box>
|
||||||
{!showContactForm && !showResultForm && (
|
{!showContactForm && !showResultForm && (
|
||||||
|
@ -30,17 +30,13 @@ export const ResultForm = ({
|
|||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
console.log(currentQuestion)
|
|
||||||
console.log(resultQuestion
|
|
||||||
)
|
|
||||||
console.log(questions)
|
|
||||||
console.log(quiz?.config.resultInfo.when)
|
|
||||||
|
|
||||||
|
|
||||||
const followNextForm = () => {
|
const followNextForm = () => {
|
||||||
setShowResultForm(false);
|
setShowResultForm(false);
|
||||||
setShowContactForm(true);
|
setShowContactForm(true);
|
||||||
};
|
};
|
||||||
|
if (resultQuestion === undefined) return <></>
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
|
@ -74,6 +74,7 @@ export const StartPageViewPublication = ({ setVisualStartPage }: Props) => {
|
|||||||
className="quiz-preview-draghandle"
|
className="quiz-preview-draghandle"
|
||||||
sx={{
|
sx={{
|
||||||
height: "100vh",
|
height: "100vh",
|
||||||
|
width: "100vw",
|
||||||
background:
|
background:
|
||||||
quiz.config.startpageType === "expanded"
|
quiz.config.startpageType === "expanded"
|
||||||
? quiz.config.startpage.position === "left"
|
? quiz.config.startpage.position === "left"
|
||||||
@ -82,6 +83,7 @@ export const StartPageViewPublication = ({ setVisualStartPage }: Props) => {
|
|||||||
? "linear-gradient(180deg,transparent,#272626)"
|
? "linear-gradient(180deg,transparent,#272626)"
|
||||||
: "linear-gradient(270deg,#272626,transparent)"
|
: "linear-gradient(270deg,#272626,transparent)"
|
||||||
: "",
|
: "",
|
||||||
|
|
||||||
color: quiz.config.startpageType === "expanded" ? "white" : "black",
|
color: quiz.config.startpageType === "expanded" ? "white" : "black",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@ -142,6 +144,9 @@ export const StartPageViewPublication = ({ setVisualStartPage }: Props) => {
|
|||||||
fontStyle: "normal",
|
fontStyle: "normal",
|
||||||
fontStretch: "normal",
|
fontStretch: "normal",
|
||||||
lineHeight: "1.2",
|
lineHeight: "1.2",
|
||||||
|
overflowWrap: "break-word",
|
||||||
|
width: "100%",
|
||||||
|
textAlign: quiz.config.startpageType === "centered" ? "center" : "-moz-initial",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{quiz.name}
|
{quiz.name}
|
||||||
@ -150,6 +155,9 @@ export const StartPageViewPublication = ({ setVisualStartPage }: Props) => {
|
|||||||
sx={{
|
sx={{
|
||||||
fontSize: "16px",
|
fontSize: "16px",
|
||||||
m: "16px 0",
|
m: "16px 0",
|
||||||
|
overflowWrap: "break-word",
|
||||||
|
width: "100%",
|
||||||
|
textAlign: quiz.config.startpageType === "centered" ? "center" : "-moz-initial",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{quiz.config.startpage.description}
|
{quiz.config.startpage.description}
|
||||||
@ -172,7 +180,7 @@ export const StartPageViewPublication = ({ setVisualStartPage }: Props) => {
|
|||||||
<Box
|
<Box
|
||||||
sx={{ mt: "46px", display: "flex", alignItems: "center", justifyContent: "space-between", width: "100%" }}
|
sx={{ mt: "46px", display: "flex", alignItems: "center", justifyContent: "space-between", width: "100%" }}
|
||||||
>
|
>
|
||||||
<Box>
|
<Box sx={{ maxWidth: "300px" }}>
|
||||||
{quiz.config.info.clickable ? (
|
{quiz.config.info.clickable ? (
|
||||||
isMobileDevice ? (
|
isMobileDevice ? (
|
||||||
<Link href={`tel:${quiz.config.info.phonenumber}`}>
|
<Link href={`tel:${quiz.config.info.phonenumber}`}>
|
||||||
@ -192,7 +200,9 @@ export const StartPageViewPublication = ({ setVisualStartPage }: Props) => {
|
|||||||
{quiz.config.info.phonenumber}
|
{quiz.config.info.phonenumber}
|
||||||
</Typography>
|
</Typography>
|
||||||
)}
|
)}
|
||||||
<Typography sx={{ fontSize: "12px", textAlign: "end" }}>{quiz.config.info.law}</Typography>
|
<Typography sx={{ width: "100%", overflowWrap: "break-word", fontSize: "12px", textAlign: "end" }}>
|
||||||
|
{quiz.config.info.law}
|
||||||
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Box
|
<Box
|
||||||
@ -288,7 +298,7 @@ function QuizPreviewLayoutByType({
|
|||||||
width: "40%",
|
width: "40%",
|
||||||
position: "relative",
|
position: "relative",
|
||||||
padding: "16px",
|
padding: "16px",
|
||||||
zIndex: 2,
|
zIndex: 3,
|
||||||
display: "flex",
|
display: "flex",
|
||||||
flexDirection: "column",
|
flexDirection: "column",
|
||||||
justifyContent: "space-between",
|
justifyContent: "space-between",
|
||||||
@ -301,11 +311,11 @@ function QuizPreviewLayoutByType({
|
|||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
position: "absolute",
|
position: "absolute",
|
||||||
|
zIndex: -1,
|
||||||
left: 0,
|
left: 0,
|
||||||
top: 0,
|
top: 0,
|
||||||
height: "100%",
|
height: "100%",
|
||||||
width: "100%",
|
width: "100%",
|
||||||
zIndex: 1,
|
|
||||||
overflow: "hidden",
|
overflow: "hidden",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@ -329,7 +339,16 @@ function QuizPreviewLayoutByType({
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{quizHeaderBlock}
|
{quizHeaderBlock}
|
||||||
{backgroundBlock && <Box>{backgroundBlock}</Box>}
|
{backgroundBlock && (
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
width: "60%",
|
||||||
|
overflow: "hidden",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{backgroundBlock}
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
{quizMainBlock}
|
{quizMainBlock}
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
|
@ -52,9 +52,11 @@ export const ViewPage = () => {
|
|||||||
questions.filter(({ type }) => type) as AnyTypedQuizQuestion[]
|
questions.filter(({ type }) => type) as AnyTypedQuizQuestion[]
|
||||||
).sort((previousItem, item) => previousItem.page - item.page);
|
).sort((previousItem, item) => previousItem.page - item.page);
|
||||||
|
|
||||||
console.log("visualStartPage ", visualStartPage);
|
|
||||||
|
console.log(questions)
|
||||||
|
|
||||||
if (visualStartPage === undefined) return <></>;
|
if (visualStartPage === undefined) return <></>;
|
||||||
if (questions.length === 0) return <ApologyPage message="Нет созданных вопросов"/>
|
if (questions.length === 0 || (questions.length === 1 && questions[0].type === "result")) return <ApologyPage message="Нет созданных вопросов"/>
|
||||||
return (
|
return (
|
||||||
<Box>
|
<Box>
|
||||||
{!visualStartPage ? (
|
{!visualStartPage ? (
|
||||||
|
@ -31,8 +31,6 @@ export const Varimg = ({ currentQuestion }: VarimgProps) => {
|
|||||||
({ id }) => answer === id
|
({ id }) => answer === id
|
||||||
);
|
);
|
||||||
|
|
||||||
console.log(currentQuestion)
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box>
|
<Box>
|
||||||
<Typography variant="h5">{currentQuestion.title}</Typography>
|
<Typography variant="h5">{currentQuestion.title}</Typography>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { quizApi } from "@api/quiz";
|
import { quizApi } from "@api/quiz";
|
||||||
import { devlog } from "@frontend/kitui";
|
import { LogoutButton } from "@ui_kit/LogoutButton";
|
||||||
import BackArrowIcon from "@icons/BackArrowIcon";
|
import BackArrowIcon from "@icons/BackArrowIcon";
|
||||||
import { Burger } from "@icons/Burger";
|
import { Burger } from "@icons/Burger";
|
||||||
import EyeIcon from "@icons/EyeIcon";
|
import EyeIcon from "@icons/EyeIcon";
|
||||||
@ -16,7 +16,7 @@ import {
|
|||||||
useMediaQuery,
|
useMediaQuery,
|
||||||
useTheme,
|
useTheme,
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
import {decrementCurrentStep, resetEditConfig, setQuizes, updateQuiz} from "@root/quizes/actions";
|
import { decrementCurrentStep, resetEditConfig, setQuizes, updateQuiz } from "@root/quizes/actions";
|
||||||
import { useCurrentQuiz } from "@root/quizes/hooks";
|
import { useCurrentQuiz } from "@root/quizes/hooks";
|
||||||
import { useQuizStore } from "@root/quizes/store";
|
import { useQuizStore } from "@root/quizes/store";
|
||||||
import CustomAvatar from "@ui_kit/Header/Avatar";
|
import CustomAvatar from "@ui_kit/Header/Avatar";
|
||||||
@ -30,9 +30,10 @@ import { enqueueSnackbar } from "notistack";
|
|||||||
import React, { useEffect, useLayoutEffect, useState } from "react";
|
import React, { useEffect, useLayoutEffect, useState } from "react";
|
||||||
import { Link, useNavigate } from "react-router-dom";
|
import { Link, useNavigate } from "react-router-dom";
|
||||||
import useSWR from "swr";
|
import useSWR from "swr";
|
||||||
|
import { useDebouncedCallback } from "use-debounce";
|
||||||
import { SidebarMobile } from "./Sidebar/SidebarMobile";
|
import { SidebarMobile } from "./Sidebar/SidebarMobile";
|
||||||
import { cleanQuestions, setQuestions } from "@root/questions/actions";
|
import { cleanQuestions, setQuestions } from "@root/questions/actions";
|
||||||
import { updateOpenBranchingPanel } from "@root/uiTools/actions";
|
import { updateOpenBranchingPanel, updateCanCreatePublic, updateModalInfoWhyCantCreate } from "@root/uiTools/actions";
|
||||||
import { BranchingPanel } from "../Questions/BranchingPanel";
|
import { BranchingPanel } from "../Questions/BranchingPanel";
|
||||||
import { useQuestionsStore } from "@root/questions/store";
|
import { useQuestionsStore } from "@root/questions/store";
|
||||||
import { useQuizes } from "@root/quizes/hooks";
|
import { useQuizes } from "@root/quizes/hooks";
|
||||||
@ -40,10 +41,16 @@ import { questionApi } from "@api/question";
|
|||||||
import { useUiTools } from "@root/uiTools/store";
|
import { useUiTools } from "@root/uiTools/store";
|
||||||
|
|
||||||
import Logotip from "../Landing/images/icons/QuizLogo";
|
import Logotip from "../Landing/images/icons/QuizLogo";
|
||||||
|
import { clearUserData } from "@root/user";
|
||||||
|
import { clearAuthToken } from "@frontend/kitui";
|
||||||
|
import { logout } from "@api/auth";
|
||||||
|
import { AnyTypedQuizQuestion } from "@model/questionTypes/shared";
|
||||||
|
import { ModalInfoWhyCantCreate } from "./ModalInfoWhyCantCreate";
|
||||||
|
|
||||||
export default function EditPage() {
|
export default function EditPage() {
|
||||||
const quiz = useCurrentQuiz();
|
const quiz = useCurrentQuiz();
|
||||||
const { editQuizId } = useQuizStore();
|
const { editQuizId } = useQuizStore();
|
||||||
|
const { questions } = useQuestionsStore();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const getData = async () => {
|
const getData = async () => {
|
||||||
@ -56,7 +63,7 @@ export default function EditPage() {
|
|||||||
getData();
|
getData();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const { openBranchingPanel } = useUiTools();
|
const { openBranchingPanel, whyCantCreatePublic, canCreatePublic } = useUiTools();
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const currentStep = useQuizStore((state) => state.currentStep);
|
const currentStep = useQuizStore((state) => state.currentStep);
|
||||||
@ -74,11 +81,61 @@ export default function EditPage() {
|
|||||||
() => () => {
|
() => () => {
|
||||||
resetEditConfig();
|
resetEditConfig();
|
||||||
cleanQuestions();
|
cleanQuestions();
|
||||||
|
updateModalInfoWhyCantCreate(false)
|
||||||
},
|
},
|
||||||
[]
|
[]
|
||||||
);
|
);
|
||||||
console.log(currentStep)
|
|
||||||
console.log(quizConfig)
|
|
||||||
|
|
||||||
|
const updateQuestionHint = useDebouncedCallback((questions: AnyTypedQuizQuestion[]) => {
|
||||||
|
|
||||||
|
const problems: any = {}
|
||||||
|
|
||||||
|
questions.forEach((question) => {
|
||||||
|
//Если не участвует в ветвлении, или безтиповый, или резулт - он нам не интересен
|
||||||
|
if (question.type === null
|
||||||
|
|| question.type === "result"
|
||||||
|
|| question.content.rule.parentId.length === 0) return
|
||||||
|
|
||||||
|
//если есть дети, но нет дефолта - логическая ошибка. Так нельзя
|
||||||
|
if (question.content.rule.children.length > 0 && question.content.rule.default.length === 0) {
|
||||||
|
problems[question.content.id] = {
|
||||||
|
name: question.title,
|
||||||
|
problems: ["Не выбран дефолтный вопрос"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
useUiTools.setState({ whyCantCreatePublic: problems })
|
||||||
|
if (Object.keys(problems).length > 0) {
|
||||||
|
updateQuiz(quiz?.id, (state) => { state.status = "stop" })
|
||||||
|
updateCanCreatePublic(false)
|
||||||
|
} else {
|
||||||
|
updateCanCreatePublic(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}, 600);
|
||||||
|
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
updateQuestionHint(questions)
|
||||||
|
}, [questions]);
|
||||||
|
|
||||||
|
|
||||||
|
async function handleLogoutClick() {
|
||||||
|
const [, logoutError] = await logout();
|
||||||
|
|
||||||
|
if (logoutError) {
|
||||||
|
return enqueueSnackbar(logoutError);
|
||||||
|
}
|
||||||
|
|
||||||
|
clearAuthToken();
|
||||||
|
clearUserData();
|
||||||
|
navigate("/");
|
||||||
|
}
|
||||||
|
|
||||||
if (!quizConfig) return <></>
|
if (!quizConfig) return <></>
|
||||||
return (
|
return (
|
||||||
@ -99,7 +156,7 @@ export default function EditPage() {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Link to="/" style={{ display: "flex" }}>
|
<Link to="/" style={{ display: "flex" }}>
|
||||||
{isMobile ? <PenaLogoIcon style={{ fontSize: "39px", color: "white" }} /> : <PenaLogo width={124} />}
|
{isMobile ? <Logotip width={100} /> : <Logotip width={124} />}
|
||||||
</Link>
|
</Link>
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
@ -155,14 +212,16 @@ export default function EditPage() {
|
|||||||
style={{ fontSize: "30px", color: "white", cursor: "pointer" }}
|
style={{ fontSize: "30px", color: "white", cursor: "pointer" }}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<CustomAvatar
|
<Box>
|
||||||
sx={{
|
<CustomAvatar
|
||||||
ml: "11px",
|
sx={{
|
||||||
backgroundColor: theme.palette.orange.main,
|
ml: "11px",
|
||||||
height: "36px",
|
backgroundColor: theme.palette.orange.main,
|
||||||
width: "36px",
|
height: "36px",
|
||||||
}}
|
width: "36px",
|
||||||
/>
|
}}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
)}
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
) : (
|
) : (
|
||||||
@ -196,6 +255,7 @@ export default function EditPage() {
|
|||||||
width: "36px",
|
width: "36px",
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
<LogoutButton onClick={handleLogoutClick} />
|
||||||
</Box>
|
</Box>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
@ -230,137 +290,144 @@ export default function EditPage() {
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
<Box
|
|
||||||
sx={{
|
<Box
|
||||||
position: "absolute",
|
sx={{
|
||||||
left: 0,
|
position: "absolute",
|
||||||
bottom: 0,
|
left: 0,
|
||||||
width: "100%",
|
bottom: 0,
|
||||||
padding: isMobile ? "20px 16px" : "20px 40px 20px 250px",
|
width: "100%",
|
||||||
display: "flex",
|
padding: isMobile ? "20px 16px" : "20px 40px 20px 250px",
|
||||||
justifyContent: "flex-start",
|
display: "flex",
|
||||||
alignItems: "center",
|
justifyContent: "flex-start",
|
||||||
gap: "15px",
|
alignItems: "center",
|
||||||
background: "#FFF",
|
gap: "15px",
|
||||||
}}
|
background: "#FFF",
|
||||||
>
|
}}
|
||||||
{[1].includes(currentStep) && !openBranchingPanel && quizConfig.type !== "form" && (
|
>
|
||||||
<Box
|
{[1].includes(currentStep) && !openBranchingPanel && quizConfig.type !== "form" && (
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
|
gap: "15px",
|
||||||
|
padding: "18px",
|
||||||
|
background: "#fff",
|
||||||
|
borderRadius: "12px",
|
||||||
|
boxShadow: "0px 10px 30px #e7e7e7",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Switch
|
||||||
|
checked={openBranchingPanel}
|
||||||
|
onChange={(e) => updateOpenBranchingPanel(e.target.checked)}
|
||||||
sx={{
|
sx={{
|
||||||
display: "flex",
|
width: 50,
|
||||||
alignItems: "center",
|
height: 30,
|
||||||
gap: "15px",
|
padding: 0,
|
||||||
padding: "18px",
|
"& .MuiSwitch-switchBase": {
|
||||||
background: "#fff",
|
padding: 0,
|
||||||
borderRadius: "12px",
|
margin: "2px",
|
||||||
boxShadow: "0px 10px 30px #e7e7e7",
|
transitionDuration: "300ms",
|
||||||
|
"&.Mui-checked": {
|
||||||
|
transform: "translateX(20px)",
|
||||||
|
color: theme.palette.brightPurple.main,
|
||||||
|
"& + .MuiSwitch-track": {
|
||||||
|
backgroundColor: "#E8DCF9",
|
||||||
|
opacity: 1,
|
||||||
|
border: 0,
|
||||||
|
},
|
||||||
|
"&.Mui-disabled + .MuiSwitch-track": { opacity: 0.5 },
|
||||||
|
},
|
||||||
|
"&.Mui-disabled .MuiSwitch-thumb": {
|
||||||
|
color: theme.palette.mode === "light" ? theme.palette.grey[100] : theme.palette.grey[600],
|
||||||
|
},
|
||||||
|
"&.Mui-disabled + .MuiSwitch-track": {
|
||||||
|
opacity: theme.palette.mode === "light" ? 0.7 : 0.3,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"& .MuiSwitch-thumb": {
|
||||||
|
boxSizing: "border-box",
|
||||||
|
width: 25,
|
||||||
|
height: 25,
|
||||||
|
},
|
||||||
|
"& .MuiSwitch-track": {
|
||||||
|
borderRadius: 13,
|
||||||
|
backgroundColor: theme.palette.mode === "light" ? "#E9E9EA" : "#39393D",
|
||||||
|
opacity: 1,
|
||||||
|
transition: theme.transitions.create(["background-color"], {
|
||||||
|
duration: 500,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Box>
|
||||||
|
<Typography sx={{ fontWeight: "bold", color: "#4D4D4D" }}>Логика ветвления</Typography>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{!canCreatePublic && quiz.config.type !== "form" ?
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
// disabled
|
||||||
|
sx={{
|
||||||
|
fontSize: "14px",
|
||||||
|
lineHeight: "18px",
|
||||||
|
height: "34px",
|
||||||
|
minWidth: "130px",
|
||||||
|
}}
|
||||||
|
onClick={() => Object.keys(whyCantCreatePublic).length === 0 ? () => {} : updateModalInfoWhyCantCreate(true)}
|
||||||
|
>
|
||||||
|
Тестовый просмотр
|
||||||
|
</Button>
|
||||||
|
:
|
||||||
|
<a href={`/view`} target="_blank" rel="noreferrer" style={{ textDecoration: "none" }}>
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
sx={{
|
||||||
|
fontSize: "14px",
|
||||||
|
lineHeight: "18px",
|
||||||
|
height: "34px",
|
||||||
|
minWidth: "130px",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Switch
|
Тестовый просмотр
|
||||||
checked={openBranchingPanel}
|
</Button>
|
||||||
onChange={(e) => updateOpenBranchingPanel(e.target.checked)}
|
</a>
|
||||||
sx={{
|
}
|
||||||
width: 50,
|
|
||||||
height: 30,
|
|
||||||
padding: 0,
|
|
||||||
"& .MuiSwitch-switchBase": {
|
|
||||||
padding: 0,
|
|
||||||
margin: "2px",
|
|
||||||
transitionDuration: "300ms",
|
|
||||||
"&.Mui-checked": {
|
|
||||||
transform: "translateX(20px)",
|
|
||||||
color: theme.palette.brightPurple.main,
|
|
||||||
"& + .MuiSwitch-track": {
|
|
||||||
backgroundColor: "#E8DCF9",
|
|
||||||
opacity: 1,
|
|
||||||
border: 0,
|
|
||||||
},
|
|
||||||
"&.Mui-disabled + .MuiSwitch-track": { opacity: 0.5 },
|
|
||||||
},
|
|
||||||
"&.Mui-disabled .MuiSwitch-thumb": {
|
|
||||||
color: theme.palette.mode === "light" ? theme.palette.grey[100] : theme.palette.grey[600],
|
|
||||||
},
|
|
||||||
"&.Mui-disabled + .MuiSwitch-track": {
|
|
||||||
opacity: theme.palette.mode === "light" ? 0.7 : 0.3,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"& .MuiSwitch-thumb": {
|
|
||||||
boxSizing: "border-box",
|
|
||||||
width: 25,
|
|
||||||
height: 25,
|
|
||||||
},
|
|
||||||
"& .MuiSwitch-track": {
|
|
||||||
borderRadius: 13,
|
|
||||||
backgroundColor: theme.palette.mode === "light" ? "#E9E9EA" : "#39393D",
|
|
||||||
opacity: 1,
|
|
||||||
transition: theme.transitions.create(["background-color"], {
|
|
||||||
duration: 500,
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<Box>
|
|
||||||
<Typography sx={{ fontWeight: "bold", color: "#4D4D4D" }}>Логика ветвления</Typography>
|
|
||||||
</Box>
|
|
||||||
</Box>
|
|
||||||
)}
|
|
||||||
{disableTest ? (
|
|
||||||
<Button
|
|
||||||
variant="contained"
|
|
||||||
disabled
|
|
||||||
sx={{
|
|
||||||
fontSize: "14px",
|
|
||||||
lineHeight: "18px",
|
|
||||||
height: "34px",
|
|
||||||
minWidth: "130px",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Тестовый просмотр
|
|
||||||
</Button>
|
|
||||||
) : (
|
|
||||||
<a href={`/view`} target="_blank" rel="noreferrer" style={{ textDecoration: "none" }}>
|
|
||||||
<Button
|
|
||||||
variant="contained"
|
|
||||||
sx={{
|
|
||||||
fontSize: "14px",
|
|
||||||
lineHeight: "18px",
|
|
||||||
height: "34px",
|
|
||||||
minWidth: "130px",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Тестовый просмотр
|
|
||||||
</Button>
|
|
||||||
</a>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
sx={{
|
sx={{
|
||||||
fontSize: "14px",
|
fontSize: "14px",
|
||||||
lineHeight: "18px",
|
lineHeight: "18px",
|
||||||
height: "34px",
|
height: "34px",
|
||||||
border: `1px solid ${theme.palette.brightPurple.main}`,
|
border: `1px solid ${theme.palette.brightPurple.main}`,
|
||||||
backgroundColor: quiz?.status === "start" ? theme.palette.brightPurple.main : "transparent",
|
backgroundColor: quiz?.status === "start" ? theme.palette.brightPurple.main : "transparent",
|
||||||
color: quiz?.status === "start" ? "#FFFFFF" : theme.palette.brightPurple.main,
|
color: quiz?.status === "start" ? "#FFFFFF" : theme.palette.brightPurple.main,
|
||||||
}}
|
}}
|
||||||
onClick={() => {
|
onClick={
|
||||||
updateQuiz(
|
Object.keys(whyCantCreatePublic).length === 0 ?
|
||||||
quiz?.id, (state) => {
|
() => updateQuiz(quiz?.id, (state) => {
|
||||||
state.status = quiz?.status === "start" ? "stop" : "start"
|
state.status = quiz?.status === "start" ? "stop" : "start";
|
||||||
}
|
})
|
||||||
)
|
:
|
||||||
}}
|
() => updateModalInfoWhyCantCreate(true)
|
||||||
>{quiz?.status === "start" ? "Стоп" : "Старт"}</Button>
|
}
|
||||||
|
>
|
||||||
{quiz?.status === "start" && <Box
|
{quiz?.status === "start" ? "Стоп" : "Старт"}
|
||||||
component={Link}
|
</Button>
|
||||||
sx={{
|
{quiz?.status === "start" && <Box
|
||||||
color: "#7e2aea",
|
component={Link}
|
||||||
fontSize: "14px"
|
sx={{
|
||||||
}}
|
color: "#7e2aea",
|
||||||
target="_blank" to={"https://hbpn.link/" + quiz.qid}>https://hbpn.link/{quiz.qid}</Box> }
|
fontSize: "14px"
|
||||||
</Box>
|
}}
|
||||||
|
target="_blank" to={"https://hbpn.link/" + quiz.qid}>https://hbpn.link/{quiz.qid}
|
||||||
|
</Box>}
|
||||||
</Box>
|
</Box>
|
||||||
|
</Box >
|
||||||
|
<ModalInfoWhyCantCreate />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
49
src/pages/startPage/ModalInfoWhyCantCreate.tsx
Normal file
49
src/pages/startPage/ModalInfoWhyCantCreate.tsx
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
import { Box, Modal, Typography, Divider } from "@mui/material"
|
||||||
|
|
||||||
|
import { useUiTools } from "@root/uiTools/store";
|
||||||
|
import { updateModalInfoWhyCantCreate } from "@root/uiTools/actions";
|
||||||
|
import { useLayoutEffect } from "react";
|
||||||
|
|
||||||
|
export const ModalInfoWhyCantCreate = () => {
|
||||||
|
|
||||||
|
const { whyCantCreatePublic, openModalInfoWhyCantCreate } = useUiTools();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
open={openModalInfoWhyCantCreate}
|
||||||
|
onClose={() => updateModalInfoWhyCantCreate(false)}
|
||||||
|
>
|
||||||
|
<Box sx={{
|
||||||
|
position: 'absolute' as 'absolute',
|
||||||
|
top: '50%',
|
||||||
|
left: '50%',
|
||||||
|
transform: 'translate(-50%, -50%)',
|
||||||
|
maxWidth: '620px',
|
||||||
|
width: '100%',
|
||||||
|
bgcolor: 'background.paper',
|
||||||
|
borderRadius: '12px',
|
||||||
|
|
||||||
|
boxShadow: 24,
|
||||||
|
p: "25px",
|
||||||
|
minHeight: "60vh",
|
||||||
|
maxHeight: "90vh",
|
||||||
|
overflow: "auto"
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{
|
||||||
|
Object.values(whyCantCreatePublic).map((data) => {
|
||||||
|
return (
|
||||||
|
<Box>
|
||||||
|
<Typography color="#7e2aea">У вопроса "{data.name}"</Typography>
|
||||||
|
{
|
||||||
|
data.problems.map((problem) => <Typography p="5px 0">{problem}</Typography>)
|
||||||
|
}
|
||||||
|
<Divider/>
|
||||||
|
</Box>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</Box>
|
||||||
|
</Modal>
|
||||||
|
)
|
||||||
|
}
|
@ -41,7 +41,6 @@ export const Restore: FC = () => {
|
|||||||
initialValues,
|
initialValues,
|
||||||
validationSchema,
|
validationSchema,
|
||||||
onSubmit: (values) => {
|
onSubmit: (values) => {
|
||||||
console.log(values);
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -297,7 +297,6 @@ export const uploadQuestionImage = async (
|
|||||||
if (!question || !quizQid) return;
|
if (!question || !quizQid) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
console.log(question.quizId)
|
|
||||||
const response = await quizApi.addImages(question.quizId, blob);
|
const response = await quizApi.addImages(question.quizId, blob);
|
||||||
|
|
||||||
const values = Object.values(response);
|
const values = Object.values(response);
|
||||||
@ -387,16 +386,13 @@ export const createTypedQuestion = async (
|
|||||||
});
|
});
|
||||||
|
|
||||||
export const deleteQuestion = async (questionId: string) => requestQueue.enqueue(async () => {
|
export const deleteQuestion = async (questionId: string) => requestQueue.enqueue(async () => {
|
||||||
console.log("Я получил запрос на удаление. ИД - ", questionId)
|
|
||||||
|
|
||||||
const question = useQuestionsStore.getState().questions.find(q => q.id === questionId);
|
const question = useQuestionsStore.getState().questions.find(q => q.id === questionId);
|
||||||
console.log("delete question ", question)
|
|
||||||
if (!question) return;
|
if (!question) return;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (question.type === null) {
|
if (question.type === null) {
|
||||||
console.log("removeQuestion")
|
|
||||||
removeQuestion(questionId);
|
removeQuestion(questionId);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -179,7 +179,6 @@ 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 => {
|
||||||
console.log("Я изменение статуса корня проекта дерева, меняю на ", id)
|
|
||||||
quiz.config.haveRoot = id
|
quiz.config.haveRoot = id
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
@ -31,4 +31,9 @@ export const updateEditSomeQuestion = (contentId?: string) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
export const updateOpenedModalSettingsId = (id?: string) => useUiTools.setState({ openedModalSettingsId: id ? id : null });
|
export const updateOpenedModalSettingsId = (id?: string) => useUiTools.setState({ openedModalSettingsId: id ? id : null });
|
||||||
|
|
||||||
|
|
||||||
|
export const updateCanCreatePublic = (can: boolean) => useUiTools.setState({ canCreatePublic: can });
|
||||||
|
|
||||||
|
export const updateModalInfoWhyCantCreate = (can: boolean) => useUiTools.setState({ openModalInfoWhyCantCreate: can });
|
@ -8,7 +8,15 @@ export type UiTools = {
|
|||||||
openBranchingPanel: boolean;
|
openBranchingPanel: boolean;
|
||||||
desireToOpenABranchingModal: string | null;
|
desireToOpenABranchingModal: string | null;
|
||||||
editSomeQuestion: string | null;
|
editSomeQuestion: string | null;
|
||||||
|
canCreatePublic: boolean;
|
||||||
|
whyCantCreatePublic: Record<string, WhyCantCreatePublic>//ид вопроса и список претензий к нему
|
||||||
|
openModalInfoWhyCantCreate: boolean;
|
||||||
};
|
};
|
||||||
|
export type WhyCantCreatePublic = {
|
||||||
|
name: string;
|
||||||
|
problems: string[]
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
const initialState: UiTools = {
|
const initialState: UiTools = {
|
||||||
openedModalSettingsId: null as null,
|
openedModalSettingsId: null as null,
|
||||||
@ -16,6 +24,9 @@ const initialState: UiTools = {
|
|||||||
openBranchingPanel: false,
|
openBranchingPanel: false,
|
||||||
desireToOpenABranchingModal: null as null,
|
desireToOpenABranchingModal: null as null,
|
||||||
editSomeQuestion: null as null,
|
editSomeQuestion: null as null,
|
||||||
|
canCreatePublic: false,
|
||||||
|
whyCantCreatePublic: {},
|
||||||
|
openModalInfoWhyCantCreate: false
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useUiTools = create<UiTools>()(
|
export const useUiTools = create<UiTools>()(
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { User } from "@frontend/kitui";
|
import { User, UserAccount } from "@frontend/kitui";
|
||||||
import { produce } from "immer";
|
import { produce } from "immer";
|
||||||
import { create } from "zustand";
|
import { create } from "zustand";
|
||||||
import { createJSONStorage, devtools, persist } from "zustand/middleware";
|
import { createJSONStorage, devtools, persist } from "zustand/middleware";
|
||||||
@ -6,12 +6,13 @@ import { createJSONStorage, devtools, persist } from "zustand/middleware";
|
|||||||
interface UserStore {
|
interface UserStore {
|
||||||
userId: string | null;
|
userId: string | null;
|
||||||
user: User | null;
|
user: User | null;
|
||||||
// userAccount: UserAccount | null;
|
userAccount: UserAccount | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const initialState: UserStore = {
|
const initialState: UserStore = {
|
||||||
userId: null,
|
userId: null,
|
||||||
user: null,
|
user: null,
|
||||||
|
userAccount: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useUserStore = create<UserStore>()(
|
export const useUserStore = create<UserStore>()(
|
||||||
@ -19,12 +20,11 @@ export const useUserStore = create<UserStore>()(
|
|||||||
devtools((set, get) => initialState, {
|
devtools((set, get) => initialState, {
|
||||||
name: "User",
|
name: "User",
|
||||||
enabled: process.env.NODE_ENV === "development",
|
enabled: process.env.NODE_ENV === "development",
|
||||||
trace: true,
|
trace: process.env.NODE_ENV === "development",
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
version: 2,
|
version: 2,
|
||||||
name: "user",
|
name: "user",
|
||||||
storage: createJSONStorage(() => localStorage),
|
|
||||||
partialize: (state) => ({
|
partialize: (state) => ({
|
||||||
userId: state.userId,
|
userId: state.userId,
|
||||||
user: state.user,
|
user: state.user,
|
||||||
@ -46,3 +46,5 @@ export const setUser = (user: User) =>
|
|||||||
);
|
);
|
||||||
|
|
||||||
export const clearUserData = () => useUserStore.setState({ ...initialState });
|
export const clearUserData = () => useUserStore.setState({ ...initialState });
|
||||||
|
|
||||||
|
export const setUserAccount = (userAccount: UserAccount) => useUserStore.setState({ userAccount });
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { FormControl, TextField, useTheme, SxProps, Theme } from "@mui/material";
|
import React, { useState } from "react";
|
||||||
|
import { Box, FormControl, TextField, Typography, useTheme } from "@mui/material";
|
||||||
import type { ChangeEvent, KeyboardEvent, FocusEvent } from "react";
|
import type { ChangeEvent, KeyboardEvent, FocusEvent } from "react";
|
||||||
import type { InputProps } from "@mui/material";
|
import type { InputProps, SxProps, Theme } from "@mui/material";
|
||||||
|
|
||||||
interface CustomTextFieldProps {
|
interface CustomTextFieldProps {
|
||||||
placeholder: string;
|
placeholder: string;
|
||||||
@ -11,6 +11,7 @@ interface CustomTextFieldProps {
|
|||||||
onKeyDown?: (event: KeyboardEvent<HTMLInputElement>) => void;
|
onKeyDown?: (event: KeyboardEvent<HTMLInputElement>) => void;
|
||||||
onBlur?: (event: FocusEvent<HTMLInputElement>) => void;
|
onBlur?: (event: FocusEvent<HTMLInputElement>) => void;
|
||||||
text?: string;
|
text?: string;
|
||||||
|
maxLength?: number;
|
||||||
sx?: SxProps<Theme>;
|
sx?: SxProps<Theme>;
|
||||||
InputProps?: Partial<InputProps>;
|
InputProps?: Partial<InputProps>;
|
||||||
}
|
}
|
||||||
@ -18,28 +19,54 @@ interface CustomTextFieldProps {
|
|||||||
export default function CustomTextField({
|
export default function CustomTextField({
|
||||||
placeholder,
|
placeholder,
|
||||||
value,
|
value,
|
||||||
text,
|
|
||||||
sx,
|
|
||||||
error,
|
|
||||||
onChange,
|
onChange,
|
||||||
onKeyDown,
|
onKeyDown,
|
||||||
onBlur,
|
onBlur,
|
||||||
|
text,
|
||||||
|
sx,
|
||||||
|
error,
|
||||||
InputProps,
|
InputProps,
|
||||||
|
maxLength = 200,
|
||||||
}: CustomTextFieldProps) {
|
}: CustomTextFieldProps) {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
|
||||||
|
const [inputValue, setInputValue] = useState(value || text || "");
|
||||||
|
const [isInputActive, setIsInputActive] = useState(false);
|
||||||
|
|
||||||
|
const handleInputChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
const inputValue = event.target.value;
|
||||||
|
setInputValue(inputValue);
|
||||||
|
|
||||||
|
if (onChange) {
|
||||||
|
onChange(event);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleInputFocus = () => {
|
||||||
|
setIsInputActive(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleInputBlur = (event: React.FocusEvent<HTMLInputElement>) => {
|
||||||
|
setIsInputActive(false);
|
||||||
|
|
||||||
|
if (onBlur) {
|
||||||
|
onBlur(event);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FormControl fullWidth variant="standard" sx={{ p: 0 }}>
|
<FormControl fullWidth variant="standard" sx={{ p: 0 }}>
|
||||||
<TextField
|
<TextField
|
||||||
defaultValue={text}
|
defaultValue={text}
|
||||||
fullWidth
|
fullWidth
|
||||||
value={value}
|
value={inputValue}
|
||||||
placeholder={placeholder}
|
placeholder={placeholder}
|
||||||
|
onChange={handleInputChange}
|
||||||
error={!!error}
|
error={!!error}
|
||||||
label={error}
|
label={error}
|
||||||
onChange={onChange}
|
onFocus={handleInputFocus}
|
||||||
|
onBlur={handleInputBlur}
|
||||||
onKeyDown={onKeyDown}
|
onKeyDown={onKeyDown}
|
||||||
onBlur={onBlur}
|
|
||||||
sx={{
|
sx={{
|
||||||
"& .MuiInputBase-root": {
|
"& .MuiInputBase-root": {
|
||||||
backgroundColor: theme.palette.background.default,
|
backgroundColor: theme.palette.background.default,
|
||||||
@ -50,19 +77,36 @@ export default function CustomTextField({
|
|||||||
fontSize: "13.5px",
|
fontSize: "13.5px",
|
||||||
marginTop: "3px",
|
marginTop: "3px",
|
||||||
},
|
},
|
||||||
...sx,
|
|
||||||
}}
|
}}
|
||||||
InputProps={InputProps}
|
InputProps={InputProps}
|
||||||
inputProps={{
|
inputProps={{
|
||||||
|
maxLength: maxLength,
|
||||||
sx: {
|
sx: {
|
||||||
borderRadius: "10px",
|
borderRadius: "10px",
|
||||||
fontSize: "18px",
|
fontSize: "18px",
|
||||||
lineHeight: "21px",
|
lineHeight: "21px",
|
||||||
py: 0,
|
py: 0,
|
||||||
},
|
},
|
||||||
|
...sx,
|
||||||
}}
|
}}
|
||||||
data-cy="textfield"
|
data-cy="textfield"
|
||||||
/>
|
/>
|
||||||
|
{isInputActive && inputValue.length >= maxLength - 7 && (
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: "flex",
|
||||||
|
marginTop: "5px",
|
||||||
|
marginLeft: "auto",
|
||||||
|
position: "absolute",
|
||||||
|
bottom: "-25px",
|
||||||
|
right: "0",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography fontSize="14px">{inputValue.length}</Typography>
|
||||||
|
<span>/</span>
|
||||||
|
<Typography fontSize="14px">{maxLength}</Typography>
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
</FormControl>
|
</FormControl>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@ import { FC, useEffect, useMemo, useRef, useState } from "react";
|
|||||||
import ReactCrop, { PercentCrop, PixelCrop } from "react-image-crop";
|
import ReactCrop, { PercentCrop, PixelCrop } from "react-image-crop";
|
||||||
import "react-image-crop/dist/ReactCrop.css";
|
import "react-image-crop/dist/ReactCrop.css";
|
||||||
import { getCroppedImageBlob, getDarkenedAndResizedImageBlob, getRotatedImageBlob } from "./utils/imageManipulation";
|
import { getCroppedImageBlob, getDarkenedAndResizedImageBlob, getRotatedImageBlob } from "./utils/imageManipulation";
|
||||||
|
import { isImageBlobAGifFile } from "../../utils/isImageBlobAGifFile";
|
||||||
|
|
||||||
|
|
||||||
const styleSlider: SxProps<Theme> = {
|
const styleSlider: SxProps<Theme> = {
|
||||||
@ -324,6 +325,9 @@ export function useCropModalState(initialOpenState = false) {
|
|||||||
image = await response.blob();
|
image = await response.blob();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const isGif = await isImageBlobAGifFile(image);
|
||||||
|
if (isGif) return;
|
||||||
|
|
||||||
setCropModalImageBlob(image);
|
setCropModalImageBlob(image);
|
||||||
setOriginalImageUrl(originalImageUrl);
|
setOriginalImageUrl(originalImageUrl);
|
||||||
setOpened(true);
|
setOpened(true);
|
||||||
|
23
src/ui_kit/ProblemIcon.tsx
Normal file
23
src/ui_kit/ProblemIcon.tsx
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
|
||||||
|
import Info from "@icons/Info";
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
blink: boolean;
|
||||||
|
onClick: (a: boolean) => void;
|
||||||
|
}
|
||||||
|
export const ProblemIcon = ({ blink, onClick }: Props) => {
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Info
|
||||||
|
sx={{
|
||||||
|
"MuiIconButton-root": {
|
||||||
|
|
||||||
|
boxShadow: "0 0 10px 10px red"
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
className={blink ? "blink" : ""}
|
||||||
|
onClick={onClick}
|
||||||
|
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
@ -24,6 +24,7 @@ export default function SwitchStepPages({
|
|||||||
quizStartPageType,
|
quizStartPageType,
|
||||||
quizResults,
|
quizResults,
|
||||||
}: Props) {
|
}: Props) {
|
||||||
|
console.log("Выбор текущей странички")
|
||||||
switch (activeStep) {
|
switch (activeStep) {
|
||||||
case 0: {
|
case 0: {
|
||||||
if (!quizType) return <StepOne />;
|
if (!quizType) return <StepOne />;
|
||||||
|
15
src/utils/isImageBlobAGifFile.ts
Normal file
15
src/utils/isImageBlobAGifFile.ts
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
const gifSignature = [0x47, 0x49, 0x46, 0x38];
|
||||||
|
|
||||||
|
export async function isImageBlobAGifFile(blob: Blob) {
|
||||||
|
const arrayBuffer = await blob.arrayBuffer();
|
||||||
|
const uint8Array = new Uint8Array(arrayBuffer);
|
||||||
|
|
||||||
|
if (
|
||||||
|
uint8Array[0] === gifSignature[0]
|
||||||
|
&& uint8Array[1] === gifSignature[1]
|
||||||
|
&& uint8Array[2] === gifSignature[2]
|
||||||
|
&& uint8Array[3] === gifSignature[3]
|
||||||
|
) return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
@ -1407,10 +1407,10 @@
|
|||||||
resolved "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.1.6.tgz"
|
resolved "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.1.6.tgz"
|
||||||
integrity sha512-OfX7E2oUDYxtBvsuS4e/jSn4Q9Qb6DzgeYtsAdkPZ47znpoNsMgZw0+tVijiv3uGNR6dgNlty6r9rzIzHjtd/A==
|
integrity sha512-OfX7E2oUDYxtBvsuS4e/jSn4Q9Qb6DzgeYtsAdkPZ47znpoNsMgZw0+tVijiv3uGNR6dgNlty6r9rzIzHjtd/A==
|
||||||
|
|
||||||
"@frontend/kitui@^1.0.54":
|
"@frontend/kitui@^1.0.55":
|
||||||
version "1.0.54"
|
version "1.0.55"
|
||||||
resolved "https://penahub.gitlab.yandexcloud.net/api/v4/projects/21/packages/npm/@frontend/kitui/-/@frontend/kitui-1.0.54.tgz#0235d5a8effb9b92351471c3c7775f28cb2839f6"
|
resolved "https://penahub.gitlab.yandexcloud.net/api/v4/projects/21/packages/npm/@frontend/kitui/-/@frontend/kitui-1.0.55.tgz#6e02f80b2c13828142ffeacaf9704e50e54324d0"
|
||||||
integrity sha1-AjXVqO/7m5I1FHHDx3dfKMsoOfY=
|
integrity sha1-bgL4CywTgoFC/+rK+XBOUOVDJNA=
|
||||||
dependencies:
|
dependencies:
|
||||||
immer "^10.0.2"
|
immer "^10.0.2"
|
||||||
reconnecting-eventsource "^1.6.2"
|
reconnecting-eventsource "^1.6.2"
|
||||||
|
Loading…
Reference in New Issue
Block a user